]> git.lyx.org Git - features.git/blob - src/LyX.cpp
Merge branch 'master' into biblatex2
[features.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 "CiteEnginesList.h"
26 #include "ColorSet.h"
27 #include "ConverterCache.h"
28 #include "Converter.h"
29 #include "CutAndPaste.h"
30 #include "EnchantChecker.h"
31 #include "Encoding.h"
32 #include "ErrorList.h"
33 #include "Format.h"
34 #include "FuncStatus.h"
35 #include "HunspellChecker.h"
36 #include "KeyMap.h"
37 #include "Language.h"
38 #include "LaTeXFonts.h"
39 #include "LayoutFile.h"
40 #include "Lexer.h"
41 #include "LyX.h"
42 #include "LyXAction.h"
43 #include "LyXRC.h"
44 #include "ModuleList.h"
45 #include "Mover.h"
46 #include "Server.h"
47 #include "ServerSocket.h"
48 #include "Session.h"
49 #include "WordList.h"
50
51 #include "frontends/alert.h"
52 #include "frontends/Application.h"
53
54 #include "support/ConsoleApplication.h"
55 #include "support/lassert.h"
56 #include "support/debug.h"
57 #include "support/environment.h"
58 #include "support/ExceptionMessage.h"
59 #include "support/filetools.h"
60 #include "support/gettext.h"
61 #include "support/lstrings.h"
62 #include "support/Messages.h"
63 #include "support/os.h"
64 #include "support/Package.h"
65 #include "support/unique_ptr.h"
66
67 #include <algorithm>
68 #include <csignal>
69 #include <iostream>
70 #include <functional>
71 #include <map>
72 #include <stdlib.h>
73 #include <string>
74 #include <vector>
75
76 using namespace std;
77 using namespace lyx::support;
78
79 #if defined (USE_MACOSX_PACKAGING)
80 #include <crt_externs.h>
81 #endif
82
83 namespace lyx {
84
85 namespace Alert = frontend::Alert;
86 namespace os = support::os;
87
88
89
90 // Are we using the GUI at all?  We default to true and this is changed
91 // to false when the export feature is used.
92
93 bool use_gui = true;
94
95
96 // Report on the terminal about spawned commands. The default is false
97 // and can be changed with the option -v (--verbose).
98
99 bool verbose = false;
100
101
102 // We default to open documents in an already running instance, provided that
103 // the lyxpipe has been setup. This can be overridden either on the command
104 // line or through preference settings.
105
106 RunMode run_mode = PREFERRED;
107
108
109 // Tell what files can be silently overwritten during batch export.
110 // Possible values are: NO_FILES, MAIN_FILE, ALL_FILES, UNSPECIFIED.
111 // Unless specified on command line (through the -f switch) or through the
112 // environment variable LYX_FORCE_OVERWRITE, the default will be MAIN_FILE.
113
114 OverwriteFiles force_overwrite = UNSPECIFIED;
115
116
117 namespace {
118
119 // Filled with the command line arguments "foo" of "-sysdir foo" or
120 // "-userdir foo".
121 string cl_system_support;
122 string cl_user_support;
123
124 string geometryArg;
125
126 LyX * singleton_ = 0;
127
128 void showFileError(string const & error)
129 {
130         Alert::warning(_("Could not read configuration file"),
131                        bformat(_("Error while reading the configuration file\n%1$s.\n"
132                            "Please check your installation."), from_utf8(error)));
133 }
134
135 } // namespace anon
136
137 /// The main application class private implementation.
138 struct LyX::Impl {
139         Impl()
140                 : latexfonts_(0), spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
141         {}
142
143         ~Impl()
144         {
145                 delete latexfonts_;
146                 delete apple_spell_checker_;
147                 delete aspell_checker_;
148                 delete enchant_checker_;
149                 delete hunspell_checker_;
150         }
151
152         ///
153         BufferList buffer_list_;
154         ///
155         KeyMap toplevel_keymap_;
156         ///
157         CmdDef toplevel_cmddef_;
158         ///
159         unique_ptr<Server> lyx_server_;
160         ///
161         unique_ptr<ServerSocket> lyx_socket_;
162         ///
163         unique_ptr<frontend::Application> application_;
164         /// lyx session, containing lastfiles, lastfilepos, and lastopened
165         unique_ptr<Session> session_;
166
167         /// Files to load at start.
168         vector<string> files_to_load_;
169
170         /// The messages translators.
171         map<string, Messages> messages_;
172
173         /// The file converters.
174         Converters converters_;
175
176         // The system converters copy after reading lyxrc.defaults.
177         Converters system_converters_;
178
179         ///
180         Movers movers_;
181         ///
182         Movers system_movers_;
183
184         /// the parsed command line batch command if any
185         vector<string> batch_commands;
186
187         ///
188         LaTeXFonts * latexfonts_;
189
190         ///
191         SpellChecker * spell_checker_;
192         ///
193         SpellChecker * apple_spell_checker_;
194         ///
195         SpellChecker * aspell_checker_;
196         ///
197         SpellChecker * enchant_checker_;
198         ///
199         SpellChecker * hunspell_checker_;
200 };
201
202
203 /// The main application class for console mode
204 class LyXConsoleApp : public ConsoleApplication
205 {
206 public:
207         LyXConsoleApp(LyX * lyx, int & argc, char * argv[])
208                 : ConsoleApplication(lyx_package, argc, argv), lyx_(lyx),
209                   argc_(argc), argv_(argv)
210         {
211         }
212         void doExec()
213         {
214                 int const exit_status = lyx_->execWithoutGui(argc_, argv_);
215                 exit(exit_status);
216         }
217 private:
218         LyX * lyx_;
219         int & argc_;
220         char ** argv_;
221 };
222
223
224 ///
225 frontend::Application * theApp()
226 {
227         if (singleton_)
228                 return singleton_->pimpl_->application_.get();
229         else
230                 return 0;
231 }
232
233
234 LyX::~LyX()
235 {
236         delete pimpl_;
237         singleton_ = 0;
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 = ".";
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         //... the modules
939         theModuleList.read();
940         //... and the cite engines
941         theCiteEnginesList.read();
942
943         // read keymap and ui files in batch mode as well
944         // because InsetInfo needs to know these to produce
945         // the correct output
946
947         // Set up command definitions
948         pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
949
950         // FIXME
951         // Set up bindings
952         pimpl_->toplevel_keymap_.read("site");
953         pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
954         // load user bind file user.bind
955         pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
956
957         if (lyxerr.debugging(Debug::LYXRC))
958                 lyxrc.print();
959
960         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
961         // Prepend path prefix a second time to take the user preferences into a account
962         if (!lyxrc.path_prefix.empty())
963                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
964
965         FileName const document_path(lyxrc.document_path);
966         if (document_path.exists() && document_path.isDirectory())
967                 package().document_dir() = document_path;
968
969         package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
970         if (package().temp_dir().empty()) {
971                 Alert::error(_("Could not create temporary directory"),
972                              bformat(_("Could not create a temporary directory in\n"
973                                                        "\"%1$s\"\n"
974                                                            "Make sure that this path exists and is writable and try again."),
975                                      from_utf8(lyxrc.tempdir_path)));
976                 // createLyXTmpDir() tries sufficiently hard to create a
977                 // usable temp dir, so the probability to come here is
978                 // close to zero. We therefore don't try to overcome this
979                 // problem with e.g. asking the user for a new path and
980                 // trying again but simply exit.
981                 return false;
982         }
983
984         LYXERR(Debug::INIT, "LyX tmp dir: `"
985                             << package().temp_dir().absFileName() << '\'');
986
987         LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
988         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
989
990         // This must happen after package initialization and after lyxrc is
991         // read, therefore it can't be done by a static object.
992         ConverterCache::init();
993
994         return true;
995 }
996
997
998 void emergencyCleanup()
999 {
1000         // what to do about tmpfiles is non-obvious. we would
1001         // like to delete any we find, but our lyxdir might
1002         // contain documents etc. which might be helpful on
1003         // a crash
1004
1005         singleton_->pimpl_->buffer_list_.emergencyWriteAll();
1006         if (use_gui) {
1007                 if (singleton_->pimpl_->lyx_server_)
1008                         singleton_->pimpl_->lyx_server_->emergencyCleanup();
1009                 singleton_->pimpl_->lyx_server_.reset();
1010                 singleton_->pimpl_->lyx_socket_.reset();
1011         }
1012 }
1013
1014
1015 bool LyX::queryUserLyXDir(bool explicit_userdir)
1016 {
1017         // Does user directory exist?
1018         FileName const sup = package().user_support();
1019         if (sup.exists() && sup.isDirectory()) {
1020                 first_start = false;
1021
1022                 return configFileNeedsUpdate("lyxrc.defaults")
1023                         || configFileNeedsUpdate("lyxmodules.lst")
1024                         || configFileNeedsUpdate("textclass.lst")
1025                         || configFileNeedsUpdate("packages.lst")
1026                         || configFileNeedsUpdate("lyxciteengines.lst");
1027         }
1028
1029         first_start = !explicit_userdir;
1030
1031         // If the user specified explicitly a directory, ask whether
1032         // to create it. If the user says "no", then exit.
1033         if (explicit_userdir &&
1034             Alert::prompt(
1035                     _("Missing user LyX directory"),
1036                     bformat(_("You have specified a non-existent user "
1037                                            "LyX directory, %1$s.\n"
1038                                            "It is needed to keep your own configuration."),
1039                             from_utf8(package().user_support().absFileName())),
1040                     1, 0,
1041                     _("&Create directory"),
1042                     _("&Exit LyX"))) {
1043                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1044                 earlyExit(EXIT_FAILURE);
1045         }
1046
1047         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1048                           from_utf8(sup.absFileName()))) << endl;
1049
1050         if (!sup.createDirectory(0755)) {
1051                 // Failed, so let's exit.
1052                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1053                        << endl;
1054                 earlyExit(EXIT_FAILURE);
1055         }
1056
1057         return true;
1058 }
1059
1060
1061 bool LyX::readRcFile(string const & name, bool check_format)
1062 {
1063         LYXERR(Debug::INIT, "About to read " << name << "... ");
1064
1065         FileName const lyxrc_path = libFileSearch(string(), name);
1066         if (lyxrc_path.empty()) {
1067                 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1068                 // FIXME
1069                 // This was the previous logic, but can it be right??
1070                 return true;
1071         }
1072         LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1073         bool const success = lyxrc.read(lyxrc_path, check_format);
1074         if (!success)
1075                 showFileError(name);
1076         return success;
1077 }
1078
1079 // Read the languages file `name'
1080 bool LyX::readLanguagesFile(string const & name)
1081 {
1082         LYXERR(Debug::INIT, "About to read " << name << "...");
1083
1084         FileName const lang_path = libFileSearch(string(), name);
1085         if (lang_path.empty()) {
1086                 showFileError(name);
1087                 return false;
1088         }
1089         languages.read(lang_path);
1090         return true;
1091 }
1092
1093
1094 // Read the encodings file `name'
1095 bool LyX::readEncodingsFile(string const & enc_name,
1096                             string const & symbols_name)
1097 {
1098         LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1099                             << symbols_name << "...");
1100
1101         FileName const symbols_path = libFileSearch(string(), symbols_name);
1102         if (symbols_path.empty()) {
1103                 showFileError(symbols_name);
1104                 return false;
1105         }
1106
1107         FileName const enc_path = libFileSearch(string(), enc_name);
1108         if (enc_path.empty()) {
1109                 showFileError(enc_name);
1110                 return false;
1111         }
1112         encodings.read(enc_path, symbols_path);
1113         return true;
1114 }
1115
1116
1117 namespace {
1118
1119 /// return the the number of arguments consumed
1120 typedef function<int(string const &, string const &, string &)> cmd_helper;
1121
1122 int parse_dbg(string const & arg, string const &, string &)
1123 {
1124         if (arg.empty()) {
1125                 cout << to_utf8(_("List of supported debug flags:")) << endl;
1126                 Debug::showTags(cout);
1127                 exit(0);
1128         }
1129         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1130
1131         lyxerr.setLevel(Debug::value(arg));
1132         Debug::showLevel(lyxerr, lyxerr.level());
1133         return 1;
1134 }
1135
1136
1137 int parse_help(string const &, string const &, string &)
1138 {
1139         cout <<
1140                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1141                   "Command line switches (case sensitive):\n"
1142                   "\t-help              summarize LyX usage\n"
1143                   "\t-userdir dir       set user directory to dir\n"
1144                   "\t-sysdir dir        set system directory to dir\n"
1145                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1146                   "\t-dbg feature[,feature]...\n"
1147                   "                  select the features to debug.\n"
1148                   "                  Type `lyx -dbg' to see the list of features\n"
1149                   "\t-x [--execute] command\n"
1150                   "                  where command is a lyx command.\n"
1151                   "\t-e [--export] fmt\n"
1152                   "                  where fmt is the export format of choice. Look in\n"
1153                   "                  Tools->Preferences->File Handling->File Formats->Short Name\n"
1154                   "                  to see which parameter (which differs from the format name\n"
1155                   "                  in the File->Export menu) should be passed.\n"
1156                   "                  Note that the order of -e and -x switches matters.\n"
1157                   "\t-E [--export-to] fmt filename\n"
1158                   "                  where fmt is the export format of choice (see --export),\n"
1159                   "                  and filename is the destination filename.\n"
1160                   "\t-i [--import] fmt file.xxx\n"
1161                   "                  where fmt is the import format of choice\n"
1162                   "                  and file.xxx is the file to be imported.\n"
1163                   "\t-f [--force-overwrite] what\n"
1164                   "                  where what is either `all', `main' or `none',\n"
1165                   "                  specifying whether all files, main file only, or no files,\n"
1166                   "                  respectively, are to be overwritten during a batch export.\n"
1167                   "                  Anything else is equivalent to `all', but is not consumed.\n"
1168                   "\t-n [--no-remote]\n"
1169                   "                  open documents in a new instance\n"
1170                   "\t-r [--remote]\n"
1171                   "                  open documents in an already running instance\n"
1172                   "                  (a working lyxpipe is needed)\n"
1173                   "\t-v [--verbose]\n"
1174                   "                  report on terminal about spawned commands.\n"
1175                   "\t-batch    execute commands without launching GUI and exit.\n"
1176                   "\t-version  summarize version and build info\n"
1177                                "Check the LyX man page for more details.")) << endl;
1178         exit(0);
1179         return 0;
1180 }
1181
1182
1183 int parse_version(string const &, string const &, string &)
1184 {
1185         cout << "LyX " << lyx_version
1186                << " (" << lyx_release_date << ")" << endl;
1187         if (string(lyx_git_commit_hash) != "none")
1188                 cout << to_utf8(_("  Git commit hash "))
1189                      << string(lyx_git_commit_hash).substr(0,8) << endl;
1190         cout << lyx_version_info << endl;
1191         exit(0);
1192         return 0;
1193 }
1194
1195
1196 int parse_sysdir(string const & arg, string const &, string &)
1197 {
1198         if (arg.empty()) {
1199                 Alert::error(_("No system directory"),
1200                         _("Missing directory for -sysdir switch"));
1201                 exit(1);
1202         }
1203         cl_system_support = arg;
1204         return 1;
1205 }
1206
1207
1208 int parse_userdir(string const & arg, string const &, string &)
1209 {
1210         if (arg.empty()) {
1211                 Alert::error(_("No user directory"),
1212                         _("Missing directory for -userdir switch"));
1213                 exit(1);
1214         }
1215         cl_user_support = arg;
1216         return 1;
1217 }
1218
1219
1220 int parse_execute(string const & arg, string const &, string & batch)
1221 {
1222         if (arg.empty()) {
1223                 Alert::error(_("Incomplete command"),
1224                         _("Missing command string after --execute switch"));
1225                 exit(1);
1226         }
1227         batch = arg;
1228         return 1;
1229 }
1230
1231
1232 int parse_export_to(string const & type, string const & output_file, string & batch)
1233 {
1234         if (type.empty()) {
1235                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1236                                          "--export-to switch")) << endl;
1237                 exit(1);
1238         }
1239         if (output_file.empty()) {
1240                 lyxerr << to_utf8(_("Missing destination filename after "
1241                                          "--export-to switch")) << endl;
1242                 exit(1);
1243         }
1244         batch = "buffer-export " + type + " " + output_file;
1245         use_gui = false;
1246         return 2;
1247 }
1248
1249
1250 int parse_export(string const & type, string const &, string & batch)
1251 {
1252         if (type.empty()) {
1253                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1254                                          "--export switch")) << endl;
1255                 exit(1);
1256         }
1257         batch = "buffer-export " + type;
1258         use_gui = false;
1259         return 1;
1260 }
1261
1262
1263 int parse_import(string const & type, string const & file, string & batch)
1264 {
1265         if (type.empty()) {
1266                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1267                                          "--import switch")) << endl;
1268                 exit(1);
1269         }
1270         if (file.empty()) {
1271                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1272                 exit(1);
1273         }
1274         batch = "buffer-import " + type + ' ' + file;
1275         return 2;
1276 }
1277
1278
1279 int parse_geometry(string const & arg1, string const &, string &)
1280 {
1281         geometryArg = arg1;
1282         // don't remove "-geometry", it will be pruned out later in the
1283         // frontend if need be.
1284         return -1;
1285 }
1286
1287
1288 int parse_batch(string const &, string const &, string &)
1289 {
1290         use_gui = false;
1291         return 0;
1292 }
1293
1294
1295 int parse_noremote(string const &, string const &, string &)
1296 {
1297         run_mode = NEW_INSTANCE;
1298         return 0;
1299 }
1300
1301
1302 int parse_remote(string const &, string const &, string &)
1303 {
1304         run_mode = USE_REMOTE;
1305         return 0;
1306 }
1307
1308
1309 int parse_verbose(string const &, string const &, string &)
1310 {
1311         verbose = true;
1312         return 0;
1313 }
1314
1315
1316 int parse_force(string const & arg, string const &, string &)
1317 {
1318         if (arg == "all") {
1319                 force_overwrite = ALL_FILES;
1320                 return 1;
1321         } else if (arg == "main") {
1322                 force_overwrite = MAIN_FILE;
1323                 return 1;
1324         } else if (arg == "none") {
1325                 force_overwrite = NO_FILES;
1326                 return 1;
1327         }
1328         force_overwrite = ALL_FILES;
1329         return 0;
1330 }
1331
1332
1333 } // namespace anon
1334
1335
1336 void LyX::easyParse(int & argc, char * argv[])
1337 {
1338         map<string, cmd_helper> cmdmap;
1339
1340         cmdmap["-dbg"] = parse_dbg;
1341         cmdmap["-help"] = parse_help;
1342         cmdmap["--help"] = parse_help;
1343         cmdmap["-version"] = parse_version;
1344         cmdmap["--version"] = parse_version;
1345         cmdmap["-sysdir"] = parse_sysdir;
1346         cmdmap["-userdir"] = parse_userdir;
1347         cmdmap["-x"] = parse_execute;
1348         cmdmap["--execute"] = parse_execute;
1349         cmdmap["-e"] = parse_export;
1350         cmdmap["--export"] = parse_export;
1351         cmdmap["-E"] = parse_export_to;
1352         cmdmap["--export-to"] = parse_export_to;
1353         cmdmap["-i"] = parse_import;
1354         cmdmap["--import"] = parse_import;
1355         cmdmap["-geometry"] = parse_geometry;
1356         cmdmap["-batch"] = parse_batch;
1357         cmdmap["-f"] = parse_force;
1358         cmdmap["--force-overwrite"] = parse_force;
1359         cmdmap["-n"] = parse_noremote;
1360         cmdmap["--no-remote"] = parse_noremote;
1361         cmdmap["-r"] = parse_remote;
1362         cmdmap["--remote"] = parse_remote;
1363         cmdmap["-v"] = parse_verbose;
1364         cmdmap["--verbose"] = parse_verbose;
1365
1366         for (int i = 1; i < argc; ++i) {
1367                 map<string, cmd_helper>::const_iterator it
1368                         = cmdmap.find(argv[i]);
1369
1370                 // don't complain if not found - may be parsed later
1371                 if (it == cmdmap.end())
1372                         continue;
1373
1374                 string const arg =
1375                         (i + 1 < argc) ? os::utf8_argv(i + 1) : string();
1376                 string const arg2 =
1377                         (i + 2 < argc) ? os::utf8_argv(i + 2) : string();
1378
1379                 string batch;
1380                 int const remove = 1 + it->second(arg, arg2, batch);
1381                 if (!batch.empty())
1382                         pimpl_->batch_commands.push_back(batch);
1383
1384                 // Now, remove used arguments by shifting
1385                 // the following ones remove places down.
1386                 if (remove > 0) {
1387                         os::remove_internal_args(i, remove);
1388                         argc -= remove;
1389                         for (int j = i; j < argc; ++j)
1390                                 argv[j] = argv[j + remove];
1391                         --i;
1392                 }
1393         }
1394 }
1395
1396
1397 FuncStatus getStatus(FuncRequest const & action)
1398 {
1399         LAPPERR(theApp());
1400         return theApp()->getStatus(action);
1401 }
1402
1403
1404 DispatchResult const & dispatch(FuncRequest const & action)
1405 {
1406         LAPPERR(theApp());
1407         return theApp()->dispatch(action);
1408 }
1409
1410
1411 void dispatch(FuncRequest const & action, DispatchResult & dr)
1412 {
1413         LAPPERR(theApp());
1414         theApp()->dispatch(action, dr);
1415 }
1416
1417
1418 vector<string> & theFilesToLoad()
1419 {
1420         LAPPERR(singleton_);
1421         return singleton_->pimpl_->files_to_load_;
1422 }
1423
1424
1425 BufferList & theBufferList()
1426 {
1427         LAPPERR(singleton_);
1428         return singleton_->pimpl_->buffer_list_;
1429 }
1430
1431
1432 Server & theServer()
1433 {
1434         // FIXME: this should not be use_gui dependent
1435         LWARNIF(use_gui);
1436         LAPPERR(singleton_);
1437         return *singleton_->pimpl_->lyx_server_;
1438 }
1439
1440
1441 ServerSocket & theServerSocket()
1442 {
1443         // FIXME: this should not be use_gui dependent
1444         LWARNIF(use_gui);
1445         LAPPERR(singleton_);
1446         return *singleton_->pimpl_->lyx_socket_;
1447 }
1448
1449
1450 KeyMap & theTopLevelKeymap()
1451 {
1452         LAPPERR(singleton_);
1453         return singleton_->pimpl_->toplevel_keymap_;
1454 }
1455
1456
1457 Converters & theConverters()
1458 {
1459         LAPPERR(singleton_);
1460         return  singleton_->pimpl_->converters_;
1461 }
1462
1463
1464 Converters & theSystemConverters()
1465 {
1466         LAPPERR(singleton_);
1467         return  singleton_->pimpl_->system_converters_;
1468 }
1469
1470
1471 Movers & theMovers()
1472 {
1473         LAPPERR(singleton_);
1474         return singleton_->pimpl_->movers_;
1475 }
1476
1477
1478 Mover const & getMover(string  const & fmt)
1479 {
1480         LAPPERR(singleton_);
1481         return singleton_->pimpl_->movers_(fmt);
1482 }
1483
1484
1485 void setMover(string const & fmt, string const & command)
1486 {
1487         LAPPERR(singleton_);
1488         singleton_->pimpl_->movers_.set(fmt, command);
1489 }
1490
1491
1492 Movers & theSystemMovers()
1493 {
1494         LAPPERR(singleton_);
1495         return singleton_->pimpl_->system_movers_;
1496 }
1497
1498
1499 Messages const & getMessages(string const & language)
1500 {
1501         LAPPERR(singleton_);
1502         return singleton_->messages(language);
1503 }
1504
1505
1506 Messages const & getGuiMessages()
1507 {
1508         LAPPERR(singleton_);
1509         return singleton_->messages(Messages::guiLanguage());
1510 }
1511
1512
1513 Session & theSession()
1514 {
1515         LAPPERR(singleton_);
1516         return *singleton_->pimpl_->session_.get();
1517 }
1518
1519
1520 LaTeXFonts & theLaTeXFonts()
1521 {
1522         LAPPERR(singleton_);
1523         if (!singleton_->pimpl_->latexfonts_)
1524                 singleton_->pimpl_->latexfonts_ = new LaTeXFonts;
1525         return *singleton_->pimpl_->latexfonts_;
1526 }
1527
1528
1529 CmdDef & theTopLevelCmdDef()
1530 {
1531         LAPPERR(singleton_);
1532         return singleton_->pimpl_->toplevel_cmddef_;
1533 }
1534
1535
1536 SpellChecker * theSpellChecker()
1537 {
1538         if (!singleton_->pimpl_->spell_checker_)
1539                 setSpellChecker();
1540         return singleton_->pimpl_->spell_checker_;
1541 }
1542
1543
1544 void setSpellChecker()
1545 {
1546         SpellChecker::ChangeNumber speller_change_number =singleton_->pimpl_->spell_checker_ ?
1547                 singleton_->pimpl_->spell_checker_->changeNumber() : 0;
1548
1549         if (lyxrc.spellchecker == "native") {
1550 #if defined(USE_MACOSX_PACKAGING)
1551                 if (!singleton_->pimpl_->apple_spell_checker_)
1552                         singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker;
1553                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_;
1554 #else
1555                 singleton_->pimpl_->spell_checker_ = 0;
1556 #endif
1557         } else if (lyxrc.spellchecker == "aspell") {
1558 #if defined(USE_ASPELL)
1559                 if (!singleton_->pimpl_->aspell_checker_)
1560                         singleton_->pimpl_->aspell_checker_ = new AspellChecker;
1561                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1562 #else
1563                 singleton_->pimpl_->spell_checker_ = 0;
1564 #endif
1565         } else if (lyxrc.spellchecker == "enchant") {
1566 #if defined(USE_ENCHANT)
1567                 if (!singleton_->pimpl_->enchant_checker_)
1568                         singleton_->pimpl_->enchant_checker_ = new EnchantChecker;
1569                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1570 #else
1571                 singleton_->pimpl_->spell_checker_ = 0;
1572 #endif
1573         } else if (lyxrc.spellchecker == "hunspell") {
1574 #if defined(USE_HUNSPELL)
1575                 if (!singleton_->pimpl_->hunspell_checker_)
1576                         singleton_->pimpl_->hunspell_checker_ = new HunspellChecker;
1577                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1578 #else
1579                 singleton_->pimpl_->spell_checker_ = 0;
1580 #endif
1581         } else {
1582                 singleton_->pimpl_->spell_checker_ = 0;
1583         }
1584         if (singleton_->pimpl_->spell_checker_) {
1585                 singleton_->pimpl_->spell_checker_->changeNumber(speller_change_number);
1586                 singleton_->pimpl_->spell_checker_->advanceChangeNumber();
1587         }
1588 }
1589
1590 } // namespace lyx