]> git.lyx.org Git - lyx.git/blob - src/support/os_cygwin.C
Fix several filename and environment variable encoding problems
[lyx.git] / src / support / os_cygwin.C
1 /**
2  * \file os_cygwin.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Ruurd A. Reitsma
7  * \author Claus Hentschel
8  * \author Angus Leeming
9  *
10  * Full author contact details are available in file CREDITS.
11  *
12  * Various OS specific functions
13  */
14
15 #include <config.h>
16
17 #include "support/os.h"
18 #include "support/lstrings.h"
19
20 #include "debug.h"
21
22 #include <windows.h>
23 #include <io.h>
24 #include <windef.h>
25 #include <shellapi.h>   
26 #include <shlwapi.h>
27
28 #include <sys/cygwin.h>
29
30 using std::endl;
31 using std::string;
32
33 using lyx::support::contains;
34
35 #ifdef X_DISPLAY_MISSING
36 #include "support/filetools.h"
37 #include "support/package.h"
38 #include "support/path.h"
39 using lyx::support::addName;
40 using lyx::support::addPath;
41 using lyx::support::package;
42
43 string const win_fonts_truetype[] = {"cmex10", "cmmi10", "cmr10", "cmsy10",
44         "eufm10", "msam10", "msbm10", "wasy10", "esint10"};
45 const int num_fonts_truetype = sizeof(win_fonts_truetype) / sizeof(*win_fonts_truetype);
46 #endif
47
48
49 namespace lyx {
50 namespace support {
51 namespace os {
52
53 namespace {
54
55 bool windows_style_tex_paths_ = false;
56
57 // In both is_posix_path() and is_windows_path() it is assumed that
58 // a valid posix or pseudo-windows path is passed. They simply tell
59 // whether the path looks posix/pseudo-windows or not.
60
61 bool is_posix_path(string const & p)
62 {
63         return  p.empty() ||
64                 (!contains(p, '\\') && (p.length() <= 1 || p[1] != ':'));
65 }
66
67 // This is a test for a win32 style path with forward slashes (pseudo-windows).
68
69 bool is_windows_path(string const & p)
70 {
71         return p.empty() || (!contains(p, '\\') && p[0] != '/');
72 }
73
74
75 enum PathStyle {
76         posix,
77         windows
78 };
79
80
81 /// Convert a path to or from posix style.
82 /// \p p is encoded in local 8bit encoding or utf8.
83 /// The result is returned in the same encoding as \p p.
84 string convert_path(string const & p, PathStyle const & target)
85 {
86         char path_buf[PATH_MAX];
87
88         if ((target == posix && is_posix_path(p)) ||
89             (target == windows && is_windows_path(p)))
90                 return p;
91
92         path_buf[0] = '\0';
93
94         // cygwin_conv_to_posix_path and cygwin_conv_to_win32_path do not
95         // care about the encoding.
96         if (target == posix)
97                 cygwin_conv_to_posix_path(p.c_str(), path_buf);
98         else
99                 cygwin_conv_to_win32_path(p.c_str(), path_buf);
100
101         return subst(path_buf[0] ? path_buf : p, '\\', '/');
102 }
103
104
105 /// Convert a path list to or from posix style.
106 /// \p p is encoded in local 8bit encoding or utf8.
107 /// The result is returned in the same encoding as \p p.
108 string convert_path_list(string const & p, PathStyle const & target)
109 {
110         if (p.empty())
111                 return p;
112
113         char const * const pc = p.c_str();
114         PathStyle const actual = cygwin_posix_path_list_p(pc) ? posix : windows;
115
116         if (target != actual) {
117                 int const target_size = (target == posix) ?
118                                 cygwin_win32_to_posix_path_list_buf_size(pc) :
119                                 cygwin_posix_to_win32_path_list_buf_size(pc);
120
121                 char * ptr = new char[target_size];
122
123                 if (ptr) {
124                         // FIXME: See comment in convert_path() above
125                         if (target == posix)
126                                 cygwin_win32_to_posix_path_list(pc, ptr);
127                         else
128                                 cygwin_posix_to_win32_path_list(pc, ptr);
129
130                         string path_list = subst(ptr, '\\', '/');
131                         delete ptr;
132                         return path_list;
133                 }
134         }
135
136         return subst(p, '\\', '/');
137 }
138
139 } // namespace anon
140
141 void os::init(int, char *[])
142 {
143         // Copy cygwin environment variables to the Windows environment
144         // if they're not already there.
145
146         char **envp = environ;
147         char curval[2];
148         string var;
149         string val;
150         bool temp_seen = false;
151
152         while (envp && *envp) {
153                 val = split(*envp++, var, '=');
154
155                 if (var == "TEMP")
156                         temp_seen = true;
157                 
158                 if (GetEnvironmentVariable(var.c_str(), curval, 2) == 0
159                                 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
160                         /* Convert to Windows style where necessary */
161                         if (var == "PATH" || var == "LD_LIBRARY_PATH") {
162                                 string const winpathlist =
163                                     convert_path_list(val, PathStyle(windows));
164                                 if (!winpathlist.empty()) {
165                                         SetEnvironmentVariable(var.c_str(),
166                                                 winpathlist.c_str());
167                                 }
168                         } else if (var == "HOME" || var == "TMPDIR" ||
169                                         var == "TMP" || var == "TEMP") {
170                                 string const winpath =
171                                         convert_path(val, PathStyle(windows));
172                                 SetEnvironmentVariable(var.c_str(), winpath.c_str());
173                         } else {
174                                 SetEnvironmentVariable(var.c_str(), val.c_str());
175                         }
176                 }
177         }
178         if (!temp_seen) {
179                 string const winpath = convert_path("/tmp", PathStyle(windows));
180                 SetEnvironmentVariable("TEMP", winpath.c_str());
181         }
182 }
183
184
185 string current_root()
186 {
187         return string("/");
188 }
189
190
191 string::size_type common_path(string const & p1, string const & p2)
192 {
193         string::size_type i = 0;
194         string::size_type       p1_len = p1.length();
195         string::size_type       p2_len = p2.length();
196         while (i < p1_len && i < p2_len && uppercase(p1[i]) == uppercase(p2[i]))
197                 ++i;
198         if ((i < p1_len && i < p2_len)
199             || (i < p1_len && p1[i] != '/' && i == p2_len)
200             || (i < p2_len && p2[i] != '/' && i == p1_len))
201         {
202                 if (i)
203                         --i;     // here was the last match
204                 while (i && p1[i] != '/')
205                         --i;
206         }
207         return i;
208 }
209
210
211 string external_path(string const & p)
212 {
213         return convert_path(p, PathStyle(posix));
214 }
215
216
217 string internal_path(string const & p)
218 {
219         return convert_path(p, PathStyle(posix));
220 }
221
222
223 string external_path_list(string const & p)
224 {
225         return convert_path_list(p, PathStyle(posix));
226 }
227
228
229 string internal_path_list(string const & p)
230 {
231         return convert_path_list(p, PathStyle(posix));
232 }
233
234
235 string latex_path(string const & p)
236 {
237         // We may need a posix style path or a windows style path (depending
238         // on windows_style_tex_paths_), but we use always forward slashes,
239         // since it gets written into a .tex file.
240
241         if (windows_style_tex_paths_ && is_absolute_path(p)) {
242                 string dos_path = convert_path(p, PathStyle(windows));
243                 lyxerr[Debug::LATEX]
244                         << "<Path correction for LaTeX> ["
245                         << p << "]->>["
246                         << dos_path << ']' << endl;
247                 return dos_path;
248         }
249
250         return convert_path(p, PathStyle(posix));
251 }
252
253
254 bool is_absolute_path(string const & p)
255 {
256         if (p.empty())
257                 return false;
258
259         bool isDosPath = (p.length() > 1 && p[1] == ':');
260         bool isUnixPath = (p[0] == '/');
261
262         return isDosPath || isUnixPath;
263 }
264
265
266 // returns a string suitable to be passed to popen when
267 // reading a pipe
268 char const * popen_read_mode()
269 {
270         return "r";
271 }
272
273
274 string const & nulldev()
275 {
276         static string const nulldev_ = "/dev/null";
277         return nulldev_;
278 }
279
280
281 shell_type shell()
282 {
283         return UNIX;
284 }
285
286
287 char path_separator()
288 {
289         return ':';
290 }
291
292
293 void windows_style_tex_paths(bool use_windows_paths)
294 {
295         windows_style_tex_paths_ = use_windows_paths;
296 }
297
298
299 bool canAutoOpenFile(string const & ext, auto_open_mode const mode)
300 {
301         if (ext.empty())
302                 return false;
303
304         string const full_ext = "." + ext;
305
306         DWORD bufSize = MAX_PATH + 100;
307         TCHAR buf[MAX_PATH + 100];
308         // reference: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc
309         //                 /platform/shell/reference/shlwapi/registry/assocquerystring.asp
310         char const * action = (mode == VIEW) ? "open" : "edit";
311         return S_OK == AssocQueryString(0, ASSOCSTR_EXECUTABLE,
312                 full_ext.c_str(), action, buf, &bufSize);
313 }
314
315
316 bool autoOpenFile(string const & filename, auto_open_mode const mode)
317 {
318         // reference: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc
319         //                 /platform/shell/reference/functions/shellexecute.asp
320         string const win_path = to_local8bit(from_utf8(convert_path(filename, PathStyle(windows))));
321         char const * action = (mode == VIEW) ? "open" : "edit";
322         return reinterpret_cast<int>(ShellExecute(NULL, action,
323                 win_path.c_str(), NULL, NULL, 1)) > 32;
324 }
325
326
327 void addFontResources()
328 {
329 #ifdef X_DISPLAY_MISSING
330         // Windows only: Add BaKoMa TrueType font resources
331         string const fonts_dir = addPath(package().system_support(), "fonts");
332         
333         for (int i = 0 ; i < num_fonts_truetype ; ++i) {
334                 string const font_current = to_local8bit(from_utf8(convert_path(
335                         addName(fonts_dir, win_fonts_truetype[i] + ".ttf"),
336                         PathStyle(windows))));
337                 AddFontResource(font_current.c_str());
338         }
339 #endif
340 }
341
342
343 void restoreFontResources()
344 {
345 #ifdef X_DISPLAY_MISSING
346         // Windows only: Remove BaKoMa TrueType font resources
347         string const fonts_dir = addPath(package().system_support(), "fonts");
348         
349         for(int i = 0 ; i < num_fonts_truetype ; ++i) {
350                 string const font_current = to_local8bit(from_utf8(convert_path(
351                         addName(fonts_dir, win_fonts_truetype[i] + ".ttf"),
352                         PathStyle(windows))));
353                 RemoveFontResource(font_current.c_str());
354         }
355 #endif
356 }
357
358 } // namespace os
359 } // namespace support
360 } // namespace lyx