]> git.lyx.org Git - features.git/blob - src/support/Package.cpp
Fix problem with python and change of PATH
[features.git] / src / support / Package.cpp
1 // -*- C++ -*-
2 /**
3  * \file package.cpp
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Angus Leeming
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "support/Package.h"
15
16 #include "support/debug.h"
17 #include "support/environment.h"
18 #include "support/ExceptionMessage.h"
19 #include "support/filetools.h"
20 #include "support/gettext.h"
21 #include "support/lassert.h"
22 #include "support/lstrings.h"
23 #include "support/os.h"
24
25 #if defined (USE_WINDOWS_PACKAGING)
26 # include "support/os_win32.h"
27 #endif
28
29
30 #include <list>
31
32 #if !defined (USE_WINDOWS_PACKAGING) && \
33     !defined (USE_MACOSX_PACKAGING) && \
34     !defined (USE_POSIX_PACKAGING)
35 #error USE_FOO_PACKAGING must be defined for FOO = WINDOWS, MACOSX or POSIX.
36 #endif
37
38 #if defined (USE_MACOSX_PACKAGING)
39 # include "support/qstring_helpers.h"
40 # include <QDir>
41 # include <QDesktopServices>
42 #endif
43
44 using namespace std;
45
46 namespace lyx {
47 namespace support {
48
49 namespace {
50
51 Package package_;
52 bool initialised_ = false;
53
54 } // namespace anon
55
56
57 void init_package(string const & command_line_arg0,
58                   string const & command_line_system_support_dir,
59                   string const & command_line_user_support_dir)
60 {
61         package_ = Package(command_line_arg0,
62                            command_line_system_support_dir,
63                            command_line_user_support_dir);
64         initialised_ = true;
65 }
66
67
68 Package const & package()
69 {
70         LAPPERR(initialised_);
71         return package_;
72 }
73
74
75 namespace {
76
77 FileName const abs_path_from_binary_name(string const & exe);
78
79
80 bool inBuildDir(FileName const & abs_binary, FileName &, FileName &);
81
82 FileName findLyxBinary(FileName const & abs_binary);
83
84 FileName const get_document_dir(FileName const & home_dir);
85
86 FileName const get_locale_dir(FileName const & system_support_dir);
87
88 FileName const get_system_support_dir(FileName const & abs_binary,
89                                     string const & command_line_system_support_dir);
90
91 FileName const get_default_user_support_dir(FileName const & home_dir);
92
93 bool userSupportDir(FileName const & default_user_support_dir,
94                      string const & command_line_user_support_dir, FileName & result);
95
96 string const & with_version_suffix();
97
98 string const fix_dir_name(string const & name);
99
100 } // namespace anon
101
102
103 Package::Package(string const & command_line_arg0,
104                  string const & command_line_system_support_dir,
105                  string const & command_line_user_support_dir)
106         : explicit_user_support_dir_(false)
107 {
108         // Specification of temp_dir_ may be reset by LyXRC,
109         // but the default is fixed for a given OS.
110         system_temp_dir_ = FileName::tempPath();
111         temp_dir_ = system_temp_dir_;
112         document_dir_ = get_document_dir(get_home_dir());
113
114         FileName const abs_binary = abs_path_from_binary_name(command_line_arg0);
115         binary_dir_ = FileName(onlyPath(abs_binary.absFileName()));
116
117         // the LyX package directory
118         lyx_dir_ = FileName(addPath(binary_dir_.absFileName(), "../"));
119         lyx_dir_ = FileName(lyx_dir_.realPath());
120
121         // Is LyX being run in-place from the build tree?
122         in_build_dir_ = inBuildDir(abs_binary, build_support_dir_, system_support_dir_);
123
124         if (!in_build_dir_) {
125                 system_support_dir_ =
126                         get_system_support_dir(abs_binary,
127                                                command_line_system_support_dir);
128         }
129
130         // Find the LyX executable
131         lyx_binary_ = findLyxBinary(abs_binary);
132
133         locale_dir_ = get_locale_dir(system_support_dir_);
134
135         FileName const default_user_support_dir =
136                 get_default_user_support_dir(get_home_dir());
137
138         explicit_user_support_dir_ = userSupportDir(default_user_support_dir,
139                                      command_line_user_support_dir, user_support_dir_);
140
141
142         LYXERR(Debug::INIT, "<package>\n"
143                 << "\tbinary_dir " << binary_dir().absFileName() << '\n'
144                 << "\tsystem_support " << system_support().absFileName() << '\n'
145                 << "\tbuild_support " << build_support().absFileName() << '\n'
146                 << "\tuser_support " << user_support().absFileName() << '\n'
147                 << "\tlocale_dir " << locale_dir().absFileName() << '\n'
148                 << "\tdocument_dir " << document_dir().absFileName() << '\n'
149                 << "\ttemp_dir " << temp_dir().absFileName() << '\n'
150                 << "\thome_dir " << get_home_dir().absFileName() << '\n'
151                 << "</package>\n");
152 }
153
154 std::string const & Package::configure_command() const
155 {
156         if (configure_command_.empty()) {
157                 std::string &command = const_cast<std::string&>(configure_command_);
158                 FileName const configure_script(addName(system_support().absFileName(), "configure.py"));
159                 command = os::python() + ' ' +
160                         quoteName(configure_script.toFilesystemEncoding()) +
161                         with_version_suffix() + " --binary-dir=" +
162                         quoteName(FileName(binary_dir().absFileName()).toFilesystemEncoding());
163         }
164         return configure_command_;
165 }
166
167
168 void Package::set_temp_dir(FileName const & temp_dir) const
169 {
170         if (temp_dir.empty())
171                 temp_dir_ = system_temp_dir_;
172         else
173                 temp_dir_ = temp_dir;
174 }
175
176
177 FileName Package::messages_file(string const & c) const
178 {
179         if (in_build_dir_) {
180                 FileName res = FileName(lyx_dir().absFileName() + "/../po/" + c + ".gmo");
181                 if (!res.isReadableFile())
182                         res = FileName(top_srcdir().absFileName() + "/po/" + c + ".gmo");
183                 return res;
184         } else
185                 return FileName(locale_dir_.absFileName() + "/" + c
186                         + "/LC_MESSAGES/" PACKAGE ".mo");
187 }
188
189
190 // The specification of home_dir_ is fixed for a given OS.
191 // A typical example on Windows: "C:/Documents and Settings/USERNAME"
192 // and on a Posix-like machine: "/home/USERNAME".
193 FileName const & Package::get_home_dir()
194 {
195 #if defined (USE_WINDOWS_PACKAGING)
196         static FileName const home_dir(getEnv("USERPROFILE"));
197 #elif defined (USE_MACOSX_PACKAGING)
198         static FileName const home_dir(fromqstr(QDir::homePath()));
199 #else // Posix-like.
200         static FileName const home_dir(getEnv("HOME"));
201 #endif
202         return home_dir;
203 }
204
205
206 namespace {
207
208 // These next functions contain the stuff that is substituted at
209 // configuration-time.
210 FileName const hardcoded_localedir()
211 {
212         // FIXME UNICODE
213         // The build system needs to make sure that this is in utf8 encoding.
214         return FileName(LYX_ABS_INSTALLED_LOCALEDIR);
215 }
216
217
218 FileName const hardcoded_system_support_dir()
219 {
220         // FIXME UNICODE
221         // The build system needs to make sure that this is in utf8 encoding.
222         return FileName(LYX_ABS_INSTALLED_DATADIR);
223 }
224
225
226 string const & with_version_suffix()
227 {
228         static string const program_suffix = PROGRAM_SUFFIX;
229         static string const with_version_suffix =
230                 " --with-version-suffix=" PROGRAM_SUFFIX;
231         return program_suffix.empty() ? program_suffix : with_version_suffix;
232 }
233
234 } // namespace anon
235
236
237 FileName const & Package::top_srcdir()
238 {
239         // FIXME UNICODE
240         // The build system needs to make sure that this is in utf8 encoding.
241         static FileName const dir(LYX_ABS_TOP_SRCDIR);
242         return dir;
243 }
244
245
246 namespace {
247
248 bool check_command_line_dir(string const & dir,
249                             string const & file,
250                             string const & command_line_switch);
251
252 FileName const extract_env_var_dir(string const & env_var);
253
254 bool check_env_var_dir(FileName const & dir,
255                        string const & env_var);
256
257 bool check_env_var_dir(FileName const & dir,
258                        string const & file,
259                        string const & env_var);
260
261 string const relative_locale_dir();
262
263 string const relative_system_support_dir();
264
265
266 /**
267  * Convert \p name to internal path and strip a trailing slash, since it
268  * comes from user input (commandline or environment).
269  * \p name is encoded in utf8.
270  */
271 string const fix_dir_name(string const & name)
272 {
273         return rtrim(os::internal_path(name), "/");
274 }
275
276
277
278 bool isBuildDir(FileName const & abs_binary, string const & dir_location,
279         FileName & build_support_dir)
280 {
281     string search_dir = onlyPath(abs_binary.absFileName()) + dir_location;
282
283     // Makefile by automake
284     build_support_dir = FileName(addPath(search_dir, "lib"));
285     if (!fileSearch(build_support_dir.absFileName(), "Makefile").empty()) {
286         return true;
287     }
288     //  cmake file, no Makefile in lib
289     FileName build_boost_dir = FileName(addPath(search_dir, "boost"));
290     if (!fileSearch(build_boost_dir.absFileName(), "cmake_install.cmake").empty()) {
291         return true;
292     }
293
294     return false;
295 }
296
297 bool inBuildDir(FileName const & abs_binary,
298         FileName & build_support_dir, FileName & system_support_dir)
299 {
300         string const check_text = "Checking whether LyX is run in place...";
301
302         // We're looking for "Makefile" in a directory
303         //   binary_dir/../lib
304         // We're also looking for "chkconfig.ltx" in a directory
305         //   top_srcdir()/lib
306         // If both are found, then we're running LyX in-place.
307
308         // Note that the name of the lyx binary may be a symbolic link.
309         // If that is the case, then we follow the links too.
310     FileName binary = abs_binary;
311         while (true) {
312                 // Try and find "lyxrc.defaults".
313                 if( isBuildDir(binary, "../", build_support_dir) ||
314             isBuildDir(binary, "../../", build_support_dir))
315         {
316                         // Try and find "chkconfig.ltx".
317                         system_support_dir =
318                                 FileName(addPath(Package::top_srcdir().absFileName(), "lib"));
319
320                         if (!fileSearch(system_support_dir.absFileName(), "chkconfig.ltx").empty()) {
321                                 LYXERR(Debug::INIT, check_text << " yes");
322                                 return true;
323                         }
324                 }
325
326                 // Check whether binary is a symbolic link.
327                 // If so, resolve it and repeat the exercise.
328                 if (!binary.isSymLink())
329                         break;
330
331                 FileName link;
332                 if (readLink(binary, link)) {
333                         binary = link;
334                 } else {
335                         // Unable to resolve the link.
336                         break;
337                 }
338         }
339
340         LYXERR(Debug::INIT, check_text << " no");
341         system_support_dir = FileName();
342         build_support_dir = FileName();
343
344     return false;
345 }
346
347
348 bool doesFileExist(FileName & result, string const & search_dir, string const & name)
349 {
350     result = fileSearch(search_dir, name);
351     if (!result.empty()) {
352         return true;
353     }
354     return false;
355 }
356
357
358 bool lyxBinaryPath(FileName & lyx_binary, string const & search_dir, string const & ext)
359 {
360     lyx_binary = FileName();
361     if(false) {   
362     } else if (doesFileExist(lyx_binary, search_dir, "lyx" + ext)) {
363     } else if (doesFileExist(lyx_binary, search_dir, "LyX" + ext)) {
364     } else if (doesFileExist(lyx_binary, search_dir, "lyx" + string(PROGRAM_SUFFIX) + ext)) {
365     } else if (doesFileExist(lyx_binary, search_dir, "LyX" + string(PROGRAM_SUFFIX) + ext)){
366     }
367     return !lyx_binary.empty() ? true : false;
368 }
369
370
371 FileName findLyxBinary(FileName const & abs_binary)
372 {
373     string ext;
374     string checkname = abs_binary.toFilesystemEncoding();
375     int check_len = checkname.length();
376     int prgsuffixlen = string(PROGRAM_SUFFIX).length();
377     if ((prgsuffixlen > 0) && (check_len > prgsuffixlen) &&
378        (checkname.substr(check_len-prgsuffixlen) == string(PROGRAM_SUFFIX))) {
379         ext = "";
380     }
381     else if (!abs_binary.extension().empty()) {
382         ext = "." + abs_binary.extension();
383     }
384     
385     string binary_dir = onlyPath(abs_binary.absFileName());
386       
387     FileName lyx_binary;
388     if (lyxBinaryPath(lyx_binary, binary_dir, ext))
389         return lyx_binary;
390
391     string search_dir = onlyPath(FileName(addPath(binary_dir, "/../")).absFileName());
392     if (lyxBinaryPath(lyx_binary, search_dir, ext))
393         return lyx_binary;
394     
395     return FileName();
396 }
397
398
399 // Specification of document_dir_ may be reset by LyXRC,
400 // but the default is fixed for a given OS.
401 FileName const get_document_dir(FileName const & home_dir)
402 {
403 #if defined (USE_WINDOWS_PACKAGING)
404         (void)home_dir; // Silence warning about unused variable.
405         os::GetFolderPath win32_folder_path;
406         return FileName(win32_folder_path(os::GetFolderPath::PERSONAL));
407 #elif defined (USE_MACOSX_PACKAGING) && (QT_VERSION >= 0x050000)
408         (void)home_dir; // Silence warning about unused variable.
409         return FileName(fromqstr(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)));
410 #elif defined (USE_MACOSX_PACKAGING)
411         (void)home_dir; // Silence warning about unused variable.
412         return FileName(fromqstr(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)));
413 #else // Posix-like.
414         return home_dir;
415 #endif
416 }
417
418
419
420 // Several sources are probed to ascertain the locale directory.
421 // The only requirement is that the result is indeed a directory.
422 FileName const get_locale_dir(FileName const & system_support_dir)
423 {
424         // 1. Use the "LYX_LOCALEDIR" environment variable.
425         FileName const path_env = extract_env_var_dir("LYX_LOCALEDIR");
426         if (!path_env.empty() && check_env_var_dir(path_env, "LYX_LOCALEDIR"))
427                 return path_env;
428
429         // 2. Search for system_support_dir / <relative locale dir>
430         // The <relative locale dir> is OS-dependent. (On Unix, it will
431         // be "../locale/".)
432         FileName path(addPath(system_support_dir.absFileName(),
433                 relative_locale_dir()));
434
435         if (path.exists() && path.isDirectory())
436                 return path;
437
438         // 3. Fall back to the hard-coded LOCALEDIR.
439         path = hardcoded_localedir();
440         if (path.exists() && path.isDirectory())
441                 return path;
442
443         return FileName();
444 }
445
446
447 // Extracts the absolute path from the foo of "-sysdir foo" or "-userdir foo"
448 FileName const abs_path_from_command_line(string const & command_line)
449 {
450         if (command_line.empty())
451                 return FileName();
452
453         string const str_path = fix_dir_name(command_line);
454         return makeAbsPath(str_path);
455 }
456
457
458 // Does the grunt work for abs_path_from_binary_name()
459 FileName const get_binary_path(string const & exe)
460 {
461 #if defined (USE_WINDOWS_PACKAGING)
462         // The executable may have been invoked either with or
463         // without the .exe extension.
464         // Ensure that it is present.
465         string const as_internal_path = os::internal_path(exe);
466         string const exe_path = suffixIs(as_internal_path, ".exe") ?
467                 as_internal_path : as_internal_path + ".exe";
468 #else
469         string const exe_path = os::internal_path(exe);
470 #endif
471         if (FileName::isAbsolute(exe_path))
472                 return FileName(exe_path);
473
474         // Two possibilities present themselves.
475         // 1. The binary is relative to the CWD.
476         FileName const abs_exe_path = makeAbsPath(exe_path);
477         if (abs_exe_path.exists())
478                 return abs_exe_path;
479
480         // 2. exe must be the name of the binary only and it
481         // can be found on the PATH.
482         string const exe_name = onlyFileName(exe_path);
483         if (exe_name != exe_path)
484                 return FileName();
485
486         vector<string> const path = getEnvPath("PATH");
487         vector<string>::const_iterator it = path.begin();
488         vector<string>::const_iterator const end = path.end();
489         for (; it != end; ++it) {
490                 // This will do nothing if *it is already absolute.
491                 string const exe_dir = makeAbsPath(*it).absFileName();
492
493                 FileName const exe_path(addName(exe_dir, exe_name));
494                 if (exe_path.exists())
495                         return exe_path;
496         }
497
498         // Didn't find anything.
499         return FileName();
500 }
501
502
503 // Extracts the absolute path to the binary name received as argv[0].
504 FileName const abs_path_from_binary_name(string const & exe)
505 {
506         FileName const abs_binary = get_binary_path(exe);
507         if (abs_binary.empty()) {
508                 // FIXME UNICODE
509                 throw ExceptionMessage(ErrorException,
510                         _("LyX binary not found"),
511                         bformat(_("Unable to determine the path to the LyX binary from the command line %1$s"),
512                                 from_utf8(exe)));
513         }
514         return abs_binary;
515 }
516
517
518 // A plethora of directories is searched to ascertain the system
519 // lyxdir which is defined as the first directory to contain
520 // "chkconfig.ltx".
521 FileName const
522 get_system_support_dir(FileName const & abs_binary,
523                   string const & command_line_system_support_dir)
524 {
525         string const chkconfig_ltx = "chkconfig.ltx";
526
527         // searched_dirs is used for diagnostic purposes only in the case
528         // that "chkconfig.ltx" is not found.
529         list<FileName> searched_dirs;
530
531         // 1. Use the -sysdir command line parameter.
532         FileName path = abs_path_from_command_line(command_line_system_support_dir);
533         if (!path.empty()) {
534                 searched_dirs.push_back(path);
535                 if (check_command_line_dir(path.absFileName(), chkconfig_ltx, "-sysdir"))
536                         return path;
537         }
538
539         // 2. Use the "LYX_DIR_${major}${minor}x" environment variable.
540         path = extract_env_var_dir(LYX_DIR_VER);
541         if (!path.empty()) {
542                 searched_dirs.push_back(path);
543                 if (check_env_var_dir(path, chkconfig_ltx, LYX_DIR_VER))
544                         return path;
545         }
546
547         // 3. Search relative to the lyx binary.
548         // We're looking for "chkconfig.ltx" in a directory
549         //   OnlyPath(abs_binary) / <relative dir> / PACKAGE /
550         // PACKAGE is hardcoded in config.h. Eg "lyx" or "lyx-1.3.6cvs".
551         // <relative dir> is OS-dependent; on Unix, it will be "../share/".
552         string const relative_lyxdir = relative_system_support_dir();
553
554         // One subtlety to be aware of. The name of the lyx binary may be
555         // a symbolic link. If that is the case, then we follow the links too.
556         FileName binary = abs_binary;
557         while (true) {
558                 // Try and find "chkconfig.ltx".
559                 string const binary_dir = onlyPath(binary.absFileName());
560
561                 FileName const lyxdir(addPath(binary_dir, relative_lyxdir));
562                 searched_dirs.push_back(lyxdir);
563
564                 if (!fileSearch(lyxdir.absFileName(), chkconfig_ltx).empty()) {
565                         // Success! "chkconfig.ltx" has been found.
566                         return lyxdir;
567                 }
568
569                 // Check whether binary is a symbolic link.
570                 // If so, resolve it and repeat the exercise.
571                 if (!binary.isSymLink())
572                         break;
573
574                 FileName link;
575                 if (readLink(binary, link)) {
576                         binary = link;
577                 } else {
578                         // Unable to resolve the link.
579                         break;
580                 }
581         }
582
583         // 4. Repeat the exercise on the directory itself.
584         FileName binary_dir(onlyPath(abs_binary.absFileName()));
585         while (true) {
586                 // This time test whether the directory is a symbolic link
587                 // *before* looking for "chkconfig.ltx".
588                 // (We've looked relative to the original already.)
589                 if (!binary.isSymLink())
590                         break;
591
592                 FileName link;
593                 if (readLink(binary_dir, link)) {
594                         binary_dir = link;
595                 } else {
596                         // Unable to resolve the link.
597                         break;
598                 }
599
600                 // Try and find "chkconfig.ltx".
601                 FileName const lyxdir(addPath(binary_dir.absFileName(),
602                         relative_lyxdir));
603                 searched_dirs.push_back(lyxdir);
604
605                 if (!fileSearch(lyxdir.absFileName(), chkconfig_ltx).empty()) {
606                         // Success! "chkconfig.ltx" has been found.
607                         return lyxdir;
608                 }
609         }
610
611         // 5. In desparation, try the hard-coded system support dir.
612         path = hardcoded_system_support_dir();
613         if (!fileSearch(path.absFileName(), chkconfig_ltx).empty())
614                 return path;
615
616         // Everything has failed :-(
617         // So inform the user and exit.
618         string searched_dirs_str;
619         typedef list<FileName>::const_iterator iterator;
620         iterator const begin = searched_dirs.begin();
621         iterator const end = searched_dirs.end();
622         for (iterator it = begin; it != end; ++it) {
623                 if (it != begin)
624                         searched_dirs_str += "\n\t";
625                 searched_dirs_str += it->absFileName();
626         }
627
628         // FIXME UNICODE
629         throw ExceptionMessage(ErrorException, _("No system directory"),
630                 bformat(_("Unable to determine the system directory "
631                                 "having searched\n"
632                                 "\t%1$s\n"
633                                 "Use the '-sysdir' command line parameter or "
634                                 "set the environment variable\n%2$s "
635                                 "to the LyX system directory containing the "
636                                 "file `chkconfig.ltx'."),
637                           from_utf8(searched_dirs_str), from_ascii(LYX_DIR_VER)));
638
639         // Keep the compiler happy.
640         return FileName();
641 }
642
643
644 // Returns the absolute path to the user lyxdir, together with a flag
645 // indicating whether this directory was specified explicitly (as -userdir
646 // or through an environment variable) or whether it was deduced.
647 bool userSupportDir(FileName const & default_user_support_dir,
648         string const & command_line_user_support_dir, FileName & result)
649 {
650         // 1. Use the -userdir command line parameter.
651         result = abs_path_from_command_line(command_line_user_support_dir);
652         if (!result.empty())
653                 return true;
654
655         // 2. Use the LYX_USERDIR_${major}${minor}x environment variable.
656         result = extract_env_var_dir(LYX_USERDIR_VER);
657         if (!result.empty())
658                 return true;
659
660         // 3. Use the OS-dependent default_user_support_dir
661         result = default_user_support_dir;
662         return false;
663 }
664
665
666 // $HOME/.lyx on POSIX but on Win32 it will be something like
667 // "C:/Documents and Settings/USERNAME/Application Data/LyX"
668 FileName const get_default_user_support_dir(FileName const & home_dir)
669 {
670 #if defined (USE_WINDOWS_PACKAGING)
671         (void)home_dir; // Silence warning about unused variable.
672
673         os::GetFolderPath win32_folder_path;
674         return FileName(addPath(win32_folder_path(os::GetFolderPath::APPDATA), PACKAGE));
675
676 #elif defined (USE_MACOSX_PACKAGING) && (QT_VERSION >= 0x050000)
677         (void)home_dir; // Silence warning about unused variable.
678         return FileName(addPath(fromqstr(QStandardPaths::writableLocation(QStandardPaths::DataLocation)), PACKAGE));
679
680 #elif defined (USE_MACOSX_PACKAGING)
681         (void)home_dir; // Silence warning about unused variable.
682         return FileName(addPath(fromqstr(QDesktopServices::storageLocation(QDesktopServices::DataLocation)), PACKAGE));
683
684 #else // USE_POSIX_PACKAGING
685         return FileName(addPath(home_dir.absFileName(), string(".") + PACKAGE));
686 #endif
687 }
688
689
690 // Check that directory @c dir contains @c file.
691 // Else emit an error message about an invalid @c command_line_switch.
692 bool check_command_line_dir(string const & dir,
693                             string const & file,
694                             string const & command_line_switch)
695 {
696         FileName const abs_path = fileSearch(dir, file);
697         if (abs_path.empty()) {
698                 // FIXME UNICODE
699                 throw ExceptionMessage(ErrorException, _("File not found"), bformat(
700                         _("Invalid %1$s switch.\nDirectory %2$s does not contain %3$s."),
701                         from_utf8(command_line_switch), from_utf8(dir),
702                         from_utf8(file)));
703         }
704
705         return !abs_path.empty();
706 }
707
708
709 // The environment variable @c env_var expands to a (single) file path.
710 FileName const extract_env_var_dir(string const & env_var)
711 {
712         string const dir = fix_dir_name(getEnv(env_var));
713         return dir.empty() ? FileName() : makeAbsPath(dir);
714 }
715
716
717 // Check that directory @c dir contains @c file.
718 // Else emit a warning about an invalid @c env_var.
719 bool check_env_var_dir(FileName const & dir,
720                        string const & file,
721                        string const & env_var)
722 {
723         FileName const abs_path = fileSearch(dir.absFileName(), file);
724         if (abs_path.empty()) {
725                 // FIXME UNICODE
726                 throw ExceptionMessage(WarningException, _("File not found"), bformat(
727                         _("Invalid %1$s environment variable.\n"
728                                 "Directory %2$s does not contain %3$s."),
729                         from_utf8(env_var), from_utf8(dir.absFileName()),
730                         from_utf8(file)));
731         }
732
733         return !abs_path.empty();
734 }
735
736
737 // Check that directory @c dir is indeed a directory.
738 // Else emit a warning about an invalid @c env_var.
739 bool check_env_var_dir(FileName const & dir,
740                        string const & env_var)
741 {
742         bool const success = dir.exists() && dir.isDirectory();
743
744         if (!success) {
745                 // Put this string on a single line so that the gettext
746                 // search mechanism in po/Makefile.in.in will register
747                 // Package.cpp.in as a file containing strings that need
748                 // translation.
749                 // FIXME UNICODE
750                 docstring const fmt =
751                         _("Invalid %1$s environment variable.\n%2$s is not a directory.");
752
753                 throw ExceptionMessage(WarningException, _("Directory not found"), bformat(
754                         fmt, from_utf8(env_var), from_utf8(dir.absFileName())));
755         }
756
757         return success;
758 }
759
760
761 // The locale directory relative to the LyX system directory.
762 string const relative_locale_dir()
763 {
764 #if defined (USE_WINDOWS_PACKAGING) || defined (USE_MACOSX_PACKAGING)
765         return "locale/";
766 #else
767         return "../locale/";
768 #endif
769 }
770
771
772 // The system lyxdir is relative to the directory containing the LyX binary.
773 string const relative_system_support_dir()
774 {
775         string result;
776
777 #if defined (USE_WINDOWS_PACKAGING) || defined (USE_MACOSX_PACKAGING)
778         result = "../Resources/";
779 #else // Posix-like.
780         result = addPath("../share/", PACKAGE);
781 #endif
782
783         return result;
784 }
785
786 } // namespace anon
787
788 } // namespace support
789 } // namespace lyx