]> git.lyx.org Git - lyx.git/blobdiff - src/support/filetools.C
some new (not extensive) changes, some fixes, will probably reverto to .la libs later...
[lyx.git] / src / support / filetools.C
index d1a05b8ad2e4f6941befc08a9b647ecd0220efce..5f3e939d2045c38d9c371d5ba3a8dcaad0a59151 100644 (file)
 #include <config.h>
 
 #include <cctype>
+#include <fstream>
+using std::fstream;
+using std::ios;
+
+#include <utility>
+using std::make_pair;
+using std::pair;
 
 #ifdef __GNUG__
 #pragma implementation "filetools.h"
 #endif
 
 #include "filetools.h"
+#include "LSubstring.h"
 #include "lyx_gui_misc.h"
 #include "FileInfo.h"
 #include "support/path.h"        // I know it's OS/2 specific (SMiyata)
 #include "gettext.h"
-#include "LAssert.h"
+#include "lyxlib.h"
 
 // Which part of this is still necessary? (JMarc).
 #if HAVE_DIRENT_H
@@ -66,22 +74,38 @@ bool IsSGMLFilename(string const & filename)
 
 
 // Substitutes spaces with underscores in filename (and path)
-string SpaceLess(string const & file)
+string MakeLatexName(string const & file)
 {
        string name = OnlyFilename(file);
        string path = OnlyPath(file);
        
        for (string::size_type i = 0; i < name.length(); ++i) {
-               name[i] &= 0x7f;
-               if (!isalnum(name[i]) && name[i] != '.')
-                       name[i] = '_';
+               name[i] &= 0x7f; // set 8th bit to 0
+       };
+
+       // ok so we scan through the string twice, but who cares.
+       string keep("abcdefghijklmnopqrstuvwxyz"
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               "@!\"'()*+,-./0123456789:;<=>?[]`|");
+       
+       string::size_type pos = 0;
+       while ((pos = name.find_first_not_of(keep, pos)) != string::npos) {
+               name[pos++] = '_';
        }
-       string temp = AddName(path, name);
-       // Replace spaces with underscores, also in directory
-       // No!!! I checked it that it is not necessary.
-       // temp.subst(' ','_');
+       return AddName(path, name);
+}
 
-       return temp;
+// Substitutes spaces with underscores in filename (and path)
+string QuoteName(string const & name)
+{
+#ifdef WITH_WARNINGS
+#warning Add proper emx support here!
+#endif
+#ifndef __EMX__
+       return '\'' + name + '\'';
+#else
+       return name; 
+#endif
 }
 
 
@@ -101,9 +125,9 @@ string TmpFileName(string const & dir, string const & mask)
        // a short string...
        string ret;
        FileInfo fnfo;
-       for (int a='a'; a<= 'z'; ++a)
-               for (int b='a'; b<= 'z'; ++b)
-                       for (int c='a'; c<= 'z'; ++c) {
+       for (int a = 'a'; a <= 'z'; ++a)
+               for (int b = 'a'; b <= 'z'; ++b)
+                       for (int c = 'a'; c <= 'z'; ++c) {
                                // if this is not enough I have no idea what
                                // to do.
                                ret = tmpfl + char(a) + char(b) + char(c);
@@ -133,16 +157,13 @@ bool IsFileReadable (string const & path)
 //      -1 error (doesn't exist, no access, anything else) 
 int IsFileWriteable (string const & path)
 {
-       FilePtr fp(path, FilePtr::update);
-       if (!fp()) {
-               if ((errno == EACCES) || (errno == EROFS)) {
-                       //fp = FilePtr(path, FilePtr::read);
-                       fp.reopen(path, FilePtr::read);
-                       if (fp()) {
-                               return 0;
-                       }
-               }
-               return -1;
+       fstream fs(path.c_str(), ios::out|ios::ate);
+       if (!fs) {
+               fs.open(path.c_str(), ios::in|ios::ate);
+               if (fs)
+                       return 0;
+               else
+                       return -1;
        }
        return 1;
 }
@@ -160,23 +181,10 @@ int IsDirWriteable (string const & path)
                             _("Could not test if directory is writeable"));
                return -1;
        } else {
-       FilePtr fp(tmpfl, FilePtr::truncate);
-       if (!fp()) {
-               if (errno == EACCES) {
-                       return 0;
-               } else { 
-                       WriteFSAlert(_("LyX Internal Error!"), 
-                                    _("Cannot open directory test file"));
-                       return -1;
-               }
-               }
-       }
-               if (remove (tmpfl.c_str())) {
-                       WriteFSAlert(_("LyX Internal Error!"), 
-                                   _("Created test file but cannot remove it?"));
-                       return -1;
+               FileInfo fi(path);
+               if (fi.writable()) return 1;
+               return 0;
        }
-       return 1;
 }
 
 
@@ -190,12 +198,12 @@ string FileOpenSearch (string const & path, string const & name,
 {
        string real_file, path_element;
        bool notfound = true;
-       string tmppath=split(path, path_element, ';');
+       string tmppath = split(path, path_element, ';');
        
        while (notfound && !path_element.empty()) {
                path_element = CleanupPath(path_element);
                if (!suffixIs(path_element, '/'))
-                       path_element+='/';
+                       path_element+= '/';
                path_element = subst(path_element, "$$LyX", system_lyxdir);
                path_element = subst(path_element, "$$User", user_lyxdir);
                
@@ -250,10 +258,10 @@ string FileSearch(string const & path, string const & name,
 //   2) build_lyxdir (if not empty)
 //   3) system_lyxdir
 string LibFileSearch(string const & dir, string const & name, 
-                     string const & ext)
+                    string const & ext)
 {
-        string fullname = FileSearch(AddPath(user_lyxdir,dir), name,
-                                     ext); 
+        string fullname = FileSearch(AddPath(user_lyxdir, dir),
+                                    name, ext); 
        if (!fullname.empty())
                return fullname;
 
@@ -263,12 +271,12 @@ string LibFileSearch(string const & dir, string const & name,
        if (!fullname.empty())
                return fullname;
 
-       return FileSearch(AddPath(system_lyxdir,dir), name, ext);
+       return FileSearch(AddPath(system_lyxdir, dir), name, ext);
 }
 
 
 string i18nLibFileSearch(string const & dir, string const & name, 
-                         string const & ext)
+                        string const & ext)
 {
        string lang = token(string(GetEnv("LANG")), '_', 0);
 
@@ -307,19 +315,35 @@ string GetEnvPath(string const & name)
 
 bool PutEnv(string const & envstr)
 {
+#ifdef WITH_WARNINGS
 #warning Look at and fix this.
+#endif
         // f.ex. what about error checking?
-        int retval = 0;
 #if HAVE_PUTENV
         // this leaks, but what can we do about it?
         //   Is doing a getenv() and a free() of the older value 
         //   a good idea? (JMarc)
-        retval = putenv((new string(envstr))->c_str());
+       // Actually we don't have to leak...calling putenv like this
+       // should be enough: ... and this is obviously not enough if putenv
+       // does not make a copy of the string. It is also not very wise to
+       // put a string on the free store. If we have to leak we should do it
+       // like this:
+       /*
+       char * leaker = new char[envstr.length() + 1];
+       envstr.copy(leaker, envstr.length());
+       leaker[envstr.length()] = '\0';
+       int retval = putenv(const_cast<PUTENV_TYPE_ARG>(leaker));
+       */
+
+       // If putenv does not make a copy of the char const * this
+       // is very dangerous. OTOH if it does take a copy this is the
+       // best solution.
+       int retval = putenv(const_cast<PUTENV_TYPE_ARG>(envstr.c_str()));
 #else
 #ifdef HAVE_SETENV 
         string varname;
         string str = envstr.split(varname,'=');
-        retval = setenv(varname.c_str(), str.c_str(), true);
+        int retval = setenv(varname.c_str(), str.c_str(), true);
 #endif
 #endif
         return retval == 0;
@@ -328,39 +352,32 @@ bool PutEnv(string const & envstr)
 
 bool PutEnvPath(string const & envstr)
 {
-        string pathlist = envstr;
-#warning Verify that this is correct.
-#ifdef __EMX__
-        pathlist.subst(':', ';');
-        pathlist.subst('/', '\\');
-#endif
-        return PutEnv(pathlist);
+        return PutEnv(envstr);
 }
 
 
 static
 int DeleteAllFilesInDir (string const & path)
 {
-       DIR * dir;
-       struct dirent * de;
-       dir = opendir(path.c_str());
+       DIR * dir = opendir(path.c_str());
        if (!dir) {
                WriteFSAlert (_("Error! Cannot open directory:"), path);
                return -1;
        }
+       struct dirent * de;
        while ((de = readdir(dir))) {
                string temp = de->d_name;
-               if (temp=="." || temp=="..") 
+               if (temp == "." || temp == "..") 
                        continue;
                string unlinkpath = AddName (path, temp);
 
                lyxerr.debug() << "Deleting file: " << unlinkpath << endl;
 
-               if (remove (unlinkpath.c_str()))
+               if (remove(unlinkpath.c_str()))
                        WriteFSAlert (_("Error! Could not remove file:"), 
                                      unlinkpath);
         }
-       closedir (dir);
+       closedir(dir);
        return 0;
 }
 
@@ -382,14 +399,11 @@ string CreateTmpDir (string const & tempdir, string const & mask)
 static
 int DestroyTmpDir (string const & tmpdir, bool Allfiles)
 {
-       if ((Allfiles) && (DeleteAllFilesInDir (tmpdir))) return -1;
-       if (rmdir(tmpdir.c_str())) { 
 #ifdef __EMX__
-               if (errno == EBUSY) {
-                       chdir(user_lyxdir.c_str()); // They are in the same drive.
-                       if (!rmdir(tmpdir.c_str())) return 0;
-               }
+       Path p(user_lyxdir);
 #endif
+       if (Allfiles && DeleteAllFilesInDir(tmpdir)) return -1;
+       if (rmdir(tmpdir.c_str())) { 
                WriteFSAlert(_("Error! Couldn't delete temporary directory:"), 
                             tmpdir);
                return -1;
@@ -400,40 +414,32 @@ int DestroyTmpDir (string const & tmpdir, bool Allfiles)
 
 string CreateBufferTmpDir (string const & pathfor)
 {
-       return CreateTmpDir (pathfor, "lyx_bufrtmp");
+       return CreateTmpDir(pathfor, "lyx_bufrtmp");
 }
 
 
 int DestroyBufferTmpDir (string const & tmpdir)
 {
-       return DestroyTmpDir (tmpdir, true);
+       return DestroyTmpDir(tmpdir, true);
 }
 
 
 string CreateLyXTmpDir (string const & deflt)
 {
-       string t;        
-
        if ((!deflt.empty()) && (deflt  != "/tmp")) {
-               if (mkdir (deflt.c_str(), 0777)) {
+               if (mkdir(deflt.c_str(), 0777)) {
 #ifdef __EMX__
-                        PathPush(user_lyxdir);
-#endif
-                       t = CreateTmpDir (deflt.c_str(), "lyx_tmp");
-#ifdef __EMX__
-                        PathPop();
+                        Path p(user_lyxdir);
 #endif
+                       string t = CreateTmpDir (deflt.c_str(), "lyx_tmp");
                         return t;
                } else
                         return deflt;
        } else {
 #ifdef __EMX__
-               PathPush(user_lyxdir);
-#endif
-               t = CreateTmpDir ("/tmp", "lyx_tmp");
-#ifdef __EMX__
-               PathPop();
+               Path p(user_lyxdir);
 #endif
+               string t = CreateTmpDir ("/tmp", "lyx_tmp");
                return t;
        }
 }
@@ -469,17 +475,17 @@ string GetCWD ()
 {
        int n = 256;    // Assume path is less than 256 chars
        char * err;
-       char * tbuf = new char [n];
-       string result;
+       char * tbuf = new char[n];
        
        // Safe. Hopefully all getcwds behave this way!
-       while (((err = getcwd (tbuf, n)) == 0) && (errno == ERANGE)) {
+       while (((err = lyx::getcwd (tbuf, n)) == 0) && (errno == ERANGE)) {
                // Buffer too small, double the buffersize and try again
                delete[] tbuf;
-               n = 2*n;
-               tbuf = new char [n];
+               n = 2 * n;
+               tbuf = new char[n];
        }
 
+       string result;
        if (err) result = tbuf;
        delete[] tbuf;
        return result;
@@ -494,7 +500,7 @@ string OnlyPath(string const & Filename)
 
        // Find last / or start of filename
        string::size_type j = Filename.rfind('/');
-       if (j==string::npos)
+       if (j == string::npos)
                return "./";
        return Filename.substr(0, j + 1);
 }
@@ -508,7 +514,7 @@ string MakeAbsPath(string const & RelPath, string const & BasePath)
        // checks for already absolute path
        if (AbsolutePath(RelPath))
 #ifdef __EMX__
-               if(RelPath[0]!='/' || RelPath[0]!='\\')
+               if(RelPath[0]!= '/' && RelPath[0]!= '\\')
 #endif
                return RelPath;
 
@@ -530,7 +536,7 @@ string MakeAbsPath(string const & RelPath, string const & BasePath)
                TempBase = GetCWD();
 #ifdef __EMX__
        if (AbsolutePath(TempRel))
-               return TempBase[0] + TempRel;
+               return TempBase.substr(0, 2) + TempRel;
 #endif
 
        // Handle /./ at the end of the path
@@ -545,18 +551,18 @@ string MakeAbsPath(string const & RelPath, string const & BasePath)
                // Split by next /
                RTemp = split(RTemp, Temp, '/');
                
-               if (Temp==".") continue;
-               if (Temp=="..") {
+               if (Temp == ".") continue;
+               if (Temp == "..") {
                        // Remove one level of TempBase
-                       int i = TempBase.length()-2;
+                       int i = TempBase.length() - 2;
 #ifndef __EMX__
-                       if (i<0) i=0;
-                       while (i>0 && TempBase[i] != '/') --i;
-                       if (i>0)
+                       if (i < 0) i = 0;
+                       while (i > 0 && TempBase[i] != '/') --i;
+                       if (i > 0)
 #else
-                               if (i<2) i=2;
-                       while (i>2 && TempBase[i] != '/') --i;
-                       if (i>2)
+                       if (i < 2) i = 2;
+                       while (i > 2 && TempBase[i] != '/') --i;
+                       if (i > 2)
 #endif
                                TempBase.erase(i, string::npos);
                        else
@@ -570,7 +576,7 @@ string MakeAbsPath(string const & RelPath, string const & BasePath)
        }
 
        // returns absolute path
-       return TempBase;        
+       return TempBase;
 }
 
 
@@ -597,7 +603,8 @@ string AddName(string const & path, string const & fname)
 // Strips path from filename
 string OnlyFilename(string const & fname)
 {
-       Assert(!fname.empty()); // We don't allow empty filename. (Lgb)
+       if (fname.empty())
+               return fname;
 
        string::size_type j = fname.rfind('/');
        if (j == string::npos) // no '/' in fname
@@ -614,7 +621,7 @@ bool AbsolutePath(string const & path)
 #ifndef __EMX__
        return (!path.empty() && path[0] == '/');
 #else
-       return (!path.empty() && path[0]=='/' || (isalpha((unsigned char) path[0]) && path[1]==':'));
+       return (!path.empty() && (path[0] == '/' || (isalpha(static_cast<unsigned char>(path[0])) && path.length()>1 && path[1] == ':')));
 #endif
 }
 
@@ -623,7 +630,6 @@ bool AbsolutePath(string const & path)
 // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
 string ExpandPath(string const & path)
 {
-       Assert(!path.empty()); // We don't allow empty path. (Lgb)
        // checks for already absolute path
        string RTemp = ReplaceEnvironmentPath(path);
        if (AbsolutePath(RTemp))
@@ -633,13 +639,13 @@ string ExpandPath(string const & path)
        string copy(RTemp);
 
        // Split by next /
-       RTemp=split(RTemp, Temp, '/');
+       RTemp= split(RTemp, Temp, '/');
 
-       if (Temp==".") {
+       if (Temp == ".") {
                return GetCWD() + '/' + RTemp;
-       } else if (Temp=="~") {
+       } else if (Temp == "~") {
                return GetEnvPath("HOME") + '/' + RTemp;
-       } else if (Temp=="..") {
+       } else if (Temp == "..") {
                return MakeAbsPath(copy);
        } else
                // Don't know how to handle this
@@ -666,15 +672,15 @@ string NormalizePath(string const & path)
                // Split by next /
                RTemp = split(RTemp, Temp, '/');
                
-               if (Temp==".") {
+               if (Temp == ".") {
                        TempBase = "./";
-               } else if (Temp=="..") {
+               } else if (Temp == "..") {
                        // Remove one level of TempBase
-                       int i = TempBase.length()-2;
-                       while (i>0 && TempBase[i] != '/')
+                       int i = TempBase.length() - 2;
+                       while (i > 0 && TempBase[i] != '/')
                                --i;
-                       if (i>=0 && TempBase[i] == '/')
-                               TempBase.erase(i+1, string::npos);
+                       if (i >= 0 && TempBase[i] == '/')
+                               TempBase.erase(i + 1, string::npos);
                        else
                                TempBase = "../";
                } else {
@@ -689,9 +695,8 @@ string NormalizePath(string const & path)
 string CleanupPath(string const & path) 
 {
 #ifdef __EMX__   /* SMiyata: This should fix searchpath bug. */
-       string temppath(path);
-       subst(tmppath, '\\', '/');
-       subst(tmppath, "//", "/");
+       string temppath = subst(path, '\\', '/');
+       temppath = subst(temppath, "//", "/");
        return lowercase(temppath);
 #else // On unix, nothing to do
        return path;
@@ -708,7 +713,6 @@ string CleanupPath(string const & path)
 
 string ReplaceEnvironmentPath(string const & path)
 {
-       Assert(!path.empty()); // We don't allow empty path. (Lgb)
 // 
 // CompareChar: Environmentvariables starts with this character
 // PathChar:    Next path component start with this character
@@ -717,14 +721,14 @@ string ReplaceEnvironmentPath(string const & path)
 //      Search Environmentvariable
 //      if found: Replace Strings
 //
-       const char CompareChar = '$';
-       const char FirstChar = '{'; 
-       const char EndChar = '}'; 
-       const char UnderscoreChar = '_'; 
+       char const CompareChar = '$';
+       char const FirstChar = '{'; 
+       char const EndChar = '}'; 
+       char const UnderscoreChar = '_'; 
        string EndString; EndString += EndChar;
        string FirstString; FirstString += FirstChar;
        string CompareString; CompareString += CompareChar;
-       const string RegExp("*}*"); // Exist EndChar inside a String?
+       string const RegExp("*}*"); // Exist EndChar inside a String?
 
 // first: Search for a '$' - Sign.
        //string copy(path);
@@ -752,20 +756,20 @@ string ReplaceEnvironmentPath(string const & path)
                        continue;
                }
                // check contents of res1
-               const char * res1_contents = res1.c_str();
+               char const * res1_contents = res1.c_str();
                if (*res1_contents != FirstChar) {
                        // Again No Environmentvariable
                        result1 += CompareString;
-                       result0  = res0;
+                       result0 = res0;
                }
 
                // Check for variable names
                // Situation ${} is detected as "No Environmentvariable"
-               const char * cp1 = res1_contents+1;
-               bool result = isalpha((unsigned char) *cp1) || (*cp1 == UnderscoreChar);
+               char const * cp1 = res1_contents + 1;
+               bool result = isalpha(*cp1) || (*cp1 == UnderscoreChar);
                ++cp1;
                while (*cp1 && result) {
-                       result = isalnum((unsigned char) *cp1) || 
+                       result = isalnum(*cp1) || 
                                (*cp1 == UnderscoreChar); 
                        ++cp1;
                }
@@ -815,8 +819,8 @@ string MakeRelPath(string const & abspath0, string const & basepath0)
 
        // Go back to last /
        if (i < abslen && i < baselen
-           || (i<abslen && abspath[i] != '/' && i==baselen)
-           || (i<baselen && basepath[i] != '/' && i==abslen))
+           || (i<abslen && abspath[i] != '/' && i == baselen)
+           || (i<baselen && basepath[i] != '/' && i == abslen))
        {
                if (i) --i;     // here was the last match
                while (i && abspath[i] != '/') --i;
@@ -841,7 +845,7 @@ string MakeRelPath(string const & abspath0, string const & basepath0)
 
        // Append relative stuff from common directory to abspath
        if (abspath[i] == '/') ++i;
-       for (; i<abslen; ++i)
+       for (; i < abslen; ++i)
                buf += abspath[i];
        // Remove trailing /
        if (suffixIs(buf, '/'))
@@ -862,16 +866,13 @@ string AddPath(string const & path, string const & path_2)
        if (!path.empty() && path != "." && path != "./") {
                buf = CleanupPath(path);
                if (path[path.length() - 1] != '/')
-                                                          
                        buf += '/';
        }
 
        if (!path2.empty()){
                int p2start = path2.find_first_not_of('/');
-               //while (path2[p2start] == '/') ++p2start;
 
                int p2end = path2.find_last_not_of('/');
-               //while (path2[p2end] == '/') --p2end;
 
                string tmp = path2.substr(p2start, p2end - p2start + 1);
                buf += tmp + '/';
@@ -898,7 +899,7 @@ string ChangeExtension(string const & oldname, string const & extension,
        string ext;
        // Make sure the extension starts with a dot
        if (!extension.empty() && extension[0] != '.')
-               ext='.' + extension;
+               ext= '.' + extension;
        else
                ext = extension;
        string ret_str;
@@ -912,7 +913,6 @@ string ChangeExtension(string const & oldname, string const & extension,
 }
 
 
-
 // Creates a nice compact path for displaying
 string MakeDisplayPath (string const & path, unsigned int threshold)
 {
@@ -962,15 +962,64 @@ string MakeDisplayPath (string const & path, unsigned int threshold)
        return prefix + relhome;
 }
 
+
 bool LyXReadLink(string const & File, string & Link)
 {
        char LinkBuffer[512];
-                // Should be PATH_MAX but that needs autconf support
-       int nRead;
-       nRead = readlink(File.c_str(), LinkBuffer,sizeof(LinkBuffer)-1);
+       // Should be PATH_MAX but that needs autconf support
+       int nRead = readlink(File.c_str(), LinkBuffer, sizeof(LinkBuffer)-1);
        if (nRead <= 0)
                return false;
        LinkBuffer[nRead] = 0;
        Link = LinkBuffer;
        return true;
 }
+
+
+typedef pair<int, string> cmdret;
+static cmdret do_popen(string const & cmd)
+{
+       // One question is if we should use popen or
+       // create our own popen based on fork, exec, pipe
+       // of course the best would be to have a
+       // pstream (process stream), with the
+       // variants ipstream, opstream
+       FILE * inf = popen(cmd.c_str(), "r");
+       string ret;
+       int c = fgetc(inf);
+       while (c != EOF) {
+               ret += static_cast<char>(c);
+               c = fgetc(inf);
+       }
+       int pret = pclose(inf);
+       return make_pair(pret, ret);
+}
+
+
+string findtexfile(string const & fil, string const & format)
+{
+       /* There is no problem to extend this function too use other
+          methods to look for files. It could be setup to look
+          in environment paths and also if wanted as a last resort
+          to a recursive find. One of the easier extensions would
+          perhaps be to use the LyX file lookup methods. But! I am
+          going to implement this until I see some demand for it.
+          Lgb
+       */
+       
+        // If fil is a file with absolute path we just return it
+        if (AbsolutePath(fil)) return fil;
+       
+        // Check in the current dir.
+        if (FileInfo(OnlyFilename(fil)).exist())
+               return OnlyFilename(fil);
+       
+        // No we try to find it using kpsewhich.
+        string kpsecmd = "kpsewhich --format= " + format + " " + OnlyFilename(fil);
+        cmdret c = do_popen(kpsecmd);
+       
+        lyxerr[Debug::LATEX] << "kpse status = " << c.first << "\n"
+                            << "kpse result = `" << strip(c.second, '\n') 
+                            << "'" << endl;
+        return c.first != -1 ? strip(c.second, '\n') : string();
+}