]> git.lyx.org Git - lyx.git/blob - src/lyx_main.C
Partial fix bug 2092: branches not propagated to child documents
[lyx.git] / src / lyx_main.C
1 /**
2  * \file lyx_main.C
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_main.h"
19
20 #include "buffer.h"
21 #include "buffer_funcs.h"
22 #include "bufferlist.h"
23 #include "converter.h"
24 #include "debug.h"
25 #include "encoding.h"
26 #include "errorlist.h"
27 #include "format.h"
28 #include "gettext.h"
29 #include "kbmap.h"
30 #include "language.h"
31 #include "lastfiles.h"
32 #include "LColor.h"
33 #include "lyxfunc.h"
34 #include "lyxlex.h"
35 #include "lyxrc.h"
36 #include "lyxtextclasslist.h"
37 #include "lyxserver.h"
38 #include "MenuBackend.h"
39 #include "mover.h"
40 #include "ToolbarBackend.h"
41
42 #include "mathed/math_inset.h"
43
44 #include "frontends/Alert.h"
45 #include "frontends/lyx_gui.h"
46 #include "frontends/LyXView.h"
47
48 #include "support/environment.h"
49 #include "support/filetools.h"
50 #include "support/lyxlib.h"
51 #include "support/os.h"
52 #include "support/package.h"
53 #include "support/path.h"
54
55 #include <boost/bind.hpp>
56 #include <boost/filesystem/operations.hpp>
57
58 #include <iostream>
59 #include <csignal>
60
61 using lyx::support::AddName;
62 using lyx::support::AddPath;
63 using lyx::support::bformat;
64 using lyx::support::createDirectory;
65 using lyx::support::createLyXTmpDir;
66 using lyx::support::FileSearch;
67 using lyx::support::getEnv;
68 using lyx::support::i18nLibFileSearch;
69 using lyx::support::LibFileSearch;
70 using lyx::support::package;
71 using lyx::support::Path;
72 using lyx::support::prependEnvPath;
73 using lyx::support::QuoteName;
74 using lyx::support::rtrim;
75
76 namespace os = lyx::support::os;
77 namespace fs = boost::filesystem;
78
79 using std::endl;
80 using std::string;
81 using std::vector;
82
83 #ifndef CXX_GLOBAL_CSTD
84 using std::exit;
85 using std::signal;
86 using std::system;
87 #endif
88
89
90 extern void QuitLyX(bool);
91
92 extern LyXServer * lyxserver;
93
94 // This is the global bufferlist object
95 BufferList bufferlist;
96
97 // convenient to have it here.
98 boost::scoped_ptr<kb_keymap> toplevel_keymap;
99
100 namespace {
101
102 // Filled with the command line arguments "foo" of "-sysdir foo" or
103 // "-userdir foo".
104 string cl_system_support;
105 string cl_user_support;
106
107
108 void showFileError(string const & error)
109 {
110         Alert::warning(_("Could not read configuration file"),
111                    bformat(_("Error while reading the configuration file\n%1$s.\n"
112                      "Please check your installation."), error));
113         exit(EXIT_FAILURE);
114 }
115
116
117 void reconfigureUserLyXDir()
118 {
119         string const configure_script =
120                 AddName(package().system_support(), "configure");
121         string const configure_command =
122                 "sh " + QuoteName(configure_script);
123
124         lyxerr << _("LyX: reconfiguring user directory") << endl;
125         Path p(package().user_support());
126         ::system(configure_command.c_str());
127         lyxerr << "LyX: " << _("Done!") << endl;
128 }
129
130 } // namespace anon
131
132
133 boost::scoped_ptr<LyX> LyX::singleton_;
134
135 void LyX::exec(int & argc, char * argv[])
136 {
137         BOOST_ASSERT(!singleton_.get());
138         // We must return from this before launching the gui so that
139         // other parts of the code can access singleton_ through
140         // LyX::ref and LyX::cref.
141         singleton_.reset(new LyX);
142         // Start the real execution loop.
143         singleton_->priv_exec(argc, argv);
144 }
145
146
147 LyX & LyX::ref()
148 {
149         BOOST_ASSERT(singleton_.get());
150         return *singleton_.get();
151 }
152
153
154 LyX const & LyX::cref()
155 {
156         BOOST_ASSERT(singleton_.get());
157         return *singleton_.get();
158 }
159
160
161 LyX::LyX()
162         : first_start(false)
163 {}
164
165
166 LastFiles & LyX::lastfiles()
167 {
168         BOOST_ASSERT(lastfiles_.get());
169         return *lastfiles_.get();
170 }
171
172
173 LastFiles const & LyX::lastfiles() const
174 {
175         BOOST_ASSERT(lastfiles_.get());
176         return *lastfiles_.get();
177 }
178
179
180 void LyX::addLyXView(boost::shared_ptr<LyXView> const & lyxview)
181 {
182         views_.push_back(lyxview);
183 }
184
185
186 Buffer const * const LyX::updateInset(InsetBase const * inset) const
187 {
188         if (!inset)
189                 return 0;
190
191         Buffer const * buffer_ptr = 0;
192         ViewList::const_iterator it = views_.begin();
193         ViewList::const_iterator const end = views_.end();
194         for (; it != end; ++it) {
195                 Buffer const * ptr = (*it)->updateInset(inset);
196                 if (ptr)
197                         buffer_ptr = ptr;
198         }
199         return buffer_ptr;
200 }
201
202
203 void LyX::priv_exec(int & argc, char * argv[])
204 {
205         // Here we need to parse the command line. At least
206         // we need to parse for "-dbg" and "-help"
207         bool const want_gui = easyParse(argc, argv);
208
209         lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
210                                    lyx::support::top_build_dir_is_one_level_up);
211
212         if (want_gui)
213                 lyx_gui::parse_init(argc, argv);
214
215         // check for any spurious extra arguments
216         // other than documents
217         for (int argi = 1; argi < argc ; ++argi) {
218                 if (argv[argi][0] == '-') {
219                         lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
220                                 argv[argi]) << endl;
221                         exit(1);
222                 }
223         }
224
225         // Initialization of LyX (reads lyxrc and more)
226         lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
227         init(want_gui);
228         lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
229
230         if (want_gui)
231                 lyx_gui::parse_lyxrc();
232
233         initMath();
234
235         vector<string> files;
236
237         for (int argi = argc - 1; argi >= 1; --argi)
238                 files.push_back(os::internal_path(argv[argi]));
239
240         if (first_start)
241                 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
242
243         // Execute batch commands if available
244         if (!batch_command.empty()) {
245
246                 lyxerr[Debug::INIT] << "About to handle -x '"
247                        << batch_command << '\'' << endl;
248
249                 Buffer * last_loaded = 0;
250
251                 vector<string>::const_iterator it = files.begin();
252                 vector<string>::const_iterator end = files.end();
253
254                 for (; it != end; ++it) {
255                         // get absolute path of file and add ".lyx" to
256                         // the filename if necessary
257                         string s = FileSearch(string(), *it, "lyx");
258                         if (s.empty()) {
259                                 last_loaded = newFile(*it, string(), true);
260                         } else {
261                                 Buffer * buf = bufferlist.newBuffer(s, false);
262                                 buf->error.connect(boost::bind(&LyX::printError, this, _1));
263                                 if (loadLyXFile(buf, s))
264                                         last_loaded = buf;
265                                 else
266                                         bufferlist.release(buf);
267                         }
268                 }
269
270                 // try to dispatch to last loaded buffer first
271                 if (last_loaded) {
272                         bool success = false;
273                         if (last_loaded->dispatch(batch_command, &success)) {
274                                 QuitLyX(false);
275                                 exit(!success);
276                         }
277                 }
278                 files.clear(); // the files are already loaded
279         }
280
281         if (want_gui)
282                 lyx_gui::start(batch_command, files);
283         else {
284                 // Something went wrong above
285                 QuitLyX(false);
286                 exit(EXIT_FAILURE);
287         }
288 }
289
290
291 /*
292 Signals and Windows
293 ===================
294 The SIGHUP signal does not exist on Windows and does not need to be handled.
295
296 Windows handles SIGFPE and SIGSEGV signals as expected.
297
298 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
299 cause a new thread to be spawned. This may well result in unexpected
300 behaviour by the single-threaded LyX.
301
302 SIGTERM signals will come only from another process actually sending
303 that signal using 'raise' in Windows' POSIX compatability layer. It will
304 not come from the general "terminate process" methods that everyone
305 actually uses (and which can't be trapped). Killing an app 'politely' on
306 Windows involves first sending a WM_CLOSE message, something that is
307 caught already by the Qt frontend.
308
309 For more information see:
310
311 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
312 ...signals are mostly useless on Windows for a variety of reasons that are
313 Windows specific...
314
315 'UNIX Application Migration Guide, Chapter 9'
316 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
317
318 'How To Terminate an Application "Cleanly" in Win32'
319 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
320 */
321 extern "C" {
322
323 static void error_handler(int err_sig)
324 {
325         // Throw away any signals other than the first one received.
326         static sig_atomic_t handling_error = false;
327         if (handling_error)
328                 return;
329         handling_error = true;
330
331         // We have received a signal indicating a fatal error, so
332         // try and save the data ASAP.
333         LyX::cref().emergencyCleanup();
334
335         // These lyxerr calls may or may not work:
336
337         // Signals are asynchronous, so the main program may be in a very
338         // fragile state when a signal is processed and thus while a signal
339         // handler function executes.
340         // In general, therefore, we should avoid performing any
341         // I/O operations or calling most library and system functions from
342         // signal handlers.
343
344         // This shouldn't matter here, however, as we've already invoked
345         // emergencyCleanup.
346         switch (err_sig) {
347 #ifdef SIGHUP
348         case SIGHUP:
349                 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
350                 break;
351 #endif
352         case SIGFPE:
353                 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
354                 break;
355         case SIGSEGV:
356                 lyxerr << "\nlyx: SIGSEGV signal caught\n"
357                           "Sorry, you have found a bug in LyX. "
358                           "Please read the bug-reporting instructions "
359                           "in Help->Introduction and send us a bug report, "
360                           "if necessary. Thanks !\nBye." << endl;
361                 break;
362         case SIGINT:
363         case SIGTERM:
364                 // no comments
365                 break;
366         }
367
368         // Deinstall the signal handlers
369 #ifdef SIGHUP
370         signal(SIGHUP, SIG_DFL);
371 #endif
372         signal(SIGINT, SIG_DFL);
373         signal(SIGFPE, SIG_DFL);
374         signal(SIGSEGV, SIG_DFL);
375         signal(SIGTERM, SIG_DFL);
376
377 #ifdef SIGHUP
378         if (err_sig == SIGSEGV ||
379             (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
380 #else
381         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
382 #endif
383                 lyx::support::abort();
384         exit(0);
385 }
386
387 }
388
389
390 void LyX::printError(ErrorItem const & ei)
391 {
392         std::cerr << _("LyX: ") << ei.error
393                   << ':' << ei.description << std::endl;
394
395 }
396
397
398 void LyX::init(bool gui)
399 {
400 #ifdef SIGHUP
401         signal(SIGHUP, error_handler);
402 #endif
403         signal(SIGFPE, error_handler);
404         signal(SIGSEGV, error_handler);
405         signal(SIGINT, error_handler);
406         signal(SIGTERM, error_handler);
407         // SIGPIPE can be safely ignored.
408
409         // Check that user LyX directory is ok. We don't do that if
410         // running in batch mode.
411         bool reconfigure = false;
412         if (gui) {
413                 reconfigure =
414                         queryUserLyXDir(package().explicit_user_support());
415         } else {
416                 first_start = false;
417         }
418
419         // Disable gui when easyparse says so
420         lyx_gui::use_gui = gui;
421
422         lyxrc.tempdir_path = package().temp_dir();
423         lyxrc.document_path = package().document_dir();
424
425         if (lyxrc.template_path.empty()) {
426                 lyxrc.template_path = AddPath(package().system_support(),
427                                               "templates");
428         }
429
430         if (lyxrc.lastfiles.empty()) {
431                 lyxrc.lastfiles = AddName(package().user_support(), "lastfiles");
432         }
433
434         if (lyxrc.roman_font_name.empty())
435                 lyxrc.roman_font_name = lyx_gui::roman_font_name();
436         if (lyxrc.sans_font_name.empty())
437                 lyxrc.sans_font_name = lyx_gui::sans_font_name();
438         if (lyxrc.typewriter_font_name.empty())
439                 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
440
441         //
442         // Read configuration files
443         //
444
445         readRcFile("lyxrc.defaults");
446         system_lyxrc = lyxrc;
447         system_formats = formats;
448         system_converters = converters;
449         system_movers = movers;
450         system_lcolor = lcolor;
451
452         string prefsfile = "preferences";
453         // back compatibility to lyxs < 1.1.6
454         if (LibFileSearch(string(), prefsfile).empty())
455                 prefsfile = "lyxrc";
456         if (!LibFileSearch(string(), prefsfile).empty())
457                 readRcFile(prefsfile);
458
459         readEncodingsFile("encodings");
460         readLanguagesFile("languages");
461
462         // Load the layouts
463         lyxerr[Debug::INIT] << "Reading layouts..." << endl;
464         LyXSetStyle();
465
466         if (gui) {
467                 // Set up bindings
468                 toplevel_keymap.reset(new kb_keymap);
469                 defaultKeyBindings(toplevel_keymap.get());
470                 toplevel_keymap->read(lyxrc.bind_file);
471
472                 // Read menus
473                 readUIFile(lyxrc.ui_file);
474         }
475
476         if (lyxerr.debugging(Debug::LYXRC))
477                 lyxrc.print();
478
479         os::cygwin_path_fix(lyxrc.cygwin_path_fix);
480         if (!lyxrc.path_prefix.empty())
481                 prependEnvPath("PATH", lyxrc.path_prefix);
482
483 #if !defined (USE_POSIX_PACKAGING)
484         // Add the directory containing the LyX executable to the path
485         // so that LyX can find things like tex2lyx.
486         if (package().build_support().empty())
487                 prependEnvPath("PATH", package().binary_dir());
488 #endif
489
490         // Having reset the PATH we're now in a position to run configure
491         // if necessary.
492         if (reconfigure)
493                 reconfigureUserLyXDir();
494
495         if (fs::exists(lyxrc.document_path) &&
496             fs::is_directory(lyxrc.document_path))
497                 package().document_dir() = lyxrc.document_path;
498
499         package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
500         if (package().temp_dir().empty()) {
501                 Alert::error(_("Could not create temporary directory"),
502                              bformat(_("Could not create a temporary directory in\n"
503                                        "%1$s. Make sure that this\n"
504                                        "path exists and is writable and try again."),
505                                      lyxrc.tempdir_path));
506                 // createLyXTmpDir() tries sufficiently hard to create a
507                 // usable temp dir, so the probability to come here is
508                 // close to zero. We therefore don't try to overcome this
509                 // problem with e.g. asking the user for a new path and
510                 // trying again but simply exit.
511                 exit(EXIT_FAILURE);
512         }
513
514         if (lyxerr.debugging(Debug::INIT)) {
515                 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
516         }
517
518         lyxerr[Debug::INIT] << "Reading lastfiles `"
519                             << lyxrc.lastfiles << "'..." << endl;
520         lastfiles_.reset(new LastFiles(lyxrc.lastfiles,
521                                        lyxrc.check_lastfiles,
522                                        lyxrc.num_lastfiles));
523 }
524
525
526 void LyX::defaultKeyBindings(kb_keymap  * kbmap)
527 {
528         kbmap->bind("Right", FuncRequest(LFUN_RIGHT));
529         kbmap->bind("Left", FuncRequest(LFUN_LEFT));
530         kbmap->bind("Up", FuncRequest(LFUN_UP));
531         kbmap->bind("Down", FuncRequest(LFUN_DOWN));
532
533         kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
534         kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
535         kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
536         kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
537
538         kbmap->bind("Home", FuncRequest(LFUN_HOME));
539         kbmap->bind("End", FuncRequest(LFUN_END));
540         kbmap->bind("Prior", FuncRequest(LFUN_PRIOR));
541         kbmap->bind("Next", FuncRequest(LFUN_NEXT));
542
543         kbmap->bind("Return", FuncRequest(LFUN_BREAKPARAGRAPH));
544         //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
545
546         kbmap->bind("Delete", FuncRequest(LFUN_DELETE));
547         kbmap->bind("BackSpace", FuncRequest(LFUN_BACKSPACE));
548
549         // kbmap->bindings to enable the use of the numeric keypad
550         // e.g. Num Lock set
551         //kbmap->bind("KP_0", FuncRequest(LFUN_SELFINSERT));
552         //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELFINSERT));
553         kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAKPARAGRAPH));
554         //kbmap->bind("KP_1", FuncRequest(LFUN_SELFINSERT));
555         //kbmap->bind("KP_2", FuncRequest(LFUN_SELFINSERT));
556         //kbmap->bind("KP_3", FuncRequest(LFUN_SELFINSERT));
557         //kbmap->bind("KP_4", FuncRequest(LFUN_SELFINSERT));
558         //kbmap->bind("KP_5", FuncRequest(LFUN_SELFINSERT));
559         //kbmap->bind("KP_6", FuncRequest(LFUN_SELFINSERT));
560         //kbmap->bind("KP_Add", FuncRequest(LFUN_SELFINSERT));
561         //kbmap->bind("KP_7", FuncRequest(LFUN_SELFINSERT));
562         //kbmap->bind("KP_8", FuncRequest(LFUN_SELFINSERT));
563         //kbmap->bind("KP_9", FuncRequest(LFUN_SELFINSERT));
564         //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELFINSERT));
565         //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELFINSERT));
566         //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELFINSERT));
567         kbmap->bind("KP_Right", FuncRequest(LFUN_RIGHT));
568         kbmap->bind("KP_Left", FuncRequest(LFUN_LEFT));
569         kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
570         kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
571         kbmap->bind("KP_Home", FuncRequest(LFUN_HOME));
572         kbmap->bind("KP_End", FuncRequest(LFUN_END));
573         kbmap->bind("KP_Prior", FuncRequest(LFUN_PRIOR));
574         kbmap->bind("KP_Next", FuncRequest(LFUN_NEXT));
575 }
576
577
578 void LyX::emergencyCleanup() const
579 {
580         // what to do about tmpfiles is non-obvious. we would
581         // like to delete any we find, but our lyxdir might
582         // contain documents etc. which might be helpful on
583         // a crash
584
585         bufferlist.emergencyWriteAll();
586         if (lyxserver)
587                 lyxserver->emergencyCleanup();
588 }
589
590
591 void LyX::deadKeyBindings(kb_keymap * kbmap)
592 {
593         // bindKeyings for transparent handling of deadkeys
594         // The keysyms are gotten from XFree86 X11R6
595         kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACUTE));
596         kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_BREVE));
597         kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_CARON));
598         kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_CEDILLA));
599         kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_CIRCLE));
600         kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_CIRCUMFLEX));
601         kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_DOT));
602         kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_GRAVE));
603         kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_HUNG_UMLAUT));
604         kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_MACRON));
605         // nothing with this name
606         // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_SPECIAL_CARON);
607         kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_TILDE));
608         kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_UMLAUT));
609         // nothing with this name either...
610         //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_UNDERBAR));
611         kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_UNDERDOT));
612         kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_TIE));
613         kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_OGONEK));
614 }
615
616
617 bool LyX::queryUserLyXDir(bool explicit_userdir)
618 {
619         bool reconfigure = false;
620
621         // Does user directory exist?
622         if (fs::exists(package().user_support()) &&
623             fs::is_directory(package().user_support())) {
624                 first_start = false;
625                 string const configure_script =
626                         AddName(package().system_support(), "configure");
627                 string const userDefaults =
628                         AddName(package().user_support(), "lyxrc.defaults");
629                 if (fs::exists(configure_script) &&
630                     fs::exists(userDefaults) &&
631                     fs::last_write_time(configure_script)
632                     > fs::last_write_time(userDefaults)) {
633                         reconfigure = true;
634                 }
635                 return reconfigure;
636         }
637
638         first_start = !explicit_userdir;
639
640         // If the user specified explicitly a directory, ask whether
641         // to create it. If the user says "no", then exit.
642         if (explicit_userdir &&
643             Alert::prompt(
644                     _("Missing user LyX directory"),
645                     bformat(_("You have specified a non-existent user "
646                               "LyX directory, %1$s.\n"
647                               "It is needed to keep your own configuration."),
648                             package().user_support()),
649                     1, 0,
650                     _("&Create directory."),
651                     _("&Exit LyX."))) {
652                 lyxerr << _("No user LyX directory. Exiting.") << endl;
653                 exit(1);
654         }
655
656         lyxerr << bformat(_("LyX: Creating directory %1$s"),
657                           package().user_support())
658                << endl;
659         reconfigure = true;
660
661         if (!createDirectory(package().user_support(), 0755)) {
662                 // Failed, so let's exit.
663                 lyxerr << _("Failed to create directory. Exiting.")
664                        << endl;
665                 exit(1);
666         }
667
668         return reconfigure;
669 }
670
671
672 void LyX::readRcFile(string const & name)
673 {
674         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
675
676         string const lyxrc_path = LibFileSearch(string(), name);
677         if (!lyxrc_path.empty()) {
678
679                 lyxerr[Debug::INIT] << "Found " << name
680                                     << " in " << lyxrc_path << endl;
681
682                 if (lyxrc.read(lyxrc_path) >= 0)
683                         return;
684         }
685
686         showFileError(name);
687 }
688
689
690 // Read the ui file `name'
691 void LyX::readUIFile(string const & name)
692 {
693         enum Uitags {
694                 ui_menuset = 1,
695                 ui_toolbar,
696                 ui_toolbars,
697                 ui_include,
698                 ui_last
699         };
700
701         struct keyword_item uitags[ui_last - 1] = {
702                 { "include", ui_include },
703                 { "menuset", ui_menuset },
704                 { "toolbar", ui_toolbar },
705                 { "toolbars", ui_toolbars }
706         };
707
708         // Ensure that a file is read only once (prevents include loops)
709         static std::list<string> uifiles;
710         std::list<string>::const_iterator it  = uifiles.begin();
711         std::list<string>::const_iterator end = uifiles.end();
712         it = std::find(it, end, name);
713         if (it != end) {
714                 lyxerr[Debug::INIT] << "UI file '" << name
715                                     << "' has been read already. "
716                                     << "Is this an include loop?"
717                                     << endl;
718                 return;
719         }
720
721         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
722
723         string const ui_path = LibFileSearch("ui", name, "ui");
724
725         if (ui_path.empty()) {
726                 lyxerr[Debug::INIT] << "Could not find " << name << endl;
727                 showFileError(name);
728                 return;
729         }
730         uifiles.push_back(name);
731
732         lyxerr[Debug::INIT] << "Found " << name
733                             << " in " << ui_path << endl;
734         LyXLex lex(uitags, ui_last - 1);
735         lex.setFile(ui_path);
736         if (!lex.isOK()) {
737                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
738                        << endl;
739         }
740
741         if (lyxerr.debugging(Debug::PARSER))
742                 lex.printTable(lyxerr);
743
744         while (lex.isOK()) {
745                 switch (lex.lex()) {
746                 case ui_include: {
747                         lex.next(true);
748                         string const file = lex.getString();
749                         readUIFile(file);
750                         break;
751                 }
752                 case ui_menuset:
753                         menubackend.read(lex);
754                         break;
755
756                 case ui_toolbar:
757                         toolbarbackend.read(lex);
758                         break;
759
760                 case ui_toolbars:
761                         toolbarbackend.readToolbars(lex);
762                         break;
763
764                 default:
765                         if (!rtrim(lex.getString()).empty())
766                                 lex.printError("LyX::ReadUIFile: "
767                                                "Unknown menu tag: `$$Token'");
768                         break;
769                 }
770         }
771 }
772
773
774 // Read the languages file `name'
775 void LyX::readLanguagesFile(string const & name)
776 {
777         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
778
779         string const lang_path = LibFileSearch(string(), name);
780         if (lang_path.empty()) {
781                 showFileError(name);
782                 return;
783         }
784         languages.read(lang_path);
785 }
786
787
788 // Read the encodings file `name'
789 void LyX::readEncodingsFile(string const & name)
790 {
791         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
792
793         string const enc_path = LibFileSearch(string(), name);
794         if (enc_path.empty()) {
795                 showFileError(name);
796                 return;
797         }
798         encodings.read(enc_path);
799 }
800
801
802 namespace {
803
804 bool is_gui = true;
805 string batch;
806
807 /// return the the number of arguments consumed
808 typedef boost::function<int(string const &, string const &)> cmd_helper;
809
810 int parse_dbg(string const & arg, string const &)
811 {
812         if (arg.empty()) {
813                 lyxerr << _("List of supported debug flags:") << endl;
814                 Debug::showTags(lyxerr);
815                 exit(0);
816         }
817         lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
818
819         lyxerr.level(Debug::value(arg));
820         Debug::showLevel(lyxerr, lyxerr.level());
821         return 1;
822 }
823
824
825 int parse_help(string const &, string const &)
826 {
827         lyxerr <<
828                 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
829                   "Command line switches (case sensitive):\n"
830                   "\t-help              summarize LyX usage\n"
831                   "\t-userdir dir       try to set user directory to dir\n"
832                   "\t-sysdir dir        try to set system directory to dir\n"
833                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
834                   "\t-dbg feature[,feature]...\n"
835                   "                  select the features to debug.\n"
836                   "                  Type `lyx -dbg' to see the list of features\n"
837                   "\t-x [--execute] command\n"
838                   "                  where command is a lyx command.\n"
839                   "\t-e [--export] fmt\n"
840                   "                  where fmt is the export format of choice.\n"
841                   "\t-i [--import] fmt file.xxx\n"
842                   "                  where fmt is the import format of choice\n"
843                   "                  and file.xxx is the file to be imported.\n"
844                   "\t-version        summarize version and build info\n"
845                   "Check the LyX man page for more details.") << endl;
846         exit(0);
847         return 0;
848 }
849
850 int parse_version(string const &, string const &)
851 {
852         lyxerr << "LyX " << lyx_version
853                << " of " << lyx_release_date << endl;
854         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
855
856         lyxerr << lyx_version_info << endl;
857         exit(0);
858         return 0;
859 }
860
861 int parse_sysdir(string const & arg, string const &)
862 {
863         if (arg.empty()) {
864                 lyxerr << _("Missing directory for -sysdir switch") << endl;
865                 exit(1);
866         }
867         cl_system_support = arg;
868         return 1;
869 }
870
871 int parse_userdir(string const & arg, string const &)
872 {
873         if (arg.empty()) {
874                 lyxerr << _("Missing directory for -userdir switch") << endl;
875                 exit(1);
876         }
877         cl_user_support = arg;
878         return 1;
879 }
880
881 int parse_execute(string const & arg, string const &)
882 {
883         if (arg.empty()) {
884                 lyxerr << _("Missing command string after --execute switch") << endl;
885                 exit(1);
886         }
887         batch = arg;
888         return 1;
889 }
890
891 int parse_export(string const & type, string const &)
892 {
893         if (type.empty()) {
894                 lyxerr << _("Missing file type [eg latex, ps...] after "
895                         "--export switch") << endl;
896                 exit(1);
897         }
898         batch = "buffer-export " + type;
899         is_gui = false;
900         return 1;
901 }
902
903 int parse_import(string const & type, string const & file)
904 {
905         if (type.empty()) {
906                 lyxerr << _("Missing file type [eg latex, ps...] after "
907                         "--import switch") << endl;
908                 exit(1);
909         }
910         if (file.empty()) {
911                 lyxerr << _("Missing filename for --import") << endl;
912                 exit(1);
913         }
914
915         batch = "buffer-import " + type + ' ' + file;
916         return 2;
917 }
918
919 } // namespace anon
920
921
922 bool LyX::easyParse(int & argc, char * argv[])
923 {
924         std::map<string, cmd_helper> cmdmap;
925
926         cmdmap["-dbg"] = parse_dbg;
927         cmdmap["-help"] = parse_help;
928         cmdmap["--help"] = parse_help;
929         cmdmap["-version"] = parse_version;
930         cmdmap["--version"] = parse_version;
931         cmdmap["-sysdir"] = parse_sysdir;
932         cmdmap["-userdir"] = parse_userdir;
933         cmdmap["-x"] = parse_execute;
934         cmdmap["--execute"] = parse_execute;
935         cmdmap["-e"] = parse_export;
936         cmdmap["--export"] = parse_export;
937         cmdmap["-i"] = parse_import;
938         cmdmap["--import"] = parse_import;
939
940         for (int i = 1; i < argc; ++i) {
941                 std::map<string, cmd_helper>::const_iterator it
942                         = cmdmap.find(argv[i]);
943
944                 // don't complain if not found - may be parsed later
945                 if (it == cmdmap.end())
946                         continue;
947
948                 string arg((i + 1 < argc) ? argv[i + 1] : "");
949                 string arg2((i + 2 < argc) ? argv[i + 2] : "");
950
951                 int const remove = 1 + it->second(arg, arg2);
952
953                 // Now, remove used arguments by shifting
954                 // the following ones remove places down.
955                 argc -= remove;
956                 for (int j = i; j < argc; ++j)
957                         argv[j] = argv[j + remove];
958                 --i;
959         }
960
961         batch_command = batch;
962
963         return is_gui;
964 }