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