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"
34 #include "support/lstrings.h"
36 #include "filetools.h"
37 #include "LSubstring.h"
38 #include "lyx_gui_misc.h"
40 #include "support/path.h" // I know it's OS/2 specific (SMiyata)
45 // Which part of this is still necessary? (JMarc).
48 # define NAMLEN(dirent) strlen((dirent)->d_name)
50 # define dirent direct
51 # define NAMLEN(dirent) (dirent)->d_namlen
53 # include <sys/ndir.h>
69 extern string system_lyxdir;
70 extern string build_lyxdir;
71 extern string user_lyxdir;
72 extern string system_tempdir;
75 bool IsLyXFilename(string const & filename)
77 return suffixIs(lowercase(filename), ".lyx");
81 bool IsSGMLFilename(string const & filename)
83 return suffixIs(lowercase(filename), ".sgml");
87 // Substitutes spaces with underscores in filename (and path)
88 string const MakeLatexName(string const & file)
90 string name = OnlyFilename(file);
91 string const path = OnlyPath(file);
93 for (string::size_type i = 0; i < name.length(); ++i) {
94 name[i] &= 0x7f; // set 8th bit to 0
97 // ok so we scan through the string twice, but who cares.
98 string const keep("abcdefghijklmnopqrstuvwxyz"
99 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
100 "@!\"'()*+,-./0123456789:;<=>?[]`|");
102 string::size_type pos = 0;
103 while ((pos = name.find_first_not_of(keep, pos)) != string::npos) {
106 return AddName(path, name);
110 // Substitutes spaces with underscores in filename (and path)
111 string const QuoteName(string const & name)
113 return (os::shell() == os::UNIX) ?
119 // Is a file readable ?
120 bool IsFileReadable (string const & path)
123 if (file.isOK() && file.isRegular() && file.readable())
130 // Is a file read_only?
131 // return 1 read-write
133 // -1 error (doesn't exist, no access, anything else)
134 int IsFileWriteable (string const & path)
137 //lyxerr << "fi : " << fi << endl;
138 //lyxerr << "fi.exists" << fi.exist() << endl;
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());
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);
253 // search first without extension, then with it.
254 if (IsFileReadable(fullname))
256 else if (ext.empty())
258 else { // Is it not more reasonable to use ChangeExtension()? (SMiyata)
261 if (IsFileReadable(fullname))
269 // Search the file name.ext in the subdirectory dir of
271 // 2) build_lyxdir (if not empty)
273 string const LibFileSearch(string const & dir, string const & name,
276 string fullname = FileSearch(AddPath(user_lyxdir, dir),
278 if (!fullname.empty())
281 if (!build_lyxdir.empty())
282 fullname = FileSearch(AddPath(build_lyxdir, dir),
284 if (!fullname.empty())
287 return FileSearch(AddPath(system_lyxdir, dir), name, ext);
292 i18nLibFileSearch(string const & dir, string const & name,
295 // this comment is from intl/dcigettext.c. We try to mimick this
297 /* The highest priority value is the `LANGUAGE' environment
298 variable. But we don't use the value if the currently
299 selected locale is the C locale. This is a GNU extension. */
301 string const lc_all = GetEnv("LC_ALL");
302 string lang = GetEnv("LANGUAGE");
303 if (lang.empty() || lc_all == "C") {
306 lang = GetEnv("LANG");
310 lang = token(lang, '_', 0);
312 if (lang.empty() || lang == "C")
313 return LibFileSearch(dir, name, ext);
315 string const tmp = LibFileSearch(dir, lang + '_' + name,
320 return LibFileSearch(dir, name, ext);
325 string const GetEnv(string const & envname)
327 // f.ex. what about error checking?
328 char const * const ch = getenv(envname.c_str());
329 string const envstr = !ch ? "" : ch;
334 string const GetEnvPath(string const & name)
337 string const pathlist = subst(GetEnv(name), ':', ';');
339 string const pathlist = os::slashify_path(GetEnv(name));
341 return strip(pathlist, ';');
345 bool PutEnv(string const & envstr)
347 // CHECK Look at and fix this.
348 // f.ex. what about error checking?
351 // this leaks, but what can we do about it?
352 // Is doing a getenv() and a free() of the older value
353 // a good idea? (JMarc)
354 // Actually we don't have to leak...calling putenv like this
355 // should be enough: ... and this is obviously not enough if putenv
356 // does not make a copy of the string. It is also not very wise to
357 // put a string on the free store. If we have to leak we should do it
359 char * leaker = new char[envstr.length() + 1];
360 envstr.copy(leaker, envstr.length());
361 leaker[envstr.length()] = '\0';
362 int const retval = lyx::putenv(leaker);
364 // If putenv does not make a copy of the char const * this
365 // is very dangerous. OTOH if it does take a copy this is the
367 // The only implementation of putenv that I have seen does not
368 // allocate memory. _And_ after testing the putenv in glibc it
369 // seems that we need to make a copy of the string contents.
370 // I will enable the above.
371 //int retval = lyx::putenv(envstr.c_str());
375 string const str = envstr.split(varname,'=');
376 int const retval = ::setenv(varname.c_str(), str.c_str(), true);
378 // No environment setting function. Can this happen?
379 int const retval = 1; //return an error condition.
386 bool PutEnvPath(string const & envstr)
388 return PutEnv(envstr);
394 int DeleteAllFilesInDir (string const & path)
396 // I have decided that we will be using parts from the boost
397 // library. Check out http://www.boost.org/
398 // For directory access we will then use the directory_iterator.
399 // Then the code will be something like:
400 // directory_iterator dit(path);
401 // directory_iterator dend;
402 // if (dit == dend) {
403 // WriteFSAlert(_("Error! Cannot open directory:"), path);
406 // for (; dit != dend; ++dit) {
407 // string filename(*dit);
408 // if (filename == "." || filename == "..")
410 // string unlinkpath(AddName(path, filename));
411 // if (lyx::unlink(unlinkpath))
412 // WriteFSAlert(_("Error! Could not remove file:"),
416 DIR * dir = ::opendir(path.c_str());
418 WriteFSAlert (_("Error! Cannot open directory:"), path);
422 int return_value = 0;
423 while ((de = readdir(dir))) {
424 string const temp = de->d_name;
425 if (temp == "." || temp == "..")
427 string const unlinkpath = AddName (path, temp);
429 lyxerr[Debug::FILES] << "Deleting file: " << unlinkpath
433 if (FileInfo(unlinkpath).isDir())
434 deleted = (DeleteAllFilesInDir(unlinkpath) == 0);
435 deleted &= (lyx::unlink(unlinkpath) == 0);
437 WriteFSAlert (_("Error! Could not remove file:"),
447 string const CreateTmpDir(string const & tempdir, string const & mask)
450 << "CreateTmpDir: tempdir=`" << tempdir << "'\n"
451 << "CreateTmpDir: mask=`" << mask << "'" << endl;
453 string const tmpfl(lyx::tempName(tempdir, mask));
454 // lyx::tempName actually creates a file to make sure that it
455 // stays unique. So we have to delete it before we can create
456 // a dir with the same name. Note also that we are not thread
457 // safe because of the gap between unlink and mkdir. (Lgb)
458 lyx::unlink(tmpfl.c_str());
460 if (tmpfl.empty() || lyx::mkdir(tmpfl, 0700)) {
461 WriteFSAlert(_("Error! Couldn't create temporary directory:"),
465 return MakeAbsPath(tmpfl);
469 int DestroyTmpDir(string const & tmpdir, bool Allfiles)
474 if (Allfiles && DeleteAllFilesInDir(tmpdir)) return -1;
475 if (lyx::rmdir(tmpdir)) {
476 WriteFSAlert(_("Error! Couldn't delete temporary directory:"),
486 string const CreateBufferTmpDir(string const & pathfor)
489 static string const tmpdir(pathfor.empty() ? os::getTmpDir() : pathfor);
490 // We are in our own directory. Why bother to mangle name?
491 // In fact I wrote this code to circumvent a problematic behaviour (bug?)
493 string const tmpfl = tmpdir + "/lyx_tmpbuf" + tostr(count++);
494 if (lyx::mkdir(tmpfl, 0777)) {
495 WriteFSAlert(_("Error! Couldn't create temporary directory:"),
503 int DestroyBufferTmpDir(string const & tmpdir)
505 return DestroyTmpDir(tmpdir, true);
509 string const CreateLyXTmpDir(string const & deflt)
511 if ((!deflt.empty()) && (deflt != "/tmp")) {
512 if (lyx::mkdir(deflt, 0777)) {
516 string const t(CreateTmpDir(deflt, "lyx_tmpdir"));
524 string const t(CreateTmpDir("/tmp", "lyx_tmpdir"));
530 int DestroyLyXTmpDir(string const & tmpdir)
532 return DestroyTmpDir (tmpdir, false); // Why false?
536 // Creates directory. Returns true if succesfull
537 bool createDirectory(string const & path, int permission)
539 string temp(strip(os::slashify_path(path), '/'));
542 WriteAlert(_("Internal error!"),
543 _("Call to createDirectory with invalid name"));
547 if (lyx::mkdir(temp, permission)) {
548 WriteFSAlert (_("Error! Couldn't create directory:"), temp);
555 // Strip filename from path name
556 string const OnlyPath(string const & Filename)
558 // If empty filename, return empty
559 if (Filename.empty()) return Filename;
561 // Find last / or start of filename
562 string::size_type j = Filename.rfind('/');
563 if (j == string::npos)
565 return Filename.substr(0, j + 1);
569 // Convert relative path into absolute path based on a basepath.
570 // If relpath is absolute, just use that.
571 // If basepath is empty, use CWD as base.
572 string const MakeAbsPath(string const & RelPath, string const & BasePath)
574 // checks for already absolute path
575 if (os::is_absolute_path(RelPath))
578 // Copies given paths
579 string TempRel(os::slashify_path(RelPath));
580 // Since TempRel is NOT absolute, we can safely replace "//" with "/"
581 TempRel = subst(TempRel, "//", "/");
585 if (os::is_absolute_path(BasePath))
588 TempBase = AddPath(lyx::getcwd(), BasePath);
590 // Handle /./ at the end of the path
591 while(suffixIs(TempBase, "/./"))
592 TempBase.erase(TempBase.length() - 2);
594 // processes relative path
595 string RTemp(TempRel);
598 while (!RTemp.empty()) {
600 RTemp = split(RTemp, Temp, '/');
602 if (Temp == ".") continue;
604 // Remove one level of TempBase
605 string::difference_type i = TempBase.length() - 2;
608 while (i > 0 && TempBase[i] != '/') --i;
612 while (i > 2 && TempBase[i] != '/') --i;
615 TempBase.erase(i, string::npos);
618 } else if (Temp.empty() && !RTemp.empty()) {
619 TempBase = os::current_root() + RTemp;
622 // Add this piece to TempBase
623 if (!suffixIs(TempBase, '/'))
629 // returns absolute path
630 return os::slashify_path(TempBase);
634 // Correctly append filename to the pathname.
635 // If pathname is '.', then don't use pathname.
636 // Chops any path of filename.
637 string const AddName(string const & path, string const & fname)
640 string const basename(OnlyFilename(fname));
644 if (path != "." && path != "./" && !path.empty()) {
645 buf = os::slashify_path(path);
646 if (!suffixIs(path, '/'))
650 return buf + basename;
654 // Strips path from filename
655 string const OnlyFilename(string const & fname)
660 string::size_type j = fname.rfind('/');
661 if (j == string::npos) // no '/' in fname
665 return fname.substr(j + 1);
669 /// Returns true is path is absolute
670 bool AbsolutePath(string const & path)
672 return os::is_absolute_path(path);
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 (os::is_absolute_path(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 (os::is_absolute_path(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 GetFileContents(string const & fname)
746 FileInfo finfo(fname);
748 ifstream ifs(fname.c_str());
753 return ofs.str().c_str();
756 lyxerr << "LyX was not able to read file '" << fname << "'" << endl;
762 // Search ${...} as Variable-Name inside the string and replace it with
763 // the denoted environmentvariable
764 // Allow Variables according to
765 // variable := '$' '{' [A-Za-z_]{[A-Za-z_0-9]*} '}'
768 string const ReplaceEnvironmentPath(string const & path)
771 // CompareChar: Environmentvariables starts with this character
772 // PathChar: Next path component start with this character
773 // while CompareChar found do:
774 // Split String with PathChar
775 // Search Environmentvariable
776 // if found: Replace Strings
778 char const CompareChar = '$';
779 char const FirstChar = '{';
780 char const EndChar = '}';
781 char const UnderscoreChar = '_';
782 string EndString; EndString += EndChar;
783 string FirstString; FirstString += FirstChar;
784 string CompareString; CompareString += CompareChar;
785 string const RegExp("*}*"); // Exist EndChar inside a String?
787 // first: Search for a '$' - Sign.
789 string result1; //(copy); // for split-calls
790 string result0 = split(path, result1, CompareChar);
791 while (!result0.empty()) {
792 string copy1(result0); // contains String after $
794 // Check, if there is an EndChar inside original String.
796 if (!regexMatch(copy1, RegExp)) {
797 // No EndChar inside. So we are finished
798 result1 += CompareString + result0;
804 string res0 = split(copy1, res1, EndChar);
805 // Now res1 holds the environmentvariable
806 // First, check, if Contents is ok.
807 if (res1.empty()) { // No environmentvariable. Continue Loop.
808 result1 += CompareString + FirstString;
812 // check contents of res1
813 char const * res1_contents = res1.c_str();
814 if (*res1_contents != FirstChar) {
815 // Again No Environmentvariable
816 result1 += CompareString;
820 // Check for variable names
821 // Situation ${} is detected as "No Environmentvariable"
822 char const * cp1 = res1_contents + 1;
823 bool result = isalpha(*cp1) || (*cp1 == UnderscoreChar);
825 while (*cp1 && result) {
826 result = isalnum(*cp1) ||
827 (*cp1 == UnderscoreChar);
832 // no correct variable name
833 result1 += CompareString + res1 + EndString;
834 result0 = split(res0, res1, CompareChar);
839 string env(GetEnv(res1_contents + 1));
841 // Congratulations. Environmentvariable found
844 result1 += CompareString + res1 + EndString;
847 result0 = split(res0, res1, CompareChar);
851 } // ReplaceEnvironmentPath
854 // Make relative path out of two absolute paths
855 string const MakeRelPath(string const & abspath, string const & basepath)
856 // Makes relative path out of absolute path. If it is deeper than basepath,
857 // it's easy. If basepath and abspath share something (they are all deeper
858 // than some directory), it'll be rendered using ..'s. If they are completely
859 // different, then the absolute path will be used as relative path.
861 string::size_type const abslen = abspath.length();
862 string::size_type const baselen = basepath.length();
864 string::size_type i = os::common_path(abspath, basepath);
867 // actually no match - cannot make it relative
871 // Count how many dirs there are in basepath above match
872 // and append as many '..''s into relpath
874 string::size_type j = i;
875 while (j < baselen) {
876 if (basepath[j] == '/') {
877 if (j + 1 == baselen) break;
883 // Append relative stuff from common directory to abspath
884 if (abspath[i] == '/') ++i;
885 for (; i < abslen; ++i)
888 if (suffixIs(buf, '/'))
889 buf.erase(buf.length() - 1);
890 // Substitute empty with .
897 // Append sub-directory(ies) to a path in an intelligent way
898 string const AddPath(string const & path, string const & path_2)
901 string const path2 = os::slashify_path(path_2);
903 if (!path.empty() && path != "." && path != "./") {
904 buf = os::slashify_path(path);
905 if (path[path.length() - 1] != '/')
909 if (!path2.empty()) {
910 string::size_type const p2start = path2.find_first_not_of('/');
911 string::size_type const p2end = path2.find_last_not_of('/');
912 string const tmp = path2.substr(p2start, p2end - p2start + 1);
920 Change extension of oldname to extension.
921 Strips path off if no_path == true.
922 If no extension on oldname, just appends.
925 ChangeExtension(string const & oldname, string const & extension)
927 string::size_type const last_slash = oldname.rfind('/');
928 string::size_type last_dot = oldname.rfind('.');
929 if (last_dot < last_slash && last_slash != string::npos)
930 last_dot = string::npos;
933 // Make sure the extension starts with a dot
934 if (!extension.empty() && extension[0] != '.')
935 ext= "." + extension;
939 return os::slashify_path(oldname.substr(0, last_dot) + ext);
943 /// Return the extension of the file (not including the .)
944 string const GetExtension(string const & name)
946 string::size_type const last_slash = name.rfind('/');
947 string::size_type const last_dot = name.rfind('.');
948 if (last_dot != string::npos &&
949 (last_slash == string::npos || last_dot > last_slash))
950 return name.substr(last_dot + 1,
951 name.length() - (last_dot + 1));
957 // Creates a nice compact path for displaying
959 MakeDisplayPath (string const & path, unsigned int threshold)
961 string::size_type const l1 = path.length();
963 // First, we try a relative path compared to home
964 string const home(GetEnvPath("HOME"));
965 string relhome = MakeRelPath(path, home);
967 string::size_type l2 = relhome.length();
971 // If we backup from home or don't have a relative path,
972 // this try is no good
973 if (prefixIs(relhome, "../") || os::is_absolute_path(relhome)) {
974 // relative path was no good, just use the original path
981 // Is the path too long?
982 if (l2 > threshold) {
988 while (relhome.length() > threshold)
989 relhome = split(relhome, temp, '/');
991 // Did we shortend everything away?
992 if (relhome.empty()) {
993 // Yes, filename in itself is too long.
994 // Pick the start and the end of the filename.
995 relhome = OnlyFilename(path);
996 string const head = relhome.substr(0, threshold/2 - 3);
998 l2 = relhome.length();
1000 relhome.substr(l2 - threshold/2 - 2, l2 - 1);
1001 relhome = head + "..." + tail;
1004 return prefix + relhome;
1008 bool LyXReadLink(string const & File, string & Link)
1010 char LinkBuffer[512];
1011 // Should be PATH_MAX but that needs autconf support
1012 int const nRead = ::readlink(File.c_str(),
1013 LinkBuffer, sizeof(LinkBuffer) - 1);
1016 LinkBuffer[nRead] = '\0'; // terminator
1024 typedef pair<int, string> cmdret;
1026 cmdret const do_popen(string const & cmd)
1028 // One question is if we should use popen or
1029 // create our own popen based on fork, exec, pipe
1030 // of course the best would be to have a
1031 // pstream (process stream), with the
1032 // variants ipstream, opstream
1033 FILE * inf = ::popen(cmd.c_str(), "r");
1037 ret += static_cast<char>(c);
1040 int const pret = pclose(inf);
1041 return make_pair(pret, ret);
1048 findtexfile(string const & fil, string const & /*format*/)
1050 /* There is no problem to extend this function too use other
1051 methods to look for files. It could be setup to look
1052 in environment paths and also if wanted as a last resort
1053 to a recursive find. One of the easier extensions would
1054 perhaps be to use the LyX file lookup methods. But! I am
1055 going to implement this until I see some demand for it.
1059 // If the file can be found directly, we just return a
1060 // absolute path version of it.
1061 if (FileInfo(fil).exist())
1062 return MakeAbsPath(fil);
1064 // No we try to find it using kpsewhich.
1065 // It seems from the kpsewhich manual page that it is safe to use
1066 // kpsewhich without --format: "When the --format option is not
1067 // given, the search path used when looking for a file is inferred
1068 // from the name given, by looking for a known extension. If no
1069 // known extension is found, the search path for TeX source files
1071 // However, we want to take advantage of the format sine almost all
1072 // the different formats has environment variables that can be used
1073 // to controll which paths to search. f.ex. bib looks in
1074 // BIBINPUTS and TEXBIB. Small list follows:
1075 // bib - BIBINPUTS, TEXBIB
1077 // graphic/figure - TEXPICTS, TEXINPUTS
1078 // ist - TEXINDEXSTYLE, INDEXSTYLE
1079 // pk - PROGRAMFONTS, PKFONTS, TEXPKS, GLYPHFONTS, TEXFONTS
1081 // tfm - TFMFONTS, TEXFONTS
1082 // This means that to use kpsewhich in the best possible way we
1083 // should help it by setting additional path in the approp. envir.var.
1084 string const kpsecmd = "kpsewhich " + fil;
1086 cmdret const c = do_popen(kpsecmd);
1088 lyxerr[Debug::LATEX] << "kpse status = " << c.first << "\n"
1089 << "kpse result = `" << strip(c.second, '\n')
1092 return os::internal_path(strip(strip(c.second, '\n'), '\r'));
1098 void removeAutosaveFile(string const & filename)
1100 string a = OnlyPath(filename);
1102 a += OnlyFilename(filename);
1104 FileInfo const fileinfo(a);
1105 if (fileinfo.exist()) {
1106 if (lyx::unlink(a) != 0) {
1107 WriteFSAlert(_("Could not delete auto-save file!"), a);