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>
63 extern string system_lyxdir;
64 extern string build_lyxdir;
65 extern string user_lyxdir;
66 extern string system_tempdir;
69 bool IsLyXFilename(string const & filename)
71 return contains(filename, ".lyx");
75 bool IsSGMLFilename(string const & filename)
77 return contains(filename, ".sgml");
81 // Substitutes spaces with underscores in filename (and path)
82 string const MakeLatexName(string const & file)
84 string name = OnlyFilename(file);
85 string const path = OnlyPath(file);
87 for (string::size_type i = 0; i < name.length(); ++i) {
88 name[i] &= 0x7f; // set 8th bit to 0
91 // ok so we scan through the string twice, but who cares.
92 string const keep("abcdefghijklmnopqrstuvwxyz"
93 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
94 "@!\"'()*+,-./0123456789:;<=>?[]`|");
96 string::size_type pos = 0;
97 while ((pos = name.find_first_not_of(keep, pos)) != string::npos) {
100 return AddName(path, name);
104 // Substitutes spaces with underscores in filename (and path)
105 string const QuoteName(string const & name)
107 // CHECK Add proper emx support here!
109 return "\'" + name + "\'";
116 // Is a file readable ?
117 bool IsFileReadable (string const & path)
120 if (file.isOK() && file.isRegular() && file.readable())
127 // Is a file read_only?
128 // return 1 read-write
130 // -1 error (doesn't exist, no access, anything else)
131 int IsFileWriteable (string const & path)
134 if (fi.access(FileInfo::wperm|FileInfo::rperm)) // read-write
136 if (fi.readable()) // read-only
138 return -1; // everything else.
142 //returns 1: dir writeable
144 // -1: error- couldn't find out
145 int IsDirWriteable (string const & path)
147 string const tmpfl(lyx::tempName(path, "lyxwritetest"));
148 // We must unlink the tmpfl.
152 WriteFSAlert(_("LyX Internal Error!"),
153 _("Could not test if directory is writeable"));
157 if (fi.writable()) return 1;
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 = CleanupPath(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());
212 while ((dire = ::readdir(dirp))) {
213 string const fil = dire->d_name;
214 if (suffixIs(fil, extension)) {
215 dirlist.push_back(fil);
220 /* I would have prefered to take a vector<string>& as parameter so
221 that we could avoid the copy of the vector when returning.
223 dirlist.swap(argvec);
224 to avoid the copy. (Lgb)
226 /* A C++ implementaion will look like this:
227 string extension(ext);
228 if (extension[0] != '.') extension.insert(0, ".");
229 vector<string> dirlist;
230 directory_iterator dit("dir");
231 while (dit != directory_iterator()) {
232 string fil = (*dit).filename;
233 if (prefixIs(fil, extension)) {
234 dirlist.push_back(fil);
238 dirlist.swap(argvec);
244 // Returns the real name of file name in directory path, with optional
246 string const FileSearch(string const & path, string const & name,
249 // if `name' is an absolute path, we ignore the setting of `path'
250 // Expand Environmentvariables in 'name'
251 string const tmpname = ReplaceEnvironmentPath(name);
252 string fullname = MakeAbsPath(tmpname, path);
254 // search first without extension, then with it.
255 if (IsFileReadable(fullname))
257 else if (ext.empty())
259 else { // Is it not more reasonable to use ChangeExtension()? (SMiyata)
262 if (IsFileReadable(fullname))
270 // Search the file name.ext in the subdirectory dir of
272 // 2) build_lyxdir (if not empty)
274 string const LibFileSearch(string const & dir, string const & name,
277 string fullname = FileSearch(AddPath(user_lyxdir, dir),
279 if (!fullname.empty())
282 if (!build_lyxdir.empty())
283 fullname = FileSearch(AddPath(build_lyxdir, dir),
285 if (!fullname.empty())
288 return FileSearch(AddPath(system_lyxdir, dir), name, ext);
293 i18nLibFileSearch(string const & dir, string const & name,
296 string const lang = token(string(GetEnv("LANG")), '_', 0);
298 if (lang.empty() || lang == "C")
299 return LibFileSearch(dir, name, ext);
301 string const tmp = LibFileSearch(dir, lang + '_' + name,
306 return LibFileSearch(dir, name, ext);
311 string const GetEnv(string const & envname)
313 // f.ex. what about error checking?
314 char const * const ch = getenv(envname.c_str());
315 string const envstr = !ch ? "" : ch;
320 string const GetEnvPath(string const & name)
323 string const pathlist = subst(GetEnv(name), ':', ';');
325 string const pathlist = subst(GetEnv(name), '\\', '/');
327 return strip(pathlist, ';');
331 bool PutEnv(string const & envstr)
333 // CHECK Look at and fix this.
334 // f.ex. what about error checking?
337 // this leaks, but what can we do about it?
338 // Is doing a getenv() and a free() of the older value
339 // a good idea? (JMarc)
340 // Actually we don't have to leak...calling putenv like this
341 // should be enough: ... and this is obviously not enough if putenv
342 // does not make a copy of the string. It is also not very wise to
343 // put a string on the free store. If we have to leak we should do it
345 char * leaker = new char[envstr.length() + 1];
346 envstr.copy(leaker, envstr.length());
347 leaker[envstr.length()] = '\0';
348 int const retval = lyx::putenv(leaker);
350 // If putenv does not make a copy of the char const * this
351 // is very dangerous. OTOH if it does take a copy this is the
353 // The only implementation of putenv that I have seen does not
354 // allocate memory. _And_ after testing the putenv in glibc it
355 // seems that we need to make a copy of the string contents.
356 // I will enable the above.
357 //int retval = lyx::putenv(envstr.c_str());
361 string const str = envstr.split(varname,'=');
362 int const retval = ::setenv(varname.c_str(), str.c_str(), true);
364 // No environment setting function. Can this happen?
365 int const retval = 1; //return an error condition.
372 bool PutEnvPath(string const & envstr)
374 return PutEnv(envstr);
379 int DeleteAllFilesInDir (string const & path)
381 // I have decided that we will be using parts from the boost
382 // library. Check out http://www.boost.org/
383 // For directory access we will then use the directory_iterator.
384 // Then the code will be something like:
385 // directory_iterator dit(path);
386 // directory_iterator dend;
387 // if (dit == dend) {
388 // WriteFSAlert(_("Error! Cannot open directory:"), path);
391 // for (; dit != dend; ++dit) {
392 // string filename(*dit);
393 // if (filename == "." || filename == "..")
395 // string unlinkpath(AddName(path, filename));
396 // if (lyx::unlink(unlinkpath))
397 // WriteFSAlert(_("Error! Could not remove file:"),
401 DIR * dir = ::opendir(path.c_str());
403 WriteFSAlert (_("Error! Cannot open directory:"), path);
407 int return_value = 0;
408 while ((de = readdir(dir))) {
409 string const temp = de->d_name;
410 if (temp == "." || temp == "..")
412 string const unlinkpath = AddName (path, temp);
414 lyxerr.debug() << "Deleting file: " << unlinkpath << endl;
417 if (FileInfo(unlinkpath).isDir())
418 deleted = (DeleteAllFilesInDir(unlinkpath) == 0);
419 deleted &= (lyx::unlink(unlinkpath) == 0);
421 WriteFSAlert (_("Error! Could not remove file:"),
432 string const CreateTmpDir(string const & tempdir, string const & mask)
435 << "CreateTmpDir: tempdir=`" << tempdir << "'\n"
436 << "CreateTmpDir: mask=`" << mask << "'" << endl;
438 string const tmpfl(lyx::tempName(tempdir, mask));
439 // lyx::tempName actually creates a file to make sure that it
440 // stays unique. So we have to delete it before we can create
441 // a dir with the same name. Note also that we are not thread
442 // safe because of the gap between unlink and mkdir. (Lgb)
443 lyx::unlink(tmpfl.c_str());
445 if (tmpfl.empty() || lyx::mkdir(tmpfl, 0777)) {
446 WriteFSAlert(_("Error! Couldn't create temporary directory:"),
450 return MakeAbsPath(tmpfl);
455 int DestroyTmpDir(string const & tmpdir, bool Allfiles)
460 if (Allfiles && DeleteAllFilesInDir(tmpdir)) return -1;
461 if (lyx::rmdir(tmpdir)) {
462 WriteFSAlert(_("Error! Couldn't delete temporary directory:"),
470 string const CreateBufferTmpDir(string const & pathfor)
472 return CreateTmpDir(pathfor, "lyx_tmpbuf");
476 int DestroyBufferTmpDir(string const & tmpdir)
478 return DestroyTmpDir(tmpdir, true);
482 string const CreateLyXTmpDir(string const & deflt)
484 if ((!deflt.empty()) && (deflt != "/tmp")) {
485 if (lyx::mkdir(deflt, 0777)) {
489 string const t(CreateTmpDir(deflt, "lyx_tmpdir"));
497 string const t(CreateTmpDir("/tmp", "lyx_tmpdir"));
503 int DestroyLyXTmpDir(string const & tmpdir)
505 return DestroyTmpDir (tmpdir, false); // Why false?
509 // Creates directory. Returns true if succesfull
510 bool createDirectory(string const & path, int permission)
512 string temp(strip(CleanupPath(path), '/'));
515 WriteAlert(_("Internal error!"),
516 _("Call to createDirectory with invalid name"));
520 if (lyx::mkdir(temp, permission)) {
521 WriteFSAlert (_("Error! Couldn't create directory:"), temp);
528 // Strip filename from path name
529 string const OnlyPath(string const & Filename)
531 // If empty filename, return empty
532 if (Filename.empty()) return Filename;
534 // Find last / or start of filename
535 string::size_type j = Filename.rfind('/');
536 if (j == string::npos)
538 return Filename.substr(0, j + 1);
542 // Convert relative path into absolute path based on a basepath.
543 // If relpath is absolute, just use that.
544 // If basepath is empty, use CWD as base.
545 string const MakeAbsPath(string const & RelPath, string const & BasePath)
547 // checks for already absolute path
548 if (AbsolutePath(RelPath))
550 if (RelPath[0]!= '/' && RelPath[0]!= '\\')
554 // Copies given paths
555 string TempRel(CleanupPath(RelPath));
559 if (!BasePath.empty()) {
563 char * with_drive = new char[_MAX_PATH];
564 _abspath(with_drive, BasePath.c_str(), _MAX_PATH);
565 TempBase = with_drive;
569 TempBase = lyx::getcwd(); //GetCWD();
571 if (AbsolutePath(TempRel))
572 return TempBase.substr(0, 2) + TempRel;
575 // Handle /./ at the end of the path
576 while(suffixIs(TempBase, "/./"))
577 TempBase.erase(TempBase.length() - 2);
579 // processes relative path
580 string RTemp(TempRel);
583 while (!RTemp.empty()) {
585 RTemp = split(RTemp, Temp, '/');
587 if (Temp == ".") continue;
589 // Remove one level of TempBase
590 string::difference_type i = TempBase.length() - 2;
593 while (i > 0 && TempBase[i] != '/') --i;
597 while (i > 2 && TempBase[i] != '/') --i;
600 TempBase.erase(i, string::npos);
604 // Add this piece to TempBase
605 if (!suffixIs(TempBase, '/'))
611 // returns absolute path
616 // Correctly append filename to the pathname.
617 // If pathname is '.', then don't use pathname.
618 // Chops any path of filename.
619 string const AddName(string const & path, string const & fname)
622 string const basename(OnlyFilename(fname));
626 if (path != "." && path != "./" && !path.empty()) {
627 buf = CleanupPath(path);
628 if (!suffixIs(path, '/'))
632 return buf + basename;
636 // Strips path from filename
637 string const OnlyFilename(string const & fname)
642 string::size_type j = fname.rfind('/');
643 if (j == string::npos) // no '/' in fname
647 return fname.substr(j + 1);
651 // Strips filename from path
652 string const BasePath(string const & fname)
657 string::size_type j = fname.rfind('/');
658 if (j == string::npos) // no '/' in fname
662 return fname.substr(0,j + 1);
666 // Is a filename/path absolute?
667 bool AbsolutePath(string const & path)
670 return (!path.empty() && path[0] == '/');
672 return (!path.empty() && (path[0] == '/' || (isalpha(static_cast<unsigned char>(path[0])) && path.length()>1 && path[1] == ':')));
677 // Create absolute path. If impossible, don't do anything
678 // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
679 string const ExpandPath(string const & path)
681 // checks for already absolute path
682 string RTemp(ReplaceEnvironmentPath(path));
683 if (AbsolutePath(RTemp))
687 string const copy(RTemp);
690 RTemp = split(RTemp, Temp, '/');
693 return lyx::getcwd() /*GetCWD()*/ + '/' + RTemp;
694 } else if (Temp == "~") {
695 return GetEnvPath("HOME") + '/' + RTemp;
696 } else if (Temp == "..") {
697 return MakeAbsPath(copy);
699 // Don't know how to handle this
705 // Constracts path/../path
706 // Can't handle "../../" or "/../" (Asger)
707 string const NormalizePath(string const & path)
713 if (AbsolutePath(path))
716 // Make implicit current directory explicit
719 while (!RTemp.empty()) {
721 RTemp = split(RTemp, Temp, '/');
725 } else if (Temp == "..") {
726 // Remove one level of TempBase
727 string::difference_type i = TempBase.length() - 2;
728 while (i > 0 && TempBase[i] != '/')
730 if (i >= 0 && TempBase[i] == '/')
731 TempBase.erase(i + 1, string::npos);
735 TempBase += Temp + '/';
739 // returns absolute path
744 string const CleanupPath(string const & path)
746 #ifdef __EMX__ /* SMiyata: This should fix searchpath bug. */
747 string temppath = subst(path, '\\', '/');
748 temppath = subst(temppath, "//", "/");
749 return lowercase(temppath);
750 #else // On unix, nothing to do
756 string const GetFileContents(string const & fname)
758 FileInfo finfo(fname);
760 ifstream ifs(fname.c_str());
761 std::ostringstream ofs;
765 return ofs.str().c_str();
768 lyxerr << "LyX was not able to read file '" << fname << "'" << endl;
774 // Search ${...} as Variable-Name inside the string and replace it with
775 // the denoted environmentvariable
776 // Allow Variables according to
777 // variable := '$' '{' [A-Za-z_]{[A-Za-z_0-9]*} '}'
780 string const ReplaceEnvironmentPath(string const & path)
783 // CompareChar: Environmentvariables starts with this character
784 // PathChar: Next path component start with this character
785 // while CompareChar found do:
786 // Split String with PathChar
787 // Search Environmentvariable
788 // if found: Replace Strings
790 char const CompareChar = '$';
791 char const FirstChar = '{';
792 char const EndChar = '}';
793 char const UnderscoreChar = '_';
794 string EndString; EndString += EndChar;
795 string FirstString; FirstString += FirstChar;
796 string CompareString; CompareString += CompareChar;
797 string const RegExp("*}*"); // Exist EndChar inside a String?
799 // first: Search for a '$' - Sign.
801 string result1; //(copy); // for split-calls
802 string result0 = split(path, result1, CompareChar);
803 while (!result0.empty()) {
804 string copy1(result0); // contains String after $
806 // Check, if there is an EndChar inside original String.
808 if (!regexMatch(copy1, RegExp)) {
809 // No EndChar inside. So we are finished
810 result1 += CompareString + result0;
816 string res0 = split(copy1, res1, EndChar);
817 // Now res1 holds the environmentvariable
818 // First, check, if Contents is ok.
819 if (res1.empty()) { // No environmentvariable. Continue Loop.
820 result1 += CompareString + FirstString;
824 // check contents of res1
825 char const * res1_contents = res1.c_str();
826 if (*res1_contents != FirstChar) {
827 // Again No Environmentvariable
828 result1 += CompareString;
832 // Check for variable names
833 // Situation ${} is detected as "No Environmentvariable"
834 char const * cp1 = res1_contents + 1;
835 bool result = isalpha(*cp1) || (*cp1 == UnderscoreChar);
837 while (*cp1 && result) {
838 result = isalnum(*cp1) ||
839 (*cp1 == UnderscoreChar);
844 // no correct variable name
845 result1 += CompareString + res1 + EndString;
846 result0 = split(res0, res1, CompareChar);
851 string env(GetEnv(res1_contents + 1));
853 // Congratulations. Environmentvariable found
856 result1 += CompareString + res1 + EndString;
859 result0 = split(res0, res1, CompareChar);
863 } // ReplaceEnvironmentPath
866 // Make relative path out of two absolute paths
867 string const MakeRelPath(string const & abspath0, string const & basepath0)
868 // Makes relative path out of absolute path. If it is deeper than basepath,
869 // it's easy. If basepath and abspath share something (they are all deeper
870 // than some directory), it'll be rendered using ..'s. If they are completely
871 // different, then the absolute path will be used as relative path.
873 // This is a hack. It should probaly be done in another way. Lgb.
874 string const abspath = CleanupPath(abspath0);
875 string const basepath = CleanupPath(basepath0);
877 return "<unknown_path>";
879 string::size_type const abslen = abspath.length();
880 string::size_type const baselen = basepath.length();
882 // Find first different character
883 string::size_type i = 0;
884 while (i < abslen && i < baselen && abspath[i] == basepath[i]) ++i;
887 if (i < abslen && i < baselen
888 || (i < abslen && abspath[i] != '/' && i == baselen)
889 || (i < baselen && basepath[i] != '/' && i == abslen))
891 if (i) --i; // here was the last match
892 while (i && abspath[i] != '/') --i;
896 // actually no match - cannot make it relative
900 // Count how many dirs there are in basepath above match
901 // and append as many '..''s into relpath
903 string::size_type j = i;
904 while (j < baselen) {
905 if (basepath[j] == '/') {
906 if (j + 1 == baselen) break;
912 // Append relative stuff from common directory to abspath
913 if (abspath[i] == '/') ++i;
914 for (; i < abslen; ++i)
917 if (suffixIs(buf, '/'))
918 buf.erase(buf.length() - 1);
919 // Substitute empty with .
926 // Append sub-directory(ies) to a path in an intelligent way
927 string const AddPath(string const & path, string const & path_2)
930 string const path2 = CleanupPath(path_2);
932 if (!path.empty() && path != "." && path != "./") {
933 buf = CleanupPath(path);
934 if (path[path.length() - 1] != '/')
939 buf += frontStrip(strip(path2, '/'), '/') + '/';
946 Change extension of oldname to extension.
947 Strips path off if no_path == true.
948 If no extension on oldname, just appends.
951 ChangeExtension(string const & oldname, string const & extension)
953 string::size_type const last_slash = oldname.rfind('/');
954 string::size_type last_dot = oldname.rfind('.');
955 if (last_dot < last_slash && last_slash != string::npos)
956 last_dot = string::npos;
959 // Make sure the extension starts with a dot
960 if (!extension.empty() && extension[0] != '.')
961 ext= "." + extension;
965 return CleanupPath(oldname.substr(0, last_dot) + ext);
969 /// Return the extension of the file (not including the .)
970 string const GetExtension(string const & name)
972 string::size_type const last_slash = name.rfind('/');
973 string::size_type const last_dot = name.rfind('.');
974 if (last_dot != string::npos &&
975 (last_slash == string::npos || last_dot > last_slash))
976 return name.substr(last_dot + 1,
977 name.length() - (last_dot + 1));
983 // Creates a nice compact path for displaying
985 MakeDisplayPath (string const & path, unsigned int threshold)
987 string::size_type const l1 = path.length();
989 // First, we try a relative path compared to home
990 string const home(GetEnvPath("HOME"));
991 string relhome = MakeRelPath(path, home);
993 string::size_type l2 = relhome.length();
997 // If we backup from home or don't have a relative path,
998 // this try is no good
999 if (prefixIs(relhome, "../") || AbsolutePath(relhome)) {
1000 // relative path was no good, just use the original path
1007 // Is the path too long?
1008 if (l2 > threshold) {
1014 while (relhome.length() > threshold)
1015 relhome = split(relhome, temp, '/');
1017 // Did we shortend everything away?
1018 if (relhome.empty()) {
1019 // Yes, filename in itself is too long.
1020 // Pick the start and the end of the filename.
1021 relhome = OnlyFilename(path);
1022 string const head = relhome.substr(0, threshold/2 - 3);
1024 l2 = relhome.length();
1026 relhome.substr(l2 - threshold/2 - 2, l2 - 1);
1027 relhome = head + "..." + tail;
1030 return prefix + relhome;
1034 bool LyXReadLink(string const & File, string & Link)
1036 char LinkBuffer[512];
1037 // Should be PATH_MAX but that needs autconf support
1038 int const nRead = ::readlink(File.c_str(),
1039 LinkBuffer, sizeof(LinkBuffer) - 1);
1042 LinkBuffer[nRead] = '\0'; // terminator
1048 typedef pair<int, string> cmdret;
1050 cmdret const do_popen(string const & cmd)
1052 // One question is if we should use popen or
1053 // create our own popen based on fork, exec, pipe
1054 // of course the best would be to have a
1055 // pstream (process stream), with the
1056 // variants ipstream, opstream
1057 FILE * inf = ::popen(cmd.c_str(), "r");
1061 ret += static_cast<char>(c);
1064 int const pret = pclose(inf);
1065 return make_pair(pret, ret);
1070 findtexfile(string const & fil, string const & /*format*/)
1072 /* There is no problem to extend this function too use other
1073 methods to look for files. It could be setup to look
1074 in environment paths and also if wanted as a last resort
1075 to a recursive find. One of the easier extensions would
1076 perhaps be to use the LyX file lookup methods. But! I am
1077 going to implement this until I see some demand for it.
1081 // If the file can be found directly, we just return a
1082 // absolute path version of it.
1083 if (FileInfo(fil).exist())
1084 return MakeAbsPath(fil);
1086 // No we try to find it using kpsewhich.
1087 // It seems from the kpsewhich manual page that it is safe to use
1088 // kpsewhich without --format: "When the --format option is not
1089 // given, the search path used when looking for a file is inferred
1090 // from the name given, by looking for a known extension. If no
1091 // known extension is found, the search path for TeX source files
1093 // However, we want to take advantage of the format sine almost all
1094 // the different formats has environment variables that can be used
1095 // to controll which paths to search. f.ex. bib looks in
1096 // BIBINPUTS and TEXBIB. Small list follows:
1097 // bib - BIBINPUTS, TEXBIB
1099 // graphic/figure - TEXPICTS, TEXINPUTS
1100 // ist - TEXINDEXSTYLE, INDEXSTYLE
1101 // pk - PROGRAMFONTS, PKFONTS, TEXPKS, GLYPHFONTS, TEXFONTS
1103 // tfm - TFMFONTS, TEXFONTS
1104 // This means that to use kpsewhich in the best possible way we
1105 // should help it by setting additional path in the approp. envir.var.
1106 string const kpsecmd = "kpsewhich " + fil;
1108 cmdret const c = do_popen(kpsecmd);
1110 lyxerr[Debug::LATEX] << "kpse status = " << c.first << "\n"
1111 << "kpse result = `" << strip(c.second, '\n')
1113 return c.first != -1 ? strip(c.second, '\n') : string();
1117 void removeAutosaveFile(string const & filename)
1119 string a = OnlyPath(filename);
1121 a += OnlyFilename(filename);
1123 FileInfo const fileinfo(a);
1124 if (fileinfo.exist()) {
1125 if (lyx::unlink(a) != 0) {
1126 WriteFSAlert(_("Could not delete auto-save file!"), a);