3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
21 #include "buffer_funcs.h"
22 #include "bufferlist.h"
23 #include "converter.h"
26 #include "errorlist.h"
37 #include "lyxtextclasslist.h"
38 #include "lyxserver.h"
39 #include "MenuBackend.h"
41 #include "ToolbarBackend.h"
43 #include "mathed/math_inset.h"
45 #include "frontends/Alert.h"
46 #include "frontends/lyx_gui.h"
47 #include "frontends/LyXView.h"
49 #include "support/environment.h"
50 #include "support/filetools.h"
51 #include "support/lyxlib.h"
52 #include "support/convert.h"
53 #include "support/os.h"
54 #include "support/package.h"
55 #include "support/path.h"
56 #include "support/systemcall.h"
58 #include <boost/bind.hpp>
59 #include <boost/filesystem/operations.hpp>
64 using lyx::support::addName;
65 using lyx::support::addPath;
66 using lyx::support::bformat;
67 using lyx::support::createDirectory;
68 using lyx::support::createLyXTmpDir;
69 using lyx::support::fileSearch;
70 using lyx::support::getEnv;
71 using lyx::support::i18nLibFileSearch;
72 using lyx::support::libFileSearch;
73 using lyx::support::package;
74 using lyx::support::Path;
75 using lyx::support::prependEnvPath;
76 using lyx::support::rtrim;
77 using lyx::support::Systemcall;
79 namespace os = lyx::support::os;
80 namespace fs = boost::filesystem;
86 #ifndef CXX_GLOBAL_CSTD
93 extern LyXServer * lyxserver;
95 // This is the global bufferlist object
96 BufferList bufferlist;
98 // convenient to have it here.
99 boost::scoped_ptr<kb_keymap> toplevel_keymap;
103 // Filled with the command line arguments "foo" of "-sysdir foo" or
105 string cl_system_support;
106 string cl_user_support;
109 void lyx_exit(int status)
111 // FIXME: We should not directly call exit(), since it only
112 // guarantees a return to the system, no application cleanup.
113 // This may cause troubles with not executed destructors.
114 if (lyx_gui::use_gui)
115 // lyx_gui::exit may return and only schedule the exit
116 lyx_gui::exit(status);
121 void showFileError(string const & error)
123 Alert::warning(_("Could not read configuration file"),
124 bformat(_("Error while reading the configuration file\n%1$s.\n"
125 "Please check your installation."), error));
129 void reconfigureUserLyXDir()
131 string const configure_command = package().configure_command();
133 lyxerr << _("LyX: reconfiguring user directory") << endl;
134 Path p(package().user_support());
136 one.startscript(Systemcall::Wait, configure_command);
137 lyxerr << "LyX: " << _("Done!") << endl;
143 boost::scoped_ptr<LyX> LyX::singleton_;
145 int LyX::exec(int & argc, char * argv[])
147 BOOST_ASSERT(!singleton_.get());
148 // We must return from this before launching the gui so that
149 // other parts of the code can access singleton_ through
150 // LyX::ref and LyX::cref.
151 singleton_.reset(new LyX);
152 // Start the real execution loop.
153 return singleton_->priv_exec(argc, argv);
159 BOOST_ASSERT(singleton_.get());
160 return *singleton_.get();
164 LyX const & LyX::cref()
166 BOOST_ASSERT(singleton_.get());
167 return *singleton_.get();
172 : first_start(false), geometryOption_(false)
176 lyx::Session & LyX::session()
178 BOOST_ASSERT(session_.get());
179 return *session_.get();
183 lyx::Session const & LyX::session() const
185 BOOST_ASSERT(session_.get());
186 return *session_.get();
190 void LyX::addLyXView(LyXView * lyxview)
192 views_.push_back(lyxview);
196 Buffer const * const LyX::updateInset(InsetBase const * inset) const
201 Buffer const * buffer_ptr = 0;
202 ViewList::const_iterator it = views_.begin();
203 ViewList::const_iterator const end = views_.end();
204 for (; it != end; ++it) {
205 Buffer const * ptr = (*it)->updateInset(inset);
213 int LyX::priv_exec(int & argc, char * argv[])
215 // Here we need to parse the command line. At least
216 // we need to parse for "-dbg" and "-help"
217 lyx_gui::use_gui = easyParse(argc, argv);
219 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
220 lyx::support::top_build_dir_is_one_level_up);
222 // Start the real execution loop.
223 if (lyx_gui::use_gui)
224 return lyx_gui::exec(argc, argv);
226 return exec2(argc, argv);
230 int LyX::exec2(int & argc, char * argv[])
232 // check for any spurious extra arguments
233 // other than documents
234 for (int argi = 1; argi < argc ; ++argi) {
235 if (argv[argi][0] == '-') {
236 lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
242 // Initialization of LyX (reads lyxrc and more)
243 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
244 bool const success = init();
245 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
249 if (lyx_gui::use_gui)
250 lyx_gui::parse_lyxrc();
252 vector<string> files;
254 for (int argi = argc - 1; argi >= 1; --argi)
255 files.push_back(os::internal_path(argv[argi]));
258 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
260 // Execute batch commands if available
261 if (!batch_command.empty()) {
263 lyxerr[Debug::INIT] << "About to handle -x '"
264 << batch_command << '\'' << endl;
266 Buffer * last_loaded = 0;
268 vector<string>::const_iterator it = files.begin();
269 vector<string>::const_iterator end = files.end();
271 for (; it != end; ++it) {
272 // get absolute path of file and add ".lyx" to
273 // the filename if necessary
274 string s = fileSearch(string(), *it, "lyx");
276 Buffer * const b = newFile(*it, string(), true);
280 Buffer * buf = bufferlist.newBuffer(s, false);
281 if (loadLyXFile(buf, s)) {
283 ErrorList const & el = buf->errorList("Parse");
285 for_each(el.begin(), el.end(),
286 boost::bind(&LyX::printError, this, _1));
289 bufferlist.release(buf);
293 // try to dispatch to last loaded buffer first
295 bool success = false;
296 if (last_loaded->dispatch(batch_command, &success)) {
301 files.clear(); // the files are already loaded
304 if (lyx_gui::use_gui) {
305 // determine windows size and position, from lyxrc and/or session
307 unsigned int width = 690;
308 unsigned int height = 510;
309 bool maximize = false;
311 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
312 width = lyxrc.geometry_width;
313 height = lyxrc.geometry_height;
315 // if lyxrc returns (0,0), then use session info
317 string val = session().loadSessionInfo("WindowWidth");
319 width = convert<unsigned int>(val);
320 val = session().loadSessionInfo("WindowHeight");
322 height = convert<unsigned int>(val);
323 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
326 // if user wants to restore window position
329 if (lyxrc.geometry_xysaved) {
330 string val = session().loadSessionInfo("WindowPosX");
332 posx = convert<int>(val);
333 val = session().loadSessionInfo("WindowPosY");
335 posy = convert<int>(val);
338 if (geometryOption_) {
342 // create the main window
343 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
346 for_each(files.begin(), files.end(),
347 bind(&LyXView::loadLyXFile, view, _1, true));
349 // if a file is specified, I assume that user wants to edit *that* file
350 if (files.empty() && lyxrc.load_session) {
351 vector<string> const & lastopened = session_->lastOpenedFiles();
352 // do not add to the lastfile list since these files are restored from
353 // last seesion, and should be already there (regular files), or should
354 // not be added at all (help files).
355 for_each(lastopened.begin(), lastopened.end(),
356 bind(&LyXView::loadLyXFile, view, _1, false));
358 // clear this list to save a few bytes of RAM
359 session_->clearLastOpenedFiles();
361 return lyx_gui::start(view, batch_command);
363 // Something went wrong above
373 The SIGHUP signal does not exist on Windows and does not need to be handled.
375 Windows handles SIGFPE and SIGSEGV signals as expected.
377 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
378 cause a new thread to be spawned. This may well result in unexpected
379 behaviour by the single-threaded LyX.
381 SIGTERM signals will come only from another process actually sending
382 that signal using 'raise' in Windows' POSIX compatability layer. It will
383 not come from the general "terminate process" methods that everyone
384 actually uses (and which can't be trapped). Killing an app 'politely' on
385 Windows involves first sending a WM_CLOSE message, something that is
386 caught already by the Qt frontend.
388 For more information see:
390 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
391 ...signals are mostly useless on Windows for a variety of reasons that are
394 'UNIX Application Migration Guide, Chapter 9'
395 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
397 'How To Terminate an Application "Cleanly" in Win32'
398 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
402 static void error_handler(int err_sig)
404 // Throw away any signals other than the first one received.
405 static sig_atomic_t handling_error = false;
408 handling_error = true;
410 // We have received a signal indicating a fatal error, so
411 // try and save the data ASAP.
412 LyX::cref().emergencyCleanup();
414 // These lyxerr calls may or may not work:
416 // Signals are asynchronous, so the main program may be in a very
417 // fragile state when a signal is processed and thus while a signal
418 // handler function executes.
419 // In general, therefore, we should avoid performing any
420 // I/O operations or calling most library and system functions from
423 // This shouldn't matter here, however, as we've already invoked
428 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
432 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
435 lyxerr << "\nlyx: SIGSEGV signal caught\n"
436 "Sorry, you have found a bug in LyX. "
437 "Please read the bug-reporting instructions "
438 "in Help->Introduction and send us a bug report, "
439 "if necessary. Thanks !\nBye." << endl;
447 // Deinstall the signal handlers
449 signal(SIGHUP, SIG_DFL);
451 signal(SIGINT, SIG_DFL);
452 signal(SIGFPE, SIG_DFL);
453 signal(SIGSEGV, SIG_DFL);
454 signal(SIGTERM, SIG_DFL);
457 if (err_sig == SIGSEGV ||
458 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
460 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
462 lyx::support::abort();
469 void LyX::printError(ErrorItem const & ei)
471 std::cerr << _("LyX: ") << ei.error
472 << ':' << ei.description << std::endl;
480 signal(SIGHUP, error_handler);
482 signal(SIGFPE, error_handler);
483 signal(SIGSEGV, error_handler);
484 signal(SIGINT, error_handler);
485 signal(SIGTERM, error_handler);
486 // SIGPIPE can be safely ignored.
488 lyxrc.tempdir_path = package().temp_dir();
489 lyxrc.document_path = package().document_dir();
491 if (lyxrc.template_path.empty()) {
492 lyxrc.template_path = addPath(package().system_support(),
496 if (lyxrc.roman_font_name.empty())
497 lyxrc.roman_font_name = lyx_gui::roman_font_name();
498 if (lyxrc.sans_font_name.empty())
499 lyxrc.sans_font_name = lyx_gui::sans_font_name();
500 if (lyxrc.typewriter_font_name.empty())
501 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
504 // Read configuration files
507 // This one may have been distributed along with LyX.
508 if (!readRcFile("lyxrc.dist"))
511 // Set the PATH correctly.
512 #if !defined (USE_POSIX_PACKAGING)
513 // Add the directory containing the LyX executable to the path
514 // so that LyX can find things like tex2lyx.
515 if (package().build_support().empty())
516 prependEnvPath("PATH", package().binary_dir());
518 if (!lyxrc.path_prefix.empty())
519 prependEnvPath("PATH", lyxrc.path_prefix);
521 // Check that user LyX directory is ok.
522 if (queryUserLyXDir(package().explicit_user_support()))
523 reconfigureUserLyXDir();
525 // no need for a splash when there is no GUI
526 if (!lyx_gui::use_gui) {
530 // This one is generated in user_support directory by lib/configure.py.
531 if (!readRcFile("lyxrc.defaults"))
534 // Query the OS to know what formats are viewed natively
535 formats.setAutoOpen();
537 system_lyxrc = lyxrc;
538 system_formats = formats;
539 system_converters = converters;
540 system_movers = movers;
541 system_lcolor = lcolor;
543 // This one is edited through the preferences dialog.
544 if (!readRcFile("preferences"))
547 if (!readEncodingsFile("encodings"))
549 if (!readLanguagesFile("languages"))
553 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
557 if (lyx_gui::use_gui) {
559 toplevel_keymap.reset(new kb_keymap);
560 defaultKeyBindings(toplevel_keymap.get());
561 toplevel_keymap->read(lyxrc.bind_file);
564 if (!readUIFile(lyxrc.ui_file))
568 if (lyxerr.debugging(Debug::LYXRC))
571 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
572 if (!lyxrc.path_prefix.empty())
573 prependEnvPath("PATH", lyxrc.path_prefix);
575 if (fs::exists(lyxrc.document_path) &&
576 fs::is_directory(lyxrc.document_path))
577 package().document_dir() = lyxrc.document_path;
579 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
580 if (package().temp_dir().empty()) {
581 Alert::error(_("Could not create temporary directory"),
582 bformat(_("Could not create a temporary directory in\n"
583 "%1$s. Make sure that this\n"
584 "path exists and is writable and try again."),
585 lyxrc.tempdir_path));
586 // createLyXTmpDir() tries sufficiently hard to create a
587 // usable temp dir, so the probability to come here is
588 // close to zero. We therefore don't try to overcome this
589 // problem with e.g. asking the user for a new path and
590 // trying again but simply exit.
594 if (lyxerr.debugging(Debug::INIT)) {
595 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
598 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
599 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
604 void LyX::defaultKeyBindings(kb_keymap * kbmap)
606 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
607 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
608 kbmap->bind("Up", FuncRequest(LFUN_UP));
609 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
611 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
612 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
613 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
614 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
616 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
617 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
618 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
619 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
621 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
622 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
624 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
625 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
627 // kbmap->bindings to enable the use of the numeric keypad
629 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
630 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
631 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
632 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
645 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
646 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
647 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
648 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
649 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
650 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
651 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
652 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
656 void LyX::emergencyCleanup() const
658 // what to do about tmpfiles is non-obvious. we would
659 // like to delete any we find, but our lyxdir might
660 // contain documents etc. which might be helpful on
663 bufferlist.emergencyWriteAll();
665 lyxserver->emergencyCleanup();
669 void LyX::deadKeyBindings(kb_keymap * kbmap)
671 // bindKeyings for transparent handling of deadkeys
672 // The keysyms are gotten from XFree86 X11R6
673 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
674 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
675 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
676 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
677 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
678 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
679 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
680 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
681 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
682 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
683 // nothing with this name
684 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
685 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
686 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
687 // nothing with this name either...
688 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
689 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
690 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
691 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
697 // return true if file does not exist or is older than configure.py.
698 bool needsUpdate(string const & file)
700 static string const configure_script =
701 addName(package().system_support(), "configure.py");
702 string const absfile =
703 addName(package().user_support(), file);
705 return (! fs::exists(absfile))
706 || (fs::last_write_time(configure_script)
707 > fs::last_write_time(absfile));
713 bool LyX::queryUserLyXDir(bool explicit_userdir)
715 // Does user directory exist?
716 if (fs::exists(package().user_support()) &&
717 fs::is_directory(package().user_support())) {
720 return needsUpdate("lyxrc.defaults")
721 || needsUpdate("textclass.lst")
722 || needsUpdate("packages.lst");
725 first_start = !explicit_userdir;
727 // If the user specified explicitly a directory, ask whether
728 // to create it. If the user says "no", then exit.
729 if (explicit_userdir &&
731 _("Missing user LyX directory"),
732 bformat(_("You have specified a non-existent user "
733 "LyX directory, %1$s.\n"
734 "It is needed to keep your own configuration."),
735 package().user_support()),
737 _("&Create directory"),
739 lyxerr << _("No user LyX directory. Exiting.") << endl;
740 lyx_exit(EXIT_FAILURE);
743 lyxerr << bformat(_("LyX: Creating directory %1$s"),
744 package().user_support())
747 if (!createDirectory(package().user_support(), 0755)) {
748 // Failed, so let's exit.
749 lyxerr << _("Failed to create directory. Exiting.")
751 lyx_exit(EXIT_FAILURE);
758 bool LyX::readRcFile(string const & name)
760 lyxerr[Debug::INIT] << "About to read " << name << "... ";
762 string const lyxrc_path = libFileSearch(string(), name);
763 if (!lyxrc_path.empty()) {
765 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
767 if (lyxrc.read(lyxrc_path) < 0) {
772 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
778 // Read the ui file `name'
779 bool LyX::readUIFile(string const & name)
789 struct keyword_item uitags[ui_last - 1] = {
790 { "include", ui_include },
791 { "menuset", ui_menuset },
792 { "toolbar", ui_toolbar },
793 { "toolbars", ui_toolbars }
796 // Ensure that a file is read only once (prevents include loops)
797 static std::list<string> uifiles;
798 std::list<string>::const_iterator it = uifiles.begin();
799 std::list<string>::const_iterator end = uifiles.end();
800 it = std::find(it, end, name);
802 lyxerr[Debug::INIT] << "UI file '" << name
803 << "' has been read already. "
804 << "Is this an include loop?"
809 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
811 string const ui_path = libFileSearch("ui", name, "ui");
813 if (ui_path.empty()) {
814 lyxerr[Debug::INIT] << "Could not find " << name << endl;
818 uifiles.push_back(name);
820 lyxerr[Debug::INIT] << "Found " << name
821 << " in " << ui_path << endl;
822 LyXLex lex(uitags, ui_last - 1);
823 lex.setFile(ui_path);
825 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
829 if (lyxerr.debugging(Debug::PARSER))
830 lex.printTable(lyxerr);
836 string const file = lex.getString();
837 if (!readUIFile(file))
842 menubackend.read(lex);
846 toolbarbackend.read(lex);
850 toolbarbackend.readToolbars(lex);
854 if (!rtrim(lex.getString()).empty())
855 lex.printError("LyX::ReadUIFile: "
856 "Unknown menu tag: `$$Token'");
864 // Read the languages file `name'
865 bool LyX::readLanguagesFile(string const & name)
867 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
869 string const lang_path = libFileSearch(string(), name);
870 if (lang_path.empty()) {
874 languages.read(lang_path);
879 // Read the encodings file `name'
880 bool LyX::readEncodingsFile(string const & name)
882 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
884 string const enc_path = libFileSearch(string(), name);
885 if (enc_path.empty()) {
889 encodings.read(enc_path);
899 /// return the the number of arguments consumed
900 typedef boost::function<int(string const &, string const &)> cmd_helper;
902 int parse_dbg(string const & arg, string const &)
905 lyxerr << _("List of supported debug flags:") << endl;
906 Debug::showTags(lyxerr);
909 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
911 lyxerr.level(Debug::value(arg));
912 Debug::showLevel(lyxerr, lyxerr.level());
917 int parse_help(string const &, string const &)
920 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
921 "Command line switches (case sensitive):\n"
922 "\t-help summarize LyX usage\n"
923 "\t-userdir dir set user directory to dir\n"
924 "\t-sysdir dir set system directory to dir\n"
925 "\t-geometry WxH+X+Y set geometry of the main window\n"
926 "\t-dbg feature[,feature]...\n"
927 " select the features to debug.\n"
928 " Type `lyx -dbg' to see the list of features\n"
929 "\t-x [--execute] command\n"
930 " where command is a lyx command.\n"
931 "\t-e [--export] fmt\n"
932 " where fmt is the export format of choice.\n"
933 "\t-i [--import] fmt file.xxx\n"
934 " where fmt is the import format of choice\n"
935 " and file.xxx is the file to be imported.\n"
936 "\t-version summarize version and build info\n"
937 "Check the LyX man page for more details.") << endl;
942 int parse_version(string const &, string const &)
944 lyxerr << "LyX " << lyx_version
945 << " (" << lyx_release_date << ")" << endl;
946 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
948 lyxerr << lyx_version_info << endl;
953 int parse_sysdir(string const & arg, string const &)
956 lyxerr << _("Missing directory for -sysdir switch") << endl;
959 cl_system_support = arg;
963 int parse_userdir(string const & arg, string const &)
966 lyxerr << _("Missing directory for -userdir switch") << endl;
969 cl_user_support = arg;
973 int parse_execute(string const & arg, string const &)
976 lyxerr << _("Missing command string after --execute switch") << endl;
983 int parse_export(string const & type, string const &)
986 lyxerr << _("Missing file type [eg latex, ps...] after "
987 "--export switch") << endl;
990 batch = "buffer-export " + type;
995 int parse_import(string const & type, string const & file)
998 lyxerr << _("Missing file type [eg latex, ps...] after "
999 "--import switch") << endl;
1003 lyxerr << _("Missing filename for --import") << endl;
1007 batch = "buffer-import " + type + ' ' + file;
1014 bool LyX::easyParse(int & argc, char * argv[])
1016 std::map<string, cmd_helper> cmdmap;
1018 cmdmap["-dbg"] = parse_dbg;
1019 cmdmap["-help"] = parse_help;
1020 cmdmap["--help"] = parse_help;
1021 cmdmap["-version"] = parse_version;
1022 cmdmap["--version"] = parse_version;
1023 cmdmap["-sysdir"] = parse_sysdir;
1024 cmdmap["-userdir"] = parse_userdir;
1025 cmdmap["-x"] = parse_execute;
1026 cmdmap["--execute"] = parse_execute;
1027 cmdmap["-e"] = parse_export;
1028 cmdmap["--export"] = parse_export;
1029 cmdmap["-i"] = parse_import;
1030 cmdmap["--import"] = parse_import;
1032 for (int i = 1; i < argc; ++i) {
1033 std::map<string, cmd_helper>::const_iterator it
1034 = cmdmap.find(argv[i]);
1036 // check for X11 -geometry option
1037 if (lyx::support::compare(argv[i], "-geometry") == 0)
1038 geometryOption_ = true;
1040 // don't complain if not found - may be parsed later
1041 if (it == cmdmap.end())
1044 string arg((i + 1 < argc) ? argv[i + 1] : "");
1045 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1047 int const remove = 1 + it->second(arg, arg2);
1049 // Now, remove used arguments by shifting
1050 // the following ones remove places down.
1052 for (int j = i; j < argc; ++j)
1053 argv[j] = argv[j + remove];
1057 batch_command = batch;