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
8 * Full author contact details are available in file CREDITS.
10 * Various OS specific functions
17 #include "support/os.h"
18 #include "support/docstring.h"
19 #include "support/environment.h"
20 #include "support/FileName.h"
21 #include "support/filetools.h"
22 #include "support/lstrings.h"
23 #include "support/lassert.h"
30 #include <CoreServices/CoreServices.h>
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <CoreFoundation/CFArray.h>
48 void init(int argc, char ** argv[])
53 // Set environment's default locale
54 setlocale(LC_ALL, "");
55 setlocale(LC_NUMERIC, "C");
59 string utf8_argv(int i)
61 LASSERT(i < argc_, return "");
62 return to_utf8(from_local8bit(argv_[i]));
66 void remove_internal_args(int, int)
76 bool isFilesystemCaseSensitive()
86 docstring::size_type common_path(docstring const & p1, docstring const & p2)
88 docstring::size_type i = 0;
89 docstring::size_type const p1_len = p1.length();
90 docstring::size_type const p2_len = p2.length();
92 while (i < p1_len && i < p2_len && uppercase(p1[i]) == uppercase(p2[i]))
95 while (i < p1_len && i < p2_len && p1[i] == p2[i])
98 if ((i < p1_len && i < p2_len)
99 || (i < p1_len && p1[i] != '/' && i == p2_len)
100 || (i < p2_len && p2[i] != '/' && i == p1_len))
103 --i; // here was the last match
104 while (i && p1[i] != '/')
111 bool path_prefix_is(string const & path, string const & pre)
114 return path_prefix_is(const_cast<string &>(path), pre, CASE_UNCHANGED);
116 return prefixIs(path, pre);
121 bool path_prefix_is(string & path, string const & pre, path_case how)
124 docstring const p1 = from_utf8(path);
125 docstring const p2 = from_utf8(pre);
126 docstring::size_type const p1_len = p1.length();
127 docstring::size_type const p2_len = p2.length();
128 docstring::size_type common_len = common_path(p1, p2);
130 if (p2[p2_len - 1] == '/' && p1_len != p2_len)
133 if (common_len != p2_len)
136 if (how == CASE_ADJUSTED && !prefixIs(path, pre)) {
137 if (p1_len < common_len)
138 path = to_utf8(p2.substr(0, p1_len));
140 path = to_utf8(p2 + p1.substr(common_len,
141 p1_len - common_len));
146 // silence compiler warnings
149 return prefixIs(path, pre);
154 string external_path(string const & p)
160 string internal_path(string const & p)
166 string safe_internal_path(string const & p, file_access)
172 string external_path_list(string const & p)
178 string internal_path_list(string const & p)
184 string latex_path(string const & p)
190 string latex_path_list(string const & p)
196 char const * popen_read_mode()
202 string const & nulldev()
204 static string const nulldev_ = "/dev/null";
215 char path_separator(path_type)
221 void windows_style_tex_paths(bool)
226 bool canAutoOpenFile(CFStringRef cfs_uti, LSRolesMask role)
229 // https://developer.apple.com/reference/coreservices/1447734-lscopydefaultapplicationurlforco
230 CFURLRef outAppRef = LSCopyDefaultApplicationURLForContentType(cfs_uti, role, NULL);
232 if (outAppRef == NULL) return false;
233 CFRelease(outAppRef);
238 bool canAutoOpenFile(string const & ext, auto_open_mode const mode)
242 // https://developer.apple.com/reference/coreservices/1447734-lscopydefaultapplicationurlforco
243 CFStringRef cfs_ext = CFStringCreateWithBytes(kCFAllocatorDefault,
244 (UInt8 *) ext.c_str(), ext.length(),
245 kCFStringEncodingISOLatin1, false);
246 CFStringRef cfs_uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, cfs_ext, NULL);
248 if (cfs_uti == NULL) return false;
250 LSRolesMask role = (mode == VIEW) ? kLSRolesViewer : kLSRolesEditor;
251 bool result = canAutoOpenFile(cfs_uti, role);
252 if (!result && mode == VIEW)
253 result = canAutoOpenFile(cfs_uti, kLSRolesEditor);
258 // silence compiler warnings
262 // currently, no default viewer is tried for non-apple system
263 // support for KDE/Gnome may be added later
269 bool autoOpenFile(string const & filename, auto_open_mode const mode,
273 // Reference: http://developer.apple.com/documentation/Carbon/Reference/LaunchServicesReference/
274 // this is what we would like to do but it seems that the
275 // viewer for PDF is often quicktime...
276 //LSRolesMask role = (mode == VIEW) ? kLSRolesViewer : kLSRolesEditor;
278 LSRolesMask role = (mode == VIEW) ? kLSRolesAll : kLSRolesEditor;
280 CFURLRef docURL = CFURLCreateFromFileSystemRepresentation(
281 NULL, (UInt8 *) filename.c_str(), filename.size(), false);
282 CFURLRef appURL = LSCopyDefaultApplicationURLForURL(docURL, role, NULL);
284 CFURLRef docURLs[] = { docURL };
285 CFArrayRef launchItems = CFArrayCreate(
287 (const void**)docURLs, sizeof(docURLs) / sizeof(CFURLRef),
289 LSLaunchURLSpec launchUrlSpec = {
290 appURL, launchItems, NULL, kLSLaunchDefaults, NULL
293 string const texinputs = os::latex_path_list(
294 replaceCurdirPath(path, lyxrc.texinputs_prefix));
295 string const otherinputs = os::latex_path_list(path);
296 string const oldtexinputs = getEnv("TEXINPUTS");
297 string const newtexinputs = ".:" + texinputs + ":" + oldtexinputs;
298 string const oldbibinputs = getEnv("BIBINPUTS");
299 string const newbibinputs = ".:" + otherinputs + ":" + oldbibinputs;
300 string const oldbstinputs = getEnv("BSTINPUTS");
301 string const newbstinputs = ".:" + otherinputs + ":" + oldbstinputs;
302 string const oldtexfonts = getEnv("TEXFONTS");
303 string const newtexfonts = ".:" + otherinputs + ":" + oldtexfonts;
304 if (!path.empty() && !lyxrc.texinputs_prefix.empty()) {
305 setEnv("TEXINPUTS", newtexinputs);
306 setEnv("BIBINPUTS", newbibinputs);
307 setEnv("BSTINPUTS", newbstinputs);
308 setEnv("TEXFONTS", newtexfonts);
310 OSStatus const status = LSOpenFromURLSpec (&launchUrlSpec, NULL);
311 CFRelease(launchItems);
312 if (!path.empty() && !lyxrc.texinputs_prefix.empty()) {
313 setEnv("TEXINPUTS", oldtexinputs);
314 setEnv("BIBINPUTS", oldbibinputs);
315 setEnv("BSTINPUTS", oldbstinputs);
316 setEnv("TEXFONTS", oldtexfonts);
320 // silence compiler warnings
325 // currently, no default viewer is tried for non-apple system
326 // support for KDE/Gnome may be added later
332 string real_path(string const & path)
334 #ifdef HAVE_DEF_PATH_MAX
335 char rpath[PATH_MAX + 1];
336 char * result = realpath(path.c_str(), rpath);
337 return FileName::fromFilesystemEncoding(result ? rpath : path).absFileName();
339 char * result = realpath(path.c_str(), NULL);
340 string ret = FileName::fromFilesystemEncoding(result ? result : path).absFileName();
347 } // namespace support