]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
613d73f38c8a33ec7196d39ae73158056c44256a
[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 "ConverterCache.h"
21 #include "Buffer.h"
22 #include "buffer_funcs.h"
23 #include "BufferList.h"
24 #include "Converter.h"
25 #include "debug.h"
26 #include "Encoding.h"
27 #include "ErrorList.h"
28 #include "Format.h"
29 #include "gettext.h"
30 #include "KeyMap.h"
31 #include "Language.h"
32 #include "Session.h"
33 #include "Color.h"
34 #include "callback.h"
35 #include "LyXAction.h"
36 #include "LyXFunc.h"
37 #include "Lexer.h"
38 #include "LyXRC.h"
39 #include "ModuleList.h"
40 #include "Server.h"
41 #include "ServerSocket.h"
42 #include "TextClassList.h"
43 #include "MenuBackend.h"
44 #include "Messages.h"
45 #include "Mover.h"
46 #include "ToolbarBackend.h"
47
48 #include "frontends/alert.h"
49 #include "frontends/Application.h"
50 #include "frontends/Dialogs.h"
51 #include "frontends/Gui.h"
52 #include "frontends/LyXView.h"
53
54 #include "support/environment.h"
55 #include "support/filetools.h"
56 #include "support/lyxlib.h"
57 #include "support/convert.h"
58 #include "support/ExceptionMessage.h"
59 #include "support/os.h"
60 #include "support/Package.h"
61 #include "support/Path.h"
62 #include "support/Systemcall.h"
63
64 #include <boost/bind.hpp>
65 #include <boost/filesystem/operations.hpp>
66
67 #include <algorithm>
68 #include <iostream>
69 #include <csignal>
70 #include <map>
71 #include <string>
72 #include <vector>
73
74 using std::endl;
75 using std::for_each;
76 using std::map;
77 using std::make_pair;
78 using std::string;
79 using std::vector;
80
81 #ifndef CXX_GLOBAL_CSTD
82 using std::exit;
83 using std::signal;
84 using std::system;
85 #endif
86
87 namespace fs = boost::filesystem;
88
89 namespace lyx {
90
91 using support::addName;
92 using support::addPath;
93 using support::bformat;
94 using support::changeExtension;
95 using support::createDirectory;
96 using support::createLyXTmpDir;
97 using support::destroyDir;
98 using support::FileName;
99 using support::fileSearch;
100 using support::getEnv;
101 using support::i18nLibFileSearch;
102 using support::libFileSearch;
103 using support::package;
104 using support::prependEnvPath;
105 using support::rtrim;
106 using support::Systemcall;
107 using frontend::LyXView;
108
109 namespace Alert = frontend::Alert;
110 namespace os = support::os;
111
112
113
114 /// are we using the GUI at all?
115 /**
116 * We default to true and this is changed to false when the export feature is used.
117 */
118 bool use_gui = true;
119
120
121 namespace {
122
123 // Filled with the command line arguments "foo" of "-sysdir foo" or
124 // "-userdir foo".
125 string cl_system_support;
126 string cl_user_support;
127
128 std::string geometryArg;
129
130 LyX * singleton_ = 0;
131
132 void showFileError(string const & error)
133 {
134         Alert::warning(_("Could not read configuration file"),
135                        bformat(_("Error while reading the configuration file\n%1$s.\n"
136                            "Please check your installation."), from_utf8(error)));
137 }
138
139
140 void reconfigureUserLyXDir()
141 {
142         string const configure_command = package().configure_command();
143
144         lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
145         support::Path p(package().user_support());
146         Systemcall one;
147         one.startscript(Systemcall::Wait, configure_command);
148         lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
149 }
150
151 } // namespace anon
152
153
154 /// The main application class private implementation.
155 struct LyX::Singletons
156 {
157         Singletons()
158         {
159                 // Set the default User Interface language as soon as possible.
160                 // The language used will be derived from the environment
161                 // variables.
162                 messages_["GUI"] = Messages();
163         }
164         /// our function handler
165         LyXFunc lyxfunc_;
166         ///
167         BufferList buffer_list_;
168         ///
169         boost::scoped_ptr<KeyMap> toplevel_keymap_;
170         ///
171         boost::scoped_ptr<Server> lyx_server_;
172         ///
173         boost::scoped_ptr<ServerSocket> lyx_socket_;
174         ///
175         boost::scoped_ptr<frontend::Application> application_;
176         /// lyx session, containing lastfiles, lastfilepos, and lastopened
177         boost::scoped_ptr<Session> session_;
178
179         /// Files to load at start.
180         vector<FileName> files_to_load_;
181
182         /// The messages translators.
183         map<string, Messages> messages_;
184
185         /// The file converters.
186         Converters converters_;
187
188         // The system converters copy after reading lyxrc.defaults.
189         Converters system_converters_;
190
191         ///
192         Movers movers_;
193
194         ///
195         Movers system_movers_;
196 };
197
198 ///
199 frontend::Application * theApp()
200 {
201         if (singleton_)
202                 return singleton_->pimpl_->application_.get();
203         else
204                 return 0;
205 }
206
207
208 LyX::~LyX()
209 {
210 }
211
212
213 LyX & LyX::ref()
214 {
215         BOOST_ASSERT(singleton_);
216         return *singleton_;
217 }
218
219
220 LyX const & LyX::cref()
221 {
222         BOOST_ASSERT(singleton_);
223         return *singleton_;
224 }
225
226
227 LyX::LyX()
228         : first_start(false)
229 {
230         singleton_ = this;
231         pimpl_.reset(new Singletons);
232 }
233
234
235 BufferList & LyX::bufferList()
236 {
237         return pimpl_->buffer_list_;
238 }
239
240
241 BufferList const & LyX::bufferList() const
242 {
243         return pimpl_->buffer_list_;
244 }
245
246
247 Session & LyX::session()
248 {
249         BOOST_ASSERT(pimpl_->session_.get());
250         return *pimpl_->session_.get();
251 }
252
253
254 Session const & LyX::session() const
255 {
256         BOOST_ASSERT(pimpl_->session_.get());
257         return *pimpl_->session_.get();
258 }
259
260
261 LyXFunc & LyX::lyxFunc()
262 {
263         return pimpl_->lyxfunc_;
264 }
265
266
267 LyXFunc const & LyX::lyxFunc() const
268 {
269         return pimpl_->lyxfunc_;
270 }
271
272
273 Server & LyX::server()
274 {
275         BOOST_ASSERT(pimpl_->lyx_server_.get());
276         return *pimpl_->lyx_server_.get();
277 }
278
279
280 Server const & LyX::server() const
281 {
282         BOOST_ASSERT(pimpl_->lyx_server_.get());
283         return *pimpl_->lyx_server_.get();
284 }
285
286
287 ServerSocket & LyX::socket()
288 {
289         BOOST_ASSERT(pimpl_->lyx_socket_.get());
290         return *pimpl_->lyx_socket_.get();
291 }
292
293
294 ServerSocket const & LyX::socket() const
295 {
296         BOOST_ASSERT(pimpl_->lyx_socket_.get());
297         return *pimpl_->lyx_socket_.get();
298 }
299
300
301 frontend::Application & LyX::application()
302 {
303         BOOST_ASSERT(pimpl_->application_.get());
304         return *pimpl_->application_.get();
305 }
306
307
308 frontend::Application const & LyX::application() const
309 {
310         BOOST_ASSERT(pimpl_->application_.get());
311         return *pimpl_->application_.get();
312 }
313
314
315 KeyMap & LyX::topLevelKeymap()
316 {
317         BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
318         return *pimpl_->toplevel_keymap_.get();
319 }
320
321
322 Converters & LyX::converters()
323 {
324         return pimpl_->converters_;
325 }
326
327
328 Converters & LyX::systemConverters()
329 {
330         return pimpl_->system_converters_;
331 }
332
333
334 KeyMap const & LyX::topLevelKeymap() const
335 {
336         BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
337         return *pimpl_->toplevel_keymap_.get();
338 }
339
340
341 Messages & LyX::getMessages(std::string const & language)
342 {
343         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
344
345         if (it != pimpl_->messages_.end())
346                 return it->second;
347
348         std::pair<map<string, Messages>::iterator, bool> result =
349                         pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
350
351         BOOST_ASSERT(result.second);
352         return result.first->second;
353 }
354
355
356 Messages & LyX::getGuiMessages()
357 {
358         return pimpl_->messages_["GUI"];
359 }
360
361
362 void LyX::setGuiLanguage(std::string const & language)
363 {
364         pimpl_->messages_["GUI"] = Messages(language);
365 }
366
367
368 Buffer const * const LyX::updateInset(Inset const * inset) const
369 {
370         if (quitting || !inset)
371                 return 0;
372
373         Buffer const * buffer_ptr = 0;
374         vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
375         vector<int>::const_iterator it = view_ids.begin();
376         vector<int>::const_iterator const end = view_ids.end();
377         for (; it != end; ++it) {
378                 Buffer const * ptr =
379                         pimpl_->application_->gui().view(*it).updateInset(inset);
380                 if (ptr)
381                         buffer_ptr = ptr;
382         }
383         return buffer_ptr;
384 }
385
386
387 void LyX::hideDialogs(std::string const & name, Inset * inset) const
388 {
389         if (quitting || !use_gui)
390                 return;
391
392         vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
393         vector<int>::const_iterator it = view_ids.begin();
394         vector<int>::const_iterator const end = view_ids.end();
395         for (; it != end; ++it)
396                 pimpl_->application_->gui().view(*it).getDialogs().
397                         hide(name, inset);
398 }
399
400
401 int LyX::exec(int & argc, char * argv[])
402 {
403         // Here we need to parse the command line. At least
404         // we need to parse for "-dbg" and "-help"
405         easyParse(argc, argv);
406
407         try { support::init_package(to_utf8(from_local8bit(argv[0])),
408                               cl_system_support, cl_user_support,
409                               support::top_build_dir_is_one_level_up);
410         } catch (support::ExceptionMessage const & message) {
411                 if (message.type_ == support::ErrorException) {
412                         Alert::error(message.title_, message.details_);
413                         exit(1);
414                 } else if (message.type_ == support::WarningException) {
415                         Alert::warning(message.title_, message.details_);
416                 }
417         }
418
419         // Reinit the messages machinery in case package() knows
420         // something interesting about the locale directory.
421         Messages::init();
422
423         if (!use_gui) {
424                 // FIXME: create a ConsoleApplication
425                 int exit_status = init(argc, argv);
426                 if (exit_status) {
427                         prepareExit();
428                         return exit_status;
429                 }
430
431                 loadFiles();
432
433                 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
434                         prepareExit();
435                         return EXIT_SUCCESS;
436                 }
437
438                 BufferList::iterator begin = pimpl_->buffer_list_.begin();
439
440                 bool final_success = false;
441                 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
442                         Buffer * buf = *I;
443                         if (buf != buf->getMasterBuffer())
444                                 continue;
445                         bool success = false;
446                         buf->dispatch(batch_command, &success);
447                         final_success |= success;
448                 }
449                 prepareExit();
450                 return !final_success;
451         }
452
453         // Let the frontend parse and remove all arguments that it knows
454         pimpl_->application_.reset(createApplication(argc, argv));
455
456         initGuiFont();
457
458         // Parse and remove all known arguments in the LyX singleton
459         // Give an error for all remaining ones.
460         int exit_status = init(argc, argv);
461         if (exit_status) {
462                 // Kill the application object before exiting.
463                 pimpl_->application_.reset();
464                 use_gui = false;
465                 prepareExit();
466                 return exit_status;
467         }
468
469         // FIXME
470         /* Create a CoreApplication class that will provide the main event loop
471         * and the socket callback registering. With Qt4, only QtCore
472         * library would be needed.
473         * When this is done, a server_mode could be created and the following two
474         * line would be moved out from here.
475         */
476         // Note: socket callback must be registered after init(argc, argv)
477         // such that package().temp_dir() is properly initialized.
478         pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
479         pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
480                         FileName(package().temp_dir().absFilename() + "/lyxsocket")));
481
482         // Start the real execution loop.
483         exit_status = pimpl_->application_->exec();
484
485         prepareExit();
486
487         return exit_status;
488 }
489
490
491 void LyX::prepareExit()
492 {
493         // Set a flag that we do quitting from the program,
494         // so no refreshes are necessary.
495         quitting = true;
496
497         // close buffers first
498         pimpl_->buffer_list_.closeAll();
499
500         // do any other cleanup procedures now
501         if (package().temp_dir() != package().system_temp_dir()) {
502                 LYXERR(Debug::INFO) << "Deleting tmp dir "
503                                     << package().temp_dir().absFilename() << endl;
504
505                 if (!destroyDir(package().temp_dir())) {
506                         docstring const msg =
507                                 bformat(_("Unable to remove the temporary directory %1$s"),
508                                 from_utf8(package().temp_dir().absFilename()));
509                         Alert::warning(_("Unable to remove temporary directory"), msg);
510                 }
511         }
512
513         if (use_gui) {
514                 if (pimpl_->session_)
515                         pimpl_->session_->writeFile();
516                 pimpl_->session_.reset();
517                 pimpl_->lyx_server_.reset();
518                 pimpl_->lyx_socket_.reset();
519         }
520
521         // Kill the application object before exiting. This avoids crashes
522         // when exiting on Linux.
523         if (pimpl_->application_)
524                 pimpl_->application_.reset();
525 }
526
527
528 void LyX::earlyExit(int status)
529 {
530         BOOST_ASSERT(pimpl_->application_.get());
531         // LyX::pimpl_::application_ is not initialised at this
532         // point so it's safe to just exit after some cleanup.
533         prepareExit();
534         exit(status);
535 }
536
537
538 int LyX::init(int & argc, char * argv[])
539 {
540         // check for any spurious extra arguments
541         // other than documents
542         for (int argi = 1; argi < argc ; ++argi) {
543                 if (argv[argi][0] == '-') {
544                         lyxerr << to_utf8(
545                                 bformat(_("Wrong command line option `%1$s'. Exiting."),
546                                 from_utf8(argv[argi]))) << endl;
547                         return EXIT_FAILURE;
548                 }
549         }
550
551         // Initialization of LyX (reads lyxrc and more)
552         LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
553         bool success = init();
554         LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
555         if (!success)
556                 return EXIT_FAILURE;
557
558         for (int argi = argc - 1; argi >= 1; --argi) {
559                 // get absolute path of file and add ".lyx" to
560                 // the filename if necessary
561                 pimpl_->files_to_load_.push_back(fileSearch(string(),
562                         os::internal_path(to_utf8(from_local8bit(argv[argi]))),
563                         "lyx", support::allow_unreadable));
564         }
565
566         if (first_start)
567                 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
568
569         return EXIT_SUCCESS;
570 }
571
572
573 void LyX::addFileToLoad(FileName const & fname)
574 {
575         vector<FileName>::const_iterator cit = std::find(
576                 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
577                 fname);
578
579         if (cit == pimpl_->files_to_load_.end())
580                 pimpl_->files_to_load_.push_back(fname);
581 }
582
583
584 void LyX::loadFiles()
585 {
586         vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
587         vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
588
589         for (; it != end; ++it) {
590                 if (it->empty())
591                         continue;
592
593                 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
594                 if (loadLyXFile(buf, *it)) {
595                         ErrorList const & el = buf->errorList("Parse");
596                         if (!el.empty())
597                                 for_each(el.begin(), el.end(),
598                                 boost::bind(&LyX::printError, this, _1));
599                 }
600                 else
601                         pimpl_->buffer_list_.release(buf);
602         }
603 }
604
605
606 void LyX::execBatchCommands()
607 {
608         // The advantage of doing this here is that the event loop
609         // is already started. So any need for interaction will be
610         // aknowledged.
611         restoreGuiSession();
612
613         // Execute batch commands if available
614         if (batch_command.empty())
615                 return;
616
617         LYXERR(Debug::INIT) << "About to handle -x '"
618                 << batch_command << '\'' << endl;
619
620         pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
621 }
622
623
624 void LyX::restoreGuiSession()
625 {
626         LyXView * view = newLyXView();
627
628         // if some files were specified at command-line we assume that the
629         // user wants to edit *these* files and not to restore the session.
630         if (!pimpl_->files_to_load_.empty()) {
631                 for_each(pimpl_->files_to_load_.begin(),
632                         pimpl_->files_to_load_.end(),
633                         bind(&LyXView::loadLyXFile, view, _1, true));
634                 // clear this list to save a few bytes of RAM
635                 pimpl_->files_to_load_.clear();
636                 pimpl_->session_->lastOpened().clear();
637
638         } else if (lyxrc.load_session) {
639                 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
640                 // do not add to the lastfile list since these files are restored from
641                 // last session, and should be already there (regular files), or should
642                 // not be added at all (help files).
643                 for_each(lastopened.begin(), lastopened.end(),
644                         bind(&LyXView::loadLyXFile, view, _1, false));
645
646                 // clear this list to save a few bytes of RAM
647                 pimpl_->session_->lastOpened().clear();
648         }
649
650         BufferList::iterator I = pimpl_->buffer_list_.begin();
651         BufferList::iterator end = pimpl_->buffer_list_.end();
652         for (; I != end; ++I) {
653                 Buffer * buf = *I;
654                 if (buf != buf->getMasterBuffer())
655                         continue;
656                 updateLabels(*buf);
657         }
658
659         // FIXME: Switch to the last loaded Buffer. This must not be the first one
660         // because the Buffer won't be connected in this case. The correct solution
661         // would be to avoid the manual connection of the current Buffer in LyXView.
662         if (!pimpl_->buffer_list_.empty())
663                 view->setBuffer(pimpl_->buffer_list_.last());
664 }
665
666
667 LyXView * LyX::newLyXView()
668 {
669         if (!lyx::use_gui)
670                 return 0;
671
672         // determine windows size and position, from lyxrc and/or session
673         // initial geometry
674         unsigned int width = 690;
675         unsigned int height = 510;
676         // default icon size, will be overwritten by  stored session value
677         unsigned int iconSizeXY = 0;
678         int maximized = LyXView::NotMaximized;
679         // first try lyxrc
680         if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
681                 width = lyxrc.geometry_width;
682                 height = lyxrc.geometry_height;
683         }
684         // if lyxrc returns (0,0), then use session info
685         else {
686                 string val = session().sessionInfo().load("WindowWidth");
687                 if (!val.empty())
688                         width = convert<unsigned int>(val);
689                 val = session().sessionInfo().load("WindowHeight");
690                 if (!val.empty())
691                         height = convert<unsigned int>(val);
692                 val = session().sessionInfo().load("WindowMaximized");
693                 if (!val.empty())
694                         maximized = convert<int>(val);
695                 val = session().sessionInfo().load("IconSizeXY");
696                 if (!val.empty())
697                         iconSizeXY = convert<unsigned int>(val);
698         }
699
700         // if user wants to restore window position
701         int posx = -1;
702         int posy = -1;
703         if (lyxrc.geometry_xysaved) {
704                 string val = session().sessionInfo().load("WindowPosX");
705                 if (!val.empty())
706                         posx = convert<int>(val);
707                 val = session().sessionInfo().load("WindowPosY");
708                 if (!val.empty())
709                         posy = convert<int>(val);
710         }
711
712         if (!geometryArg.empty())
713         {
714                 width = 0;
715                 height = 0;
716         }
717
718         // create the main window
719         LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximized, iconSizeXY, geometryArg);
720
721         return view;
722 }
723
724 /*
725 Signals and Windows
726 ===================
727 The SIGHUP signal does not exist on Windows and does not need to be handled.
728
729 Windows handles SIGFPE and SIGSEGV signals as expected.
730
731 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
732 cause a new thread to be spawned. This may well result in unexpected
733 behaviour by the single-threaded LyX.
734
735 SIGTERM signals will come only from another process actually sending
736 that signal using 'raise' in Windows' POSIX compatability layer. It will
737 not come from the general "terminate process" methods that everyone
738 actually uses (and which can't be trapped). Killing an app 'politely' on
739 Windows involves first sending a WM_CLOSE message, something that is
740 caught already by the Qt frontend.
741
742 For more information see:
743
744 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
745 ...signals are mostly useless on Windows for a variety of reasons that are
746 Windows specific...
747
748 'UNIX Application Migration Guide, Chapter 9'
749 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
750
751 'How To Terminate an Application "Cleanly" in Win32'
752 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
753 */
754 extern "C" {
755
756 static void error_handler(int err_sig)
757 {
758         // Throw away any signals other than the first one received.
759         static sig_atomic_t handling_error = false;
760         if (handling_error)
761                 return;
762         handling_error = true;
763
764         // We have received a signal indicating a fatal error, so
765         // try and save the data ASAP.
766         LyX::cref().emergencyCleanup();
767
768         // These lyxerr calls may or may not work:
769
770         // Signals are asynchronous, so the main program may be in a very
771         // fragile state when a signal is processed and thus while a signal
772         // handler function executes.
773         // In general, therefore, we should avoid performing any
774         // I/O operations or calling most library and system functions from
775         // signal handlers.
776
777         // This shouldn't matter here, however, as we've already invoked
778         // emergencyCleanup.
779         switch (err_sig) {
780 #ifdef SIGHUP
781         case SIGHUP:
782                 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
783                 break;
784 #endif
785         case SIGFPE:
786                 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
787                 break;
788         case SIGSEGV:
789                 lyxerr << "\nlyx: SIGSEGV signal caught\n"
790                           "Sorry, you have found a bug in LyX. "
791                           "Please read the bug-reporting instructions "
792                           "in Help->Introduction and send us a bug report, "
793                           "if necessary. Thanks !\nBye." << endl;
794                 break;
795         case SIGINT:
796         case SIGTERM:
797                 // no comments
798                 break;
799         }
800
801         // Deinstall the signal handlers
802 #ifdef SIGHUP
803         signal(SIGHUP, SIG_DFL);
804 #endif
805         signal(SIGINT, SIG_DFL);
806         signal(SIGFPE, SIG_DFL);
807         signal(SIGSEGV, SIG_DFL);
808         signal(SIGTERM, SIG_DFL);
809
810 #ifdef SIGHUP
811         if (err_sig == SIGSEGV ||
812             (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
813 #else
814         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
815 #endif
816                 support::abort();
817         exit(0);
818 }
819
820 }
821
822
823 void LyX::printError(ErrorItem const & ei)
824 {
825         docstring tmp = _("LyX: ") + ei.error + char_type(':')
826                 + ei.description;
827         std::cerr << to_utf8(tmp) << std::endl;
828 }
829
830
831 void LyX::initGuiFont()
832 {
833         if (lyxrc.roman_font_name.empty())
834                 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
835
836         if (lyxrc.sans_font_name.empty())
837                 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
838
839         if (lyxrc.typewriter_font_name.empty())
840                 lyxrc.typewriter_font_name
841                         = pimpl_->application_->typewriterFontName();
842 }
843
844
845 bool LyX::init()
846 {
847 #ifdef SIGHUP
848         signal(SIGHUP, error_handler);
849 #endif
850         signal(SIGFPE, error_handler);
851         signal(SIGSEGV, error_handler);
852         signal(SIGINT, error_handler);
853         signal(SIGTERM, error_handler);
854         // SIGPIPE can be safely ignored.
855
856         lyxrc.tempdir_path = package().temp_dir().absFilename();
857         lyxrc.document_path = package().document_dir().absFilename();
858
859         if (lyxrc.template_path.empty()) {
860                 lyxrc.template_path = addPath(package().system_support().absFilename(),
861                                               "templates");
862         }
863
864         //
865         // Read configuration files
866         //
867
868         // This one may have been distributed along with LyX.
869         if (!readRcFile("lyxrc.dist"))
870                 return false;
871
872         // Set the language defined by the distributor.
873         //setGuiLanguage(lyxrc.gui_language);
874
875         // Set the PATH correctly.
876 #if !defined (USE_POSIX_PACKAGING)
877         // Add the directory containing the LyX executable to the path
878         // so that LyX can find things like tex2lyx.
879         if (package().build_support().empty())
880                 prependEnvPath("PATH", package().binary_dir().absFilename());
881 #endif
882         if (!lyxrc.path_prefix.empty())
883                 prependEnvPath("PATH", lyxrc.path_prefix);
884
885         // Check that user LyX directory is ok.
886         if (queryUserLyXDir(package().explicit_user_support()))
887                 reconfigureUserLyXDir();
888
889         // no need for a splash when there is no GUI
890         if (!use_gui) {
891                 first_start = false;
892         }
893
894         // This one is generated in user_support directory by lib/configure.py.
895         if (!readRcFile("lyxrc.defaults"))
896                 return false;
897
898         // Query the OS to know what formats are viewed natively
899         formats.setAutoOpen();
900
901         // Read lyxrc.dist again to be able to override viewer auto-detection.
902         readRcFile("lyxrc.dist");
903
904         system_lyxrc = lyxrc;
905         system_formats = formats;
906         pimpl_->system_converters_ = pimpl_->converters_;
907         pimpl_->system_movers_ = pimpl_->movers_;
908         system_lcolor = lcolor;
909
910         // This one is edited through the preferences dialog.
911         if (!readRcFile("preferences"))
912                 return false;
913
914         if (!readEncodingsFile("encodings", "unicodesymbols"))
915                 return false;
916         if (!readLanguagesFile("languages"))
917                 return false;
918
919         // Load the layouts
920         LYXERR(Debug::INIT) << "Reading layouts..." << endl;
921         if (!LyXSetStyle())
922                 return false;
923         //...and the modules
924         moduleList.load();
925
926         if (use_gui) {
927                 // Set the language defined by the user.
928                 //setGuiLanguage(lyxrc.gui_language);
929
930                 // Set up bindings
931                 pimpl_->toplevel_keymap_.reset(new KeyMap);
932                 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
933                 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
934
935                 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
936
937                 // Read menus
938                 if (!readUIFile(lyxrc.ui_file))
939                         return false;
940         }
941
942         if (lyxerr.debugging(Debug::LYXRC))
943                 lyxrc.print();
944
945         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
946         if (!lyxrc.path_prefix.empty())
947                 prependEnvPath("PATH", lyxrc.path_prefix);
948
949         FileName const document_path(lyxrc.document_path);
950         if (fs::exists(document_path.toFilesystemEncoding()) &&
951             fs::is_directory(document_path.toFilesystemEncoding()))
952                 package().document_dir() = document_path;
953
954         package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
955         if (package().temp_dir().empty()) {
956                 Alert::error(_("Could not create temporary directory"),
957                              bformat(_("Could not create a temporary directory in\n"
958                                                     "%1$s. Make sure that this\n"
959                                                     "path exists and is writable and try again."),
960                                      from_utf8(lyxrc.tempdir_path)));
961                 // createLyXTmpDir() tries sufficiently hard to create a
962                 // usable temp dir, so the probability to come here is
963                 // close to zero. We therefore don't try to overcome this
964                 // problem with e.g. asking the user for a new path and
965                 // trying again but simply exit.
966                 return false;
967         }
968
969         LYXERR(Debug::INIT) << "LyX tmp dir: `"
970                             << package().temp_dir().absFilename()
971                             << '\'' << endl;
972
973         LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
974         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
975
976         // This must happen after package initialization and after lyxrc is
977         // read, therefore it can't be done by a static object.
978         ConverterCache::init();
979
980         return true;
981 }
982
983
984 void LyX::defaultKeyBindings(KeyMap  * kbmap)
985 {
986         kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
987         kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
988         kbmap->bind("Up", FuncRequest(LFUN_UP));
989         kbmap->bind("Down", FuncRequest(LFUN_DOWN));
990
991         kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
992         kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
993         kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
994         kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
995
996         kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
997         kbmap->bind("End", FuncRequest(LFUN_LINE_END));
998         kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
999         kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
1000
1001         kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
1002         //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
1003
1004         kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
1005         kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
1006
1007         // kbmap->bindings to enable the use of the numeric keypad
1008         // e.g. Num Lock set
1009         //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
1010         //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
1011         kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
1012         //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
1013         //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
1014         //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
1015         //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
1016         //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
1017         //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
1018         //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
1019         //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
1020         //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
1021         //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
1022         //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
1023         //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
1024         //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
1025         kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
1026         kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
1027         kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
1028         kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
1029         kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
1030         kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
1031         kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
1032         kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
1033 }
1034
1035
1036 void LyX::emergencyCleanup() const
1037 {
1038         // what to do about tmpfiles is non-obvious. we would
1039         // like to delete any we find, but our lyxdir might
1040         // contain documents etc. which might be helpful on
1041         // a crash
1042
1043         pimpl_->buffer_list_.emergencyWriteAll();
1044         if (use_gui) {
1045                 if (pimpl_->lyx_server_)
1046                         pimpl_->lyx_server_->emergencyCleanup();
1047                 pimpl_->lyx_server_.reset();
1048                 pimpl_->lyx_socket_.reset();
1049         }
1050 }
1051
1052
1053 void LyX::deadKeyBindings(KeyMap * kbmap)
1054 {
1055         // bindKeyings for transparent handling of deadkeys
1056         // The keysyms are gotten from XFree86 X11R6
1057         kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1058         kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1059         kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1060         kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1061         kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1062         kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1063         kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1064         kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1065         kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1066         kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1067         // nothing with this name
1068         // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1069         kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1070         kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1071         // nothing with this name either...
1072         //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1073         kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1074         kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1075         kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1076 }
1077
1078
1079 namespace {
1080
1081 // return true if file does not exist or is older than configure.py.
1082 bool needsUpdate(string const & file)
1083 {
1084         // We cannot initialize configure_script directly because the package
1085         // is not initialized yet when  static objects are constructed.
1086         static string configure_script;
1087         static bool firstrun = true;
1088         if (firstrun) {
1089                 configure_script = FileName(addName(
1090                                 package().system_support().absFilename(),
1091                                 "configure.py")).toFilesystemEncoding();
1092                 firstrun = false;
1093         }
1094
1095         string const absfile = FileName(addName(
1096                 package().user_support().absFilename(), file)).toFilesystemEncoding();
1097         return (! fs::exists(absfile))
1098                 || (fs::last_write_time(configure_script)
1099                     > fs::last_write_time(absfile));
1100 }
1101
1102 }
1103
1104
1105 bool LyX::queryUserLyXDir(bool explicit_userdir)
1106 {
1107         // Does user directory exist?
1108         string const user_support =
1109                 package().user_support().toFilesystemEncoding();
1110         if (fs::exists(user_support) && fs::is_directory(user_support)) {
1111                 first_start = false;
1112
1113                 return needsUpdate("lyxrc.defaults")
1114                         || needsUpdate("lyxmodules.lst")
1115                         || needsUpdate("textclass.lst")
1116                         || needsUpdate("packages.lst");
1117         }
1118
1119         first_start = !explicit_userdir;
1120
1121         // If the user specified explicitly a directory, ask whether
1122         // to create it. If the user says "no", then exit.
1123         if (explicit_userdir &&
1124             Alert::prompt(
1125                     _("Missing user LyX directory"),
1126                     bformat(_("You have specified a non-existent user "
1127                                            "LyX directory, %1$s.\n"
1128                                            "It is needed to keep your own configuration."),
1129                             from_utf8(package().user_support().absFilename())),
1130                     1, 0,
1131                     _("&Create directory"),
1132                     _("&Exit LyX"))) {
1133                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1134                 earlyExit(EXIT_FAILURE);
1135         }
1136
1137         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1138                           from_utf8(package().user_support().absFilename())))
1139                << endl;
1140
1141         if (!createDirectory(package().user_support(), 0755)) {
1142                 // Failed, so let's exit.
1143                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1144                        << endl;
1145                 earlyExit(EXIT_FAILURE);
1146         }
1147
1148         return true;
1149 }
1150
1151
1152 bool LyX::readRcFile(string const & name)
1153 {
1154         LYXERR(Debug::INIT) << "About to read " << name << "... ";
1155
1156         FileName const lyxrc_path = libFileSearch(string(), name);
1157         if (!lyxrc_path.empty()) {
1158
1159                 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1160
1161                 if (lyxrc.read(lyxrc_path) < 0) {
1162                         showFileError(name);
1163                         return false;
1164                 }
1165         } else
1166                 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1167         return true;
1168
1169 }
1170
1171
1172 // Read the ui file `name'
1173 bool LyX::readUIFile(string const & name, bool include)
1174 {
1175         enum Uitags {
1176                 ui_menuset = 1,
1177                 ui_toolbars,
1178                 ui_toolbarset,
1179                 ui_include,
1180                 ui_last
1181         };
1182
1183         struct keyword_item uitags[ui_last - 1] = {
1184                 { "include", ui_include },
1185                 { "menuset", ui_menuset },
1186                 { "toolbars", ui_toolbars },
1187                 { "toolbarset", ui_toolbarset }
1188         };
1189
1190         // Ensure that a file is read only once (prevents include loops)
1191         static std::list<string> uifiles;
1192         std::list<string>::const_iterator it  = uifiles.begin();
1193         std::list<string>::const_iterator end = uifiles.end();
1194         it = std::find(it, end, name);
1195         if (it != end) {
1196                 LYXERR(Debug::INIT) << "UI file '" << name
1197                                     << "' has been read already. "
1198                                     << "Is this an include loop?"
1199                                     << endl;
1200                 return false;
1201         }
1202
1203         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1204
1205
1206         FileName ui_path;
1207         if (include) {
1208                 ui_path = libFileSearch("ui", name, "inc");
1209                 if (ui_path.empty())
1210                         ui_path = libFileSearch("ui",
1211                                                 changeExtension(name, "inc"));
1212         }
1213         else
1214                 ui_path = libFileSearch("ui", name, "ui");
1215
1216         if (ui_path.empty()) {
1217                 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1218                 showFileError(name);
1219                 return false;
1220         }
1221
1222         uifiles.push_back(name);
1223
1224         LYXERR(Debug::INIT) << "Found " << name
1225                             << " in " << ui_path << endl;
1226         Lexer lex(uitags, ui_last - 1);
1227         lex.setFile(ui_path);
1228         if (!lex.isOK()) {
1229                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1230                        << endl;
1231         }
1232
1233         if (lyxerr.debugging(Debug::PARSER))
1234                 lex.printTable(lyxerr);
1235
1236         while (lex.isOK()) {
1237                 switch (lex.lex()) {
1238                 case ui_include: {
1239                         lex.next(true);
1240                         string const file = lex.getString();
1241                         if (!readUIFile(file, true))
1242                                 return false;
1243                         break;
1244                 }
1245                 case ui_menuset:
1246                         menubackend.read(lex);
1247                         break;
1248
1249                 case ui_toolbarset:
1250                         toolbarbackend.readToolbars(lex);
1251                         break;
1252
1253                 case ui_toolbars:
1254                         toolbarbackend.readToolbarSettings(lex);
1255                         break;
1256
1257                 default:
1258                         if (!rtrim(lex.getString()).empty())
1259                                 lex.printError("LyX::ReadUIFile: "
1260                                                "Unknown menu tag: `$$Token'");
1261                         break;
1262                 }
1263         }
1264         return true;
1265 }
1266
1267
1268 // Read the languages file `name'
1269 bool LyX::readLanguagesFile(string const & name)
1270 {
1271         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1272
1273         FileName const lang_path = libFileSearch(string(), name);
1274         if (lang_path.empty()) {
1275                 showFileError(name);
1276                 return false;
1277         }
1278         languages.read(lang_path);
1279         return true;
1280 }
1281
1282
1283 // Read the encodings file `name'
1284 bool LyX::readEncodingsFile(string const & enc_name,
1285                             string const & symbols_name)
1286 {
1287         LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1288                             << symbols_name << "..." << endl;
1289
1290         FileName const symbols_path = libFileSearch(string(), symbols_name);
1291         if (symbols_path.empty()) {
1292                 showFileError(symbols_name);
1293                 return false;
1294         }
1295
1296         FileName const enc_path = libFileSearch(string(), enc_name);
1297         if (enc_path.empty()) {
1298                 showFileError(enc_name);
1299                 return false;
1300         }
1301         encodings.read(enc_path, symbols_path);
1302         return true;
1303 }
1304
1305
1306 namespace {
1307
1308 string batch;
1309
1310 /// return the the number of arguments consumed
1311 typedef boost::function<int(string const &, string const &)> cmd_helper;
1312
1313 int parse_dbg(string const & arg, string const &)
1314 {
1315         if (arg.empty()) {
1316                 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1317                 Debug::showTags(lyxerr);
1318                 exit(0);
1319         }
1320         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1321
1322         lyxerr.level(Debug::value(arg));
1323         Debug::showLevel(lyxerr, lyxerr.level());
1324         return 1;
1325 }
1326
1327
1328 int parse_help(string const &, string const &)
1329 {
1330         lyxerr <<
1331                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1332                   "Command line switches (case sensitive):\n"
1333                   "\t-help              summarize LyX usage\n"
1334                   "\t-userdir dir       set user directory to dir\n"
1335                   "\t-sysdir dir        set system directory to dir\n"
1336                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1337                   "\t-dbg feature[,feature]...\n"
1338                   "                  select the features to debug.\n"
1339                   "                  Type `lyx -dbg' to see the list of features\n"
1340                   "\t-x [--execute] command\n"
1341                   "                  where command is a lyx command.\n"
1342                   "\t-e [--export] fmt\n"
1343                   "                  where fmt is the export format of choice.\n"
1344                   "\t-i [--import] fmt file.xxx\n"
1345                   "                  where fmt is the import format of choice\n"
1346                   "                  and file.xxx is the file to be imported.\n"
1347                   "\t-version        summarize version and build info\n"
1348                                "Check the LyX man page for more details.")) << endl;
1349         exit(0);
1350         return 0;
1351 }
1352
1353 int parse_version(string const &, string const &)
1354 {
1355         lyxerr << "LyX " << lyx_version
1356                << " (" << lyx_release_date << ")" << endl;
1357         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1358
1359         lyxerr << lyx_version_info << endl;
1360         exit(0);
1361         return 0;
1362 }
1363
1364 int parse_sysdir(string const & arg, string const &)
1365 {
1366         if (arg.empty()) {
1367                 Alert::error(_("No system directory"),
1368                         _("Missing directory for -sysdir switch"));
1369                 exit(1);
1370         }
1371         cl_system_support = arg;
1372         return 1;
1373 }
1374
1375 int parse_userdir(string const & arg, string const &)
1376 {
1377         if (arg.empty()) {
1378                 Alert::error(_("No user directory"),
1379                         _("Missing directory for -userdir switch"));
1380                 exit(1);
1381         }
1382         cl_user_support = arg;
1383         return 1;
1384 }
1385
1386 int parse_execute(string const & arg, string const &)
1387 {
1388         if (arg.empty()) {
1389                 Alert::error(_("Incomplete command"),
1390                         _("Missing command string after --execute switch"));
1391                 exit(1);
1392         }
1393         batch = arg;
1394         return 1;
1395 }
1396
1397 int parse_export(string const & type, string const &)
1398 {
1399         if (type.empty()) {
1400                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1401                                          "--export switch")) << endl;
1402                 exit(1);
1403         }
1404         batch = "buffer-export " + type;
1405         use_gui = false;
1406         return 1;
1407 }
1408
1409 int parse_import(string const & type, string const & file)
1410 {
1411         if (type.empty()) {
1412                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1413                                          "--import switch")) << endl;
1414                 exit(1);
1415         }
1416         if (file.empty()) {
1417                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1418                 exit(1);
1419         }
1420
1421         batch = "buffer-import " + type + ' ' + file;
1422         return 2;
1423 }
1424
1425 int parse_geometry(string const & arg1, string const &)
1426 {
1427         geometryArg = arg1;
1428 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1429         // remove also the arg
1430         return 1;
1431 #else
1432         // don't remove "-geometry"
1433         return -1;
1434 #endif
1435 }
1436
1437
1438 } // namespace anon
1439
1440
1441 void LyX::easyParse(int & argc, char * argv[])
1442 {
1443         std::map<string, cmd_helper> cmdmap;
1444
1445         cmdmap["-dbg"] = parse_dbg;
1446         cmdmap["-help"] = parse_help;
1447         cmdmap["--help"] = parse_help;
1448         cmdmap["-version"] = parse_version;
1449         cmdmap["--version"] = parse_version;
1450         cmdmap["-sysdir"] = parse_sysdir;
1451         cmdmap["-userdir"] = parse_userdir;
1452         cmdmap["-x"] = parse_execute;
1453         cmdmap["--execute"] = parse_execute;
1454         cmdmap["-e"] = parse_export;
1455         cmdmap["--export"] = parse_export;
1456         cmdmap["-i"] = parse_import;
1457         cmdmap["--import"] = parse_import;
1458         cmdmap["-geometry"] = parse_geometry;
1459
1460         for (int i = 1; i < argc; ++i) {
1461                 std::map<string, cmd_helper>::const_iterator it
1462                         = cmdmap.find(argv[i]);
1463
1464                 // don't complain if not found - may be parsed later
1465                 if (it == cmdmap.end())
1466                         continue;
1467
1468                 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1469                 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1470
1471                 int const remove = 1 + it->second(arg, arg2);
1472
1473                 // Now, remove used arguments by shifting
1474                 // the following ones remove places down.
1475                 if (remove > 0) {
1476                         argc -= remove;
1477                         for (int j = i; j < argc; ++j)
1478                                 argv[j] = argv[j + remove];
1479                         --i;
1480                 }
1481         }
1482
1483         batch_command = batch;
1484 }
1485
1486
1487 FuncStatus getStatus(FuncRequest const & action)
1488 {
1489         return LyX::ref().lyxFunc().getStatus(action);
1490 }
1491
1492
1493 void dispatch(FuncRequest const & action)
1494 {
1495         LyX::ref().lyxFunc().dispatch(action);
1496 }
1497
1498
1499 BufferList & theBufferList()
1500 {
1501         return LyX::ref().bufferList();
1502 }
1503
1504
1505 LyXFunc & theLyXFunc()
1506 {
1507         return LyX::ref().lyxFunc();
1508 }
1509
1510
1511 Server & theServer()
1512 {
1513         // FIXME: this should not be use_gui dependent
1514         BOOST_ASSERT(use_gui);
1515         return LyX::ref().server();
1516 }
1517
1518
1519 ServerSocket & theServerSocket()
1520 {
1521         // FIXME: this should not be use_gui dependent
1522         BOOST_ASSERT(use_gui);
1523         return LyX::ref().socket();
1524 }
1525
1526
1527 KeyMap & theTopLevelKeymap()
1528 {
1529         BOOST_ASSERT(use_gui);
1530         return LyX::ref().topLevelKeymap();
1531 }
1532
1533
1534 Converters & theConverters()
1535 {
1536         return  LyX::ref().converters();
1537 }
1538
1539
1540 Converters & theSystemConverters()
1541 {
1542         return  LyX::ref().systemConverters();
1543 }
1544
1545
1546 Movers & theMovers()
1547 {
1548         return  LyX::ref().pimpl_->movers_;
1549 }
1550
1551
1552 Mover const & getMover(std::string  const & fmt)
1553 {
1554         return  LyX::ref().pimpl_->movers_(fmt);
1555 }
1556
1557
1558 void setMover(std::string const & fmt, std::string const & command)
1559 {
1560         LyX::ref().pimpl_->movers_.set(fmt, command);
1561 }
1562
1563
1564 Movers & theSystemMovers()
1565 {
1566         return  LyX::ref().pimpl_->system_movers_;
1567 }
1568
1569
1570 Messages & getMessages(std::string const & language)
1571 {
1572         return LyX::ref().getMessages(language);
1573 }
1574
1575
1576 Messages & getGuiMessages()
1577 {
1578         return LyX::ref().getGuiMessages();
1579 }
1580
1581 } // namespace lyx