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