3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Ruurd A. Reitsma
7 * \author Claus Hentschel
8 * \author Angus Leeming
9 * \author Enrico Forestieri
11 * Full author contact details are available in file CREDITS.
13 * Various OS specific functions
18 #include "support/os.h"
20 #include "support/FileName.h"
21 #include "support/lassert.h"
22 #include "support/lstrings.h"
23 #include "support/debug.h"
33 #include <cygwin/version.h>
34 #include <sys/cygwin.h>
52 bool windows_style_tex_paths_ = false;
54 // In both is_posix_path() and is_windows_path() it is assumed that
55 // a valid posix or pseudo-windows path is passed. They simply tell
56 // whether the path looks posix/pseudo-windows or not.
58 bool is_posix_path(string const & p)
61 (!contains(p, '\\') && (p.length() <= 1 || p[1] != ':'));
64 // This is a test for a win32 style path with forward slashes (pseudo-windows).
66 bool is_windows_path(string const & p)
68 return p.empty() || (!contains(p, '\\') && p[0] != '/');
72 // Starting from Cygwin 1.7, new APIs for path conversions were introduced.
73 // The old ones are now deprecated, so avoid them if we detect a modern Cygwin.
75 #if CYGWIN_VERSION_DLL_MAJOR >= 1007
78 posix = CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
79 windows = CCP_POSIX_TO_WIN_A | CCP_RELATIVE
83 /// Convert a path to or from posix style.
84 /// \p p is encoded in local 8bit encoding or utf8.
85 /// The result is returned in the same encoding as \p p.
86 string convert_path(string const & p, PathStyle const & target)
88 if ((target == posix && is_posix_path(p)) ||
89 (target == windows && is_windows_path(p)))
92 char path_buf[PATH_MAX];
94 // cygwin_conv_path does not care about the encoding.
95 if (cygwin_conv_path(target, p.c_str(), path_buf, sizeof(path_buf))) {
96 lyxerr << "LyX: Cannot convert path: " << p << endl;
97 return subst(p, '\\', '/');
99 return subst(path_buf, '\\', '/');
103 /// Convert a path list to or from posix style.
104 /// \p p is encoded in local 8bit encoding or utf8.
105 /// The result is returned in the same encoding as \p p.
106 string convert_path_list(string const & p, PathStyle const & target)
111 char const * const pc = p.c_str();
112 PathStyle const actual = cygwin_posix_path_list_p(pc) ? posix : windows;
114 if (target != actual) {
115 int const size = cygwin_conv_path_list(target, pc, NULL, 0);
116 char * ptr = new char[size];
117 if (ptr && cygwin_conv_path_list(target, pc, ptr, size) == 0) {
118 string const path_list = subst(ptr, '\\', '/');
122 lyxerr << "LyX: Cannot convert path list: " << p << endl;
124 return subst(p, '\\', '/');
135 /// Convert a path to or from posix style.
136 /// \p p is encoded in local 8bit encoding or utf8.
137 /// The result is returned in the same encoding as \p p.
138 string convert_path(string const & p, PathStyle const & target)
140 char path_buf[PATH_MAX];
142 if ((target == posix && is_posix_path(p)) ||
143 (target == windows && is_windows_path(p)))
148 // cygwin_conv_to_posix_path and cygwin_conv_to_win32_path do not
149 // care about the encoding.
151 cygwin_conv_to_posix_path(p.c_str(), path_buf);
153 cygwin_conv_to_win32_path(p.c_str(), path_buf);
155 return subst(path_buf[0] ? path_buf : p, '\\', '/');
159 /// Convert a path list to or from posix style.
160 /// \p p is encoded in local 8bit encoding or utf8.
161 /// The result is returned in the same encoding as \p p.
162 string convert_path_list(string const & p, PathStyle const & target)
167 char const * const pc = p.c_str();
168 PathStyle const actual = cygwin_posix_path_list_p(pc) ? posix : windows;
170 if (target != actual) {
171 int const target_size = (target == posix) ?
172 cygwin_win32_to_posix_path_list_buf_size(pc) :
173 cygwin_posix_to_win32_path_list_buf_size(pc);
175 char * ptr = new char[target_size];
178 // FIXME: See comment in convert_path() above
180 cygwin_win32_to_posix_path_list(pc, ptr);
182 cygwin_posix_to_win32_path_list(pc, ptr);
184 string path_list = subst(ptr, '\\', '/');
190 return subst(p, '\\', '/');
196 BOOL terminate_handler(DWORD event)
198 if (event == CTRL_CLOSE_EVENT
199 || event == CTRL_LOGOFF_EVENT
200 || event == CTRL_SHUTDOWN_EVENT) {
209 void init(int argc, char * argv[])
214 // Make sure that the TEMP variable is set
215 // and sync the Windows environment.
216 setenv("TEMP", "/tmp", false);
217 cygwin_internal(CW_SYNC_WINENV);
219 // Catch shutdown events.
220 SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminate_handler, TRUE);
224 string utf8_argv(int i)
226 LASSERT(i < argc_, /**/);
227 return to_utf8(from_local8bit(argv_[i]));
231 string current_root()
237 bool isFilesystemCaseSensitive()
243 docstring::size_type common_path(docstring const & p1, docstring const & p2)
245 docstring::size_type i = 0;
246 docstring::size_type const p1_len = p1.length();
247 docstring::size_type const p2_len = p2.length();
248 while (i < p1_len && i < p2_len && uppercase(p1[i]) == uppercase(p2[i]))
250 if ((i < p1_len && i < p2_len)
251 || (i < p1_len && p1[i] != '/' && i == p2_len)
252 || (i < p2_len && p2[i] != '/' && i == p1_len))
255 --i; // here was the last match
256 while (i && p1[i] != '/')
263 bool path_prefix_is(string const & path, string const & pre)
265 return path_prefix_is(const_cast<string &>(path), pre, CASE_UNCHANGED);
269 bool path_prefix_is(string & path, string const & pre, path_case how)
271 docstring const p1 = from_utf8(path);
272 docstring const p2 = from_utf8(pre);
273 docstring::size_type const p1_len = p1.length();
274 docstring::size_type const p2_len = p2.length();
275 docstring::size_type common_len = common_path(p1, p2);
277 if (p2[p2_len - 1] == '/' && p1_len != p2_len)
280 if (common_len != p2_len)
283 if (how == CASE_ADJUSTED && !prefixIs(path, pre)) {
284 if (p1_len < common_len)
285 path = to_utf8(p2.substr(0, p1_len));
287 path = to_utf8(p2 + p1.substr(common_len,
288 p1_len - common_len));
295 string external_path(string const & p)
297 return convert_path(p, PathStyle(posix));
301 string internal_path(string const & p)
303 return convert_path(p, PathStyle(posix));
307 string safe_internal_path(string const & p, file_access)
309 return convert_path(p, PathStyle(posix));
313 string external_path_list(string const & p)
315 return convert_path_list(p, PathStyle(posix));
319 string internal_path_list(string const & p)
321 return convert_path_list(p, PathStyle(posix));
325 string latex_path(string const & p)
327 // We may need a posix style path or a windows style path (depending
328 // on windows_style_tex_paths_), but we use always forward slashes,
329 // since it gets written into a .tex file.
331 if (windows_style_tex_paths_ && FileName::isAbsolute(p)) {
332 string dos_path = convert_path(p, PathStyle(windows));
333 LYXERR(Debug::LATEX, "<Path correction for LaTeX> ["
334 << p << "]->>[" << dos_path << ']');
338 return convert_path(p, PathStyle(posix));
342 bool is_valid_strftime(string const & p)
344 string::size_type pos = p.find_first_of('%');
345 while (pos != string::npos) {
346 if (pos + 1 == string::npos)
348 if (!containsOnly(p.substr(pos + 1, 1),
349 "aAbBcCdDeEFgGhHIjklmMnOpPrRsStTuUVwWxXyYzZ%+"))
351 if (pos + 2 == string::npos)
353 pos = p.find_first_of('%', pos + 2);
359 // returns a string suitable to be passed to popen when
361 char const * popen_read_mode()
367 string const & nulldev()
369 static string const nulldev_ = "/dev/null";
374 bool is_terminal(io_channel channel)
376 return isatty(channel);
386 char path_separator()
392 void windows_style_tex_paths(bool use_windows_paths)
394 windows_style_tex_paths_ = use_windows_paths;
398 bool canAutoOpenFile(string const & ext, auto_open_mode const mode)
403 string const full_ext = "." + ext;
405 DWORD bufSize = MAX_PATH + 100;
406 TCHAR buf[MAX_PATH + 100];
407 // reference: http://msdn.microsoft.com/en-us/library/bb773471.aspx
408 char const * action = (mode == VIEW) ? "open" : "edit";
409 return S_OK == AssocQueryString(ASSOCF_INIT_IGNOREUNKNOWN,
410 ASSOCSTR_EXECUTABLE, full_ext.c_str(), action, buf, &bufSize);
414 bool autoOpenFile(string const & filename, auto_open_mode const mode)
416 // reference: http://msdn.microsoft.com/en-us/library/bb762153.aspx
417 string const win_path = to_local8bit(from_utf8(convert_path(filename, PathStyle(windows))));
418 char const * action = (mode == VIEW) ? "open" : "edit";
419 return reinterpret_cast<int>(ShellExecute(NULL, action,
420 win_path.c_str(), NULL, NULL, 1)) > 32;
424 string real_path(string const & path)
426 char rpath[PATH_MAX + 1];
427 char * result = realpath(path.c_str(), rpath);
428 return FileName::fromFilesystemEncoding(result ? rpath : path).absFilename();
432 } // namespace support