]> git.lyx.org Git - lyx.git/blob - src/support/os_unix.cpp
230dab5aa953a4d893af6e02ff665cc58d24f7e3
[lyx.git] / src / support / os_unix.cpp
1 /**
2  * \file os_unix.cpp
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  *
8  * Full author contact details are available in file CREDITS.
9  *
10  * Various OS specific functions
11  */
12
13 #include <config.h>
14
15 #include "LyXRC.h"
16
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"
24
25 #include <limits.h>
26 #include <locale.h>
27 #include <stdlib.h>
28
29 #ifdef __APPLE__
30 #include <CoreServices/CoreServices.h>
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <CoreFoundation/CFArray.h>
33 #endif
34
35 using namespace std;
36
37 namespace lyx {
38 namespace support {
39 namespace os {
40
41 namespace {
42
43 int argc_ = 0;
44 char ** argv_ = 0;
45
46 } // namespace anon
47
48 void init(int argc, char * argv[])
49 {
50         argc_ = argc;
51         argv_ = argv;
52
53         // Set environment's default locale
54         setlocale(LC_ALL, "");
55         setlocale(LC_NUMERIC, "C");
56 }
57
58
59 string utf8_argv(int i)
60 {
61         LASSERT(i < argc_, return "");
62         return to_utf8(from_local8bit(argv_[i]));
63 }
64
65
66 void remove_internal_args(int, int)
67 {}
68
69
70 string current_root()
71 {
72         return "/";
73 }
74
75
76 bool isFilesystemCaseSensitive()
77 {
78 #ifdef __APPLE__
79         return false;
80 #else
81         return true;
82 #endif
83 }
84
85
86 docstring::size_type common_path(docstring const & p1, docstring const & p2)
87 {
88         docstring::size_type i = 0;
89         docstring::size_type const p1_len = p1.length();
90         docstring::size_type const p2_len = p2.length();
91 #ifdef __APPLE__
92         while (i < p1_len && i < p2_len && uppercase(p1[i]) == uppercase(p2[i]))
93                 ++i;
94 #else
95         while (i < p1_len && i < p2_len && p1[i] == p2[i])
96                 ++i;
97 #endif
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))
101         {
102                 if (i)
103                         --i;     // here was the last match
104                 while (i && p1[i] != '/')
105                         --i;
106         }
107         return i;
108 }
109
110
111 bool path_prefix_is(string const & path, string const & pre)
112 {
113 #ifdef __APPLE__
114         return path_prefix_is(const_cast<string &>(path), pre, CASE_UNCHANGED);
115 #else
116         return prefixIs(path, pre);
117 #endif
118 }
119
120
121 bool path_prefix_is(string & path, string const & pre, path_case how)
122 {
123 #ifdef __APPLE__
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);
129
130         if (p2[p2_len - 1] == '/' && p1_len != p2_len)
131                 ++common_len;
132
133         if (common_len != p2_len)
134                 return false;
135
136         if (how == CASE_ADJUSTED && !prefixIs(path, pre)) {
137                 if (p1_len < common_len)
138                         path = to_utf8(p2.substr(0, p1_len));
139                 else
140                         path = to_utf8(p2 + p1.substr(common_len,
141                                                         p1_len - common_len));
142         }
143
144         return true;
145 #else
146         // silence compiler warnings
147         (void)how;
148
149         return prefixIs(path, pre);
150 #endif
151 }
152
153
154 string external_path(string const & p)
155 {
156         return p;
157 }
158
159
160 string internal_path(string const & p)
161 {
162         return p;
163 }
164
165
166 string safe_internal_path(string const & p, file_access)
167 {
168         return p;
169 }
170
171
172 string external_path_list(string const & p)
173 {
174         return p;
175 }
176
177
178 string internal_path_list(string const & p)
179 {
180         return p;
181 }
182
183
184 string latex_path(string const & p)
185 {
186         return p;
187 }
188
189
190 string latex_path_list(string const & p)
191 {
192         return p;
193 }
194
195
196 bool is_valid_strftime(string const & p)
197 {
198         string::size_type pos = p.find_first_of('%');
199         while (pos != string::npos) {
200                 if (pos + 1 == string::npos)
201                         break;
202                 if (!containsOnly(p.substr(pos + 1, 1),
203                         "aAbBcCdDeEFgGhHIjklmMnOpPrRsStTuUVwWxXyYzZ%+"))
204                         return false;
205                 if (pos + 2 == string::npos)
206                       break;
207                 pos = p.find_first_of('%', pos + 2);
208         }
209         return true;
210 }
211
212
213 char const * popen_read_mode()
214 {
215         return "r";
216 }
217
218
219 string const & nulldev()
220 {
221         static string const nulldev_ = "/dev/null";
222         return nulldev_;
223 }
224
225
226 shell_type shell()
227 {
228         return UNIX;
229 }
230
231
232 char path_separator(path_type)
233 {
234         return ':';
235 }
236
237
238 void windows_style_tex_paths(bool)
239 {}
240
241
242 #ifdef __APPLE__
243 bool canAutoOpenFile(CFStringRef cfs_uti, LSRolesMask role)
244 {
245         // Reference:
246         // https://developer.apple.com/reference/coreservices/1447734-lscopydefaultapplicationurlforco
247         CFURLRef outAppRef = LSCopyDefaultApplicationURLForContentType(cfs_uti, role, NULL);
248
249         if (outAppRef == NULL) return false;
250         CFRelease(outAppRef);
251         return true;
252 }
253 #endif
254
255 bool canAutoOpenFile(string const & ext, auto_open_mode const mode)
256 {
257 #ifdef __APPLE__
258         // References:
259         // https://developer.apple.com/reference/coreservices/1447734-lscopydefaultapplicationurlforco
260         CFStringRef cfs_ext = CFStringCreateWithBytes(kCFAllocatorDefault,
261                                         (UInt8 *) ext.c_str(), ext.length(),
262                                         kCFStringEncodingISOLatin1, false);
263         CFStringRef cfs_uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, cfs_ext, NULL);
264         CFRelease(cfs_ext);
265         if (cfs_uti == NULL) return false;
266
267         LSRolesMask role = (mode == VIEW) ? kLSRolesViewer :  kLSRolesEditor;
268         bool result = canAutoOpenFile(cfs_uti, role);
269         if (!result && mode == VIEW)
270                 result = canAutoOpenFile(cfs_uti, kLSRolesEditor);
271
272         CFRelease(cfs_uti);
273         return result;
274 #else
275         // silence compiler warnings
276         (void)ext;
277         (void)mode;
278
279         // currently, no default viewer is tried for non-apple system
280         // support for KDE/Gnome may be added later
281         return false;
282 #endif
283 }
284
285
286 bool autoOpenFile(string const & filename, auto_open_mode const mode,
287                   string const & path)
288 {
289 #ifdef __APPLE__
290 // Reference: http://developer.apple.com/documentation/Carbon/Reference/LaunchServicesReference/
291         // this is what we would like to do but it seems that the
292         // viewer for PDF is often quicktime...
293         //LSRolesMask role = (mode == VIEW) ? kLSRolesViewer :  kLSRolesEditor;
294         (void)mode;
295         LSRolesMask role = (mode == VIEW) ? kLSRolesAll :  kLSRolesEditor;
296
297         CFURLRef docURL = CFURLCreateFromFileSystemRepresentation(
298                 NULL, (UInt8 *) filename.c_str(), filename.size(), false);
299         CFURLRef appURL = LSCopyDefaultApplicationURLForURL(docURL, role, NULL);
300
301         CFURLRef docURLs[] = { docURL };
302         CFArrayRef launchItems = CFArrayCreate(
303                 NULL,
304                 (const void**)docURLs, sizeof(docURLs) / sizeof(CFURLRef),
305                 NULL);
306         LSLaunchURLSpec launchUrlSpec = {
307                 appURL, launchItems, NULL, kLSLaunchDefaults, NULL
308         };
309
310         string const texinputs = os::latex_path_list(
311                 replaceCurdirPath(path, lyxrc.texinputs_prefix));
312         string const otherinputs = os::latex_path_list(path);
313         string const oldtexinputs = getEnv("TEXINPUTS");
314         string const newtexinputs = ".:" + texinputs + ":" + oldtexinputs;
315         string const oldbibinputs = getEnv("BIBINPUTS");
316         string const newbibinputs = ".:" + otherinputs + ":" + oldbibinputs;
317         string const oldbstinputs = getEnv("BSTINPUTS");
318         string const newbstinputs = ".:" + otherinputs + ":" + oldbstinputs;
319         string const oldtexfonts = getEnv("TEXFONTS");
320         string const newtexfonts = ".:" + otherinputs + ":" + oldtexfonts;
321         if (!path.empty() && !lyxrc.texinputs_prefix.empty()) {
322                 setEnv("TEXINPUTS", newtexinputs);
323                 setEnv("BIBINPUTS", newbibinputs);
324                 setEnv("BSTINPUTS", newbstinputs);
325                 setEnv("TEXFONTS", newtexfonts);
326         }
327         OSStatus const status = LSOpenFromURLSpec (&launchUrlSpec, NULL);
328         CFRelease(launchItems);
329         if (!path.empty() && !lyxrc.texinputs_prefix.empty()) {
330                 setEnv("TEXINPUTS", oldtexinputs);
331                 setEnv("BIBINPUTS", oldbibinputs);
332                 setEnv("BSTINPUTS", oldbstinputs);
333                 setEnv("TEXFONTS", oldtexfonts);
334         }
335         return status == 0;
336 #else
337         // silence compiler warnings
338         (void)filename;
339         (void)mode;
340         (void)path;
341
342         // currently, no default viewer is tried for non-apple system
343         // support for KDE/Gnome may be added later
344         return false;
345 #endif
346 }
347
348
349 string real_path(string const & path)
350 {
351 #ifdef HAVE_DEF_PATH_MAX
352         char rpath[PATH_MAX + 1];
353         char * result = realpath(path.c_str(), rpath);
354         return FileName::fromFilesystemEncoding(result ? rpath : path).absFileName();
355 #else
356         char * result = realpath(path.c_str(), NULL);
357         string ret = FileName::fromFilesystemEncoding(result ? result : path).absFileName();
358         free(result);
359         return ret;
360 #endif
361 }
362
363 } // namespace os
364 } // namespace support
365 } // namespace lyx