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