2 filetools.C (former paths.C) - part of LyX project
3 General path-mangling functions
4 Copyright 1996 Ivan Schreter
5 Parts Copyright 1996 Dirk Niggemann
6 Parts Copyright 1985, 1990, 1993 Free Software Foundation, Inc.
7 Parts Copyright 1996 Asger Alstrup
11 lyx-filetool.C : tools functions for file/path handling
12 this file is part of LyX, the High Level Word Processor
13 Copyright 1995-1996, Matthias Ettrich and the LyX Team
27 #pragma implementation "filetools.h"
35 #include "support/lstrings.h"
37 #include "filetools.h"
38 #include "LSubstring.h"
39 #include "frontends/Alert.h"
41 #include "support/path.h" // I know it's OS/2 specific (SMiyata)
46 // Which part of this is still necessary? (JMarc).
49 # define NAMLEN(dirent) strlen((dirent)->d_name)
51 # define dirent direct
52 # define NAMLEN(dirent) (dirent)->d_namlen
54 # include <sys/ndir.h>
70 extern string system_lyxdir;
71 extern string build_lyxdir;
72 extern string user_lyxdir;
73 extern string system_tempdir;
76 bool IsLyXFilename(string const & filename)
78 return suffixIs(lowercase(filename), ".lyx");
82 bool IsSGMLFilename(string const & filename)
84 return suffixIs(lowercase(filename), ".sgml");
88 // Substitutes spaces with underscores in filename (and path)
89 string const MakeLatexName(string const & file)
91 string name = OnlyFilename(file);
92 string const path = OnlyPath(file);
94 for (string::size_type i = 0; i < name.length(); ++i) {
95 name[i] &= 0x7f; // set 8th bit to 0
98 // ok so we scan through the string twice, but who cares.
99 string const keep("abcdefghijklmnopqrstuvwxyz"
100 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
101 "@!\"'()*+,-./0123456789:;<=>?[]`|");
103 string::size_type pos = 0;
104 while ((pos = name.find_first_not_of(keep, pos)) != string::npos) {
107 return AddName(path, name);
111 // Substitutes spaces with underscores in filename (and path)
112 string const QuoteName(string const & name)
114 return (os::shell() == os::UNIX) ?
120 // Is a file readable ?
121 bool IsFileReadable (string const & path)
124 if (file.isOK() && file.isRegular() && file.readable())
131 // Is a file read_only?
132 // return 1 read-write
134 // -1 error (doesn't exist, no access, anything else)
135 int IsFileWriteable (string const & path)
139 if (fi.access(FileInfo::wperm|FileInfo::rperm)) // read-write
141 if (fi.readable()) // read-only
143 return -1; // everything else.
147 //returns true: dir writeable
148 // false: not writeable
149 bool IsDirWriteable (string const & path)
151 lyxerr[Debug::FILES] << "IsDirWriteable: " << path << endl;
153 string const tmpfl(lyx::tempName(path, "lyxwritetest"));
163 // Uses a string of paths separated by ";"s to find a file to open.
164 // Can't cope with pathnames with a ';' in them. Returns full path to file.
165 // If path entry begins with $$LyX/, use system_lyxdir
166 // If path entry begins with $$User/, use user_lyxdir
167 // Example: "$$User/doc;$$LyX/doc"
168 string const FileOpenSearch (string const & path, string const & name,
171 string real_file, path_element;
172 bool notfound = true;
173 string tmppath = split(path, path_element, ';');
175 while (notfound && !path_element.empty()) {
176 path_element = os::slashify_path(path_element);
177 if (!suffixIs(path_element, '/'))
179 path_element = subst(path_element, "$$LyX", system_lyxdir);
180 path_element = subst(path_element, "$$User", user_lyxdir);
182 real_file = FileSearch(path_element, name, ext);
184 if (real_file.empty()) {
186 tmppath = split(tmppath, path_element, ';');
187 } while (!tmppath.empty() && path_element.empty());
193 if (ext.empty() && notfound) {
194 real_file = FileOpenSearch(path, name, "exe");
195 if (notfound) real_file = FileOpenSearch(path, name, "cmd");
202 /// Returns a vector of all files in directory dir having extension ext.
203 vector<string> const DirList(string const & dir, string const & ext)
205 // This is a non-error checking C/system implementation
206 string extension(ext);
207 if (!extension.empty() && extension[0] != '.')
208 extension.insert(0, ".");
209 vector<string> dirlist;
210 DIR * dirp = ::opendir(dir.c_str());
213 << "Directory \"" << dir
214 << "\" does not exist to DirList." << endl;
219 while ((dire = ::readdir(dirp))) {
220 string const fil = dire->d_name;
221 if (suffixIs(fil, extension)) {
222 dirlist.push_back(fil);
227 /* I would have prefered to take a vector<string>& as parameter so
228 that we could avoid the copy of the vector when returning.
230 dirlist.swap(argvec);
231 to avoid the copy. (Lgb)
233 /* A C++ implementaion will look like this:
234 string extension(ext);
235 if (extension[0] != '.') extension.insert(0, ".");
236 vector<string> dirlist;
237 directory_iterator dit("dir");
238 while (dit != directory_iterator()) {
239 string fil = dit->filename;
240 if (prefixIs(fil, extension)) {
241 dirlist.push_back(fil);
245 dirlist.swap(argvec);
251 // Returns the real name of file name in directory path, with optional
253 string const FileSearch(string const & path, string const & name,
256 // if `name' is an absolute path, we ignore the setting of `path'
257 // Expand Environmentvariables in 'name'
258 string const tmpname = ReplaceEnvironmentPath(name);
259 string fullname = MakeAbsPath(tmpname, path);
260 // search first without extension, then with it.
261 if (IsFileReadable(fullname))
263 else if (ext.empty())
265 else { // Is it not more reasonable to use ChangeExtension()? (SMiyata)
268 if (IsFileReadable(fullname))
276 // Search the file name.ext in the subdirectory dir of
278 // 2) build_lyxdir (if not empty)
280 string const LibFileSearch(string const & dir, string const & name,
283 string fullname = FileSearch(AddPath(user_lyxdir, dir), name, ext);
284 if (!fullname.empty())
287 if (!build_lyxdir.empty())
288 fullname = FileSearch(AddPath(build_lyxdir, dir), name, ext);
289 if (!fullname.empty())
292 return FileSearch(AddPath(system_lyxdir, dir), name, ext);
297 i18nLibFileSearch(string const & dir, string const & name,
300 // this comment is from intl/dcigettext.c. We try to mimick this
302 /* The highest priority value is the `LANGUAGE' environment
303 variable. But we don't use the value if the currently
304 selected locale is the C locale. This is a GNU extension. */
306 string const lc_all = GetEnv("LC_ALL");
307 string lang = GetEnv("LANGUAGE");
308 if (lang.empty() || lc_all == "C") {
311 lang = GetEnv("LANG");
315 lang = token(lang, '_', 0);
317 if (lang.empty() || lang == "C")
318 return LibFileSearch(dir, name, ext);
320 string const tmp = LibFileSearch(dir, lang + '_' + name,
325 return LibFileSearch(dir, name, ext);
330 string const GetEnv(string const & envname)
332 // f.ex. what about error checking?
333 char const * const ch = getenv(envname.c_str());
334 string const envstr = !ch ? "" : ch;
339 string const GetEnvPath(string const & name)
342 string const pathlist = subst(GetEnv(name), ':', ';');
344 string const pathlist = os::slashify_path(GetEnv(name));
346 return strip(pathlist, ';');
350 bool PutEnv(string const & envstr)
352 // CHECK Look at and fix this.
353 // f.ex. what about error checking?
356 // this leaks, but what can we do about it?
357 // Is doing a getenv() and a free() of the older value
358 // a good idea? (JMarc)
359 // Actually we don't have to leak...calling putenv like this
360 // should be enough: ... and this is obviously not enough if putenv
361 // does not make a copy of the string. It is also not very wise to
362 // put a string on the free store. If we have to leak we should do it
364 char * leaker = new char[envstr.length() + 1];
365 envstr.copy(leaker, envstr.length());
366 leaker[envstr.length()] = '\0';
367 int const retval = lyx::putenv(leaker);
369 // If putenv does not make a copy of the char const * this
370 // is very dangerous. OTOH if it does take a copy this is the
372 // The only implementation of putenv that I have seen does not
373 // allocate memory. _And_ after testing the putenv in glibc it
374 // seems that we need to make a copy of the string contents.
375 // I will enable the above.
376 //int retval = lyx::putenv(envstr.c_str());
380 string const str = envstr.split(varname,'=');
381 int const retval = ::setenv(varname.c_str(), str.c_str(), true);
383 // No environment setting function. Can this happen?
384 int const retval = 1; //return an error condition.
391 bool PutEnvPath(string const & envstr)
393 return PutEnv(envstr);
399 int DeleteAllFilesInDir (string const & path)
401 // I have decided that we will be using parts from the boost
402 // library. Check out http://www.boost.org/
403 // For directory access we will then use the directory_iterator.
404 // Then the code will be something like:
405 // directory_iterator dit(path);
406 // directory_iterator dend;
407 // if (dit == dend) {
408 // Alert::err_alert(_("Error! Cannot open directory:"), path);
411 // for (; dit != dend; ++dit) {
412 // string filename(*dit);
413 // if (filename == "." || filename == "..")
415 // string unlinkpath(AddName(path, filename));
416 // if (lyx::unlink(unlinkpath))
417 // Alert::err_alert(_("Error! Could not remove file:"),
421 DIR * dir = ::opendir(path.c_str());
423 Alert::err_alert (_("Error! Cannot open directory:"), path);
427 int return_value = 0;
428 while ((de = readdir(dir))) {
429 string const temp = de->d_name;
430 if (temp == "." || temp == "..")
432 string const unlinkpath = AddName (path, temp);
434 lyxerr[Debug::FILES] << "Deleting file: " << unlinkpath
438 FileInfo fi(unlinkpath);
439 if (fi.isOK() && fi.isDir())
440 deleted = (DeleteAllFilesInDir(unlinkpath) == 0);
441 deleted &= (lyx::unlink(unlinkpath) == 0);
443 Alert::err_alert(_("Error! Could not remove file:"),
453 string const CreateTmpDir(string const & tempdir, string const & mask)
456 << "CreateTmpDir: tempdir=`" << tempdir << "'\n"
457 << "CreateTmpDir: mask=`" << mask << "'" << endl;
459 string const tmpfl(lyx::tempName(tempdir, mask));
460 // lyx::tempName actually creates a file to make sure that it
461 // stays unique. So we have to delete it before we can create
462 // a dir with the same name. Note also that we are not thread
463 // safe because of the gap between unlink and mkdir. (Lgb)
464 lyx::unlink(tmpfl.c_str());
466 if (tmpfl.empty() || lyx::mkdir(tmpfl, 0700)) {
467 Alert::err_alert(_("Error! Couldn't create temporary directory:"),
471 return MakeAbsPath(tmpfl);
475 int DestroyTmpDir(string const & tmpdir, bool Allfiles)
480 if (Allfiles && DeleteAllFilesInDir(tmpdir)) {
483 if (lyx::rmdir(tmpdir)) {
484 Alert::err_alert(_("Error! Couldn't delete temporary directory:"),
494 string const CreateBufferTmpDir(string const & pathfor)
497 static string const tmpdir(pathfor.empty() ? os::getTmpDir() : pathfor);
498 // We are in our own directory. Why bother to mangle name?
499 // In fact I wrote this code to circumvent a problematic behaviour (bug?)
501 string const tmpfl = tmpdir + "/lyx_tmpbuf" + tostr(count++);
502 if (lyx::mkdir(tmpfl, 0777)) {
503 Alert::err_alert(_("Error! Couldn't create temporary directory:"),
511 int DestroyBufferTmpDir(string const & tmpdir)
513 return DestroyTmpDir(tmpdir, true);
517 string const CreateLyXTmpDir(string const & deflt)
519 if ((!deflt.empty()) && (deflt != "/tmp")) {
520 if (lyx::mkdir(deflt, 0777)) {
524 return CreateTmpDir(deflt, "lyx_tmpdir");
531 return CreateTmpDir("/tmp", "lyx_tmpdir");
536 int DestroyLyXTmpDir(string const & tmpdir)
538 return DestroyTmpDir (tmpdir, false); // Why false?
542 // Creates directory. Returns true if succesfull
543 bool createDirectory(string const & path, int permission)
545 string temp(strip(os::slashify_path(path), '/'));
548 Alert::alert(_("Internal error!"),
549 _("Call to createDirectory with invalid name"));
553 if (lyx::mkdir(temp, permission)) {
554 Alert::err_alert (_("Error! Couldn't create directory:"), temp);
561 // Strip filename from path name
562 string const OnlyPath(string const & Filename)
564 // If empty filename, return empty
565 if (Filename.empty()) return Filename;
567 // Find last / or start of filename
568 string::size_type j = Filename.rfind('/');
569 if (j == string::npos)
571 return Filename.substr(0, j + 1);
575 // Convert relative path into absolute path based on a basepath.
576 // If relpath is absolute, just use that.
577 // If basepath is empty, use CWD as base.
578 string const MakeAbsPath(string const & RelPath, string const & BasePath)
580 // checks for already absolute path
581 if (os::is_absolute_path(RelPath))
584 // Copies given paths
585 string TempRel(os::slashify_path(RelPath));
586 // Since TempRel is NOT absolute, we can safely replace "//" with "/"
587 TempRel = subst(TempRel, "//", "/");
591 if (os::is_absolute_path(BasePath))
594 TempBase = AddPath(lyx::getcwd(), BasePath);
596 // Handle /./ at the end of the path
597 while (suffixIs(TempBase, "/./"))
598 TempBase.erase(TempBase.length() - 2);
600 // processes relative path
601 string RTemp(TempRel);
604 while (!RTemp.empty()) {
606 RTemp = split(RTemp, Temp, '/');
608 if (Temp == ".") continue;
610 // Remove one level of TempBase
611 string::difference_type i = TempBase.length() - 2;
614 while (i > 0 && TempBase[i] != '/') --i;
618 while (i > 2 && TempBase[i] != '/') --i;
621 TempBase.erase(i, string::npos);
624 } else if (Temp.empty() && !RTemp.empty()) {
625 TempBase = os::current_root() + RTemp;
628 // Add this piece to TempBase
629 if (!suffixIs(TempBase, '/'))
635 // returns absolute path
636 return os::slashify_path(TempBase);
640 // Correctly append filename to the pathname.
641 // If pathname is '.', then don't use pathname.
642 // Chops any path of filename.
643 string const AddName(string const & path, string const & fname)
646 string const basename(OnlyFilename(fname));
650 if (path != "." && path != "./" && !path.empty()) {
651 buf = os::slashify_path(path);
652 if (!suffixIs(path, '/'))
656 return buf + basename;
660 // Strips path from filename
661 string const OnlyFilename(string const & fname)
666 string::size_type j = fname.rfind('/');
667 if (j == string::npos) // no '/' in fname
671 return fname.substr(j + 1);
675 /// Returns true is path is absolute
676 bool AbsolutePath(string const & path)
678 return os::is_absolute_path(path);
683 // Create absolute path. If impossible, don't do anything
684 // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
685 string const ExpandPath(string const & path)
687 // checks for already absolute path
688 string RTemp(ReplaceEnvironmentPath(path));
689 if (os::is_absolute_path(RTemp))
693 string const copy(RTemp);
696 RTemp = split(RTemp, Temp, '/');
699 return lyx::getcwd() /*GetCWD()*/ + '/' + RTemp;
702 return GetEnvPath("HOME") + '/' + RTemp;
705 return MakeAbsPath(copy);
707 // Don't know how to handle this
713 // Constracts path/../path
714 // Can't handle "../../" or "/../" (Asger)
715 string const NormalizePath(string const & path)
721 if (os::is_absolute_path(path))
724 // Make implicit current directory explicit
727 while (!RTemp.empty()) {
729 RTemp = split(RTemp, Temp, '/');
733 } else if (Temp == "..") {
734 // Remove one level of TempBase
735 string::difference_type i = TempBase.length() - 2;
736 while (i > 0 && TempBase[i] != '/')
738 if (i >= 0 && TempBase[i] == '/')
739 TempBase.erase(i + 1, string::npos);
743 TempBase += Temp + '/';
747 // returns absolute path
752 string const GetFileContents(string const & fname)
754 FileInfo finfo(fname);
756 ifstream ifs(fname.c_str());
761 return ofs.str().c_str();
764 lyxerr << "LyX was not able to read file '" << fname << "'" << endl;
770 // Search ${...} as Variable-Name inside the string and replace it with
771 // the denoted environmentvariable
772 // Allow Variables according to
773 // variable := '$' '{' [A-Za-z_]{[A-Za-z_0-9]*} '}'
776 string const ReplaceEnvironmentPath(string const & path)
779 // CompareChar: Environmentvariables starts with this character
780 // PathChar: Next path component start with this character
781 // while CompareChar found do:
782 // Split String with PathChar
783 // Search Environmentvariable
784 // if found: Replace Strings
786 char const CompareChar = '$';
787 char const FirstChar = '{';
788 char const EndChar = '}';
789 char const UnderscoreChar = '_';
790 string EndString; EndString += EndChar;
791 string FirstString; FirstString += FirstChar;
792 string CompareString; CompareString += CompareChar;
793 string const RegExp("*}*"); // Exist EndChar inside a String?
795 // first: Search for a '$' - Sign.
797 string result1; //(copy); // for split-calls
798 string result0 = split(path, result1, CompareChar);
799 while (!result0.empty()) {
800 string copy1(result0); // contains String after $
802 // Check, if there is an EndChar inside original String.
804 if (!regexMatch(copy1, RegExp)) {
805 // No EndChar inside. So we are finished
806 result1 += CompareString + result0;
812 string res0 = split(copy1, res1, EndChar);
813 // Now res1 holds the environmentvariable
814 // First, check, if Contents is ok.
815 if (res1.empty()) { // No environmentvariable. Continue Loop.
816 result1 += CompareString + FirstString;
820 // check contents of res1
821 char const * res1_contents = res1.c_str();
822 if (*res1_contents != FirstChar) {
823 // Again No Environmentvariable
824 result1 += CompareString;
828 // Check for variable names
829 // Situation ${} is detected as "No Environmentvariable"
830 char const * cp1 = res1_contents + 1;
831 bool result = isalpha(*cp1) || (*cp1 == UnderscoreChar);
833 while (*cp1 && result) {
834 result = isalnum(*cp1) ||
835 (*cp1 == UnderscoreChar);
840 // no correct variable name
841 result1 += CompareString + res1 + EndString;
842 result0 = split(res0, res1, CompareChar);
847 string env(GetEnv(res1_contents + 1));
849 // Congratulations. Environmentvariable found
852 result1 += CompareString + res1 + EndString;
855 result0 = split(res0, res1, CompareChar);
859 } // ReplaceEnvironmentPath
862 // Make relative path out of two absolute paths
863 string const MakeRelPath(string const & abspath, string const & basepath)
864 // Makes relative path out of absolute path. If it is deeper than basepath,
865 // it's easy. If basepath and abspath share something (they are all deeper
866 // than some directory), it'll be rendered using ..'s. If they are completely
867 // different, then the absolute path will be used as relative path.
869 string::size_type const abslen = abspath.length();
870 string::size_type const baselen = basepath.length();
872 string::size_type i = os::common_path(abspath, basepath);
875 // actually no match - cannot make it relative
879 // Count how many dirs there are in basepath above match
880 // and append as many '..''s into relpath
882 string::size_type j = i;
883 while (j < baselen) {
884 if (basepath[j] == '/') {
885 if (j + 1 == baselen)
892 // Append relative stuff from common directory to abspath
893 if (abspath[i] == '/')
895 for (; i < abslen; ++i)
898 if (suffixIs(buf, '/'))
899 buf.erase(buf.length() - 1);
900 // Substitute empty with .
907 // Append sub-directory(ies) to a path in an intelligent way
908 string const AddPath(string const & path, string const & path_2)
911 string const path2 = os::slashify_path(path_2);
913 if (!path.empty() && path != "." && path != "./") {
914 buf = os::slashify_path(path);
915 if (path[path.length() - 1] != '/')
919 if (!path2.empty()) {
920 string::size_type const p2start = path2.find_first_not_of('/');
921 string::size_type const p2end = path2.find_last_not_of('/');
922 string const tmp = path2.substr(p2start, p2end - p2start + 1);
930 Change extension of oldname to extension.
931 Strips path off if no_path == true.
932 If no extension on oldname, just appends.
934 string const ChangeExtension(string const & oldname, string const & extension)
936 string::size_type const last_slash = oldname.rfind('/');
937 string::size_type last_dot = oldname.rfind('.');
938 if (last_dot < last_slash && last_slash != string::npos)
939 last_dot = string::npos;
942 // Make sure the extension starts with a dot
943 if (!extension.empty() && extension[0] != '.')
944 ext= "." + extension;
948 return os::slashify_path(oldname.substr(0, last_dot) + ext);
952 /// Return the extension of the file (not including the .)
953 string const GetExtension(string const & name)
955 string::size_type const last_slash = name.rfind('/');
956 string::size_type const last_dot = name.rfind('.');
957 if (last_dot != string::npos &&
958 (last_slash == string::npos || last_dot > last_slash))
959 return name.substr(last_dot + 1,
960 name.length() - (last_dot + 1));
966 // Creates a nice compact path for displaying
968 MakeDisplayPath (string const & path, unsigned int threshold)
970 string::size_type const l1 = path.length();
972 // First, we try a relative path compared to home
973 string const home(GetEnvPath("HOME"));
974 string relhome = MakeRelPath(path, home);
976 string::size_type l2 = relhome.length();
980 // If we backup from home or don't have a relative path,
981 // this try is no good
982 if (prefixIs(relhome, "../") || os::is_absolute_path(relhome)) {
983 // relative path was no good, just use the original path
990 // Is the path too long?
991 if (l2 > threshold) {
997 while (relhome.length() > threshold)
998 relhome = split(relhome, temp, '/');
1000 // Did we shortend everything away?
1001 if (relhome.empty()) {
1002 // Yes, filename in itself is too long.
1003 // Pick the start and the end of the filename.
1004 relhome = OnlyFilename(path);
1005 string const head = relhome.substr(0, threshold/2 - 3);
1007 l2 = relhome.length();
1009 relhome.substr(l2 - threshold/2 - 2, l2 - 1);
1010 relhome = head + "..." + tail;
1013 return prefix + relhome;
1017 bool LyXReadLink(string const & File, string & Link)
1019 char LinkBuffer[512];
1020 // Should be PATH_MAX but that needs autconf support
1021 int const nRead = ::readlink(File.c_str(),
1022 LinkBuffer, sizeof(LinkBuffer) - 1);
1025 LinkBuffer[nRead] = '\0'; // terminator
1033 typedef pair<int, string> cmdret;
1035 cmdret const do_popen(string const & cmd)
1037 // One question is if we should use popen or
1038 // create our own popen based on fork, exec, pipe
1039 // of course the best would be to have a
1040 // pstream (process stream), with the
1041 // variants ipstream, opstream
1042 FILE * inf = ::popen(cmd.c_str(), "r");
1046 ret += static_cast<char>(c);
1049 int const pret = pclose(inf);
1050 return make_pair(pret, ret);
1056 string const findtexfile(string const & fil, string const & /*format*/)
1058 /* There is no problem to extend this function too use other
1059 methods to look for files. It could be setup to look
1060 in environment paths and also if wanted as a last resort
1061 to a recursive find. One of the easier extensions would
1062 perhaps be to use the LyX file lookup methods. But! I am
1063 going to implement this until I see some demand for it.
1067 // If the file can be found directly, we just return a
1068 // absolute path version of it.
1069 if (FileInfo(fil).exist())
1070 return MakeAbsPath(fil);
1072 // No we try to find it using kpsewhich.
1073 // It seems from the kpsewhich manual page that it is safe to use
1074 // kpsewhich without --format: "When the --format option is not
1075 // given, the search path used when looking for a file is inferred
1076 // from the name given, by looking for a known extension. If no
1077 // known extension is found, the search path for TeX source files
1079 // However, we want to take advantage of the format sine almost all
1080 // the different formats has environment variables that can be used
1081 // to controll which paths to search. f.ex. bib looks in
1082 // BIBINPUTS and TEXBIB. Small list follows:
1083 // bib - BIBINPUTS, TEXBIB
1085 // graphic/figure - TEXPICTS, TEXINPUTS
1086 // ist - TEXINDEXSTYLE, INDEXSTYLE
1087 // pk - PROGRAMFONTS, PKFONTS, TEXPKS, GLYPHFONTS, TEXFONTS
1089 // tfm - TFMFONTS, TEXFONTS
1090 // This means that to use kpsewhich in the best possible way we
1091 // should help it by setting additional path in the approp. envir.var.
1092 string const kpsecmd = "kpsewhich " + fil;
1094 cmdret const c = do_popen(kpsecmd);
1096 lyxerr[Debug::LATEX] << "kpse status = " << c.first << "\n"
1097 << "kpse result = `" << strip(c.second, '\n')
1100 return os::internal_path(strip(strip(c.second, '\n'), '\r'));
1106 void removeAutosaveFile(string const & filename)
1108 string a = OnlyPath(filename);
1110 a += OnlyFilename(filename);
1112 FileInfo const fileinfo(a);
1113 if (fileinfo.exist()) {
1114 if (lyx::unlink(a) != 0) {
1115 Alert::err_alert(_("Could not delete auto-save file!"), a);