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::quoteName;
77 using lyx::support::rtrim;
78 using lyx::support::Systemcall;
80 namespace os = lyx::support::os;
81 namespace fs = boost::filesystem;
87 #ifndef CXX_GLOBAL_CSTD
94 extern LyXServer * lyxserver;
96 // This is the global bufferlist object
97 BufferList bufferlist;
99 // convenient to have it here.
100 boost::scoped_ptr<kb_keymap> toplevel_keymap;
104 // Filled with the command line arguments "foo" of "-sysdir foo" or
106 string cl_system_support;
107 string cl_user_support;
110 void lyx_exit(int status)
112 // FIXME: We should not directly call exit(), since it only
113 // guarantees a return to the system, no application cleanup.
114 // This may cause troubles with not executed destructors.
115 if (lyx_gui::use_gui)
116 // lyx_gui::exit may return and only schedule the exit
117 lyx_gui::exit(status);
122 void showFileError(string const & error)
124 Alert::warning(_("Could not read configuration file"),
125 bformat(_("Error while reading the configuration file\n%1$s.\n"
126 "Please check your installation."), error));
130 void reconfigureUserLyXDir()
132 string const configure_command = package().configure_command();
134 lyxerr << _("LyX: reconfiguring user directory") << endl;
135 Path p(package().user_support());
137 one.startscript(Systemcall::Wait, configure_command);
138 lyxerr << "LyX: " << _("Done!") << endl;
144 boost::scoped_ptr<LyX> LyX::singleton_;
146 int LyX::exec(int & argc, char * argv[])
148 BOOST_ASSERT(!singleton_.get());
149 // We must return from this before launching the gui so that
150 // other parts of the code can access singleton_ through
151 // LyX::ref and LyX::cref.
152 singleton_.reset(new LyX);
153 // Start the real execution loop.
154 return singleton_->priv_exec(argc, argv);
160 BOOST_ASSERT(singleton_.get());
161 return *singleton_.get();
165 LyX const & LyX::cref()
167 BOOST_ASSERT(singleton_.get());
168 return *singleton_.get();
173 : first_start(false), geometryOption_(false)
177 lyx::Session & LyX::session()
179 BOOST_ASSERT(session_.get());
180 return *session_.get();
184 lyx::Session const & LyX::session() const
186 BOOST_ASSERT(session_.get());
187 return *session_.get();
191 void LyX::addLyXView(LyXView * lyxview)
193 views_.push_back(lyxview);
197 Buffer const * const LyX::updateInset(InsetBase const * inset) const
202 Buffer const * buffer_ptr = 0;
203 ViewList::const_iterator it = views_.begin();
204 ViewList::const_iterator const end = views_.end();
205 for (; it != end; ++it) {
206 Buffer const * ptr = (*it)->updateInset(inset);
214 int LyX::priv_exec(int & argc, char * argv[])
216 // Here we need to parse the command line. At least
217 // we need to parse for "-dbg" and "-help"
218 lyx_gui::use_gui = easyParse(argc, argv);
220 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
221 lyx::support::top_build_dir_is_one_level_up);
223 // Start the real execution loop.
224 if (lyx_gui::use_gui)
225 return lyx_gui::exec(argc, argv);
227 return exec2(argc, argv);
231 int LyX::exec2(int & argc, char * argv[])
233 // check for any spurious extra arguments
234 // other than documents
235 for (int argi = 1; argi < argc ; ++argi) {
236 if (argv[argi][0] == '-') {
237 lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
243 // Initialization of LyX (reads lyxrc and more)
244 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
245 bool const success = init();
246 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
250 if (lyx_gui::use_gui)
251 lyx_gui::parse_lyxrc();
253 vector<string> files;
255 for (int argi = argc - 1; argi >= 1; --argi)
256 files.push_back(os::internal_path(argv[argi]));
259 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
261 // Execute batch commands if available
262 if (!batch_command.empty()) {
264 lyxerr[Debug::INIT] << "About to handle -x '"
265 << batch_command << '\'' << endl;
267 Buffer * last_loaded = 0;
269 vector<string>::const_iterator it = files.begin();
270 vector<string>::const_iterator end = files.end();
272 for (; it != end; ++it) {
273 // get absolute path of file and add ".lyx" to
274 // the filename if necessary
275 string s = fileSearch(string(), *it, "lyx");
277 Buffer * const b = newFile(*it, string(), true);
281 Buffer * buf = bufferlist.newBuffer(s, false);
282 if (loadLyXFile(buf, s)) {
284 ErrorList const & el = buf->errorList("Parse");
286 for_each(el.begin(), el.end(),
287 boost::bind(&LyX::printError, this, _1));
290 bufferlist.release(buf);
294 // try to dispatch to last loaded buffer first
296 bool success = false;
297 if (last_loaded->dispatch(batch_command, &success)) {
302 files.clear(); // the files are already loaded
305 if (lyx_gui::use_gui) {
306 // determine windows size and position, from lyxrc and/or session
308 unsigned int width = 690;
309 unsigned int height = 510;
310 bool maximize = false;
312 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
313 width = lyxrc.geometry_width;
314 height = lyxrc.geometry_height;
316 // if lyxrc returns (0,0), then use session info
318 string val = session().loadSessionInfo("WindowWidth");
320 width = convert<unsigned int>(val);
321 val = session().loadSessionInfo("WindowHeight");
323 height = convert<unsigned int>(val);
324 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
327 // if user wants to restore window position
330 if (lyxrc.geometry_xysaved) {
331 string val = session().loadSessionInfo("WindowPosX");
333 posx = convert<int>(val);
334 val = session().loadSessionInfo("WindowPosY");
336 posy = convert<int>(val);
339 if (geometryOption_) {
343 // create the main window
344 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
347 for_each(files.begin(), files.end(),
348 bind(&LyXView::loadLyXFile, view, _1, true));
350 // if a file is specified, I assume that user wants to edit *that* file
351 if (files.empty() && lyxrc.load_session) {
352 vector<string> const & lastopened = session_->lastOpenedFiles();
353 // do not add to the lastfile list since these files are restored from
354 // last seesion, and should be already there (regular files), or should
355 // not be added at all (help files).
356 for_each(lastopened.begin(), lastopened.end(),
357 bind(&LyXView::loadLyXFile, view, _1, false));
359 // clear this list to save a few bytes of RAM
360 session_->clearLastOpenedFiles();
362 return lyx_gui::start(view, batch_command);
364 // Something went wrong above
374 The SIGHUP signal does not exist on Windows and does not need to be handled.
376 Windows handles SIGFPE and SIGSEGV signals as expected.
378 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
379 cause a new thread to be spawned. This may well result in unexpected
380 behaviour by the single-threaded LyX.
382 SIGTERM signals will come only from another process actually sending
383 that signal using 'raise' in Windows' POSIX compatability layer. It will
384 not come from the general "terminate process" methods that everyone
385 actually uses (and which can't be trapped). Killing an app 'politely' on
386 Windows involves first sending a WM_CLOSE message, something that is
387 caught already by the Qt frontend.
389 For more information see:
391 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
392 ...signals are mostly useless on Windows for a variety of reasons that are
395 'UNIX Application Migration Guide, Chapter 9'
396 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
398 'How To Terminate an Application "Cleanly" in Win32'
399 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
403 static void error_handler(int err_sig)
405 // Throw away any signals other than the first one received.
406 static sig_atomic_t handling_error = false;
409 handling_error = true;
411 // We have received a signal indicating a fatal error, so
412 // try and save the data ASAP.
413 LyX::cref().emergencyCleanup();
415 // These lyxerr calls may or may not work:
417 // Signals are asynchronous, so the main program may be in a very
418 // fragile state when a signal is processed and thus while a signal
419 // handler function executes.
420 // In general, therefore, we should avoid performing any
421 // I/O operations or calling most library and system functions from
424 // This shouldn't matter here, however, as we've already invoked
429 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
433 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
436 lyxerr << "\nlyx: SIGSEGV signal caught\n"
437 "Sorry, you have found a bug in LyX. "
438 "Please read the bug-reporting instructions "
439 "in Help->Introduction and send us a bug report, "
440 "if necessary. Thanks !\nBye." << endl;
448 // Deinstall the signal handlers
450 signal(SIGHUP, SIG_DFL);
452 signal(SIGINT, SIG_DFL);
453 signal(SIGFPE, SIG_DFL);
454 signal(SIGSEGV, SIG_DFL);
455 signal(SIGTERM, SIG_DFL);
458 if (err_sig == SIGSEGV ||
459 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
461 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
463 lyx::support::abort();
470 void LyX::printError(ErrorItem const & ei)
472 std::cerr << _("LyX: ") << ei.error
473 << ':' << ei.description << std::endl;
481 signal(SIGHUP, error_handler);
483 signal(SIGFPE, error_handler);
484 signal(SIGSEGV, error_handler);
485 signal(SIGINT, error_handler);
486 signal(SIGTERM, error_handler);
487 // SIGPIPE can be safely ignored.
489 lyxrc.tempdir_path = package().temp_dir();
490 lyxrc.document_path = package().document_dir();
492 if (lyxrc.template_path.empty()) {
493 lyxrc.template_path = addPath(package().system_support(),
497 if (lyxrc.roman_font_name.empty())
498 lyxrc.roman_font_name = lyx_gui::roman_font_name();
499 if (lyxrc.sans_font_name.empty())
500 lyxrc.sans_font_name = lyx_gui::sans_font_name();
501 if (lyxrc.typewriter_font_name.empty())
502 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
505 // Read configuration files
508 // This one may have been distributed along with LyX.
509 if (!readRcFile("lyxrc.dist"))
512 // Set the PATH correctly.
513 #if !defined (USE_POSIX_PACKAGING)
514 // Add the directory containing the LyX executable to the path
515 // so that LyX can find things like tex2lyx.
516 if (package().build_support().empty())
517 prependEnvPath("PATH", package().binary_dir());
519 if (!lyxrc.path_prefix.empty())
520 prependEnvPath("PATH", lyxrc.path_prefix);
522 // Check that user LyX directory is ok.
523 if (queryUserLyXDir(package().explicit_user_support()))
524 reconfigureUserLyXDir();
526 // no need for a splash when there is no GUI
527 if (!lyx_gui::use_gui) {
531 // This one is generated in user_support directory by lib/configure.py.
532 if (!readRcFile("lyxrc.defaults"))
535 // Query the OS to know what formats are viewed natively
536 formats.setAutoOpen();
538 system_lyxrc = lyxrc;
539 system_formats = formats;
540 system_converters = converters;
541 system_movers = movers;
542 system_lcolor = lcolor;
544 // This one is edited through the preferences dialog.
545 if (!readRcFile("preferences"))
548 if (!readEncodingsFile("encodings"))
550 if (!readLanguagesFile("languages"))
554 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
558 if (lyx_gui::use_gui) {
560 toplevel_keymap.reset(new kb_keymap);
561 defaultKeyBindings(toplevel_keymap.get());
562 toplevel_keymap->read(lyxrc.bind_file);
565 if (!readUIFile(lyxrc.ui_file))
569 if (lyxerr.debugging(Debug::LYXRC))
572 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
573 if (!lyxrc.path_prefix.empty())
574 prependEnvPath("PATH", lyxrc.path_prefix);
576 if (fs::exists(lyxrc.document_path) &&
577 fs::is_directory(lyxrc.document_path))
578 package().document_dir() = lyxrc.document_path;
580 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
581 if (package().temp_dir().empty()) {
582 Alert::error(_("Could not create temporary directory"),
583 bformat(_("Could not create a temporary directory in\n"
584 "%1$s. Make sure that this\n"
585 "path exists and is writable and try again."),
586 lyxrc.tempdir_path));
587 // createLyXTmpDir() tries sufficiently hard to create a
588 // usable temp dir, so the probability to come here is
589 // close to zero. We therefore don't try to overcome this
590 // problem with e.g. asking the user for a new path and
591 // trying again but simply exit.
595 if (lyxerr.debugging(Debug::INIT)) {
596 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
599 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
600 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
605 void LyX::defaultKeyBindings(kb_keymap * kbmap)
607 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
608 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
609 kbmap->bind("Up", FuncRequest(LFUN_UP));
610 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
612 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
613 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
614 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
615 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
617 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
618 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
619 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
620 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
622 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
623 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
625 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
626 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
628 // kbmap->bindings to enable the use of the numeric keypad
630 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
631 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
632 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
633 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
646 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
647 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
648 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
649 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
650 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
651 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
652 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
653 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
657 void LyX::emergencyCleanup() const
659 // what to do about tmpfiles is non-obvious. we would
660 // like to delete any we find, but our lyxdir might
661 // contain documents etc. which might be helpful on
664 bufferlist.emergencyWriteAll();
666 lyxserver->emergencyCleanup();
670 void LyX::deadKeyBindings(kb_keymap * kbmap)
672 // bindKeyings for transparent handling of deadkeys
673 // The keysyms are gotten from XFree86 X11R6
674 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
675 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
676 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
677 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
678 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
679 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
680 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
681 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
682 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
683 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
684 // nothing with this name
685 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
686 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
687 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
688 // nothing with this name either...
689 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
690 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
691 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
692 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
698 // return true if file does not exist or is older than configure.py.
699 bool needsUpdate(string const & file)
701 static string const configure_script =
702 addName(package().system_support(), "configure.py");
703 string const absfile =
704 addName(package().user_support(), file);
706 return (! fs::exists(absfile))
707 || (fs::last_write_time(configure_script)
708 > fs::last_write_time(absfile));
714 bool LyX::queryUserLyXDir(bool explicit_userdir)
716 // Does user directory exist?
717 if (fs::exists(package().user_support()) &&
718 fs::is_directory(package().user_support())) {
721 return needsUpdate("lyxrc.defaults")
722 || needsUpdate("textclass.lst")
723 || needsUpdate("packages.lst");
726 first_start = !explicit_userdir;
728 // If the user specified explicitly a directory, ask whether
729 // to create it. If the user says "no", then exit.
730 if (explicit_userdir &&
732 _("Missing user LyX directory"),
733 bformat(_("You have specified a non-existent user "
734 "LyX directory, %1$s.\n"
735 "It is needed to keep your own configuration."),
736 package().user_support()),
738 _("&Create directory"),
740 lyxerr << _("No user LyX directory. Exiting.") << endl;
741 lyx_exit(EXIT_FAILURE);
744 lyxerr << bformat(_("LyX: Creating directory %1$s"),
745 package().user_support())
748 if (!createDirectory(package().user_support(), 0755)) {
749 // Failed, so let's exit.
750 lyxerr << _("Failed to create directory. Exiting.")
752 lyx_exit(EXIT_FAILURE);
759 bool LyX::readRcFile(string const & name)
761 lyxerr[Debug::INIT] << "About to read " << name << "... ";
763 string const lyxrc_path = libFileSearch(string(), name);
764 if (!lyxrc_path.empty()) {
766 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
768 if (lyxrc.read(lyxrc_path) < 0) {
773 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
779 // Read the ui file `name'
780 bool LyX::readUIFile(string const & name)
790 struct keyword_item uitags[ui_last - 1] = {
791 { "include", ui_include },
792 { "menuset", ui_menuset },
793 { "toolbar", ui_toolbar },
794 { "toolbars", ui_toolbars }
797 // Ensure that a file is read only once (prevents include loops)
798 static std::list<string> uifiles;
799 std::list<string>::const_iterator it = uifiles.begin();
800 std::list<string>::const_iterator end = uifiles.end();
801 it = std::find(it, end, name);
803 lyxerr[Debug::INIT] << "UI file '" << name
804 << "' has been read already. "
805 << "Is this an include loop?"
810 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
812 string const ui_path = libFileSearch("ui", name, "ui");
814 if (ui_path.empty()) {
815 lyxerr[Debug::INIT] << "Could not find " << name << endl;
819 uifiles.push_back(name);
821 lyxerr[Debug::INIT] << "Found " << name
822 << " in " << ui_path << endl;
823 LyXLex lex(uitags, ui_last - 1);
824 lex.setFile(ui_path);
826 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
830 if (lyxerr.debugging(Debug::PARSER))
831 lex.printTable(lyxerr);
837 string const file = lex.getString();
838 if (!readUIFile(file))
843 menubackend.read(lex);
847 toolbarbackend.read(lex);
851 toolbarbackend.readToolbars(lex);
855 if (!rtrim(lex.getString()).empty())
856 lex.printError("LyX::ReadUIFile: "
857 "Unknown menu tag: `$$Token'");
865 // Read the languages file `name'
866 bool LyX::readLanguagesFile(string const & name)
868 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
870 string const lang_path = libFileSearch(string(), name);
871 if (lang_path.empty()) {
875 languages.read(lang_path);
880 // Read the encodings file `name'
881 bool LyX::readEncodingsFile(string const & name)
883 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
885 string const enc_path = libFileSearch(string(), name);
886 if (enc_path.empty()) {
890 encodings.read(enc_path);
900 /// return the the number of arguments consumed
901 typedef boost::function<int(string const &, string const &)> cmd_helper;
903 int parse_dbg(string const & arg, string const &)
906 lyxerr << _("List of supported debug flags:") << endl;
907 Debug::showTags(lyxerr);
910 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
912 lyxerr.level(Debug::value(arg));
913 Debug::showLevel(lyxerr, lyxerr.level());
918 int parse_help(string const &, string const &)
921 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
922 "Command line switches (case sensitive):\n"
923 "\t-help summarize LyX usage\n"
924 "\t-userdir dir set user directory to dir\n"
925 "\t-sysdir dir set system directory to dir\n"
926 "\t-geometry WxH+X+Y set geometry of the main window\n"
927 "\t-dbg feature[,feature]...\n"
928 " select the features to debug.\n"
929 " Type `lyx -dbg' to see the list of features\n"
930 "\t-x [--execute] command\n"
931 " where command is a lyx command.\n"
932 "\t-e [--export] fmt\n"
933 " where fmt is the export format of choice.\n"
934 "\t-i [--import] fmt file.xxx\n"
935 " where fmt is the import format of choice\n"
936 " and file.xxx is the file to be imported.\n"
937 "\t-version summarize version and build info\n"
938 "Check the LyX man page for more details.") << endl;
943 int parse_version(string const &, string const &)
945 lyxerr << "LyX " << lyx_version
946 << " (" << lyx_release_date << ")" << endl;
947 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
949 lyxerr << lyx_version_info << endl;
954 int parse_sysdir(string const & arg, string const &)
957 lyxerr << _("Missing directory for -sysdir switch") << endl;
960 cl_system_support = arg;
964 int parse_userdir(string const & arg, string const &)
967 lyxerr << _("Missing directory for -userdir switch") << endl;
970 cl_user_support = arg;
974 int parse_execute(string const & arg, string const &)
977 lyxerr << _("Missing command string after --execute switch") << endl;
984 int parse_export(string const & type, string const &)
987 lyxerr << _("Missing file type [eg latex, ps...] after "
988 "--export switch") << endl;
991 batch = "buffer-export " + type;
996 int parse_import(string const & type, string const & file)
999 lyxerr << _("Missing file type [eg latex, ps...] after "
1000 "--import switch") << endl;
1004 lyxerr << _("Missing filename for --import") << endl;
1008 batch = "buffer-import " + type + ' ' + file;
1015 bool LyX::easyParse(int & argc, char * argv[])
1017 std::map<string, cmd_helper> cmdmap;
1019 cmdmap["-dbg"] = parse_dbg;
1020 cmdmap["-help"] = parse_help;
1021 cmdmap["--help"] = parse_help;
1022 cmdmap["-version"] = parse_version;
1023 cmdmap["--version"] = parse_version;
1024 cmdmap["-sysdir"] = parse_sysdir;
1025 cmdmap["-userdir"] = parse_userdir;
1026 cmdmap["-x"] = parse_execute;
1027 cmdmap["--execute"] = parse_execute;
1028 cmdmap["-e"] = parse_export;
1029 cmdmap["--export"] = parse_export;
1030 cmdmap["-i"] = parse_import;
1031 cmdmap["--import"] = parse_import;
1033 for (int i = 1; i < argc; ++i) {
1034 std::map<string, cmd_helper>::const_iterator it
1035 = cmdmap.find(argv[i]);
1037 // check for X11 -geometry option
1038 if (lyx::support::compare(argv[i], "-geometry") == 0)
1039 geometryOption_ = true;
1041 // don't complain if not found - may be parsed later
1042 if (it == cmdmap.end())
1045 string arg((i + 1 < argc) ? argv[i + 1] : "");
1046 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1048 int const remove = 1 + it->second(arg, arg2);
1050 // Now, remove used arguments by shifting
1051 // the following ones remove places down.
1053 for (int j = i; j < argc; ++j)
1054 argv[j] = argv[j + remove];
1058 batch_command = batch;