]> git.lyx.org Git - lyx.git/blob - src/support/filename.C
Detect mode_t for safe use of chmod, and for scons/msvc
[lyx.git] / src / support / filename.C
1 /**
2  * \file filename.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "support/filename.h"
14 #include "support/filetools.h"
15 #include "support/lstrings.h"
16 #include "support/os.h"
17
18 #include <boost/assert.hpp>
19
20 #include <map>
21 #include <sstream>
22 #include <algorithm>
23
24
25 using std::map;
26 using std::string;
27
28
29 namespace lyx {
30 namespace support {
31
32
33 FileName::FileName()
34 {}
35
36
37 FileName::FileName(string const & abs_filename)
38         : name_(abs_filename)
39 {
40         BOOST_ASSERT(absolutePath(name_));
41 }
42
43
44 bool operator==(FileName const & lhs, FileName const & rhs)
45 {
46         return lhs.absFilename() == rhs.absFilename();
47 }
48
49
50 bool operator!=(FileName const & lhs, FileName const & rhs)
51 {
52         return lhs.absFilename() != rhs.absFilename();
53 }
54
55
56 DocFileName::DocFileName()
57         : save_abs_path_(true)
58 {}
59
60
61 DocFileName::DocFileName(string const & abs_filename, bool save_abs)
62         : FileName(abs_filename), save_abs_path_(save_abs), zipped_valid_(false)
63 {}
64
65
66 void DocFileName::set(string const & name, string const & buffer_path)
67 {
68         save_abs_path_ = absolutePath(name);
69         name_ = save_abs_path_ ? name : makeAbsPath(name, buffer_path);
70         zipped_valid_ = false;
71 }
72
73
74 void DocFileName::erase()
75 {
76         name_.erase();
77         zipped_valid_ = false;
78 }
79
80
81 string const DocFileName::relFilename(string const & path) const
82 {
83         return makeRelPath(name_, path);
84 }
85
86
87 string const DocFileName::outputFilename(string const & path) const
88 {
89         return save_abs_path_ ? name_ : makeRelPath(name_, path);
90 }
91
92
93 string const DocFileName::mangledFilename(std::string const & dir) const
94 {
95         // We need to make sure that every DocFileName instance for a given
96         // filename returns the same mangled name.
97         typedef map<string, string> MangledMap;
98         static MangledMap mangledNames;
99         MangledMap::const_iterator const it = mangledNames.find(name_);
100         if (it != mangledNames.end())
101                 return (*it).second;
102
103         // Now the real work
104         string mname = os::internal_path(name_);
105         // Remove the extension.
106         mname = changeExtension(name_, string());
107         // Replace '/' in the file name with '_'
108         mname = subst(mname, "/", "_");
109         // Replace '.' in the file name with '_'
110         mname = subst(mname, ".", "_");
111         // Replace ' ' in the file name with '_'
112         mname = subst(mname, " ", "_");
113         // Replace ':' in the file name with '_'
114         mname = subst(mname, ":", "_");
115         // Add the extension back on
116         mname = changeExtension(mname, getExtension(name_));
117
118         // Prepend a counter to the filename. This is necessary to make
119         // the mangled name unique.
120         static int counter = 0;
121         std::ostringstream s;
122         s << counter++ << mname;
123         mname = s.str();
124
125         // MiKTeX's YAP (version 2.4.1803) crashes if the file name
126         // is longer than about 160 characters. MiKTeX's pdflatex
127         // is even pickier. A maximum length of 100 has been proven to work.
128         // If dir.size() > max length, all bets are off for YAP. We truncate
129         // the filename nevertheless, keeping a minimum of 10 chars.
130
131         string::size_type max_length = std::max(100 - ((int)dir.size() + 1), 10);
132
133         // If the mangled file name is too long, hack it to fit.
134         // We know we're guaranteed to have a unique file name because
135         // of the counter.
136         if (mname.size() > max_length) {
137                 int const half = (int(max_length) / 2) - 2;
138                 if (half > 0) {
139                         mname = mname.substr(0, half) + "___" +
140                                 mname.substr(mname.size() - half);
141                 }
142         }
143
144         mangledNames[name_] = mname;
145         return mname;
146 }
147
148
149 bool DocFileName::isZipped() const
150 {
151         if (!zipped_valid_) {
152                 zipped_ = zippedFile(name_);
153                 zipped_valid_ = true;
154         }
155         return zipped_;
156 }
157
158
159 string const DocFileName::unzippedFilename() const
160 {
161         return unzippedFileName(name_);
162 }
163
164
165 bool operator==(DocFileName const & lhs, DocFileName const & rhs)
166 {
167         return lhs.absFilename() == rhs.absFilename() &&
168                 lhs.saveAbsPath() == rhs.saveAbsPath();
169 }
170
171
172 bool operator!=(DocFileName const & lhs, DocFileName const & rhs)
173 {
174         return !(lhs == rhs);
175 }
176
177 } // namespace support
178 } // namespace lyx