]> git.lyx.org Git - lyx.git/blobdiff - src/support/filetools.C
in addition to the changes mentioned in ChangeLog, there is the usual batch of whites...
[lyx.git] / src / support / filetools.C
index f7f1eaa8aaa3a9fb88bb1b24d0cedd2ee32b134a..e29bbcdd02eba81e37ace3281cdf6753aa687057 100644 (file)
@@ -17,6 +17,9 @@
 #include <config.h>
 
 #include <cctype>
+#include <utility>
+using std::make_pair;
+using std::pair;
 
 #ifdef __GNUG__
 #pragma implementation "filetools.h"
 #include "filetools.h"
 #include "lyx_gui_misc.h"
 #include "FileInfo.h"
-#include "pathstack.h"        // I know it's OS/2 specific (SMiyata)
+#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
@@ -71,16 +76,19 @@ string SpaceLess(string const & 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] = '_';
-       }
-       string temp = AddName(path, name);
-       // Replace spaces with underscores, also in directory
-       // No!!! I checked it that it is not necessary.
-       // temp.subst(' ','_');
+               name[i] &= 0x7f; // set 8th bit to 0
+       };
 
-       return temp;
+       // 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++] = '_';
+       }
+       return AddName(path, name);
 }
 
 
@@ -100,9 +108,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);
@@ -110,7 +118,7 @@ string TmpFileName(string const & dir, string const & mask)
                                if (!fnfo.newFile(ret).exist())
                                        return ret;
                        }
-       lyxerr.print("Not able to find a uniq tmpfile name.");
+       lyxerr << "Not able to find a uniq tmpfile name." << endl;
        return string();
 }
 
@@ -135,7 +143,6 @@ 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;
@@ -189,19 +196,21 @@ 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);
                
                real_file = FileSearch(path_element, name, ext);
 
                if (real_file.empty()) {
-                 tmppath = split(tmppath, path_element, ';');
+                 do {
+                   tmppath = split(tmppath, path_element, ';');
+                 } while(!tmppath.empty() && path_element.empty());
                } else {
                  notfound = false;
                }
@@ -249,7 +258,7 @@ string FileSearch(string const & path, string const & name,
 string LibFileSearch(string const & dir, string const & name, 
                      string const & ext)
 {
-        string fullname = FileSearch(AddPath(user_lyxdir,dir), name,
+        string fullname = FileSearch(AddPath(user_lyxdir, dir), name,
                                      ext); 
        if (!fullname.empty())
                return fullname;
@@ -260,7 +269,7 @@ 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);
 }
 
 
@@ -304,7 +313,9 @@ 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
@@ -325,33 +336,26 @@ 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;
        }
        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);
+               lyxerr.debug() << "Deleting file: " << unlinkpath << endl;
 
                if (remove (unlinkpath.c_str()))
                        WriteFSAlert (_("Error! Could not remove file:"), 
@@ -379,14 +383,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;
@@ -414,23 +415,17 @@ string CreateLyXTmpDir (string const & deflt)
        if ((!deflt.empty()) && (deflt  != "/tmp")) {
                if (mkdir (deflt.c_str(), 0777)) {
 #ifdef __EMX__
-                        PathPush(user_lyxdir);
+                        Path p(user_lyxdir);
 #endif
                        t = CreateTmpDir (deflt.c_str(), "lyx_tmp");
-#ifdef __EMX__
-                        PathPop();
-#endif
                         return t;
                } else
                         return deflt;
        } else {
 #ifdef __EMX__
-               PathPush(user_lyxdir);
+               Path p(user_lyxdir);
 #endif
                t = CreateTmpDir ("/tmp", "lyx_tmp");
-#ifdef __EMX__
-               PathPop();
-#endif
                return t;
        }
 }
@@ -466,15 +461,15 @@ string GetCWD ()
 {
        int n = 256;    // Assume path is less than 256 chars
        char * err;
-       char * tbuf = new char [n];
+       char * tbuf = new char[n];
        string result;
        
        // 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];
        }
 
        if (err) result = tbuf;
@@ -491,9 +486,9 @@ 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);
+       return Filename.substr(0, j + 1);
 }
 
 
@@ -505,7 +500,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;
 
@@ -527,7 +522,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
@@ -542,18 +537,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;
 #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
@@ -594,7 +589,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
@@ -611,7 +607,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
 }
 
@@ -620,7 +616,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))
@@ -630,13 +625,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
@@ -649,8 +644,6 @@ string ExpandPath(string const & path)
 // Can't handle "../../" or "/../" (Asger)
 string NormalizePath(string const & path)
 {
-       Assert(!path.empty()); // We don't allow empty path. (Lgb)
-       
        string TempBase;
        string RTemp;
        string Temp;
@@ -665,14 +658,14 @@ 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] != '/')
                                --i;
-                       if (i>=0 && TempBase[i] == '/')
+                       if (i>= 0 && TempBase[i] == '/')
                                TempBase.erase(i+1, string::npos);
                        else
                                TempBase = "../";
@@ -688,9 +681,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;
@@ -707,7 +699,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
@@ -716,14 +707,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);
@@ -737,7 +728,7 @@ string ReplaceEnvironmentPath(string const & path)
                if (!regexMatch(copy1, RegExp)) {
                        // No EndChar inside. So we are finished
                        result1 += CompareString + result0;
-                       result0.erase();
+                       result0.clear();
                        continue;
                }
 
@@ -751,7 +742,7 @@ 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;
@@ -760,11 +751,11 @@ string ReplaceEnvironmentPath(string const & path)
 
                // 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;
                }
@@ -814,8 +805,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;
@@ -867,10 +858,8 @@ string AddPath(string const & path, string const & path_2)
 
        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 + '/';
@@ -897,7 +886,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;
@@ -961,15 +950,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);
+       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 and
+       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 << "kpse status = " << c.first << "\n"
+               << "kpse result = `" << strip(c.second, '\n') << "'" << endl;
+        return c.first != -1 ? strip(c.second, '\n') : string();
+}