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