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)
38 // Which part of this is still necessary? (JMarc).
41 # define NAMLEN(dirent) strlen((dirent)->d_name)
43 # define dirent direct
44 # define NAMLEN(dirent) (dirent)->d_namlen
46 # include <sys/ndir.h>
61 extern string system_lyxdir;
62 extern string build_lyxdir;
63 extern string user_lyxdir;
64 extern string system_tempdir;
67 bool IsLyXFilename(string const & filename)
69 return contains(filename, ".lyx");
73 // Substitutes spaces with underscores in filename (and path)
74 string const MakeLatexName(string const & file)
76 string name = OnlyFilename(file);
77 string const path = OnlyPath(file);
79 for (string::size_type i = 0; i < name.length(); ++i) {
80 name[i] &= 0x7f; // set 8th bit to 0
83 // ok so we scan through the string twice, but who cares.
84 string const keep("abcdefghijklmnopqrstuvwxyz"
85 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
86 "@!\"'()*+,-./0123456789:;<=>?[]`|");
88 string::size_type pos = 0;
89 while ((pos = name.find_first_not_of(keep, pos)) != string::npos) {
92 return AddName(path, name);
96 // Substitutes spaces with underscores in filename (and path)
97 string const QuoteName(string const & name)
99 // CHECK Add proper emx support here!
101 return "\'" + name + "\'";
108 // Returns an unique name to be used as a temporary file.
109 string const TmpFileName(string const & dir, string const & mask)
110 {// With all these temporary variables, it should be safe enough :-) (JMarc)
113 tmpdir = system_tempdir;
116 string tmpfl(AddName(tmpdir, mask));
118 // find a uniq postfix for the filename...
119 // using the pid, and...
120 tmpfl += tostr(getpid());
124 for (int a = 'a'; a <= 'z'; ++a)
125 for (int b = 'a'; b <= 'z'; ++b)
126 for (int c = 'a'; c <= 'z'; ++c) {
127 // if this is not enough I have no idea what
129 ret = tmpfl + char(a) + char(b) + char(c);
130 // check if the file exist
131 if (!fnfo.newFile(ret).exist())
134 lyxerr << "Not able to find a uniq tmpfile name." << endl;
139 // Is a file readable ?
140 bool IsFileReadable (string const & path)
143 if (file.isOK() && file.isRegular() && file.readable())
150 // Is a file read_only?
151 // return 1 read-write
153 // -1 error (doesn't exist, no access, anything else)
154 int IsFileWriteable (string const & path)
157 if (fi.access(FileInfo::wperm|FileInfo::rperm)) // read-write
159 if (fi.readable()) // read-only
161 return -1; // everything else.
165 //returns 1: dir writeable
167 // -1: error- couldn't find out
168 int IsDirWriteable (string const & path)
170 string const tmpfl(TmpFileName(path));
173 WriteFSAlert(_("LyX Internal Error!"),
174 _("Could not test if directory is writeable"));
178 if (fi.writable()) return 1;
184 // Uses a string of paths separated by ";"s to find a file to open.
185 // Can't cope with pathnames with a ';' in them. Returns full path to file.
186 // If path entry begins with $$LyX/, use system_lyxdir
187 // If path entry begins with $$User/, use user_lyxdir
188 // Example: "$$User/doc;$$LyX/doc"
189 string const FileOpenSearch (string const & path, string const & name,
192 string real_file, path_element;
193 bool notfound = true;
194 string tmppath = split(path, path_element, ';');
196 while (notfound && !path_element.empty()) {
197 path_element = CleanupPath(path_element);
198 if (!suffixIs(path_element, '/'))
200 path_element = subst(path_element, "$$LyX", system_lyxdir);
201 path_element = subst(path_element, "$$User", user_lyxdir);
203 real_file = FileSearch(path_element, name, ext);
205 if (real_file.empty()) {
207 tmppath = split(tmppath, path_element, ';');
208 } while(!tmppath.empty() && path_element.empty());
214 if (ext.empty() && notfound) {
215 real_file = FileOpenSearch(path, name, "exe");
216 if (notfound) real_file = FileOpenSearch(path, name, "cmd");
223 // Returns the real name of file name in directory path, with optional
225 string const FileSearch(string const & path, string const & name,
228 // if `name' is an absolute path, we ignore the setting of `path'
229 // Expand Environmentvariables in 'name'
230 string const tmpname = ReplaceEnvironmentPath(name);
231 string fullname = MakeAbsPath(tmpname, path);
233 // search first without extension, then with it.
234 if (IsFileReadable(fullname))
236 else if (ext.empty())
238 else { // Is it not more reasonable to use ChangeExtension()? (SMiyata)
241 if (IsFileReadable(fullname))
249 // Search the file name.ext in the subdirectory dir of
251 // 2) build_lyxdir (if not empty)
253 string const LibFileSearch(string const & dir, string const & name,
256 string fullname = FileSearch(AddPath(user_lyxdir, dir),
258 if (!fullname.empty())
261 if (!build_lyxdir.empty())
262 fullname = FileSearch(AddPath(build_lyxdir, dir),
264 if (!fullname.empty())
267 return FileSearch(AddPath(system_lyxdir, dir), name, ext);
272 i18nLibFileSearch(string const & dir, string const & name,
275 string const lang = token(string(GetEnv("LANG")), '_', 0);
277 if (lang.empty() || lang == "C")
278 return LibFileSearch(dir, name, ext);
280 string const tmp = LibFileSearch(dir, lang + '_' + name,
285 return LibFileSearch(dir, name, ext);
290 string const GetEnv(string const & envname)
292 // f.ex. what about error checking?
293 char const * const ch = ::getenv(envname.c_str());
294 string const envstr = !ch ? "" : ch;
299 string const GetEnvPath(string const & name)
302 string const pathlist = subst(GetEnv(name), ':', ';');
304 string const pathlist = subst(GetEnv(name), '\\', '/');
306 return strip(pathlist, ';');
310 bool PutEnv(string const & envstr)
312 // CHECK Look at and fix this.
313 // f.ex. what about error checking?
316 // this leaks, but what can we do about it?
317 // Is doing a getenv() and a free() of the older value
318 // a good idea? (JMarc)
319 // Actually we don't have to leak...calling putenv like this
320 // should be enough: ... and this is obviously not enough if putenv
321 // does not make a copy of the string. It is also not very wise to
322 // put a string on the free store. If we have to leak we should do it
324 char * leaker = new char[envstr.length() + 1];
325 envstr.copy(leaker, envstr.length());
326 leaker[envstr.length()] = '\0';
327 int const retval = lyx::putenv(leaker);
329 // If putenv does not make a copy of the char const * this
330 // is very dangerous. OTOH if it does take a copy this is the
332 // The only implementation of putenv that I have seen does not
333 // allocate memory. _And_ after testing the putenv in glibc it
334 // seems that we need to make a copy of the string contents.
335 // I will enable the above.
336 //int retval = lyx::putenv(envstr.c_str());
340 string const str = envstr.split(varname,'=');
341 int const retval = ::setenv(varname.c_str(), str.c_str(), true);
343 // No environment setting function. Can this happen?
344 int const retval = 1; //return an error condition.
351 bool PutEnvPath(string const & envstr)
353 return PutEnv(envstr);
358 int DeleteAllFilesInDir (string const & path)
360 // I have decided that we will be using parts from the boost
361 // library. Check out http://www.boost.org/
362 // For directory access we will then use the directory_iterator.
363 // Then the code will be something like:
364 // directory_iterator dit(path);
365 // directory_iterator dend;
366 // if (dit == dend) {
367 // WriteFSAlert(_("Error! Cannot open directory:"), path);
370 // for (; dit != dend; ++dit) {
371 // string filename(*dit);
372 // if (filename == "." || filename == "..")
374 // string unlinkpath(AddName(path, filename));
375 // if (lyx::unlink(unlinkpath))
376 // WriteFSAlert(_("Error! Could not remove file:"),
380 DIR * dir = ::opendir(path.c_str());
382 WriteFSAlert (_("Error! Cannot open directory:"), path);
386 int return_value = 0;
387 while ((de = readdir(dir))) {
388 string const temp = de->d_name;
389 if (temp == "." || temp == "..")
391 string const unlinkpath = AddName (path, temp);
393 lyxerr.debug() << "Deleting file: " << unlinkpath << endl;
396 if (FileInfo(unlinkpath).isDir())
397 deleted = (DeleteAllFilesInDir(unlinkpath) == 0);
398 deleted &= (lyx::unlink(unlinkpath) == 0);
400 WriteFSAlert (_("Error! Could not remove file:"),
411 string const CreateTmpDir(string const & tempdir, string const & mask)
413 string const tmpfl(TmpFileName(tempdir, mask));
415 if ((tmpfl.empty()) || lyx::mkdir(tmpfl, 0777)) {
416 WriteFSAlert(_("Error! Couldn't create temporary directory:"),
420 return MakeAbsPath(tmpfl);
425 int DestroyTmpDir(string const & tmpdir, bool Allfiles)
430 if (Allfiles && DeleteAllFilesInDir(tmpdir)) return -1;
431 if (lyx::rmdir(tmpdir)) {
432 WriteFSAlert(_("Error! Couldn't delete temporary directory:"),
440 string const CreateBufferTmpDir(string const & pathfor)
442 return CreateTmpDir(pathfor, "lyx_bufrtmp");
446 int DestroyBufferTmpDir(string const & tmpdir)
448 return DestroyTmpDir(tmpdir, true);
452 string const CreateLyXTmpDir(string const & deflt)
454 if ((!deflt.empty()) && (deflt != "/tmp")) {
455 if (lyx::mkdir(deflt, 0777)) {
459 string const t(CreateTmpDir(deflt, "lyx_tmp"));
467 string const t(CreateTmpDir("/tmp", "lyx_tmp"));
473 int DestroyLyXTmpDir (string const & tmpdir)
475 return DestroyTmpDir (tmpdir, false); // Why false?
479 // Creates directory. Returns true if succesfull
480 bool createDirectory(string const & path, int permission)
482 string temp(strip(CleanupPath(path), '/'));
485 WriteAlert(_("Internal error!"),
486 _("Call to createDirectory with invalid name"));
490 if (lyx::mkdir(temp, permission)) {
491 WriteFSAlert (_("Error! Couldn't create directory:"), temp);
498 // Returns current working directory
499 string const GetCWD ()
501 int n = 256; // Assume path is less than 256 chars
503 char * tbuf = new char[n];
505 // Safe. Hopefully all getcwds behave this way!
506 while (((err = lyx::getcwd(tbuf, n)) == 0) && (errno == ERANGE)) {
507 // Buffer too small, double the buffersize and try again
514 if (err) result = tbuf;
520 // Strip filename from path name
521 string const OnlyPath(string const & Filename)
523 // If empty filename, return empty
524 if (Filename.empty()) return Filename;
526 // Find last / or start of filename
527 string::size_type j = Filename.rfind('/');
528 if (j == string::npos)
530 return Filename.substr(0, j + 1);
534 // Convert relative path into absolute path based on a basepath.
535 // If relpath is absolute, just use that.
536 // If basepath is empty, use CWD as base.
537 string const MakeAbsPath(string const & RelPath, string const & BasePath)
539 // checks for already absolute path
540 if (AbsolutePath(RelPath))
542 if(RelPath[0]!= '/' && RelPath[0]!= '\\')
546 // Copies given paths
547 string TempRel(CleanupPath(RelPath));
551 if (!BasePath.empty()) {
555 char * with_drive = new char[_MAX_PATH];
556 _abspath(with_drive, BasePath.c_str(), _MAX_PATH);
557 TempBase = with_drive;
563 if (AbsolutePath(TempRel))
564 return TempBase.substr(0, 2) + TempRel;
567 // Handle /./ at the end of the path
568 while(suffixIs(TempBase, "/./"))
569 TempBase.erase(TempBase.length() - 2);
571 // processes relative path
572 string RTemp(TempRel);
575 while (!RTemp.empty()) {
577 RTemp = split(RTemp, Temp, '/');
579 if (Temp == ".") continue;
581 // Remove one level of TempBase
582 int i = TempBase.length() - 2;
585 while (i > 0 && TempBase[i] != '/') --i;
589 while (i > 2 && TempBase[i] != '/') --i;
592 TempBase.erase(i, string::npos);
596 // Add this piece to TempBase
597 if (!suffixIs(TempBase, '/'))
603 // returns absolute path
608 // Correctly append filename to the pathname.
609 // If pathname is '.', then don't use pathname.
610 // Chops any path of filename.
611 string const AddName(string const & path, string const & fname)
614 string const basename(OnlyFilename(fname));
618 if (path != "." && path != "./" && !path.empty()) {
619 buf = CleanupPath(path);
620 if (!suffixIs(path, '/'))
624 return buf + basename;
628 // Strips path from filename
629 string const OnlyFilename(string const & fname)
634 string::size_type j = fname.rfind('/');
635 if (j == string::npos) // no '/' in fname
639 return fname.substr(j + 1);
643 // Is a filename/path absolute?
644 bool AbsolutePath(string const & path)
647 return (!path.empty() && path[0] == '/');
649 return (!path.empty() && (path[0] == '/' || (isalpha(static_cast<unsigned char>(path[0])) && path.length()>1 && path[1] == ':')));
654 // Create absolute path. If impossible, don't do anything
655 // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
656 string const ExpandPath(string const & path)
658 // checks for already absolute path
659 string RTemp(ReplaceEnvironmentPath(path));
660 if (AbsolutePath(RTemp))
664 string const copy(RTemp);
667 RTemp = split(RTemp, Temp, '/');
670 return GetCWD() + '/' + RTemp;
671 } else if (Temp == "~") {
672 return GetEnvPath("HOME") + '/' + RTemp;
673 } else if (Temp == "..") {
674 return MakeAbsPath(copy);
676 // Don't know how to handle this
682 // Constracts path/../path
683 // Can't handle "../../" or "/../" (Asger)
684 string const NormalizePath(string const & path)
690 if (AbsolutePath(path))
693 // Make implicit current directory explicit
696 while (!RTemp.empty()) {
698 RTemp = split(RTemp, Temp, '/');
702 } else if (Temp == "..") {
703 // Remove one level of TempBase
704 int i = TempBase.length() - 2;
705 while (i > 0 && TempBase[i] != '/')
707 if (i >= 0 && TempBase[i] == '/')
708 TempBase.erase(i + 1, string::npos);
712 TempBase += Temp + '/';
716 // returns absolute path
721 string const CleanupPath(string const & path)
723 #ifdef __EMX__ /* SMiyata: This should fix searchpath bug. */
724 string temppath = subst(path, '\\', '/');
725 temppath = subst(temppath, "//", "/");
726 return lowercase(temppath);
727 #else // On unix, nothing to do
733 string const GetFileContents(string const & fname)
735 FileInfo finfo(fname);
737 ifstream ifs(fname.c_str());
738 std::ostringstream ofs;
742 return ofs.str().c_str();
745 lyxerr << "LyX was not able to read file '" << fname << "'" << endl;
751 // Search ${...} as Variable-Name inside the string and replace it with
752 // the denoted environmentvariable
753 // Allow Variables according to
754 // variable := '$' '{' [A-Za-z_]{[A-Za-z_0-9]*} '}'
757 string const ReplaceEnvironmentPath(string const & path)
760 // CompareChar: Environmentvariables starts with this character
761 // PathChar: Next path component start with this character
762 // while CompareChar found do:
763 // Split String with PathChar
764 // Search Environmentvariable
765 // if found: Replace Strings
767 char const CompareChar = '$';
768 char const FirstChar = '{';
769 char const EndChar = '}';
770 char const UnderscoreChar = '_';
771 string EndString; EndString += EndChar;
772 string FirstString; FirstString += FirstChar;
773 string CompareString; CompareString += CompareChar;
774 string const RegExp("*}*"); // Exist EndChar inside a String?
776 // first: Search for a '$' - Sign.
778 string result1; //(copy); // for split-calls
779 string result0 = split(path, result1, CompareChar);
780 while (!result0.empty()) {
781 string copy1(result0); // contains String after $
783 // Check, if there is an EndChar inside original String.
785 if (!regexMatch(copy1, RegExp)) {
786 // No EndChar inside. So we are finished
787 result1 += CompareString + result0;
793 string res0 = split(copy1, res1, EndChar);
794 // Now res1 holds the environmentvariable
795 // First, check, if Contents is ok.
796 if (res1.empty()) { // No environmentvariable. Continue Loop.
797 result1 += CompareString + FirstString;
801 // check contents of res1
802 char const * res1_contents = res1.c_str();
803 if (*res1_contents != FirstChar) {
804 // Again No Environmentvariable
805 result1 += CompareString;
809 // Check for variable names
810 // Situation ${} is detected as "No Environmentvariable"
811 char const * cp1 = res1_contents + 1;
812 bool result = isalpha(*cp1) || (*cp1 == UnderscoreChar);
814 while (*cp1 && result) {
815 result = isalnum(*cp1) ||
816 (*cp1 == UnderscoreChar);
821 // no correct variable name
822 result1 += CompareString + res1 + EndString;
823 result0 = split(res0, res1, CompareChar);
828 string env(GetEnv(res1_contents + 1));
830 // Congratulations. Environmentvariable found
833 result1 += CompareString + res1 + EndString;
836 result0 = split(res0, res1, CompareChar);
840 } // ReplaceEnvironmentPath
843 // Make relative path out of two absolute paths
844 string const MakeRelPath(string const & abspath0, string const & basepath0)
845 // Makes relative path out of absolute path. If it is deeper than basepath,
846 // it's easy. If basepath and abspath share something (they are all deeper
847 // than some directory), it'll be rendered using ..'s. If they are completely
848 // different, then the absolute path will be used as relative path.
850 // This is a hack. It should probaly be done in another way. Lgb.
851 string abspath = CleanupPath(abspath0);
852 string basepath = CleanupPath(basepath0);
854 return "<unknown_path>";
856 int const abslen = abspath.length();
857 int const baselen = basepath.length();
859 // Find first different character
861 while (i < abslen && i < baselen && abspath[i] == basepath[i]) ++i;
864 if (i < abslen && i < baselen
865 || (i<abslen && abspath[i] != '/' && i == baselen)
866 || (i<baselen && basepath[i] != '/' && i == abslen))
868 if (i) --i; // here was the last match
869 while (i && abspath[i] != '/') --i;
873 // actually no match - cannot make it relative
877 // Count how many dirs there are in basepath above match
878 // and append as many '..''s into relpath
881 while (j < baselen) {
882 if (basepath[j] == '/') {
883 if (j + 1 == baselen) break;
889 // Append relative stuff from common directory to abspath
890 if (abspath[i] == '/') ++i;
891 for (; i < abslen; ++i)
894 if (suffixIs(buf, '/'))
895 buf.erase(buf.length() - 1);
896 // Substitute empty with .
903 // Append sub-directory(ies) to a path in an intelligent way
904 string const AddPath(string const & path, string const & path_2)
907 string const path2 = CleanupPath(path_2);
909 if (!path.empty() && path != "." && path != "./") {
910 buf = CleanupPath(path);
911 if (path[path.length() - 1] != '/')
916 int p2start = path2.find_first_not_of('/');
918 int p2end = path2.find_last_not_of('/');
920 string tmp = path2.substr(p2start, p2end - p2start + 1);
928 Change extension of oldname to extension.
929 Strips path off if no_path == true.
930 If no extension on oldname, just appends.
933 ChangeExtension(string const & oldname, string const & extension)
935 string::size_type const last_slash = oldname.rfind('/');
936 string::size_type last_dot = oldname.rfind('.');
937 if (last_dot < last_slash && last_slash != string::npos)
938 last_dot = string::npos;
941 // Make sure the extension starts with a dot
942 if (!extension.empty() && extension[0] != '.')
943 ext= "." + extension;
947 return CleanupPath(oldname.substr(0, last_dot) + ext);
951 /// Return the extension of the file (not including the .)
952 string const GetExtension(string const & name)
954 string::size_type const last_slash = name.rfind('/');
955 string::size_type const last_dot = name.rfind('.');
956 if (last_dot != string::npos &&
957 (last_slash == string::npos || last_dot > last_slash))
958 return name.substr(last_dot + 1,
959 name.length() - (last_dot + 1));
965 // Creates a nice compact path for displaying
967 MakeDisplayPath (string const & path, unsigned int threshold)
969 int const l1 = path.length();
971 // First, we try a relative path compared to home
972 string const home(GetEnvPath("HOME"));
973 string relhome = MakeRelPath(path, home);
975 unsigned int l2 = relhome.length();
979 // If we backup from home or don't have a relative path,
980 // this try is no good
981 if (prefixIs(relhome, "../") || AbsolutePath(relhome)) {
982 // relative path was no good, just use the original path
989 // Is the path too long?
990 if (l2 > threshold) {
996 while (relhome.length() > threshold)
997 relhome = split(relhome, temp, '/');
999 // Did we shortend everything away?
1000 if (relhome.empty()) {
1001 // Yes, filename in itself is too long.
1002 // Pick the start and the end of the filename.
1003 relhome = OnlyFilename(path);
1004 string head = relhome.substr(0, threshold/2 - 3);
1006 l2 = relhome.length();
1008 relhome.substr(l2 - threshold/2 - 2, l2 - 1);
1009 relhome = head + "..." + tail;
1012 return prefix + relhome;
1016 bool LyXReadLink(string const & File, string & Link)
1018 char LinkBuffer[512];
1019 // Should be PATH_MAX but that needs autconf support
1020 int const nRead = ::readlink(File.c_str(),
1021 LinkBuffer, sizeof(LinkBuffer) - 1);
1024 LinkBuffer[nRead] = 0;
1030 typedef pair<int, string> cmdret;
1032 cmdret const do_popen(string const & cmd)
1034 // One question is if we should use popen or
1035 // create our own popen based on fork, exec, pipe
1036 // of course the best would be to have a
1037 // pstream (process stream), with the
1038 // variants ipstream, opstream
1039 FILE * inf = ::popen(cmd.c_str(), "r");
1043 ret += static_cast<char>(c);
1046 int pret = pclose(inf);
1047 return make_pair(pret, ret);
1052 findtexfile(string const & fil, string const & /*format*/)
1054 /* There is no problem to extend this function too use other
1055 methods to look for files. It could be setup to look
1056 in environment paths and also if wanted as a last resort
1057 to a recursive find. One of the easier extensions would
1058 perhaps be to use the LyX file lookup methods. But! I am
1059 going to implement this until I see some demand for it.
1063 // If the file can be found directly, we just return a
1064 // absolute path version of it.
1065 if (FileInfo(fil).exist())
1066 return MakeAbsPath(fil);
1068 // No we try to find it using kpsewhich.
1069 // It seems from the kpsewhich manual page that it is safe to use
1070 // kpsewhich without --format: "When the --format option is not
1071 // given, the search path used when looking for a file is inferred
1072 // from the name given, by looking for a known extension. If no
1073 // known extension is found, the search path for TeX source files
1075 // However, we want to take advantage of the format sine almost all
1076 // the different formats has environment variables that can be used
1077 // to controll which paths to search. f.ex. bib looks in
1078 // BIBINPUTS and TEXBIB. Small list follows:
1079 // bib - BIBINPUTS, TEXBIB
1081 // graphic/figure - TEXPICTS, TEXINPUTS
1082 // ist - TEXINDEXSTYLE, INDEXSTYLE
1083 // pk - PROGRAMFONTS, PKFONTS, TEXPKS, GLYPHFONTS, TEXFONTS
1085 // tfm - TFMFONTS, TEXFONTS
1086 // This means that to use kpsewhich in the best possible way we
1087 // should help it by setting additional path in the approp. envir.var.
1088 string const kpsecmd = "kpsewhich " + fil;
1090 cmdret const c = do_popen(kpsecmd);
1092 lyxerr[Debug::LATEX] << "kpse status = " << c.first << "\n"
1093 << "kpse result = `" << strip(c.second, '\n')
1095 return c.first != -1 ? strip(c.second, '\n') : string();
1099 void removeAutosaveFile(string const & filename)
1101 string a = OnlyPath(filename);
1103 a += OnlyFilename(filename);
1105 FileInfo fileinfo(a);
1106 if (fileinfo.exist()) {
1107 if (lyx::unlink(a) != 0) {
1108 WriteFSAlert(_("Could not delete auto-save file!"), a);