]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
Do not rely on math macros being updated
[lyx.git] / src / LyX.cpp
1 /**
2  * \file LyX.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16 #include <version.h>
17
18 #include "LyX.h"
19
20 #include "AppleSpellChecker.h"
21 #include "AspellChecker.h"
22 #include "Buffer.h"
23 #include "BufferList.h"
24 #include "CmdDef.h"
25 #include "ColorSet.h"
26 #include "ConverterCache.h"
27 #include "Converter.h"
28 #include "CutAndPaste.h"
29 #include "EnchantChecker.h"
30 #include "Encoding.h"
31 #include "ErrorList.h"
32 #include "Format.h"
33 #include "FuncStatus.h"
34 #include "HunspellChecker.h"
35 #include "KeyMap.h"
36 #include "Language.h"
37 #include "LaTeXFonts.h"
38 #include "LayoutFile.h"
39 #include "Lexer.h"
40 #include "LyX.h"
41 #include "LyXAction.h"
42 #include "LyXRC.h"
43 #include "ModuleList.h"
44 #include "Mover.h"
45 #include "Server.h"
46 #include "ServerSocket.h"
47 #include "Session.h"
48 #include "WordList.h"
49
50 #include "frontends/alert.h"
51 #include "frontends/Application.h"
52
53 #include "support/ConsoleApplication.h"
54 #include "support/lassert.h"
55 #include "support/debug.h"
56 #include "support/environment.h"
57 #include "support/ExceptionMessage.h"
58 #include "support/filetools.h"
59 #include "support/gettext.h"
60 #include "support/lstrings.h"
61 #include "support/Messages.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64 #include "support/unique_ptr.h"
65
66 #include <algorithm>
67 #include <csignal>
68 #include <iostream>
69 #include <functional>
70 #include <map>
71 #include <stdlib.h>
72 #include <string>
73 #include <vector>
74
75 using namespace std;
76 using namespace lyx::support;
77
78 #if defined (USE_MACOSX_PACKAGING)
79 #include <crt_externs.h>
80 #endif
81
82 namespace lyx {
83
84 namespace Alert = frontend::Alert;
85 namespace os = support::os;
86
87
88
89 // Are we using the GUI at all?  We default to true and this is changed
90 // to false when the export feature is used.
91
92 bool use_gui = true;
93
94
95 // Report on the terminal about spawned commands. The default is false
96 // and can be changed with the option -v (--verbose).
97
98 bool verbose = false;
99
100
101 // We default to open documents in an already running instance, provided that
102 // the lyxpipe has been setup. This can be overridden either on the command
103 // line or through preference settings.
104
105 RunMode run_mode = PREFERRED;
106
107
108 // Tell what files can be silently overwritten during batch export.
109 // Possible values are: NO_FILES, MAIN_FILE, ALL_FILES, UNSPECIFIED.
110 // Unless specified on command line (through the -f switch) or through the
111 // environment variable LYX_FORCE_OVERWRITE, the default will be MAIN_FILE.
112
113 OverwriteFiles force_overwrite = UNSPECIFIED;
114
115
116 namespace {
117
118 // Filled with the command line arguments "foo" of "-sysdir foo" or
119 // "-userdir foo".
120 string cl_system_support;
121 string cl_user_support;
122
123 string geometryArg;
124
125 LyX * singleton_ = 0;
126
127 void showFileError(string const & error)
128 {
129         Alert::warning(_("Could not read configuration file"),
130                        bformat(_("Error while reading the configuration file\n%1$s.\n"
131                            "Please check your installation."), from_utf8(error)));
132 }
133
134 } // namespace anon
135
136 /// The main application class private implementation.
137 struct LyX::Impl {
138         Impl()
139                 : latexfonts_(0), spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
140         {}
141
142         ~Impl()
143         {
144                 delete latexfonts_;
145                 delete apple_spell_checker_;
146                 delete aspell_checker_;
147                 delete enchant_checker_;
148                 delete hunspell_checker_;
149         }
150
151         ///
152         BufferList buffer_list_;
153         ///
154         KeyMap toplevel_keymap_;
155         ///
156         CmdDef toplevel_cmddef_;
157         ///
158         unique_ptr<Server> lyx_server_;
159         ///
160         unique_ptr<ServerSocket> lyx_socket_;
161         ///
162         unique_ptr<frontend::Application> application_;
163         /// lyx session, containing lastfiles, lastfilepos, and lastopened
164         unique_ptr<Session> session_;
165
166         /// Files to load at start.
167         vector<string> files_to_load_;
168
169         /// The messages translators.
170         map<string, Messages> messages_;
171
172         /// The file converters.
173         Converters converters_;
174
175         // The system converters copy after reading lyxrc.defaults.
176         Converters system_converters_;
177
178         ///
179         Movers movers_;
180         ///
181         Movers system_movers_;
182
183         /// the parsed command line batch command if any
184         vector<string> batch_commands;
185
186         ///
187         LaTeXFonts * latexfonts_;
188
189         ///
190         SpellChecker * spell_checker_;
191         ///
192         SpellChecker * apple_spell_checker_;
193         ///
194         SpellChecker * aspell_checker_;
195         ///
196         SpellChecker * enchant_checker_;
197         ///
198         SpellChecker * hunspell_checker_;
199 };
200
201
202 /// The main application class for console mode
203 class LyXConsoleApp : public ConsoleApplication
204 {
205 public:
206         LyXConsoleApp(LyX * lyx, int & argc, char * argv[])
207                 : ConsoleApplication(lyx_package, argc, argv), lyx_(lyx),
208                   argc_(argc), argv_(argv)
209         {
210         }
211         void doExec()
212         {
213                 int const exit_status = lyx_->execWithoutGui(argc_, argv_);
214                 exit(exit_status);
215         }
216 private:
217         LyX * lyx_;
218         int & argc_;
219         char ** argv_;
220 };
221
222
223 ///
224 frontend::Application * theApp()
225 {
226         if (singleton_)
227                 return singleton_->pimpl_->application_.get();
228         else
229                 return 0;
230 }
231
232
233 LyX::~LyX()
234 {
235         delete pimpl_;
236         singleton_ = 0;
237         WordList::cleanupWordLists();
238 }
239
240
241 void lyx_exit(int exit_code)
242 {
243         if (exit_code)
244                 // Something wrong happened so better save everything, just in
245                 // case.
246                 emergencyCleanup();
247
248 #ifndef NDEBUG
249         // Properly crash in debug mode in order to get a useful backtrace.
250         abort();
251 #endif
252
253         // In release mode, try to exit gracefully.
254         if (theApp())
255                 theApp()->exit(exit_code);
256         else
257                 exit(exit_code);
258 }
259
260
261 LyX::LyX()
262         : first_start(false)
263 {
264         singleton_ = this;
265         pimpl_ = new Impl;
266 }
267
268
269 Messages & LyX::messages(string const & language)
270 {
271         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
272
273         if (it != pimpl_->messages_.end())
274                 return it->second;
275
276         pair<map<string, Messages>::iterator, bool> result =
277                         pimpl_->messages_.insert(make_pair(language, Messages(language)));
278
279         LATTEST(result.second);
280         return result.first->second;
281 }
282
283
284 int LyX::exec(int & argc, char * argv[])
285 {
286         // Minimal setting of locale before parsing command line
287         try {
288                 init_package(os::utf8_argv(0), string(), string());
289                 // we do not get to this point when init_package throws an exception
290                 setLocale();
291         } catch (ExceptionMessage const & message) {
292                 LYXERR(Debug::LOCALE, message.title_ + ", " + message.details_);
293         }
294
295         // Here we need to parse the command line. At least
296         // we need to parse for "-dbg" and "-help"
297         easyParse(argc, argv);
298
299         try {
300                 init_package(os::utf8_argv(0), cl_system_support, cl_user_support);
301         } catch (ExceptionMessage const & message) {
302                 if (message.type_ == ErrorException) {
303                         Alert::error(message.title_, message.details_);
304                         lyx_exit(1);
305                 } else if (message.type_ == WarningException) {
306                         Alert::warning(message.title_, message.details_);
307                 }
308         }
309
310         // Reinit the messages machinery in case package() knows
311         // something interesting about the locale directory.
312         setLocale();
313
314         if (!use_gui) {
315                 LyXConsoleApp app(this, argc, argv);
316
317                 // Reestablish our defaults, as Qt overwrites them
318                 // after creating app
319                 setLocale();//???
320
321                 return app.exec();
322         }
323
324         // Let the frontend parse and remove all arguments that it knows
325         pimpl_->application_.reset(createApplication(argc, argv));
326
327         // Reestablish our defaults, as Qt overwrites them
328         // after createApplication()
329         setLocale();//???
330
331         // Parse and remove all known arguments in the LyX singleton
332         // Give an error for all remaining ones.
333         int exit_status = init(argc, argv);
334         if (exit_status) {
335                 // Kill the application object before exiting.
336                 pimpl_->application_.reset();
337                 use_gui = false;
338                 prepareExit();
339                 return exit_status;
340         }
341
342         // If not otherwise specified by a command line option or
343         // by preferences, we default to reuse a running instance.
344         if (run_mode == PREFERRED)
345                 run_mode = USE_REMOTE;
346
347         // FIXME
348         /* Create a CoreApplication class that will provide the main event loop
349         * and the socket callback registering. With Qt, only QtCore
350         * library would be needed.
351         * When this is done, a server_mode could be created and the following two
352         * line would be moved out from here.
353         * However, note that the first of the two lines below triggers the
354         * "single instance" behavior, which should occur right at this point.
355         */
356         // Note: socket callback must be registered after init(argc, argv)
357         // such that package().temp_dir() is properly initialized.
358         pimpl_->lyx_server_.reset(new Server(lyxrc.lyxpipes));
359         pimpl_->lyx_socket_.reset(new ServerSocket(
360                         FileName(package().temp_dir().absFileName() + "/lyxsocket")));
361
362         // Start the real execution loop.
363         if (!theServer().deferredLoadingToOtherInstance())
364                 exit_status = pimpl_->application_->exec();
365         else if (!pimpl_->files_to_load_.empty()) {
366                 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
367                 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
368                 lyxerr << _("The following files could not be loaded:") << endl;
369                 for (; it != end; ++it)
370                         lyxerr << *it << endl;
371         }
372
373         prepareExit();
374
375         return exit_status;
376 }
377
378
379 void LyX::prepareExit()
380 {
381         // Clear the clipboard and selection stack:
382         cap::clearCutStack();
383         cap::clearSelection();
384
385         // Write the index file of the converter cache
386         ConverterCache::get().writeIndex();
387
388         // close buffers first
389         pimpl_->buffer_list_.closeAll();
390
391         // register session changes and shutdown server and socket
392         if (use_gui) {
393                 if (pimpl_->session_)
394                         pimpl_->session_->writeFile();
395                 pimpl_->session_.reset();
396                 pimpl_->lyx_server_.reset();
397                 pimpl_->lyx_socket_.reset();
398         }
399
400         // do any other cleanup procedures now
401         if (package().temp_dir() != package().system_temp_dir()) {
402                 string const abs_tmpdir = package().temp_dir().absFileName();
403                 if (!contains(package().temp_dir().absFileName(), "lyx_tmpdir")) {
404                         docstring const msg =
405                                 bformat(_("%1$s does not appear like a LyX created temporary directory."),
406                                 from_utf8(abs_tmpdir));
407                         Alert::warning(_("Cannot remove temporary directory"), msg);
408                 } else {
409                         LYXERR(Debug::INFO, "Deleting tmp dir "
410                                 << package().temp_dir().absFileName());
411                         if (!package().temp_dir().destroyDirectory()) {
412                                 LYXERR0(bformat(_("Unable to remove the temporary directory %1$s"),
413                                         from_utf8(package().temp_dir().absFileName())));
414                         }
415                 }
416         }
417
418         // Kill the application object before exiting. This avoids crashes
419         // when exiting on Linux.
420         pimpl_->application_.reset();
421 }
422
423
424 void LyX::earlyExit(int status)
425 {
426         LATTEST(pimpl_->application_.get());
427         // LyX::pimpl_::application_ is not initialised at this
428         // point so it's safe to just exit after some cleanup.
429         prepareExit();
430         exit(status);
431 }
432
433
434 int LyX::init(int & argc, char * argv[])
435 {
436         // check for any spurious extra arguments
437         // other than documents
438         for (int argi = 1; argi < argc ; ++argi) {
439                 if (argv[argi][0] == '-') {
440                         lyxerr << to_utf8(
441                                 bformat(_("Wrong command line option `%1$s'. Exiting."),
442                                 from_utf8(os::utf8_argv(argi)))) << endl;
443                         return EXIT_FAILURE;
444                 }
445         }
446
447         // Initialization of LyX (reads lyxrc and more)
448         LYXERR(Debug::INIT, "Initializing LyX::init...");
449         bool success = init();
450         LYXERR(Debug::INIT, "Initializing LyX::init...done");
451         if (!success)
452                 return EXIT_FAILURE;
453
454         // Remaining arguments are assumed to be files to load.
455         for (int argi = 1; argi < argc; ++argi)
456                 pimpl_->files_to_load_.push_back(os::utf8_argv(argi));
457
458         if (!use_gui && pimpl_->files_to_load_.empty()) {
459                 lyxerr << to_utf8(_("Missing filename for this operation.")) << endl;
460                 return EXIT_FAILURE;
461         }
462
463         if (first_start) {
464                 pimpl_->files_to_load_.push_back(
465                         i18nLibFileSearch("examples", "splash.lyx").absFileName());
466         }
467
468         return EXIT_SUCCESS;
469 }
470
471
472 int LyX::execWithoutGui(int & argc, char * argv[])
473 {
474         int exit_status = init(argc, argv);
475         if (exit_status) {
476                 prepareExit();
477                 return exit_status;
478         }
479
480         // Used to keep track of which buffers were explicitly loaded by user request.
481         // This is necessary because master and child document buffers are loaded, even 
482         // if they were not named on the command line. We do not want to dispatch to
483         // those.
484         vector<Buffer *> command_line_buffers;
485
486         // Load the files specified on the command line
487         vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
488         vector<string>::const_iterator end = pimpl_->files_to_load_.end();
489         for (; it != end; ++it) {
490                 // get absolute path of file and add ".lyx" to the filename if necessary
491                 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
492                                                                                                                                 may_not_exist);
493
494                 if (fname.empty())
495                         continue;
496
497                 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFileName());
498                 LYXERR(Debug::FILES, "Loading " << fname);
499                 if (buf && buf->loadLyXFile() == Buffer::ReadSuccess) {
500                         ErrorList const & el = buf->errorList("Parse");
501                         for(ErrorItem const & e : el)
502                                 printError(e);
503                         command_line_buffers.push_back(buf);
504                 } else {
505                         if (buf)
506                                 pimpl_->buffer_list_.release(buf);
507                         docstring const error_message =
508                                         bformat(_("LyX failed to load the following file: %1$s"),
509                                                                         from_utf8(fname.absFileName()));
510                         lyxerr << to_utf8(error_message) << endl;
511                         exit_status = 1; // failed
512                 }
513         }
514
515         if (exit_status || pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
516                 prepareExit();
517                 return exit_status;
518         }
519
520         // Iterate through the buffers that were specified on the command line
521         bool final_success = false;
522         vector<Buffer *>::iterator buf_it = command_line_buffers.begin();
523         for (; buf_it != command_line_buffers.end(); ++buf_it) {
524                 Buffer * buf = *buf_it;
525                 vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
526                 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
527                 DispatchResult dr;
528                 for (; bcit != bcend; ++bcit) {
529                         LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit);
530                         buf->dispatch(*bcit, dr);
531                         final_success |= !dr.error();
532                 }
533         }
534         prepareExit();
535         return !final_success;
536 }
537
538
539 void execBatchCommands()
540 {
541         LAPPERR(singleton_);
542         singleton_->execCommands();
543 }
544
545
546 void LyX::execCommands()
547 {
548         // The advantage of doing this here is that the event loop
549         // is already started. So any need for interaction will be
550         // aknowledged.
551
552         // if reconfiguration is needed.
553         if (LayoutFileList::get().empty()) {
554                 switch (Alert::prompt(
555                         _("No textclass is found"),
556                         _("LyX will only have minimal functionality because no textclasses "
557                                 "have been found. You can either try to reconfigure LyX normally, "
558                                 "try to reconfigure without checking your LaTeX installation, or continue."),
559                         0, 2,
560                         _("&Reconfigure"),
561                         _("&Without LaTeX"),
562                         _("&Continue")))
563                 {
564                 case 0:
565                         // regular reconfigure
566                         lyx::dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
567                         break;
568                 case 1:
569                         // reconfigure --without-latex-config
570                         lyx::dispatch(FuncRequest(LFUN_RECONFIGURE,
571                                 " --without-latex-config"));
572                         break;
573                 default:
574                         break;
575                 }
576         }
577
578         // create the first main window
579         lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
580
581         if (!pimpl_->files_to_load_.empty()) {
582                 // if some files were specified at command-line we assume that the
583                 // user wants to edit *these* files and not to restore the session.
584                 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
585                         lyx::dispatch(
586                                 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
587                 }
588                 // clear this list to save a few bytes of RAM
589                 pimpl_->files_to_load_.clear();
590         } else
591                 pimpl_->application_->restoreGuiSession();
592
593         // Execute batch commands if available
594         if (pimpl_->batch_commands.empty())
595                 return;
596
597         vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
598         vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
599         for (; bcit != bcend; ++bcit) {
600                 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
601                 lyx::dispatch(lyxaction.lookupFunc(*bcit));
602         }
603 }
604
605
606 /*
607 Signals and Windows
608 ===================
609 The SIGHUP signal does not exist on Windows and does not need to be handled.
610
611 Windows handles SIGFPE and SIGSEGV signals as expected.
612
613 Ctrl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
614 cause a new thread to be spawned. This may well result in unexpected
615 behaviour by the single-threaded LyX.
616
617 SIGTERM signals will come only from another process actually sending
618 that signal using 'raise' in Windows' POSIX compatability layer. It will
619 not come from the general "terminate process" methods that everyone
620 actually uses (and which can't be trapped). Killing an app 'politely' on
621 Windows involves first sending a WM_CLOSE message, something that is
622 caught already by the Qt frontend.
623
624 For more information see:
625
626 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
627 ...signals are mostly useless on Windows for a variety of reasons that are
628 Windows specific...
629
630 'UNIX Application Migration Guide, Chapter 9'
631 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
632
633 'How To Terminate an Application "Cleanly" in Win32'
634 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
635 */
636 extern "C" {
637
638 static void error_handler(int err_sig)
639 {
640         // Throw away any signals other than the first one received.
641         static sig_atomic_t handling_error = false;
642         if (handling_error)
643                 return;
644         handling_error = true;
645
646         // We have received a signal indicating a fatal error, so
647         // try and save the data ASAP.
648         emergencyCleanup();
649
650         // These lyxerr calls may or may not work:
651
652         // Signals are asynchronous, so the main program may be in a very
653         // fragile state when a signal is processed and thus while a signal
654         // handler function executes.
655         // In general, therefore, we should avoid performing any
656         // I/O operations or calling most library and system functions from
657         // signal handlers.
658
659         // This shouldn't matter here, however, as we've already invoked
660         // emergencyCleanup.
661         docstring msg;
662         switch (err_sig) {
663 #ifdef SIGHUP
664         case SIGHUP:
665                 msg = _("SIGHUP signal caught!\nBye.");
666                 break;
667 #endif
668         case SIGFPE:
669                 msg = _("SIGFPE signal caught!\nBye.");
670                 break;
671         case SIGSEGV:
672                 msg = _("SIGSEGV signal caught!\n"
673                           "Sorry, you have found a bug in LyX, "
674                           "hope you have not lost any data.\n"
675                           "Please read the bug-reporting instructions "
676                           "in 'Help->Introduction' and send us a bug report, "
677                           "if necessary. Thanks!\nBye.");
678                 break;
679         case SIGINT:
680         case SIGTERM:
681                 // no comments
682                 break;
683         }
684
685         if (!msg.empty()) {
686                 lyxerr << "\nlyx: " << msg << endl;
687                 // try to make a GUI message
688                 Alert::error(_("LyX crashed!"), msg, true);
689         }
690
691         // Deinstall the signal handlers
692 #ifdef SIGHUP
693         signal(SIGHUP, SIG_DFL);
694 #endif
695         signal(SIGINT, SIG_DFL);
696         signal(SIGFPE, SIG_DFL);
697         signal(SIGSEGV, SIG_DFL);
698         signal(SIGTERM, SIG_DFL);
699
700 #ifdef SIGHUP
701         if (err_sig == SIGSEGV ||
702                 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty())) {
703 #else
704         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty()) {
705 #endif
706 #ifdef _MSC_VER
707                 // with abort() it crashes again.
708                 exit(err_sig);
709 #else
710                 abort();
711 #endif
712         }
713
714         exit(0);
715 }
716
717 }
718
719
720 void LyX::printError(ErrorItem const & ei)
721 {
722         docstring tmp = _("LyX: ") + ei.error + char_type(':')
723                 + ei.description;
724         cerr << to_utf8(tmp) << endl;
725 }
726
727 #if defined (USE_MACOSX_PACKAGING)
728 namespace {
729         // Unexposed--extract an environment variable name from its NAME=VALUE
730         // representation
731         std::string varname(const char* line)
732         {
733                 size_t nameLen = strcspn(line, "=");
734                 if (nameLen == strlen(line)) {
735                         return std::string();
736                 } else {
737                         return std::string(line, nameLen);
738                 }
739         }
740 }
741
742 void cleanDuplicateEnvVars()
743 {
744         std::set<std::string> seen;
745         std::set<std::string> dupes;
746
747         // Create a list of the environment variables that appear more than once
748         for (char **read = *_NSGetEnviron(); *read; read++) {
749                 std::string name = varname(*read);
750                 if (name.size() == 0) {
751                         continue;
752                 }
753                 if (seen.find(name) != seen.end()) {
754                         dupes.insert(name);
755                 } else {
756                         seen.insert(name);
757                 }
758         }
759
760         // Loop over the list of duplicated variables
761         std::set<std::string>::iterator dupe = dupes.begin();
762         std::set<std::string>::iterator const dend = dupes.end();
763         for (; dupe != dend; ++dupe) {
764                 const char *name = (*dupe).c_str();
765                 char *val = getenv(name);
766                 if (val != NULL) {
767                         LYXERR(Debug::INIT, "Duplicate environment variable: " << name);
768                         // unsetenv removes *all* instances of the variable from the environment
769                         unsetenv(name);
770
771                         // replace with the value from getenv (in practice appears to be the
772                         // first value in the list)
773                         setenv(name, val, 0);
774                 }
775         }
776 }
777 #endif
778
779
780 static void initTemplatePath()
781 {
782         FileName const package_template_path =
783                 FileName(addName(package().system_support().absFileName(), "templates"));
784
785         if (lyxrc.template_path.empty()) {
786                 lyxrc.template_path = package_template_path.absFileName();
787         }
788 #if defined (USE_MACOSX_PACKAGING)
789         FileName const user_template_path =
790                 FileName(addName(package().user_support().absFileName(), "templates"));
791
792         if (package_template_path != FileName(lyxrc.template_path) &&
793                 user_template_path != FileName(lyxrc.template_path))
794         {
795                 return;
796         }
797         FileName const user_template_link =
798                 FileName(addName(user_template_path.absFileName(),"SystemTemplates"));
799         if (user_template_link.isSymLink() && !equivalent(user_template_link, package_template_path)) {
800                 user_template_link.removeFile();
801         }
802         if (!user_template_link.exists()) {
803                 if (!package_template_path.link(user_template_link)) {
804                         FileName const user_support = package().user_support();
805                         if (user_support.exists() && user_support.isDirectory()) {
806                                 LYXERR(Debug::INIT, "Cannot create symlink " + user_template_link.absFileName());
807                                 lyxrc.template_path = package_template_path.absFileName();
808                         }
809                         return;
810                 }
811                 LYXERR(Debug::INIT, "Symlink \"" << user_template_link.absFileName() << "\" created.");
812         }
813         lyxrc.template_path = user_template_path.absFileName();
814 #endif
815 }
816
817
818 bool LyX::init()
819 {
820 #ifdef SIGHUP
821         signal(SIGHUP, error_handler);
822 #endif
823         signal(SIGFPE, error_handler);
824         signal(SIGSEGV, error_handler);
825         signal(SIGINT, error_handler);
826         signal(SIGTERM, error_handler);
827         // SIGPIPE can be safely ignored.
828
829 #if defined (USE_MACOSX_PACKAGING)
830         cleanDuplicateEnvVars();
831 #endif
832
833         lyxrc.tempdir_path = package().temp_dir().absFileName();
834         lyxrc.document_path = package().document_dir().absFileName();
835
836         if (lyxrc.example_path.empty()) {
837                 lyxrc.example_path = addPath(package().system_support().absFileName(),
838                                               "examples");
839         }
840         initTemplatePath();
841
842         // init LyXDir environment variable
843         string const lyx_dir = package().lyx_dir().absFileName();
844         LYXERR(Debug::INIT, "Setting LyXDir... to \"" << lyx_dir << "\"");
845         if (!setEnv("LyXDir", lyx_dir))
846                 LYXERR(Debug::INIT, "\t... failed!");
847
848         if (package().explicit_user_support() && getEnv(LYX_USERDIR_VER).empty()) {
849                 // -userdir was given on the command line.
850                 // Make it available to child processes, otherwise tex2lyx
851                 // would not find all layout files, and other converters might
852                 // use it as well.
853                 string const user_dir = package().user_support().absFileName();
854                 LYXERR(Debug::INIT, "Setting " LYX_USERDIR_VER "... to \""
855                                     << user_dir << '"');
856                 if (!setEnv(LYX_USERDIR_VER, user_dir))
857                         LYXERR(Debug::INIT, "\t... failed!");
858         }
859
860         //
861         // Read configuration files
862         //
863
864         // This one may have been distributed along with LyX.
865         if (!readRcFile("lyxrc.dist"))
866                 return false;
867
868         // Set the PATH correctly.
869 #if !defined (USE_POSIX_PACKAGING) && !defined (USE_HAIKU_PACKAGING)
870         // Add the directory containing the LyX executable to the path
871         // so that LyX can find things like tex2lyx.
872         if (package().build_support().empty())
873                 prependEnvPath("PATH", package().binary_dir().absFileName());
874 #endif
875         if (!lyxrc.path_prefix.empty())
876                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
877
878         // Check that user LyX directory is ok.
879         {
880                 string const lock_file = package().getConfigureLockName();
881                 int fd = fileLock(lock_file.c_str());
882
883                 if (queryUserLyXDir(package().explicit_user_support())) {
884                         package().reconfigureUserLyXDir("");
885                         // Now the user directory is present on first start.
886                         initTemplatePath();
887                 }
888                 fileUnlock(fd, lock_file.c_str());
889         }
890
891         if (!use_gui) {
892                 // No need for a splash when there is no GUI
893                 first_start = false;
894                 // Default is to overwrite the main file during export, unless
895                 // the -f switch was specified or LYX_FORCE_OVERWRITE was set
896                 if (force_overwrite == UNSPECIFIED) {
897                         string const what = getEnv("LYX_FORCE_OVERWRITE");
898                         if (what == "all")
899                                 force_overwrite = ALL_FILES;
900                         else if (what == "none")
901                                 force_overwrite = NO_FILES;
902                         else
903                                 force_overwrite = MAIN_FILE;
904                 }
905         }
906
907         // This one is generated in user_support directory by lib/configure.py.
908         if (!readRcFile("lyxrc.defaults"))
909                 return false;
910
911         // Query the OS to know what formats are viewed natively
912         formats.setAutoOpen();
913
914         // Read lyxrc.dist again to be able to override viewer auto-detection.
915         readRcFile("lyxrc.dist");
916
917         system_lyxrc = lyxrc;
918         system_formats = formats;
919         pimpl_->system_converters_ = pimpl_->converters_;
920         pimpl_->system_movers_ = pimpl_->movers_;
921         system_lcolor = lcolor;
922
923         // This one is edited through the preferences dialog.
924         if (!readRcFile("preferences", true))
925                 return false;
926
927         // The language may have been set to someting useful through prefs
928         setLocale();
929
930         if (!readEncodingsFile("encodings", "unicodesymbols"))
931                 return false;
932         if (!readLanguagesFile("languages"))
933                 return false;
934
935         LYXERR(Debug::INIT, "Reading layouts...");
936         // Load the layouts
937         LayoutFileList::get().read();
938         //...and the modules
939         theModuleList.read();
940
941         // read keymap and ui files in batch mode as well
942         // because InsetInfo needs to know these to produce
943         // the correct output
944
945         // Set up command definitions
946         pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
947
948         // FIXME
949         // Set up bindings
950         pimpl_->toplevel_keymap_.read("site");
951         pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
952         // load user bind file user.bind
953         pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
954
955         if (lyxerr.debugging(Debug::LYXRC))
956                 lyxrc.print();
957
958         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
959         // Prepend path prefix a second time to take the user preferences into a account
960         if (!lyxrc.path_prefix.empty())
961                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
962
963         FileName const document_path(lyxrc.document_path);
964         if (document_path.exists() && document_path.isDirectory())
965                 package().document_dir() = document_path;
966
967         package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
968         if (package().temp_dir().empty()) {
969                 Alert::error(_("Could not create temporary directory"),
970                              bformat(_("Could not create a temporary directory in\n"
971                                                        "\"%1$s\"\n"
972                                                            "Make sure that this path exists and is writable and try again."),
973                                      from_utf8(lyxrc.tempdir_path)));
974                 // createLyXTmpDir() tries sufficiently hard to create a
975                 // usable temp dir, so the probability to come here is
976                 // close to zero. We therefore don't try to overcome this
977                 // problem with e.g. asking the user for a new path and
978                 // trying again but simply exit.
979                 return false;
980         }
981
982         LYXERR(Debug::INIT, "LyX tmp dir: `"
983                             << package().temp_dir().absFileName() << '\'');
984
985         LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
986         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
987
988         // This must happen after package initialization and after lyxrc is
989         // read, therefore it can't be done by a static object.
990         ConverterCache::init();
991
992         return true;
993 }
994
995
996 void emergencyCleanup()
997 {
998         // what to do about tmpfiles is non-obvious. we would
999         // like to delete any we find, but our lyxdir might
1000         // contain documents etc. which might be helpful on
1001         // a crash
1002
1003         singleton_->pimpl_->buffer_list_.emergencyWriteAll();
1004         if (use_gui) {
1005                 if (singleton_->pimpl_->lyx_server_)
1006                         singleton_->pimpl_->lyx_server_->emergencyCleanup();
1007                 singleton_->pimpl_->lyx_server_.reset();
1008                 singleton_->pimpl_->lyx_socket_.reset();
1009         }
1010 }
1011
1012
1013 bool LyX::queryUserLyXDir(bool explicit_userdir)
1014 {
1015         // Does user directory exist?
1016         FileName const sup = package().user_support();
1017         if (sup.exists() && sup.isDirectory()) {
1018                 first_start = false;
1019
1020                 return configFileNeedsUpdate("lyxrc.defaults")
1021                         || configFileNeedsUpdate("lyxmodules.lst")
1022                         || configFileNeedsUpdate("textclass.lst")
1023                         || configFileNeedsUpdate("packages.lst");
1024         }
1025
1026         first_start = !explicit_userdir;
1027
1028         // If the user specified explicitly a directory, ask whether
1029         // to create it. If the user says "no", then exit.
1030         if (explicit_userdir &&
1031             Alert::prompt(
1032                     _("Missing user LyX directory"),
1033                     bformat(_("You have specified a non-existent user "
1034                                            "LyX directory, %1$s.\n"
1035                                            "It is needed to keep your own configuration."),
1036                             from_utf8(package().user_support().absFileName())),
1037                     1, 0,
1038                     _("&Create directory"),
1039                     _("&Exit LyX"))) {
1040                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1041                 earlyExit(EXIT_FAILURE);
1042         }
1043
1044         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1045                           from_utf8(sup.absFileName()))) << endl;
1046
1047         if (!sup.createDirectory(0755)) {
1048                 // Failed, so let's exit.
1049                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1050                        << endl;
1051                 earlyExit(EXIT_FAILURE);
1052         }
1053
1054         return true;
1055 }
1056
1057
1058 bool LyX::readRcFile(string const & name, bool check_format)
1059 {
1060         LYXERR(Debug::INIT, "About to read " << name << "... ");
1061
1062         FileName const lyxrc_path = libFileSearch(string(), name);
1063         if (lyxrc_path.empty()) {
1064                 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1065                 // FIXME
1066                 // This was the previous logic, but can it be right??
1067                 return true;
1068         }
1069         LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1070         bool const success = lyxrc.read(lyxrc_path, check_format);
1071         if (!success)
1072                 showFileError(name);
1073         return success;
1074 }
1075
1076 // Read the languages file `name'
1077 bool LyX::readLanguagesFile(string const & name)
1078 {
1079         LYXERR(Debug::INIT, "About to read " << name << "...");
1080
1081         FileName const lang_path = libFileSearch(string(), name);
1082         if (lang_path.empty()) {
1083                 showFileError(name);
1084                 return false;
1085         }
1086         languages.read(lang_path);
1087         return true;
1088 }
1089
1090
1091 // Read the encodings file `name'
1092 bool LyX::readEncodingsFile(string const & enc_name,
1093                             string const & symbols_name)
1094 {
1095         LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1096                             << symbols_name << "...");
1097
1098         FileName const symbols_path = libFileSearch(string(), symbols_name);
1099         if (symbols_path.empty()) {
1100                 showFileError(symbols_name);
1101                 return false;
1102         }
1103
1104         FileName const enc_path = libFileSearch(string(), enc_name);
1105         if (enc_path.empty()) {
1106                 showFileError(enc_name);
1107                 return false;
1108         }
1109         encodings.read(enc_path, symbols_path);
1110         return true;
1111 }
1112
1113
1114 namespace {
1115
1116 /// return the the number of arguments consumed
1117 typedef function<int(string const &, string const &, string &)> cmd_helper;
1118
1119 int parse_dbg(string const & arg, string const &, string &)
1120 {
1121         if (arg.empty()) {
1122                 cout << to_utf8(_("List of supported debug flags:")) << endl;
1123                 Debug::showTags(cout);
1124                 exit(0);
1125         }
1126         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1127
1128         lyxerr.setLevel(Debug::value(arg));
1129         Debug::showLevel(lyxerr, lyxerr.level());
1130         return 1;
1131 }
1132
1133
1134 int parse_help(string const &, string const &, string &)
1135 {
1136         cout <<
1137                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1138                   "Command line switches (case sensitive):\n"
1139                   "\t-help              summarize LyX usage\n"
1140                   "\t-userdir dir       set user directory to dir\n"
1141                   "\t-sysdir dir        set system directory to dir\n"
1142                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1143                   "\t-dbg feature[,feature]...\n"
1144                   "                  select the features to debug.\n"
1145                   "                  Type `lyx -dbg' to see the list of features\n"
1146                   "\t-x [--execute] command\n"
1147                   "                  where command is a lyx command.\n"
1148                   "\t-e [--export] fmt\n"
1149                   "                  where fmt is the export format of choice. Look in\n"
1150                   "                  Tools->Preferences->File Handling->File Formats->Short Name\n"
1151                   "                  to see which parameter (which differs from the format name\n"
1152                   "                  in the File->Export menu) should be passed.\n"
1153                   "                  Note that the order of -e and -x switches matters.\n"
1154                   "\t-E [--export-to] fmt filename\n"
1155                   "                  where fmt is the export format of choice (see --export),\n"
1156                   "                  and filename is the destination filename.\n"
1157                   "\t-i [--import] fmt file.xxx\n"
1158                   "                  where fmt is the import format of choice\n"
1159                   "                  and file.xxx is the file to be imported.\n"
1160                   "\t-f [--force-overwrite] what\n"
1161                   "                  where what is either `all', `main' or `none',\n"
1162                   "                  specifying whether all files, main file only, or no files,\n"
1163                   "                  respectively, are to be overwritten during a batch export.\n"
1164                   "                  Anything else is equivalent to `all', but is not consumed.\n"
1165                   "\t-n [--no-remote]\n"
1166                   "                  open documents in a new instance\n"
1167                   "\t-r [--remote]\n"
1168                   "                  open documents in an already running instance\n"
1169                   "                  (a working lyxpipe is needed)\n"
1170                   "\t-v [--verbose]\n"
1171                   "                  report on terminal about spawned commands.\n"
1172                   "\t-batch    execute commands without launching GUI and exit.\n"
1173                   "\t-version  summarize version and build info\n"
1174                                "Check the LyX man page for more details.")) << endl;
1175         exit(0);
1176         return 0;
1177 }
1178
1179
1180 int parse_version(string const &, string const &, string &)
1181 {
1182         cout << "LyX " << lyx_version
1183                << " (" << lyx_release_date << ")" << endl;
1184         if (string(lyx_git_commit_hash) != "none")
1185                 cout << to_utf8(_("  Git commit hash "))
1186                      << string(lyx_git_commit_hash).substr(0,8) << endl;
1187         cout << lyx_version_info << endl;
1188         exit(0);
1189         return 0;
1190 }
1191
1192
1193 int parse_sysdir(string const & arg, string const &, string &)
1194 {
1195         if (arg.empty()) {
1196                 Alert::error(_("No system directory"),
1197                         _("Missing directory for -sysdir switch"));
1198                 exit(1);
1199         }
1200         cl_system_support = arg;
1201         return 1;
1202 }
1203
1204
1205 int parse_userdir(string const & arg, string const &, string &)
1206 {
1207         if (arg.empty()) {
1208                 Alert::error(_("No user directory"),
1209                         _("Missing directory for -userdir switch"));
1210                 exit(1);
1211         }
1212         cl_user_support = arg;
1213         return 1;
1214 }
1215
1216
1217 int parse_execute(string const & arg, string const &, string & batch)
1218 {
1219         if (arg.empty()) {
1220                 Alert::error(_("Incomplete command"),
1221                         _("Missing command string after --execute switch"));
1222                 exit(1);
1223         }
1224         batch = arg;
1225         return 1;
1226 }
1227
1228
1229 int parse_export_to(string const & type, string const & output_file, string & batch)
1230 {
1231         if (type.empty()) {
1232                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1233                                          "--export-to switch")) << endl;
1234                 exit(1);
1235         }
1236         if (output_file.empty()) {
1237                 lyxerr << to_utf8(_("Missing destination filename after "
1238                                          "--export-to switch")) << endl;
1239                 exit(1);
1240         }
1241         batch = "buffer-export " + type + " " + output_file;
1242         use_gui = false;
1243         return 2;
1244 }
1245
1246
1247 int parse_export(string const & type, string const &, string & batch)
1248 {
1249         if (type.empty()) {
1250                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1251                                          "--export switch")) << endl;
1252                 exit(1);
1253         }
1254         batch = "buffer-export " + type;
1255         use_gui = false;
1256         return 1;
1257 }
1258
1259
1260 int parse_import(string const & type, string const & file, string & batch)
1261 {
1262         if (type.empty()) {
1263                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1264                                          "--import switch")) << endl;
1265                 exit(1);
1266         }
1267         if (file.empty()) {
1268                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1269                 exit(1);
1270         }
1271         batch = "buffer-import " + type + ' ' + file;
1272         return 2;
1273 }
1274
1275
1276 int parse_geometry(string const & arg1, string const &, string &)
1277 {
1278         geometryArg = arg1;
1279         // don't remove "-geometry", it will be pruned out later in the
1280         // frontend if need be.
1281         return -1;
1282 }
1283
1284
1285 int parse_batch(string const &, string const &, string &)
1286 {
1287         use_gui = false;
1288         return 0;
1289 }
1290
1291
1292 int parse_noremote(string const &, string const &, string &)
1293 {
1294         run_mode = NEW_INSTANCE;
1295         return 0;
1296 }
1297
1298
1299 int parse_remote(string const &, string const &, string &)
1300 {
1301         run_mode = USE_REMOTE;
1302         return 0;
1303 }
1304
1305
1306 int parse_verbose(string const &, string const &, string &)
1307 {
1308         verbose = true;
1309         return 0;
1310 }
1311
1312
1313 int parse_force(string const & arg, string const &, string &)
1314 {
1315         if (arg == "all") {
1316                 force_overwrite = ALL_FILES;
1317                 return 1;
1318         } else if (arg == "main") {
1319                 force_overwrite = MAIN_FILE;
1320                 return 1;
1321         } else if (arg == "none") {
1322                 force_overwrite = NO_FILES;
1323                 return 1;
1324         }
1325         force_overwrite = ALL_FILES;
1326         return 0;
1327 }
1328
1329
1330 } // namespace anon
1331
1332
1333 void LyX::easyParse(int & argc, char * argv[])
1334 {
1335         map<string, cmd_helper> cmdmap;
1336
1337         cmdmap["-dbg"] = parse_dbg;
1338         cmdmap["-help"] = parse_help;
1339         cmdmap["--help"] = parse_help;
1340         cmdmap["-version"] = parse_version;
1341         cmdmap["--version"] = parse_version;
1342         cmdmap["-sysdir"] = parse_sysdir;
1343         cmdmap["-userdir"] = parse_userdir;
1344         cmdmap["-x"] = parse_execute;
1345         cmdmap["--execute"] = parse_execute;
1346         cmdmap["-e"] = parse_export;
1347         cmdmap["--export"] = parse_export;
1348         cmdmap["-E"] = parse_export_to;
1349         cmdmap["--export-to"] = parse_export_to;
1350         cmdmap["-i"] = parse_import;
1351         cmdmap["--import"] = parse_import;
1352         cmdmap["-geometry"] = parse_geometry;
1353         cmdmap["-batch"] = parse_batch;
1354         cmdmap["-f"] = parse_force;
1355         cmdmap["--force-overwrite"] = parse_force;
1356         cmdmap["-n"] = parse_noremote;
1357         cmdmap["--no-remote"] = parse_noremote;
1358         cmdmap["-r"] = parse_remote;
1359         cmdmap["--remote"] = parse_remote;
1360         cmdmap["-v"] = parse_verbose;
1361         cmdmap["--verbose"] = parse_verbose;
1362
1363         for (int i = 1; i < argc; ++i) {
1364                 map<string, cmd_helper>::const_iterator it
1365                         = cmdmap.find(argv[i]);
1366
1367                 // don't complain if not found - may be parsed later
1368                 if (it == cmdmap.end())
1369                         continue;
1370
1371                 string const arg =
1372                         (i + 1 < argc) ? os::utf8_argv(i + 1) : string();
1373                 string const arg2 =
1374                         (i + 2 < argc) ? os::utf8_argv(i + 2) : string();
1375
1376                 string batch;
1377                 int const remove = 1 + it->second(arg, arg2, batch);
1378                 if (!batch.empty())
1379                         pimpl_->batch_commands.push_back(batch);
1380
1381                 // Now, remove used arguments by shifting
1382                 // the following ones remove places down.
1383                 if (remove > 0) {
1384                         os::remove_internal_args(i, remove);
1385                         argc -= remove;
1386                         for (int j = i; j < argc; ++j)
1387                                 argv[j] = argv[j + remove];
1388                         --i;
1389                 }
1390         }
1391 }
1392
1393
1394 FuncStatus getStatus(FuncRequest const & action)
1395 {
1396         LAPPERR(theApp());
1397         return theApp()->getStatus(action);
1398 }
1399
1400
1401 DispatchResult const & dispatch(FuncRequest const & action)
1402 {
1403         LAPPERR(theApp());
1404         return theApp()->dispatch(action);
1405 }
1406
1407
1408 void dispatch(FuncRequest const & action, DispatchResult & dr)
1409 {
1410         LAPPERR(theApp());
1411         theApp()->dispatch(action, dr);
1412 }
1413
1414
1415 vector<string> & theFilesToLoad()
1416 {
1417         LAPPERR(singleton_);
1418         return singleton_->pimpl_->files_to_load_;
1419 }
1420
1421
1422 BufferList & theBufferList()
1423 {
1424         LAPPERR(singleton_);
1425         return singleton_->pimpl_->buffer_list_;
1426 }
1427
1428
1429 Server & theServer()
1430 {
1431         // FIXME: this should not be use_gui dependent
1432         LWARNIF(use_gui);
1433         LAPPERR(singleton_);
1434         return *singleton_->pimpl_->lyx_server_;
1435 }
1436
1437
1438 ServerSocket & theServerSocket()
1439 {
1440         // FIXME: this should not be use_gui dependent
1441         LWARNIF(use_gui);
1442         LAPPERR(singleton_);
1443         return *singleton_->pimpl_->lyx_socket_;
1444 }
1445
1446
1447 KeyMap & theTopLevelKeymap()
1448 {
1449         LAPPERR(singleton_);
1450         return singleton_->pimpl_->toplevel_keymap_;
1451 }
1452
1453
1454 Converters & theConverters()
1455 {
1456         LAPPERR(singleton_);
1457         return  singleton_->pimpl_->converters_;
1458 }
1459
1460
1461 Converters & theSystemConverters()
1462 {
1463         LAPPERR(singleton_);
1464         return  singleton_->pimpl_->system_converters_;
1465 }
1466
1467
1468 Movers & theMovers()
1469 {
1470         LAPPERR(singleton_);
1471         return singleton_->pimpl_->movers_;
1472 }
1473
1474
1475 Mover const & getMover(string  const & fmt)
1476 {
1477         LAPPERR(singleton_);
1478         return singleton_->pimpl_->movers_(fmt);
1479 }
1480
1481
1482 void setMover(string const & fmt, string const & command)
1483 {
1484         LAPPERR(singleton_);
1485         singleton_->pimpl_->movers_.set(fmt, command);
1486 }
1487
1488
1489 Movers & theSystemMovers()
1490 {
1491         LAPPERR(singleton_);
1492         return singleton_->pimpl_->system_movers_;
1493 }
1494
1495
1496 Messages const & getMessages(string const & language)
1497 {
1498         LAPPERR(singleton_);
1499         return singleton_->messages(language);
1500 }
1501
1502
1503 Messages const & getGuiMessages()
1504 {
1505         LAPPERR(singleton_);
1506         return singleton_->messages(Messages::guiLanguage());
1507 }
1508
1509
1510 Session & theSession()
1511 {
1512         LAPPERR(singleton_);
1513         return *singleton_->pimpl_->session_.get();
1514 }
1515
1516
1517 LaTeXFonts & theLaTeXFonts()
1518 {
1519         LAPPERR(singleton_);
1520         if (!singleton_->pimpl_->latexfonts_)
1521                 singleton_->pimpl_->latexfonts_ = new LaTeXFonts;
1522         return *singleton_->pimpl_->latexfonts_;
1523 }
1524
1525
1526 CmdDef & theTopLevelCmdDef()
1527 {
1528         LAPPERR(singleton_);
1529         return singleton_->pimpl_->toplevel_cmddef_;
1530 }
1531
1532
1533 SpellChecker * theSpellChecker()
1534 {
1535         if (!singleton_->pimpl_->spell_checker_)
1536                 setSpellChecker();
1537         return singleton_->pimpl_->spell_checker_;
1538 }
1539
1540
1541 void setSpellChecker()
1542 {
1543         SpellChecker::ChangeNumber speller_change_number =singleton_->pimpl_->spell_checker_ ?
1544                 singleton_->pimpl_->spell_checker_->changeNumber() : 0;
1545
1546         if (lyxrc.spellchecker == "native") {
1547 #if defined(USE_MACOSX_PACKAGING)
1548                 if (!singleton_->pimpl_->apple_spell_checker_)
1549                         singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker;
1550                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_;
1551 #else
1552                 singleton_->pimpl_->spell_checker_ = 0;
1553 #endif
1554         } else if (lyxrc.spellchecker == "aspell") {
1555 #if defined(USE_ASPELL)
1556                 if (!singleton_->pimpl_->aspell_checker_)
1557                         singleton_->pimpl_->aspell_checker_ = new AspellChecker;
1558                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1559 #else
1560                 singleton_->pimpl_->spell_checker_ = 0;
1561 #endif
1562         } else if (lyxrc.spellchecker == "enchant") {
1563 #if defined(USE_ENCHANT)
1564                 if (!singleton_->pimpl_->enchant_checker_)
1565                         singleton_->pimpl_->enchant_checker_ = new EnchantChecker;
1566                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1567 #else
1568                 singleton_->pimpl_->spell_checker_ = 0;
1569 #endif
1570         } else if (lyxrc.spellchecker == "hunspell") {
1571 #if defined(USE_HUNSPELL)
1572                 if (!singleton_->pimpl_->hunspell_checker_)
1573                         singleton_->pimpl_->hunspell_checker_ = new HunspellChecker;
1574                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1575 #else
1576                 singleton_->pimpl_->spell_checker_ = 0;
1577 #endif
1578         } else {
1579                 singleton_->pimpl_->spell_checker_ = 0;
1580         }
1581         if (singleton_->pimpl_->spell_checker_) {
1582                 singleton_->pimpl_->spell_checker_->changeNumber(speller_change_number);
1583                 singleton_->pimpl_->spell_checker_->advanceChangeNumber();
1584         }
1585 }
1586
1587 } // namespace lyx