3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS.
13 #include "support/filename.h"
14 #include "support/filetools.h"
15 #include "support/lstrings.h"
16 #include "support/os.h"
18 #include <boost/assert.hpp>
33 : save_abs_path_(true)
37 FileName::FileName(string const & abs_filename, bool save_abs)
38 : name_(abs_filename), save_abs_path_(save_abs)
40 BOOST_ASSERT(AbsolutePath(name_));
44 void FileName::set(string const & name, string const & buffer_path)
46 save_abs_path_ = AbsolutePath(name);
47 name_ = save_abs_path_ ? name : MakeAbsPath(name, buffer_path);
51 void FileName::erase()
57 string const FileName::relFilename(string const & path) const
59 return MakeRelPath(name_, path);
63 string const FileName::outputFilename(string const & path) const
65 return save_abs_path_ ? name_ : MakeRelPath(name_, path);
69 string const FileName::mangledFilename(std::string const & dir) const
71 // We need to make sure that every FileName instance for a given
72 // filename returns the same mangled name.
73 typedef map<string, string> MangledMap;
74 static MangledMap mangledNames;
75 MangledMap::const_iterator const it = mangledNames.find(name_);
76 if (it != mangledNames.end())
80 string mname = os::internal_path(name_);
81 // Remove the extension.
82 mname = ChangeExtension(name_, string());
83 // Replace '/' in the file name with '_'
84 mname = subst(mname, "/", "_");
85 // Replace '.' in the file name with '_'
86 mname = subst(mname, ".", "_");
87 // Replace ' ' in the file name with '_'
88 mname = subst(mname, " ", "_");
89 // Replace ':' in the file name with '_'
90 mname = subst(mname, ":", "_");
91 // Add the extension back on
92 mname = ChangeExtension(mname, GetExtension(name_));
94 // Prepend a counter to the filename. This is necessary to make
95 // the mangled name unique.
96 static int counter = 0;
98 s << counter++ << mname;
101 // Experiments show that MiKTeX's YAP (version 2.4.1803)
102 // will crash if the string referencing the file name in
103 // the .dvi file is longer than 220 characters.
104 // This string contains about 50 chars-worth of other data,
105 // leaving us, say, 160 characters for the file name itself.
106 // (Erring on the side of caution.)
107 // Other experiments show that MiKTeX's pdflatex compiler is even
108 // more picky. A maximum length of 140 has been proven to work.
109 string::size_type max_length = 140;
110 if (dir.size() - 1 < max_length) {
111 // "+ 1" for the directory separator.
112 max_length -= dir.size() + 1;
114 // If dir.size() > max_length, all bets are off for YAP anyway.
115 // We truncate the filename nevertheless because of MiKTeX's
116 // pdflatex compiler.
118 // If the mangled file name is too long, hack it to fit.
119 // We know we're guaranteed to have a unique file name because
121 if (mname.size() > max_length) {
122 int const half = (int(max_length) / 2) - 2;
124 mname = mname.substr(0, half) + "___" +
125 mname.substr(mname.size() - half);
129 mangledNames[name_] = mname;
134 bool FileName::isZipped() const
136 return zippedFile(name_);
140 string const FileName::unzippedFilename() const
142 return unzippedFileName(name_);
146 bool operator==(FileName const & lhs, FileName const & rhs)
148 return lhs.absFilename() == rhs.absFilename() &&
149 lhs.saveAbsPath() == rhs.saveAbsPath();
153 bool operator!=(FileName const & lhs, FileName const & rhs)
155 return !(lhs == rhs);
158 } // namespace support