]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
85abc0f1d7d079908383a3d030ce91dc9d4a8c46
[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         // load user bind file user.bind
969         pimpl_->toplevel_keymap_->read("user");
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 (!sup.createDirectory(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