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