]> git.lyx.org Git - lyx.git/blobdiff - src/support/filetools.C
small changes read ChangeLog
[lyx.git] / src / support / filetools.C
index d1a05b8ad2e4f6941befc08a9b647ecd0220efce..52e642203bf262f1fe9295f5ee27aabd6d891ece 100644 (file)
 
 #include <cctype>
 
+#include <utility>
+#include <fstream>
+
+#ifdef HAVE_SSTREAM
+#include <sstream>
+#else
+#include <strstream>
+#endif
+
 #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
 # endif
 #endif
 
+using std::make_pair;
+using std::pair;
+using std::endl;
+using std::ifstream;
+
 extern string system_lyxdir;
 extern string build_lyxdir;
 extern string user_lyxdir;
@@ -59,29 +74,37 @@ bool IsLyXFilename(string const & filename)
 }
 
 
-bool IsSGMLFilename(string const & filename)
-{
-       return contains(filename, ".sgml");
-}
-
-
 // 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)
+{
+       // CHECK Add proper emx support here!
+#ifndef __EMX__
+       return '\'' + name + '\'';
+#else
+       return name; 
+#endif
 }
 
 
@@ -101,9 +124,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,18 +156,12 @@ 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;
-       }
-       return 1;
+       FileInfo fi(path);
+       if (fi.access(FileInfo::wperm|FileInfo::rperm)) // read-write
+               return 1;
+       if (fi.readable()) // read-only
+               return 0;
+       return -1; // everything else.
 }
 
 
@@ -160,23 +177,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;
-               }
-               }
+               FileInfo fi(path);
+               if (fi.writable()) return 1;
+               return 0;
        }
-               if (remove (tmpfl.c_str())) {
-                       WriteFSAlert(_("LyX Internal Error!"), 
-                                   _("Created test file but cannot remove it?"));
-                       return -1;
-       }
-       return 1;
 }
 
 
@@ -186,27 +190,27 @@ int IsDirWriteable (string const & path)
 // If path entry begins with $$User/, use user_lyxdir
 // Example: "$$User/doc;$$LyX/doc"
 string FileOpenSearch (string const & path, string const & name, 
-                       string const & ext)
+                      string const & ext)
 {
        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()) {
-                 do {
-                   tmppath = split(tmppath, path_element, ';');
-                 } while(!tmppath.empty() && path_element.empty());
+                       do {
+                               tmppath = split(tmppath, path_element, ';');
+                       } while(!tmppath.empty() && path_element.empty());
                } else {
-                 notfound = false;
+                       notfound = false;
                }
        }
 #ifdef __EMX__
@@ -250,33 +254,33 @@ 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;
-
+       
        if (!build_lyxdir.empty()) 
                fullname = FileSearch(AddPath(build_lyxdir, dir), 
                                      name, ext);
        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);
-
+       
        if (lang.empty() || lang == "C")
                return LibFileSearch(dir, name, ext);
        else {
                string tmp = LibFileSearch(dir, lang + '_' + name,
-                                           ext);
+                                          ext);
                if (!tmp.empty())
                        return tmp;
                else
@@ -307,19 +311,39 @@ string GetEnvPath(string const & name)
 
 bool PutEnv(string const & envstr)
 {
-#warning Look at and fix this.
+       // CHECK Look at and fix this.
         // 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 = lyx::putenv(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.
+       // The  only implementation of putenv that I have seen does not
+       // allocate memory. _And_ after testing the putenv in glibc it
+       // seems that we need to make a copy of the string contents.
+       // I will enable the above.
+       //int retval = lyx::putenv(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);
+#else
+       // No environment setting function. Can this happen?
+       int retval = 1; //return an error condition.
 #endif
 #endif
         return retval == 0;
@@ -328,39 +352,50 @@ 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());
+       // I have decided that we will be using parts from the boost
+       // library. Check out http://www.boost.org/
+       // For directory access we will then use the directory_iterator.
+       // Then the code will be something like:
+       // directory_iterator dit(path.c_str());
+       // if (<some way to detect failure>) {
+       //         WriteFSAlert(_("Error! Cannot open directory:"), path);
+       //         return -1;
+       // }
+       // for (; dit != <someend>; ++dit) {
+       //         if ((*dit) == 2." || (*dit) == "..")
+       //                 continue;
+       //         string unlinkpath = AddName(path, temp);
+       //         if (remove(unlinkpath.c_str()))
+       //                 WriteFSAlert(_("Error! Could not remove file:"),
+       //                              unlinkpath);
+       // }
+       // return 0;
+       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;
 }
 
@@ -370,7 +405,7 @@ string CreateTmpDir (string const & tempdir, string const & mask)
 {
        string tmpfl = TmpFileName(tempdir, mask);
        
-       if ((tmpfl.empty()) || mkdir (tmpfl.c_str(), 0777)) {
+       if ((tmpfl.empty()) || lyx::mkdir (tmpfl.c_str(), 0777)) {
                WriteFSAlert(_("Error! Couldn't create temporary directory:"),
                             tempdir);
                return string();
@@ -382,14 +417,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 +432,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 (lyx::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;
        }
 }
@@ -456,7 +480,7 @@ bool createDirectory(string const & path, int permission)
                return false;
        }
 
-       if (mkdir(temp.c_str(), permission)) {
+       if (lyx::mkdir(temp.c_str(), permission)) {
                WriteFSAlert (_("Error! Couldn't create directory:"), temp);
                return false;
        }
@@ -469,17 +493,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 +518,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 +532,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 +554,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 +569,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 +594,7 @@ string MakeAbsPath(string const & RelPath, string const & BasePath)
        }
 
        // returns absolute path
-       return TempBase;        
+       return TempBase;
 }
 
 
@@ -597,7 +621,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 +639,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 +648,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 +657,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 +690,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,15 +713,42 @@ 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;
 #endif
 }
 
+string GetFileContents(string const & fname) {
+       FileInfo finfo(fname);
+       if (finfo.exist()) {
+               ifstream ifs(fname.c_str());
+#ifdef HAVE_SSTREAM
+               std::ostringstream ofs;
+#else
+#warning The rumour goes that this might leak, but who really cares?
+               ostrstream ofs;
+#endif
+               if (ifs && ofs) {
+                       ofs << ifs.rdbuf();
+                       ifs.close();
+#ifdef HAVE_SSTREAM
+                       return ofs.str().c_str();
+#else
+                       ofs << '\0';
+                       char const * tmp = ofs.str();
+                       string ret(tmp);
+                       delete[] tmp;
+                       return ret;
+#endif
+               }
+       }
+       lyxerr << "LyX was not able to read file '" << fname << "'" << endl;
+       return string();
+}
+
 
 //
 // Search ${...} as Variable-Name inside the string and replace it with
@@ -708,7 +759,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 +767,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);
@@ -738,7 +788,7 @@ string ReplaceEnvironmentPath(string const & path)
                if (!regexMatch(copy1, RegExp)) {
                        // No EndChar inside. So we are finished
                        result1 += CompareString + result0;
-                       result0.clear();
+                       result0.erase();
                        continue;
                }
 
@@ -752,20 +802,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 +865,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;
@@ -833,7 +883,7 @@ string MakeRelPath(string const & abspath0, string const & basepath0)
        int j = i;
        while (j < baselen) {
                if (basepath[j] == '/') {
-                       if (j+1 == baselen) break;
+                       if (j + 1 == baselen) break;
                        buf += "../";
                }
                ++j;
@@ -841,7 +891,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 +912,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 + '/';
@@ -885,32 +932,22 @@ string AddPath(string const & path, string const & path_2)
  Strips path off if no_path == true.
  If no extension on oldname, just appends.
  */
-string ChangeExtension(string const & oldname, string const & extension, 
-                       bool no_path) 
+string ChangeExtension(string const & oldname, string const & extension)
 {
        string::size_type last_slash = oldname.rfind('/');
-       string::size_type last_dot;
-       if (last_slash != string::npos)
-               last_dot = oldname.find('.', last_slash);
-       else
-               last_dot = oldname.rfind('.');
-
+       string::size_type last_dot = oldname.rfind('.');
+       if (last_dot < last_slash && last_slash != string::npos)
+               last_dot = string::npos;
+       
        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;
-       if (no_path && last_slash != string::npos) {
-               ++last_slash; // step it
-               ret_str = oldname.substr(last_slash,
-                                        last_dot - last_slash) + ext;
-       } else
-               ret_str = oldname.substr(0, last_dot) + ext;
-       return CleanupPath(ret_str);
-}
 
+       return CleanupPath(oldname.substr(0, last_dot) + ext);
+}
 
 
 // Creates a nice compact path for displaying
@@ -962,15 +999,83 @@ 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 the file can be found directly, we just return a
+       // absolute path version of it. 
+        if (FileInfo(fil).exist())
+               return MakeAbsPath(fil);
+
+        // No we try to find it using kpsewhich.
+       // It seems from the kpsewhich manual page that it is safe to use
+       // kpsewhich without --format: "When the --format option is not
+       // given, the search path used when looking for a file is inferred
+       // from the name given, by looking for a known extension. If no
+       // known extension is found, the search path for TeX source files
+       // is used."
+       // However, we want to take advantage of the format sine almost all
+       // the different formats has environment variables that can be used
+       // to controll which paths to search. f.ex. bib looks in
+       // BIBINPUTS and TEXBIB. Small list follows:
+       // bib - BIBINPUTS, TEXBIB
+       // bst - BSTINPUTS
+       // graphic/figure - TEXPICTS, TEXINPUTS
+       // ist - TEXINDEXSTYLE, INDEXSTYLE
+       // pk - PROGRAMFONTS, PKFONTS, TEXPKS, GLYPHFONTS, TEXFONTS
+       // tex - TEXINPUTS
+       // tfm - TFMFONTS, TEXFONTS
+       // This means that to use kpsewhich in the best possible way we
+       // should help it by setting additional path in the approp. envir.var.
+        string kpsecmd = "kpsewhich " + 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();
+}