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"
30 #include "filetools.h"
31 #include "LSubstring.h"
32 #include "lyx_gui_misc.h"
34 #include "support/path.h" // I know it's OS/2 specific (SMiyata)
35 #include "support/syscall.h"
39 // Which part of this is still necessary? (JMarc).
42 # define NAMLEN(dirent) strlen((dirent)->d_name)
44 # define dirent direct
45 # define NAMLEN(dirent) (dirent)->d_namlen
47 # 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 contains(filename, ".lyx");
82 bool IsSGMLFilename(string const & filename)
84 return contains(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 // CHECK Add proper emx support here!
116 return "\'" + name + "\'";
123 // Is a file readable ?
124 bool IsFileReadable (string const & path)
127 if (file.isOK() && file.isRegular() && file.readable())
134 // Is a file read_only?
135 // return 1 read-write
137 // -1 error (doesn't exist, no access, anything else)
138 int IsFileWriteable (string const & path)
141 if (fi.access(FileInfo::wperm|FileInfo::rperm)) // read-write
143 if (fi.readable()) // read-only
145 return -1; // everything else.
149 //returns 1: dir writeable
151 // -1: error- couldn't find out
152 int IsDirWriteable (string const & path)
154 string const tmpfl(lyx::tempName(path, "lyxwritetest"));
155 // We must unlink the tmpfl.
159 WriteFSAlert(_("LyX Internal Error!"),
160 _("Could not test if directory is writeable"));
164 if (fi.writable()) return 1;
170 // Uses a string of paths separated by ";"s to find a file to open.
171 // Can't cope with pathnames with a ';' in them. Returns full path to file.
172 // If path entry begins with $$LyX/, use system_lyxdir
173 // If path entry begins with $$User/, use user_lyxdir
174 // Example: "$$User/doc;$$LyX/doc"
175 string const FileOpenSearch (string const & path, string const & name,
178 string real_file, path_element;
179 bool notfound = true;
180 string tmppath = split(path, path_element, ';');
182 while (notfound && !path_element.empty()) {
183 path_element = CleanupPath(path_element);
184 if (!suffixIs(path_element, '/'))
186 path_element = subst(path_element, "$$LyX", system_lyxdir);
187 path_element = subst(path_element, "$$User", user_lyxdir);
189 real_file = FileSearch(path_element, name, ext);
191 if (real_file.empty()) {
193 tmppath = split(tmppath, path_element, ';');
194 } while(!tmppath.empty() && path_element.empty());
200 if (ext.empty() && notfound) {
201 real_file = FileOpenSearch(path, name, "exe");
202 if (notfound) real_file = FileOpenSearch(path, name, "cmd");
209 /// Returns a vector of all files in directory dir having extension ext.
210 vector<string> const DirList(string const & dir, string const & ext)
212 // This is a non-error checking C/system implementation
213 string extension(ext);
214 if (!extension.empty() && extension[0] != '.')
215 extension.insert(0, ".");
216 vector<string> dirlist;
217 DIR * dirp = ::opendir(dir.c_str());
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);
261 // search first without extension, then with it.
262 if (IsFileReadable(fullname))
264 else if (ext.empty())
266 else { // Is it not more reasonable to use ChangeExtension()? (SMiyata)
269 if (IsFileReadable(fullname))
277 // Search the file name.ext in the subdirectory dir of
279 // 2) build_lyxdir (if not empty)
281 string const LibFileSearch(string const & dir, string const & name,
284 string fullname = FileSearch(AddPath(user_lyxdir, dir),
286 if (!fullname.empty())
289 if (!build_lyxdir.empty())
290 fullname = FileSearch(AddPath(build_lyxdir, dir),
292 if (!fullname.empty())
295 return FileSearch(AddPath(system_lyxdir, dir), name, ext);
300 i18nLibFileSearch(string const & dir, string const & name,
303 string const lang = token(string(GetEnv("LANG")), '_', 0);
305 if (lang.empty() || lang == "C")
306 return LibFileSearch(dir, name, ext);
308 string const tmp = LibFileSearch(dir, lang + '_' + name,
313 return LibFileSearch(dir, name, ext);
318 string const GetEnv(string const & envname)
320 // f.ex. what about error checking?
321 char const * const ch = getenv(envname.c_str());
322 string const envstr = !ch ? "" : ch;
327 string const GetEnvPath(string const & name)
330 string const pathlist = subst(GetEnv(name), ':', ';');
332 string const pathlist = subst(GetEnv(name), '\\', '/');
334 return strip(pathlist, ';');
338 bool PutEnv(string const & envstr)
340 // CHECK Look at and fix this.
341 // f.ex. what about error checking?
344 // this leaks, but what can we do about it?
345 // Is doing a getenv() and a free() of the older value
346 // a good idea? (JMarc)
347 // Actually we don't have to leak...calling putenv like this
348 // should be enough: ... and this is obviously not enough if putenv
349 // does not make a copy of the string. It is also not very wise to
350 // put a string on the free store. If we have to leak we should do it
352 char * leaker = new char[envstr.length() + 1];
353 envstr.copy(leaker, envstr.length());
354 leaker[envstr.length()] = '\0';
355 int const retval = lyx::putenv(leaker);
357 // If putenv does not make a copy of the char const * this
358 // is very dangerous. OTOH if it does take a copy this is the
360 // The only implementation of putenv that I have seen does not
361 // allocate memory. _And_ after testing the putenv in glibc it
362 // seems that we need to make a copy of the string contents.
363 // I will enable the above.
364 //int retval = lyx::putenv(envstr.c_str());
368 string const str = envstr.split(varname,'=');
369 int const retval = ::setenv(varname.c_str(), str.c_str(), true);
371 // No environment setting function. Can this happen?
372 int const retval = 1; //return an error condition.
379 bool PutEnvPath(string const & envstr)
381 return PutEnv(envstr);
386 int DeleteAllFilesInDir (string const & path)
388 // I have decided that we will be using parts from the boost
389 // library. Check out http://www.boost.org/
390 // For directory access we will then use the directory_iterator.
391 // Then the code will be something like:
392 // directory_iterator dit(path);
393 // directory_iterator dend;
394 // if (dit == dend) {
395 // WriteFSAlert(_("Error! Cannot open directory:"), path);
398 // for (; dit != dend; ++dit) {
399 // string filename(*dit);
400 // if (filename == "." || filename == "..")
402 // string unlinkpath(AddName(path, filename));
403 // if (lyx::unlink(unlinkpath))
404 // WriteFSAlert(_("Error! Could not remove file:"),
408 DIR * dir = ::opendir(path.c_str());
410 WriteFSAlert (_("Error! Cannot open directory:"), path);
414 int return_value = 0;
415 while ((de = readdir(dir))) {
416 string const temp = de->d_name;
417 if (temp == "." || temp == "..")
419 string const unlinkpath = AddName (path, temp);
421 lyxerr.debug() << "Deleting file: " << unlinkpath << endl;
424 if (FileInfo(unlinkpath).isDir())
425 deleted = (DeleteAllFilesInDir(unlinkpath) == 0);
426 deleted &= (lyx::unlink(unlinkpath) == 0);
428 WriteFSAlert (_("Error! Could not remove file:"),
439 string const CreateTmpDir(string const & tempdir, string const & mask)
442 << "CreateTmpDir: tempdir=`" << tempdir << "'\n"
443 << "CreateTmpDir: mask=`" << mask << "'" << endl;
445 string const tmpfl(lyx::tempName(tempdir, mask));
446 // lyx::tempName actually creates a file to make sure that it
447 // stays unique. So we have to delete it before we can create
448 // a dir with the same name. Note also that we are not thread
449 // safe because of the gap between unlink and mkdir. (Lgb)
450 lyx::unlink(tmpfl.c_str());
452 if (tmpfl.empty() || lyx::mkdir(tmpfl, 0777)) {
453 WriteFSAlert(_("Error! Couldn't create temporary directory:"),
457 return MakeAbsPath(tmpfl);
462 int DestroyTmpDir(string const & tmpdir, bool Allfiles)
467 if (Allfiles && DeleteAllFilesInDir(tmpdir)) return -1;
468 if (lyx::rmdir(tmpdir)) {
469 WriteFSAlert(_("Error! Couldn't delete temporary directory:"),
477 string const CreateBufferTmpDir(string const & pathfor)
479 return CreateTmpDir(pathfor, "lyx_tmpbuf");
483 int DestroyBufferTmpDir(string const & tmpdir)
485 return DestroyTmpDir(tmpdir, true);
489 string const CreateLyXTmpDir(string const & deflt)
491 if ((!deflt.empty()) && (deflt != "/tmp")) {
492 if (lyx::mkdir(deflt, 0777)) {
496 string const t(CreateTmpDir(deflt, "lyx_tmpdir"));
504 string const t(CreateTmpDir("/tmp", "lyx_tmpdir"));
510 int DestroyLyXTmpDir(string const & tmpdir)
512 return DestroyTmpDir (tmpdir, false); // Why false?
516 // Creates directory. Returns true if succesfull
517 bool createDirectory(string const & path, int permission)
519 string temp(strip(CleanupPath(path), '/'));
522 WriteAlert(_("Internal error!"),
523 _("Call to createDirectory with invalid name"));
527 if (lyx::mkdir(temp, permission)) {
528 WriteFSAlert (_("Error! Couldn't create directory:"), temp);
535 // Strip filename from path name
536 string const OnlyPath(string const & Filename)
538 // If empty filename, return empty
539 if (Filename.empty()) return Filename;
541 // Find last / or start of filename
542 string::size_type j = Filename.rfind('/');
543 if (j == string::npos)
545 return Filename.substr(0, j + 1);
549 // Convert relative path into absolute path based on a basepath.
550 // If relpath is absolute, just use that.
551 // If basepath is empty, use CWD as base.
552 string const MakeAbsPath(string const & RelPath, string const & BasePath)
554 // checks for already absolute path
555 if (AbsolutePath(RelPath))
557 if (RelPath[0]!= '/' && RelPath[0]!= '\\')
561 // Copies given paths
562 string TempRel(CleanupPath(RelPath));
566 if (!BasePath.empty()) {
570 char * with_drive = new char[_MAX_PATH];
571 _abspath(with_drive, BasePath.c_str(), _MAX_PATH);
572 TempBase = with_drive;
576 TempBase = lyx::getcwd(); //GetCWD();
578 if (AbsolutePath(TempRel))
579 return TempBase.substr(0, 2) + TempRel;
582 // Handle /./ at the end of the path
583 while(suffixIs(TempBase, "/./"))
584 TempBase.erase(TempBase.length() - 2);
586 // processes relative path
587 string RTemp(TempRel);
590 while (!RTemp.empty()) {
592 RTemp = split(RTemp, Temp, '/');
594 if (Temp == ".") continue;
596 // Remove one level of TempBase
597 string::difference_type i = TempBase.length() - 2;
600 while (i > 0 && TempBase[i] != '/') --i;
604 while (i > 2 && TempBase[i] != '/') --i;
607 TempBase.erase(i, string::npos);
611 // Add this piece to TempBase
612 if (!suffixIs(TempBase, '/'))
618 // returns absolute path
623 // Correctly append filename to the pathname.
624 // If pathname is '.', then don't use pathname.
625 // Chops any path of filename.
626 string const AddName(string const & path, string const & fname)
629 string const basename(OnlyFilename(fname));
633 if (path != "." && path != "./" && !path.empty()) {
634 buf = CleanupPath(path);
635 if (!suffixIs(path, '/'))
639 return buf + basename;
643 // Strips path from filename
644 string const OnlyFilename(string const & fname)
649 string::size_type j = fname.rfind('/');
650 if (j == string::npos) // no '/' in fname
654 return fname.substr(j + 1);
658 // Strips filename from path
659 string const BasePath(string const & fname)
664 string::size_type j = fname.rfind('/');
665 if (j == string::npos) // no '/' in fname
669 return fname.substr(0,j + 1);
673 // Is a filename/path absolute?
674 bool AbsolutePath(string const & path)
677 return (!path.empty() && path[0] == '/');
679 return (!path.empty() && (path[0] == '/' || (isalpha(static_cast<unsigned char>(path[0])) && path.length()>1 && path[1] == ':')));
684 // Create absolute path. If impossible, don't do anything
685 // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
686 string const ExpandPath(string const & path)
688 // checks for already absolute path
689 string RTemp(ReplaceEnvironmentPath(path));
690 if (AbsolutePath(RTemp))
694 string const copy(RTemp);
697 RTemp = split(RTemp, Temp, '/');
700 return lyx::getcwd() /*GetCWD()*/ + '/' + RTemp;
701 } else if (Temp == "~") {
702 return GetEnvPath("HOME") + '/' + RTemp;
703 } else if (Temp == "..") {
704 return MakeAbsPath(copy);
706 // Don't know how to handle this
712 // Constracts path/../path
713 // Can't handle "../../" or "/../" (Asger)
714 string const NormalizePath(string const & path)
720 if (AbsolutePath(path))
723 // Make implicit current directory explicit
726 while (!RTemp.empty()) {
728 RTemp = split(RTemp, Temp, '/');
732 } else if (Temp == "..") {
733 // Remove one level of TempBase
734 string::difference_type i = TempBase.length() - 2;
735 while (i > 0 && TempBase[i] != '/')
737 if (i >= 0 && TempBase[i] == '/')
738 TempBase.erase(i + 1, string::npos);
742 TempBase += Temp + '/';
746 // returns absolute path
751 string const CleanupPath(string const & path)
753 #ifdef __EMX__ /* SMiyata: This should fix searchpath bug. */
754 string temppath = subst(path, '\\', '/');
755 temppath = subst(temppath, "//", "/");
756 return lowercase(temppath);
757 #else // On unix, nothing to do
763 string const GetFileContents(string const & fname)
765 FileInfo finfo(fname);
767 ifstream ifs(fname.c_str());
768 std::ostringstream ofs;
772 return ofs.str().c_str();
775 lyxerr << "LyX was not able to read file '" << fname << "'" << endl;
781 // Search ${...} as Variable-Name inside the string and replace it with
782 // the denoted environmentvariable
783 // Allow Variables according to
784 // variable := '$' '{' [A-Za-z_]{[A-Za-z_0-9]*} '}'
787 string const ReplaceEnvironmentPath(string const & path)
790 // CompareChar: Environmentvariables starts with this character
791 // PathChar: Next path component start with this character
792 // while CompareChar found do:
793 // Split String with PathChar
794 // Search Environmentvariable
795 // if found: Replace Strings
797 char const CompareChar = '$';
798 char const FirstChar = '{';
799 char const EndChar = '}';
800 char const UnderscoreChar = '_';
801 string EndString; EndString += EndChar;
802 string FirstString; FirstString += FirstChar;
803 string CompareString; CompareString += CompareChar;
804 string const RegExp("*}*"); // Exist EndChar inside a String?
806 // first: Search for a '$' - Sign.
808 string result1; //(copy); // for split-calls
809 string result0 = split(path, result1, CompareChar);
810 while (!result0.empty()) {
811 string copy1(result0); // contains String after $
813 // Check, if there is an EndChar inside original String.
815 if (!regexMatch(copy1, RegExp)) {
816 // No EndChar inside. So we are finished
817 result1 += CompareString + result0;
823 string res0 = split(copy1, res1, EndChar);
824 // Now res1 holds the environmentvariable
825 // First, check, if Contents is ok.
826 if (res1.empty()) { // No environmentvariable. Continue Loop.
827 result1 += CompareString + FirstString;
831 // check contents of res1
832 char const * res1_contents = res1.c_str();
833 if (*res1_contents != FirstChar) {
834 // Again No Environmentvariable
835 result1 += CompareString;
839 // Check for variable names
840 // Situation ${} is detected as "No Environmentvariable"
841 char const * cp1 = res1_contents + 1;
842 bool result = isalpha(*cp1) || (*cp1 == UnderscoreChar);
844 while (*cp1 && result) {
845 result = isalnum(*cp1) ||
846 (*cp1 == UnderscoreChar);
851 // no correct variable name
852 result1 += CompareString + res1 + EndString;
853 result0 = split(res0, res1, CompareChar);
858 string env(GetEnv(res1_contents + 1));
860 // Congratulations. Environmentvariable found
863 result1 += CompareString + res1 + EndString;
866 result0 = split(res0, res1, CompareChar);
870 } // ReplaceEnvironmentPath
873 // Make relative path out of two absolute paths
874 string const MakeRelPath(string const & abspath0, string const & basepath0)
875 // Makes relative path out of absolute path. If it is deeper than basepath,
876 // it's easy. If basepath and abspath share something (they are all deeper
877 // than some directory), it'll be rendered using ..'s. If they are completely
878 // different, then the absolute path will be used as relative path.
880 // This is a hack. It should probaly be done in another way. Lgb.
881 string const abspath = CleanupPath(abspath0);
882 string const basepath = CleanupPath(basepath0);
884 return "<unknown_path>";
886 string::size_type const abslen = abspath.length();
887 string::size_type const baselen = basepath.length();
889 // Find first different character
890 string::size_type i = 0;
891 while (i < abslen && i < baselen && abspath[i] == basepath[i]) ++i;
894 if (i < abslen && i < baselen
895 || (i < abslen && abspath[i] != '/' && i == baselen)
896 || (i < baselen && basepath[i] != '/' && i == abslen))
898 if (i) --i; // here was the last match
899 while (i && abspath[i] != '/') --i;
903 // actually no match - cannot make it relative
907 // Count how many dirs there are in basepath above match
908 // and append as many '..''s into relpath
910 string::size_type j = i;
911 while (j < baselen) {
912 if (basepath[j] == '/') {
913 if (j + 1 == baselen) break;
919 // Append relative stuff from common directory to abspath
920 if (abspath[i] == '/') ++i;
921 for (; i < abslen; ++i)
924 if (suffixIs(buf, '/'))
925 buf.erase(buf.length() - 1);
926 // Substitute empty with .
933 // Append sub-directory(ies) to a path in an intelligent way
934 string const AddPath(string const & path, string const & path_2)
937 string const path2 = CleanupPath(path_2);
939 if (!path.empty() && path != "." && path != "./") {
940 buf = CleanupPath(path);
941 if (path[path.length() - 1] != '/')
945 if (!path2.empty()) {
946 string::size_type const p2start = path2.find_first_not_of('/');
947 string::size_type const p2end = path2.find_last_not_of('/');
948 string const tmp = path2.substr(p2start, p2end - p2start + 1);
956 Change extension of oldname to extension.
957 Strips path off if no_path == true.
958 If no extension on oldname, just appends.
961 ChangeExtension(string const & oldname, string const & extension)
963 string::size_type const last_slash = oldname.rfind('/');
964 string::size_type last_dot = oldname.rfind('.');
965 if (last_dot < last_slash && last_slash != string::npos)
966 last_dot = string::npos;
969 // Make sure the extension starts with a dot
970 if (!extension.empty() && extension[0] != '.')
971 ext= "." + extension;
975 return CleanupPath(oldname.substr(0, last_dot) + ext);
979 /// Return the extension of the file (not including the .)
980 string const GetExtension(string const & name)
982 string::size_type const last_slash = name.rfind('/');
983 string::size_type const last_dot = name.rfind('.');
984 if (last_dot != string::npos &&
985 (last_slash == string::npos || last_dot > last_slash))
986 return name.substr(last_dot + 1,
987 name.length() - (last_dot + 1));
993 // Creates a nice compact path for displaying
995 MakeDisplayPath (string const & path, unsigned int threshold)
997 string::size_type const l1 = path.length();
999 // First, we try a relative path compared to home
1000 string const home(GetEnvPath("HOME"));
1001 string relhome = MakeRelPath(path, home);
1003 string::size_type l2 = relhome.length();
1007 // If we backup from home or don't have a relative path,
1008 // this try is no good
1009 if (prefixIs(relhome, "../") || AbsolutePath(relhome)) {
1010 // relative path was no good, just use the original path
1017 // Is the path too long?
1018 if (l2 > threshold) {
1024 while (relhome.length() > threshold)
1025 relhome = split(relhome, temp, '/');
1027 // Did we shortend everything away?
1028 if (relhome.empty()) {
1029 // Yes, filename in itself is too long.
1030 // Pick the start and the end of the filename.
1031 relhome = OnlyFilename(path);
1032 string const head = relhome.substr(0, threshold/2 - 3);
1034 l2 = relhome.length();
1036 relhome.substr(l2 - threshold/2 - 2, l2 - 1);
1037 relhome = head + "..." + tail;
1040 return prefix + relhome;
1044 bool LyXReadLink(string const & File, string & Link)
1046 char LinkBuffer[512];
1047 // Should be PATH_MAX but that needs autconf support
1048 int const nRead = ::readlink(File.c_str(),
1049 LinkBuffer, sizeof(LinkBuffer) - 1);
1052 LinkBuffer[nRead] = '\0'; // terminator
1058 typedef pair<int, string> cmdret;
1060 cmdret const do_popen(string const & cmd)
1062 // One question is if we should use popen or
1063 // create our own popen based on fork, exec, pipe
1064 // of course the best would be to have a
1065 // pstream (process stream), with the
1066 // variants ipstream, opstream
1067 FILE * inf = ::popen(cmd.c_str(), "r");
1071 ret += static_cast<char>(c);
1074 int const pret = pclose(inf);
1075 return make_pair(pret, ret);
1080 findtexfile(string const & fil, string const & /*format*/)
1082 /* There is no problem to extend this function too use other
1083 methods to look for files. It could be setup to look
1084 in environment paths and also if wanted as a last resort
1085 to a recursive find. One of the easier extensions would
1086 perhaps be to use the LyX file lookup methods. But! I am
1087 going to implement this until I see some demand for it.
1091 // If the file can be found directly, we just return a
1092 // absolute path version of it.
1093 if (FileInfo(fil).exist())
1094 return MakeAbsPath(fil);
1096 // No we try to find it using kpsewhich.
1097 // It seems from the kpsewhich manual page that it is safe to use
1098 // kpsewhich without --format: "When the --format option is not
1099 // given, the search path used when looking for a file is inferred
1100 // from the name given, by looking for a known extension. If no
1101 // known extension is found, the search path for TeX source files
1103 // However, we want to take advantage of the format sine almost all
1104 // the different formats has environment variables that can be used
1105 // to controll which paths to search. f.ex. bib looks in
1106 // BIBINPUTS and TEXBIB. Small list follows:
1107 // bib - BIBINPUTS, TEXBIB
1109 // graphic/figure - TEXPICTS, TEXINPUTS
1110 // ist - TEXINDEXSTYLE, INDEXSTYLE
1111 // pk - PROGRAMFONTS, PKFONTS, TEXPKS, GLYPHFONTS, TEXFONTS
1113 // tfm - TFMFONTS, TEXFONTS
1114 // This means that to use kpsewhich in the best possible way we
1115 // should help it by setting additional path in the approp. envir.var.
1116 string const kpsecmd = "kpsewhich " + fil;
1118 cmdret const c = do_popen(kpsecmd);
1120 lyxerr[Debug::LATEX] << "kpse status = " << c.first << "\n"
1121 << "kpse result = `" << strip(c.second, '\n')
1123 return c.first != -1 ? strip(c.second, '\n') : string();
1127 void removeAutosaveFile(string const & filename)
1129 string a = OnlyPath(filename);
1131 a += OnlyFilename(filename);
1133 FileInfo const fileinfo(a);
1134 if (fileinfo.exist()) {
1135 if (lyx::unlink(a) != 0) {
1136 WriteFSAlert(_("Could not delete auto-save file!"), a);