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 void remove_internal_args(int, int)
235 string current_root()
241 bool isFilesystemCaseSensitive()
247 docstring::size_type common_path(docstring const & p1, docstring const & p2)
249 docstring::size_type i = 0;
250 docstring::size_type const p1_len = p1.length();
251 docstring::size_type const p2_len = p2.length();
252 while (i < p1_len && i < p2_len && uppercase(p1[i]) == uppercase(p2[i]))
254 if ((i < p1_len && i < p2_len)
255 || (i < p1_len && p1[i] != '/' && i == p2_len)
256 || (i < p2_len && p2[i] != '/' && i == p1_len))
259 --i; // here was the last match
260 while (i && p1[i] != '/')
267 bool path_prefix_is(string const & path, string const & pre)
269 return path_prefix_is(const_cast<string &>(path), pre, CASE_UNCHANGED);
273 bool path_prefix_is(string & path, string const & pre, path_case how)
275 docstring const p1 = from_utf8(path);
276 docstring const p2 = from_utf8(pre);
277 docstring::size_type const p1_len = p1.length();
278 docstring::size_type const p2_len = p2.length();
279 docstring::size_type common_len = common_path(p1, p2);
281 if (p2[p2_len - 1] == '/' && p1_len != p2_len)
284 if (common_len != p2_len)
287 if (how == CASE_ADJUSTED && !prefixIs(path, pre)) {
288 if (p1_len < common_len)
289 path = to_utf8(p2.substr(0, p1_len));
291 path = to_utf8(p2 + p1.substr(common_len,
292 p1_len - common_len));
299 string external_path(string const & p)
301 return convert_path(p, PathStyle(posix));
305 string internal_path(string const & p)
307 return convert_path(p, PathStyle(posix));
311 string safe_internal_path(string const & p, file_access)
313 return convert_path(p, PathStyle(posix));
317 string external_path_list(string const & p)
319 return convert_path_list(p, PathStyle(posix));
323 string internal_path_list(string const & p)
325 return convert_path_list(p, PathStyle(posix));
329 string latex_path(string const & p)
331 // We may need a posix style path or a windows style path (depending
332 // on windows_style_tex_paths_), but we use always forward slashes,
333 // since it gets written into a .tex file.
335 if (windows_style_tex_paths_ && FileName::isAbsolute(p)) {
336 string dos_path = convert_path(p, PathStyle(windows));
337 LYXERR(Debug::LATEX, "<Path correction for LaTeX> ["
338 << p << "]->>[" << dos_path << ']');
342 return convert_path(p, PathStyle(posix));
346 bool is_valid_strftime(string const & p)
348 string::size_type pos = p.find_first_of('%');
349 while (pos != string::npos) {
350 if (pos + 1 == string::npos)
352 if (!containsOnly(p.substr(pos + 1, 1),
353 "aAbBcCdDeEFgGhHIjklmMnOpPrRsStTuUVwWxXyYzZ%+"))
355 if (pos + 2 == string::npos)
357 pos = p.find_first_of('%', pos + 2);
363 // returns a string suitable to be passed to popen when
365 char const * popen_read_mode()
371 string const & nulldev()
373 static string const nulldev_ = "/dev/null";
378 bool is_terminal(io_channel channel)
380 return isatty(channel);
390 char path_separator()
396 void windows_style_tex_paths(bool use_windows_paths)
398 windows_style_tex_paths_ = use_windows_paths;
402 bool canAutoOpenFile(string const & ext, auto_open_mode const mode)
407 string const full_ext = "." + ext;
409 DWORD bufSize = MAX_PATH + 100;
410 TCHAR buf[MAX_PATH + 100];
411 // reference: http://msdn.microsoft.com/en-us/library/bb773471.aspx
412 char const * action = (mode == VIEW) ? "open" : "edit";
413 return S_OK == AssocQueryString(ASSOCF_INIT_IGNOREUNKNOWN,
414 ASSOCSTR_EXECUTABLE, full_ext.c_str(), action, buf, &bufSize);
418 bool autoOpenFile(string const & filename, auto_open_mode const mode)
420 // reference: http://msdn.microsoft.com/en-us/library/bb762153.aspx
421 string const win_path = to_local8bit(from_utf8(convert_path(filename, PathStyle(windows))));
422 char const * action = (mode == VIEW) ? "open" : "edit";
423 return reinterpret_cast<int>(ShellExecute(NULL, action,
424 win_path.c_str(), NULL, NULL, 1)) > 32;
428 string real_path(string const & path)
430 char rpath[PATH_MAX + 1];
431 char * result = realpath(path.c_str(), rpath);
432 return FileName::fromFilesystemEncoding(result ? rpath : path).absFilename();
436 } // namespace support