]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
Change the "empty layout" to the "plain layout", to try to avoid confusion.
[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 "LayoutFile.h"
21 #include "Buffer.h"
22 #include "BufferList.h"
23 #include "CmdDef.h"
24 #include "Color.h"
25 #include "ConverterCache.h"
26 #include "Converter.h"
27 #include "CutAndPaste.h"
28 #include "Encoding.h"
29 #include "ErrorList.h"
30 #include "Format.h"
31 #include "FuncStatus.h"
32 #include "KeyMap.h"
33 #include "Language.h"
34 #include "Lexer.h"
35 #include "LyXAction.h"
36 #include "LyXFunc.h"
37 #include "LyXRC.h"
38 #include "ModuleList.h"
39 #include "Mover.h"
40 #include "Server.h"
41 #include "ServerSocket.h"
42 #include "Session.h"
43
44 #include "frontends/alert.h"
45 #include "frontends/Application.h"
46
47 #include "graphics/Previews.h"
48
49 #include "support/lassert.h"
50 #include "support/debug.h"
51 #include "support/environment.h"
52 #include "support/ExceptionMessage.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/lstrings.h"
56 #include "support/Messages.h"
57 #include "support/os.h"
58 #include "support/Package.h"
59 #include "support/Path.h"
60 #include "support/Systemcall.h"
61
62 #include <boost/bind.hpp>
63 #include <boost/scoped_ptr.hpp>
64
65 #include <algorithm>
66 #include <iostream>
67 #include <csignal>
68 #include <map>
69 #include <stdlib.h>
70 #include <string>
71 #include <vector>
72
73 using namespace std;
74 using namespace lyx::support;
75
76 namespace lyx {
77
78 namespace Alert = frontend::Alert;
79 namespace os = support::os;
80
81
82
83 // Are we using the GUI at all?  We default to true and this is changed
84 // to false when the export feature is used.
85
86 bool use_gui = true;
87
88 namespace {
89
90 // Filled with the command line arguments "foo" of "-sysdir foo" or
91 // "-userdir foo".
92 string cl_system_support;
93 string cl_user_support;
94
95 string geometryArg;
96
97 LyX * singleton_ = 0;
98
99 void showFileError(string const & error)
100 {
101         Alert::warning(_("Could not read configuration file"),
102                        bformat(_("Error while reading the configuration file\n%1$s.\n"
103                            "Please check your installation."), from_utf8(error)));
104 }
105
106
107 void reconfigureUserLyXDir()
108 {
109         string const configure_command = package().configure_command();
110
111         lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
112         PathChanger p(package().user_support());
113         Systemcall one;
114         one.startscript(Systemcall::Wait, configure_command);
115         lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
116 }
117
118 } // namespace anon
119
120
121 /// The main application class private implementation.
122 struct LyX::Impl
123 {
124         Impl()
125         {
126                 // Set the default User Interface language as soon as possible.
127                 // The language used will be derived from the environment
128                 // variables.
129                 messages_["GUI"] = Messages();
130         }
131         /// our function handler
132         LyXFunc lyxfunc_;
133         ///
134         BufferList buffer_list_;
135         ///
136         KeyMap toplevel_keymap_;
137         ///
138         CmdDef toplevel_cmddef_;
139         ///
140         boost::scoped_ptr<Server> lyx_server_;
141         ///
142         boost::scoped_ptr<ServerSocket> lyx_socket_;
143         ///
144         boost::scoped_ptr<frontend::Application> application_;
145         /// lyx session, containing lastfiles, lastfilepos, and lastopened
146         boost::scoped_ptr<Session> session_;
147
148         /// Files to load at start.
149         vector<string> files_to_load_;
150
151         /// The messages translators.
152         map<string, Messages> messages_;
153
154         /// The file converters.
155         Converters converters_;
156
157         // The system converters copy after reading lyxrc.defaults.
158         Converters system_converters_;
159
160         ///
161         Movers movers_;
162         ///
163         Movers system_movers_;
164
165         /// has this user started lyx for the first time?
166         bool first_start;
167         /// the parsed command line batch command if any
168         vector<string> batch_commands;
169
170         ///
171         graphics::Previews preview_;
172 };
173
174 ///
175 frontend::Application * theApp()
176 {
177         if (singleton_)
178                 return singleton_->pimpl_->application_.get();
179         else
180                 return 0;
181 }
182
183
184 LyX::~LyX()
185 {
186         singleton_ = 0;
187         delete pimpl_;
188 }
189
190
191 void lyx_exit(int exit_code)
192 {
193         if (exit_code)
194                 // Something wrong happened so better save everything, just in
195                 // case.
196                 emergencyCleanup();
197
198 #ifndef NDEBUG
199         // Properly crash in debug mode in order to get a useful backtrace.
200         abort();
201 #endif
202
203         // In release mode, try to exit gracefully.
204         if (theApp())
205                 theApp()->exit(exit_code);
206         else
207                 exit(exit_code);
208 }
209
210
211 LyX::LyX()
212         : first_start(false)
213 {
214         singleton_ = this;
215         pimpl_ = new Impl;
216 }
217
218
219 Messages & LyX::messages(string const & language)
220 {
221         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
222
223         if (it != pimpl_->messages_.end())
224                 return it->second;
225
226         pair<map<string, Messages>::iterator, bool> result =
227                         pimpl_->messages_.insert(make_pair(language, Messages(language)));
228
229         LASSERT(result.second, /**/);
230         return result.first->second;
231 }
232
233
234 void setRcGuiLanguage()
235 {
236         LASSERT(singleton_, /**/);
237         if (lyxrc.gui_language == "auto")
238                 return;
239         Language const * language = languages.getLanguage(lyxrc.gui_language);
240         if (language) {
241                 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
242                 if (!setEnv("LANGUAGE", language->code()))
243                         LYXERR(Debug::LOCALE, "\t... failed!");
244         }
245         LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
246         if (!setEnv("LC_ALL", "en_US"))
247                 LYXERR(Debug::LOCALE, "\t... failed!");
248         Messages::init();
249         singleton_->pimpl_->messages_["GUI"] = Messages();
250 }
251
252
253 int LyX::exec(int & argc, char * argv[])
254 {
255         // Here we need to parse the command line. At least
256         // we need to parse for "-dbg" and "-help"
257         easyParse(argc, argv);
258
259         try {
260                 init_package(to_utf8(from_local8bit(argv[0])),
261                               cl_system_support, cl_user_support,
262                               top_build_dir_is_one_level_up);
263         } catch (ExceptionMessage const & message) {
264                 if (message.type_ == ErrorException) {
265                         Alert::error(message.title_, message.details_);
266                         lyx_exit(1);
267                 } else if (message.type_ == WarningException) {
268                         Alert::warning(message.title_, message.details_);
269                 }
270         }
271
272         // Reinit the messages machinery in case package() knows
273         // something interesting about the locale directory.
274         Messages::init();
275
276         if (!use_gui) {
277                 // FIXME: create a ConsoleApplication
278                 int exit_status = init(argc, argv);
279                 if (exit_status) {
280                         prepareExit();
281                         return exit_status;
282                 }
283
284                 // this is correct, since return values are inverted.
285                 exit_status = !loadFiles();
286
287                 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
288                         prepareExit();
289                         return exit_status;
290                 }
291
292                 BufferList::iterator begin = pimpl_->buffer_list_.begin();
293
294                 bool final_success = false;
295                 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
296                         Buffer * buf = *I;
297                         if (buf != buf->masterBuffer())
298                                 continue;
299                         bool success = false;
300                         vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
301                         vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
302                         for (; bcit != bcend; bcit++) {
303                                 buf->dispatch(*bcit, &success);
304                                 final_success |= success;
305                         }
306                 }
307                 prepareExit();
308                 return !final_success;
309         }
310
311         // Let the frontend parse and remove all arguments that it knows
312         pimpl_->application_.reset(createApplication(argc, argv));
313
314         // Reestablish our defaults, as Qt overwrites them
315         // after createApplication()
316         locale_init();
317
318         // Parse and remove all known arguments in the LyX singleton
319         // Give an error for all remaining ones.
320         int exit_status = init(argc, argv);
321         if (exit_status) {
322                 // Kill the application object before exiting.
323                 pimpl_->application_.reset();
324                 use_gui = false;
325                 prepareExit();
326                 return exit_status;
327         }
328  
329         // FIXME
330         /* Create a CoreApplication class that will provide the main event loop
331         * and the socket callback registering. With Qt4, only QtCore
332         * library would be needed.
333         * When this is done, a server_mode could be created and the following two
334         * line would be moved out from here.
335         */
336         // Note: socket callback must be registered after init(argc, argv)
337         // such that package().temp_dir() is properly initialized.
338         pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
339         pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
340                         FileName(package().temp_dir().absFilename() + "/lyxsocket")));
341
342         // Start the real execution loop.
343         exit_status = pimpl_->application_->exec();
344
345         prepareExit();
346
347         return exit_status;
348 }
349
350
351 void LyX::prepareExit()
352 {
353         // Clear the clipboard and selection stack:
354         cap::clearCutStack();
355         cap::clearSelection();
356
357         // close buffers first
358         pimpl_->buffer_list_.closeAll();
359
360         // register session changes and shutdown server and socket
361         if (use_gui) {
362                 if (pimpl_->session_)
363                         pimpl_->session_->writeFile();
364                 pimpl_->session_.reset();
365                 pimpl_->lyx_server_.reset();
366                 pimpl_->lyx_socket_.reset();
367         }
368
369         // do any other cleanup procedures now
370         if (package().temp_dir() != package().system_temp_dir()) {
371                 string const abs_tmpdir = package().temp_dir().absFilename();
372                 if (!contains(package().temp_dir().absFilename(), "lyx_tmpdir")) {
373                         docstring const msg =
374                                 bformat(_("%1$s does not appear like a LyX created temporary directory."),
375                                 from_utf8(abs_tmpdir));
376                         Alert::warning(_("Cannot remove temporary directory"), msg);
377                 } else {
378                         LYXERR(Debug::INFO, "Deleting tmp dir "
379                                 << package().temp_dir().absFilename());
380                         if (!package().temp_dir().destroyDirectory()) {
381                                 docstring const msg =
382                                         bformat(_("Unable to remove the temporary directory %1$s"),
383                                         from_utf8(package().temp_dir().absFilename()));
384                                 Alert::warning(_("Unable to remove temporary directory"), msg);
385                         }
386                 }
387         }
388
389         // Kill the application object before exiting. This avoids crashes
390         // when exiting on Linux.
391         if (pimpl_->application_)
392                 pimpl_->application_.reset();
393 }
394
395
396 void LyX::earlyExit(int status)
397 {
398         LASSERT(pimpl_->application_.get(), /**/);
399         // LyX::pimpl_::application_ is not initialised at this
400         // point so it's safe to just exit after some cleanup.
401         prepareExit();
402         exit(status);
403 }
404
405
406 int LyX::init(int & argc, char * argv[])
407 {
408         // check for any spurious extra arguments
409         // other than documents
410         for (int argi = 1; argi < argc ; ++argi) {
411                 if (argv[argi][0] == '-') {
412                         lyxerr << to_utf8(
413                                 bformat(_("Wrong command line option `%1$s'. Exiting."),
414                                 from_utf8(argv[argi]))) << endl;
415                         return EXIT_FAILURE;
416                 }
417         }
418
419         // Initialization of LyX (reads lyxrc and more)
420         LYXERR(Debug::INIT, "Initializing LyX::init...");
421         bool success = init();
422         LYXERR(Debug::INIT, "Initializing LyX::init...done");
423         if (!success)
424                 return EXIT_FAILURE;
425
426         // Remaining arguments are assumed to be files to load.
427         for (int argi = argc - 1; argi >= 1; --argi)
428                 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
429
430         if (first_start) {
431                 pimpl_->files_to_load_.push_back(
432                         i18nLibFileSearch("examples", "splash.lyx").absFilename());
433         }
434
435         return EXIT_SUCCESS;
436 }
437
438
439 bool LyX::loadFiles()
440 {
441         LASSERT(!use_gui, /**/);
442         bool success = true;
443         vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
444         vector<string>::const_iterator end = pimpl_->files_to_load_.end();
445
446         for (; it != end; ++it) {
447                 // get absolute path of file and add ".lyx" to
448                 // the filename if necessary
449                 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
450                         may_not_exist);
451
452                 if (fname.empty())
453                         continue;
454
455                 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
456                 if (buf->loadLyXFile(fname)) {
457                         ErrorList const & el = buf->errorList("Parse");
458                         if (!el.empty())
459                                 for_each(el.begin(), el.end(),
460                                 boost::bind(&LyX::printError, this, _1));
461                 }
462                 else {
463                         pimpl_->buffer_list_.release(buf);
464                         success = false;
465                 }
466         }
467         return success;
468 }
469
470
471 void execBatchCommands()
472 {
473         LASSERT(singleton_, /**/);
474         singleton_->execCommands();
475 }
476
477
478 void LyX::execCommands()
479 {
480         // The advantage of doing this here is that the event loop
481         // is already started. So any need for interaction will be
482         // aknowledged.
483
484         // if reconfiguration is needed.
485         while (LayoutFileList::get().empty()) {
486                 switch (Alert::prompt(
487                         _("No textclass is found"),
488                         _("LyX cannot continue because no textclass is found. "
489                                 "You can either reconfigure normally, or reconfigure using "
490                                 "default textclasses, or quit LyX."),
491                         0, 2,
492                         _("&Reconfigure"),
493                         _("&Use Default"),
494                         _("&Exit LyX")))
495                 {
496                 case 0:
497                         // regular reconfigure
498                         pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
499                         break;
500                 case 1:
501                         // reconfigure --without-latex-config
502                         pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
503                                 " --without-latex-config"));
504                         break;
505                 default:
506                         pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
507                         return;
508                 }
509         }
510         
511         // create the first main window
512         pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
513
514         if (!pimpl_->files_to_load_.empty()) {
515                 // if some files were specified at command-line we assume that the
516                 // user wants to edit *these* files and not to restore the session.
517                 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
518                         pimpl_->lyxfunc_.dispatch(
519                                 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
520                 }
521                 // clear this list to save a few bytes of RAM
522                 pimpl_->files_to_load_.clear();
523         }
524         else
525                 pimpl_->application_->restoreGuiSession();
526
527         // Execute batch commands if available
528         if (pimpl_->batch_commands.empty())
529                 return;
530
531         vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
532         vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
533         for (; bcit != bcend; bcit++) {
534                 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
535                 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(*bcit));
536         }
537 }
538
539
540 /*
541 Signals and Windows
542 ===================
543 The SIGHUP signal does not exist on Windows and does not need to be handled.
544
545 Windows handles SIGFPE and SIGSEGV signals as expected.
546
547 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
548 cause a new thread to be spawned. This may well result in unexpected
549 behaviour by the single-threaded LyX.
550
551 SIGTERM signals will come only from another process actually sending
552 that signal using 'raise' in Windows' POSIX compatability layer. It will
553 not come from the general "terminate process" methods that everyone
554 actually uses (and which can't be trapped). Killing an app 'politely' on
555 Windows involves first sending a WM_CLOSE message, something that is
556 caught already by the Qt frontend.
557
558 For more information see:
559
560 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
561 ...signals are mostly useless on Windows for a variety of reasons that are
562 Windows specific...
563
564 'UNIX Application Migration Guide, Chapter 9'
565 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
566
567 'How To Terminate an Application "Cleanly" in Win32'
568 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
569 */
570 extern "C" {
571
572 static void error_handler(int err_sig)
573 {
574         // Throw away any signals other than the first one received.
575         static sig_atomic_t handling_error = false;
576         if (handling_error)
577                 return;
578         handling_error = true;
579
580         // We have received a signal indicating a fatal error, so
581         // try and save the data ASAP.
582         emergencyCleanup();
583
584         // These lyxerr calls may or may not work:
585
586         // Signals are asynchronous, so the main program may be in a very
587         // fragile state when a signal is processed and thus while a signal
588         // handler function executes.
589         // In general, therefore, we should avoid performing any
590         // I/O operations or calling most library and system functions from
591         // signal handlers.
592
593         // This shouldn't matter here, however, as we've already invoked
594         // emergencyCleanup.
595         switch (err_sig) {
596 #ifdef SIGHUP
597         case SIGHUP:
598                 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
599                 break;
600 #endif
601         case SIGFPE:
602                 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
603                 break;
604         case SIGSEGV:
605                 lyxerr << "\nlyx: SIGSEGV signal caught\n"
606                           "Sorry, you have found a bug in LyX. "
607                           "Please read the bug-reporting instructions "
608                           "in Help->Introduction and send us a bug report, "
609                           "if necessary. Thanks !\nBye." << endl;
610                 break;
611         case SIGINT:
612         case SIGTERM:
613                 // no comments
614                 break;
615         }
616
617         // Deinstall the signal handlers
618 #ifdef SIGHUP
619         signal(SIGHUP, SIG_DFL);
620 #endif
621         signal(SIGINT, SIG_DFL);
622         signal(SIGFPE, SIG_DFL);
623         signal(SIGSEGV, SIG_DFL);
624         signal(SIGTERM, SIG_DFL);
625
626 #ifdef SIGHUP
627         if (err_sig == SIGSEGV ||
628             (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
629 #else
630         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
631 #endif
632                 abort();
633         exit(0);
634 }
635
636 }
637
638
639 void LyX::printError(ErrorItem const & ei)
640 {
641         docstring tmp = _("LyX: ") + ei.error + char_type(':')
642                 + ei.description;
643         cerr << to_utf8(tmp) << endl;
644 }
645
646
647 bool LyX::init()
648 {
649 #ifdef SIGHUP
650         signal(SIGHUP, error_handler);
651 #endif
652         signal(SIGFPE, error_handler);
653         signal(SIGSEGV, error_handler);
654         signal(SIGINT, error_handler);
655         signal(SIGTERM, error_handler);
656         // SIGPIPE can be safely ignored.
657
658         lyxrc.tempdir_path = package().temp_dir().absFilename();
659         lyxrc.document_path = package().document_dir().absFilename();
660
661         if (lyxrc.example_path.empty()) {
662                 lyxrc.example_path = addPath(package().system_support().absFilename(),
663                                               "examples");
664         }
665         if (lyxrc.template_path.empty()) {
666                 lyxrc.template_path = addPath(package().system_support().absFilename(),
667                                               "templates");
668         }
669
670         //
671         // Read configuration files
672         //
673
674         // This one may have been distributed along with LyX.
675         if (!readRcFile("lyxrc.dist"))
676                 return false;
677
678         // Set the language defined by the distributor.
679         setRcGuiLanguage();
680
681         // Set the PATH correctly.
682 #if !defined (USE_POSIX_PACKAGING)
683         // Add the directory containing the LyX executable to the path
684         // so that LyX can find things like tex2lyx.
685         if (package().build_support().empty())
686                 prependEnvPath("PATH", package().binary_dir().absFilename());
687 #endif
688         if (!lyxrc.path_prefix.empty())
689                 prependEnvPath("PATH", lyxrc.path_prefix);
690
691         // Check that user LyX directory is ok.
692         if (queryUserLyXDir(package().explicit_user_support()))
693                 reconfigureUserLyXDir();
694
695         // no need for a splash when there is no GUI
696         if (!use_gui) {
697                 first_start = false;
698         }
699
700         // This one is generated in user_support directory by lib/configure.py.
701         if (!readRcFile("lyxrc.defaults"))
702                 return false;
703
704         // Query the OS to know what formats are viewed natively
705         formats.setAutoOpen();
706
707         // Read lyxrc.dist again to be able to override viewer auto-detection.
708         readRcFile("lyxrc.dist");
709
710         // Set again the language defined by the distributor.
711         setRcGuiLanguage();
712
713         system_lyxrc = lyxrc;
714         system_formats = formats;
715         pimpl_->system_converters_ = pimpl_->converters_;
716         pimpl_->system_movers_ = pimpl_->movers_;
717         system_lcolor = lcolor;
718
719         // This one is edited through the preferences dialog.
720         if (!readRcFile("preferences"))
721                 return false;
722
723         if (!readEncodingsFile("encodings", "unicodesymbols"))
724                 return false;
725         if (!readLanguagesFile("languages"))
726                 return false;
727
728         // Set the language defined by the user.
729         setRcGuiLanguage();
730
731         // Load the layouts
732         LYXERR(Debug::INIT, "Reading layouts...");
733         if (!LyXSetStyle())
734                 return false;
735         //...and the modules
736         moduleList.load();
737
738         // read keymap and ui files in batch mode as well
739         // because InsetInfo needs to know these to produce
740         // the correct output
741
742         // Set up command definitions
743         pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
744
745         // Set up bindings
746         pimpl_->toplevel_keymap_.read("site");
747         pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
748         // load user bind file user.bind
749         pimpl_->toplevel_keymap_.read("user");
750
751         pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
752
753         if (lyxerr.debugging(Debug::LYXRC))
754                 lyxrc.print();
755
756         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
757         if (!lyxrc.path_prefix.empty())
758                 prependEnvPath("PATH", lyxrc.path_prefix);
759
760         FileName const document_path(lyxrc.document_path);
761         if (document_path.exists() && document_path.isDirectory())
762                 package().document_dir() = document_path;
763
764         package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
765         if (package().temp_dir().empty()) {
766                 Alert::error(_("Could not create temporary directory"),
767                              bformat(_("Could not create a temporary directory in\n"
768                                                        "\"%1$s\"\n"
769                                                            "Make sure that this path exists and is writable and try again."),
770                                      from_utf8(lyxrc.tempdir_path)));
771                 // createLyXTmpDir() tries sufficiently hard to create a
772                 // usable temp dir, so the probability to come here is
773                 // close to zero. We therefore don't try to overcome this
774                 // problem with e.g. asking the user for a new path and
775                 // trying again but simply exit.
776                 return false;
777         }
778
779         LYXERR(Debug::INIT, "LyX tmp dir: `"
780                             << package().temp_dir().absFilename() << '\'');
781
782         LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
783         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
784
785         // This must happen after package initialization and after lyxrc is
786         // read, therefore it can't be done by a static object.
787         ConverterCache::init();
788                 
789         return true;
790 }
791
792
793 void emergencyCleanup()
794 {
795         // what to do about tmpfiles is non-obvious. we would
796         // like to delete any we find, but our lyxdir might
797         // contain documents etc. which might be helpful on
798         // a crash
799
800         singleton_->pimpl_->buffer_list_.emergencyWriteAll();
801         if (use_gui) {
802                 if (singleton_->pimpl_->lyx_server_)
803                         singleton_->pimpl_->lyx_server_->emergencyCleanup();
804                 singleton_->pimpl_->lyx_server_.reset();
805                 singleton_->pimpl_->lyx_socket_.reset();
806         }
807 }
808
809
810 // return true if file does not exist or is older than configure.py.
811 static bool needsUpdate(string const & file)
812 {
813         // We cannot initialize configure_script directly because the package
814         // is not initialized yet when  static objects are constructed.
815         static FileName configure_script;
816         static bool firstrun = true;
817         if (firstrun) {
818                 configure_script =
819                         FileName(addName(package().system_support().absFilename(),
820                                 "configure.py"));
821                 firstrun = false;
822         }
823
824         FileName absfile = 
825                 FileName(addName(package().user_support().absFilename(), file));
826         return !absfile.exists()
827                 || configure_script.lastModified() > absfile.lastModified();
828 }
829
830
831 bool LyX::queryUserLyXDir(bool explicit_userdir)
832 {
833         // Does user directory exist?
834         FileName const sup = package().user_support();
835         if (sup.exists() && sup.isDirectory()) {
836                 first_start = false;
837
838                 return needsUpdate("lyxrc.defaults")
839                         || needsUpdate("lyxmodules.lst")
840                         || needsUpdate("textclass.lst")
841                         || needsUpdate("packages.lst");
842         }
843
844         first_start = !explicit_userdir;
845
846         // If the user specified explicitly a directory, ask whether
847         // to create it. If the user says "no", then exit.
848         if (explicit_userdir &&
849             Alert::prompt(
850                     _("Missing user LyX directory"),
851                     bformat(_("You have specified a non-existent user "
852                                            "LyX directory, %1$s.\n"
853                                            "It is needed to keep your own configuration."),
854                             from_utf8(package().user_support().absFilename())),
855                     1, 0,
856                     _("&Create directory"),
857                     _("&Exit LyX"))) {
858                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
859                 earlyExit(EXIT_FAILURE);
860         }
861
862         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
863                           from_utf8(sup.absFilename()))) << endl;
864
865         if (!sup.createDirectory(0755)) {
866                 // Failed, so let's exit.
867                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
868                        << endl;
869                 earlyExit(EXIT_FAILURE);
870         }
871
872         return true;
873 }
874
875
876 bool LyX::readRcFile(string const & name)
877 {
878         LYXERR(Debug::INIT, "About to read " << name << "... ");
879
880         FileName const lyxrc_path = libFileSearch(string(), name);
881         if (!lyxrc_path.empty()) {
882                 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
883                 if (lyxrc.read(lyxrc_path) < 0) {
884                         showFileError(name);
885                         return false;
886                 }
887         } else {
888                 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
889         }
890         return true;
891 }
892
893 // Read the languages file `name'
894 bool LyX::readLanguagesFile(string const & name)
895 {
896         LYXERR(Debug::INIT, "About to read " << name << "...");
897
898         FileName const lang_path = libFileSearch(string(), name);
899         if (lang_path.empty()) {
900                 showFileError(name);
901                 return false;
902         }
903         languages.read(lang_path);
904         return true;
905 }
906
907
908 // Read the encodings file `name'
909 bool LyX::readEncodingsFile(string const & enc_name,
910                             string const & symbols_name)
911 {
912         LYXERR(Debug::INIT, "About to read " << enc_name << " and "
913                             << symbols_name << "...");
914
915         FileName const symbols_path = libFileSearch(string(), symbols_name);
916         if (symbols_path.empty()) {
917                 showFileError(symbols_name);
918                 return false;
919         }
920
921         FileName const enc_path = libFileSearch(string(), enc_name);
922         if (enc_path.empty()) {
923                 showFileError(enc_name);
924                 return false;
925         }
926         encodings.read(enc_path, symbols_path);
927         return true;
928 }
929
930
931 namespace {
932
933 /// return the the number of arguments consumed
934 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
935
936 int parse_dbg(string const & arg, string const &, string &)
937 {
938         if (arg.empty()) {
939                 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
940                 Debug::showTags(lyxerr);
941                 exit(0);
942         }
943         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
944
945         lyxerr.level(Debug::value(arg));
946         Debug::showLevel(lyxerr, lyxerr.level());
947         return 1;
948 }
949
950
951 int parse_help(string const &, string const &, string &)
952 {
953         lyxerr <<
954                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
955                   "Command line switches (case sensitive):\n"
956                   "\t-help              summarize LyX usage\n"
957                   "\t-userdir dir       set user directory to dir\n"
958                   "\t-sysdir dir        set system directory to dir\n"
959                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
960                   "\t-dbg feature[,feature]...\n"
961                   "                  select the features to debug.\n"
962                   "                  Type `lyx -dbg' to see the list of features\n"
963                   "\t-x [--execute] command\n"
964                   "                  where command is a lyx command.\n"
965                   "\t-e [--export] fmt\n"
966                   "                  where fmt is the export format of choice.\n"
967                   "                  Look on Tools->Preferences->File formats->Format\n"
968                   "                  to get an idea which parameters should be passed.\n"
969                   "\t-i [--import] fmt file.xxx\n"
970                   "                  where fmt is the import format of choice\n"
971                   "                  and file.xxx is the file to be imported.\n"
972                   "\t-version        summarize version and build info\n"
973                                "Check the LyX man page for more details.")) << endl;
974         exit(0);
975         return 0;
976 }
977
978
979 int parse_version(string const &, string const &, string &)
980 {
981         lyxerr << "LyX " << lyx_version
982                << " (" << lyx_release_date << ")" << endl;
983         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
984
985         lyxerr << lyx_version_info << endl;
986         exit(0);
987         return 0;
988 }
989
990
991 int parse_sysdir(string const & arg, string const &, string &)
992 {
993         if (arg.empty()) {
994                 Alert::error(_("No system directory"),
995                         _("Missing directory for -sysdir switch"));
996                 exit(1);
997         }
998         cl_system_support = arg;
999         return 1;
1000 }
1001
1002
1003 int parse_userdir(string const & arg, string const &, string &)
1004 {
1005         if (arg.empty()) {
1006                 Alert::error(_("No user directory"),
1007                         _("Missing directory for -userdir switch"));
1008                 exit(1);
1009         }
1010         cl_user_support = arg;
1011         return 1;
1012 }
1013
1014
1015 int parse_execute(string const & arg, string const &, string & batch)
1016 {
1017         if (arg.empty()) {
1018                 Alert::error(_("Incomplete command"),
1019                         _("Missing command string after --execute switch"));
1020                 exit(1);
1021         }
1022         batch = arg;
1023         return 1;
1024 }
1025
1026
1027 int parse_export(string const & type, string const &, string & batch)
1028 {
1029         if (type.empty()) {
1030                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1031                                          "--export switch")) << endl;
1032                 exit(1);
1033         }
1034         batch = "buffer-export " + type;
1035         use_gui = false;
1036         return 1;
1037 }
1038
1039
1040 int parse_import(string const & type, string const & file, string & batch)
1041 {
1042         if (type.empty()) {
1043                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1044                                          "--import switch")) << endl;
1045                 exit(1);
1046         }
1047         if (file.empty()) {
1048                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1049                 exit(1);
1050         }
1051
1052         batch = "buffer-import " + type + ' ' + file;
1053         return 2;
1054 }
1055
1056
1057 int parse_geometry(string const & arg1, string const &, string &)
1058 {
1059         geometryArg = arg1;
1060 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1061         // remove also the arg
1062         return 1;
1063 #else
1064         // don't remove "-geometry"
1065         return -1;
1066 #endif
1067 }
1068
1069
1070 } // namespace anon
1071
1072
1073 void LyX::easyParse(int & argc, char * argv[])
1074 {
1075         map<string, cmd_helper> cmdmap;
1076
1077         cmdmap["-dbg"] = parse_dbg;
1078         cmdmap["-help"] = parse_help;
1079         cmdmap["--help"] = parse_help;
1080         cmdmap["-version"] = parse_version;
1081         cmdmap["--version"] = parse_version;
1082         cmdmap["-sysdir"] = parse_sysdir;
1083         cmdmap["-userdir"] = parse_userdir;
1084         cmdmap["-x"] = parse_execute;
1085         cmdmap["--execute"] = parse_execute;
1086         cmdmap["-e"] = parse_export;
1087         cmdmap["--export"] = parse_export;
1088         cmdmap["-i"] = parse_import;
1089         cmdmap["--import"] = parse_import;
1090         cmdmap["-geometry"] = parse_geometry;
1091
1092         for (int i = 1; i < argc; ++i) {
1093                 map<string, cmd_helper>::const_iterator it
1094                         = cmdmap.find(argv[i]);
1095
1096                 // don't complain if not found - may be parsed later
1097                 if (it == cmdmap.end())
1098                         continue;
1099
1100                 string const arg =
1101                         (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1102                 string const arg2 =
1103                         (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1104
1105                 string batch;
1106                 int const remove = 1 + it->second(arg, arg2, batch);
1107                 if (!batch.empty())
1108                         pimpl_->batch_commands.push_back(batch);
1109
1110                 // Now, remove used arguments by shifting
1111                 // the following ones remove places down.
1112                 if (remove > 0) {
1113                         argc -= remove;
1114                         for (int j = i; j < argc; ++j)
1115                                 argv[j] = argv[j + remove];
1116                         --i;
1117                 }
1118         }
1119 }
1120
1121
1122 FuncStatus getStatus(FuncRequest const & action)
1123 {
1124         LASSERT(singleton_, /**/);
1125         return singleton_->pimpl_->lyxfunc_.getStatus(action);
1126 }
1127
1128
1129 void dispatch(FuncRequest const & action)
1130 {
1131         LASSERT(singleton_, /**/);
1132         singleton_->pimpl_->lyxfunc_.dispatch(action);
1133 }
1134
1135
1136 BufferList & theBufferList()
1137 {
1138         LASSERT(singleton_, /**/);
1139         return singleton_->pimpl_->buffer_list_;
1140 }
1141
1142
1143 LyXFunc & theLyXFunc()
1144 {
1145         LASSERT(singleton_, /**/);
1146         return singleton_->pimpl_->lyxfunc_;
1147 }
1148
1149
1150 Server & theServer()
1151 {
1152         // FIXME: this should not be use_gui dependent
1153         LASSERT(use_gui, /**/);
1154         LASSERT(singleton_, /**/);
1155         return *singleton_->pimpl_->lyx_server_.get();
1156 }
1157
1158
1159 ServerSocket & theServerSocket()
1160 {
1161         // FIXME: this should not be use_gui dependent
1162         LASSERT(use_gui, /**/);
1163         LASSERT(singleton_, /**/);
1164         return *singleton_->pimpl_->lyx_socket_.get();
1165 }
1166
1167
1168 KeyMap & theTopLevelKeymap()
1169 {
1170         LASSERT(singleton_, /**/);
1171         return singleton_->pimpl_->toplevel_keymap_;
1172 }
1173
1174
1175 Converters & theConverters()
1176 {
1177         LASSERT(singleton_, /**/);
1178         return  singleton_->pimpl_->converters_;
1179 }
1180
1181
1182 Converters & theSystemConverters()
1183 {
1184         LASSERT(singleton_, /**/);
1185         return  singleton_->pimpl_->system_converters_;
1186 }
1187
1188
1189 Movers & theMovers()
1190 {
1191         LASSERT(singleton_, /**/);
1192         return singleton_->pimpl_->movers_;
1193 }
1194
1195
1196 Mover const & getMover(string  const & fmt)
1197 {
1198         LASSERT(singleton_, /**/);
1199         return singleton_->pimpl_->movers_(fmt);
1200 }
1201
1202
1203 void setMover(string const & fmt, string const & command)
1204 {
1205         LASSERT(singleton_, /**/);
1206         singleton_->pimpl_->movers_.set(fmt, command);
1207 }
1208
1209
1210 Movers & theSystemMovers()
1211 {
1212         LASSERT(singleton_, /**/);
1213         return singleton_->pimpl_->system_movers_;
1214 }
1215
1216
1217 Messages & getMessages(string const & language)
1218 {
1219         LASSERT(singleton_, /**/);
1220         return singleton_->messages(language);
1221 }
1222
1223
1224 Messages & getGuiMessages()
1225 {
1226         LASSERT(singleton_, /**/);
1227         return singleton_->pimpl_->messages_["GUI"];
1228 }
1229
1230
1231 graphics::Previews & thePreviews()
1232 {
1233         LASSERT(singleton_, /**/);
1234         return singleton_->pimpl_->preview_;
1235 }
1236
1237
1238 Session & theSession()
1239 {
1240         LASSERT(singleton_, /**/);
1241         return *singleton_->pimpl_->session_.get();
1242 }
1243
1244
1245 CmdDef & theTopLevelCmdDef()
1246 {
1247         LASSERT(singleton_, /**/);
1248         return singleton_->pimpl_->toplevel_cmddef_;
1249 }
1250
1251 } // namespace lyx