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 "converter.h"
25 #include "errorlist.h"
36 #include "lyxtextclasslist.h"
37 #include "MenuBackend.h"
39 #include "ToolbarBackend.h"
41 #include "frontends/Alert.h"
42 #include "frontends/Application.h"
43 #include "frontends/lyx_gui.h"
44 #include "frontends/LyXView.h"
46 #include "support/environment.h"
47 #include "support/filetools.h"
48 #include "support/lyxlib.h"
49 #include "support/convert.h"
50 #include "support/os.h"
51 #include "support/package.h"
52 #include "support/path.h"
53 #include "support/systemcall.h"
55 #include <boost/bind.hpp>
56 #include <boost/filesystem/operations.hpp>
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::prependEnvPath;
72 using lyx::support::rtrim;
73 using lyx::support::Systemcall;
77 namespace os = lyx::support::os;
78 namespace fs = boost::filesystem;
84 #ifndef CXX_GLOBAL_CSTD
91 // convenient to have it here.
92 boost::scoped_ptr<kb_keymap> toplevel_keymap;
96 // Filled with the command line arguments "foo" of "-sysdir foo" or
98 string cl_system_support;
99 string cl_user_support;
102 void lyx_exit(int status)
104 // FIXME: We should not directly call exit(), since it only
105 // guarantees a return to the system, no application cleanup.
106 // This may cause troubles with not executed destructors.
107 if (lyx_gui::use_gui)
108 // lyx_gui::exit may return and only schedule the exit
109 lyx_gui::exit(status);
114 void showFileError(string const & error)
116 Alert::warning(_("Could not read configuration file"),
117 bformat(_("Error while reading the configuration file\n%1$s.\n"
118 "Please check your installation."), lyx::from_utf8(error)));
122 void reconfigureUserLyXDir()
124 string const configure_command = package().configure_command();
126 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
127 lyx::support::Path p(package().user_support());
129 one.startscript(Systemcall::Wait, configure_command);
130 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
136 boost::scoped_ptr<LyX> LyX::singleton_;
138 int LyX::exec(int & argc, char * argv[])
140 BOOST_ASSERT(!singleton_.get());
141 // We must return from this before launching the gui so that
142 // other parts of the code can access singleton_ through
143 // LyX::ref and LyX::cref.
144 singleton_.reset(new LyX);
145 // Start the real execution loop.
146 return singleton_->priv_exec(argc, argv);
152 BOOST_ASSERT(singleton_.get());
153 return *singleton_.get();
157 LyX const & LyX::cref()
159 BOOST_ASSERT(singleton_.get());
160 return *singleton_.get();
165 : first_start(false), geometryOption_(false)
169 lyx::Session & LyX::session()
171 BOOST_ASSERT(session_.get());
172 return *session_.get();
176 lyx::Session const & LyX::session() const
178 BOOST_ASSERT(session_.get());
179 return *session_.get();
183 void LyX::addLyXView(LyXView * lyxview)
185 views_.push_back(lyxview);
189 Buffer const * const LyX::updateInset(InsetBase const * inset) const
194 Buffer const * buffer_ptr = 0;
195 ViewList::const_iterator it = views_.begin();
196 ViewList::const_iterator const end = views_.end();
197 for (; it != end; ++it) {
198 Buffer const * ptr = (*it)->updateInset(inset);
206 int LyX::priv_exec(int & argc, char * argv[])
208 // Here we need to parse the command line. At least
209 // we need to parse for "-dbg" and "-help"
210 lyx_gui::use_gui = easyParse(argc, argv);
212 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
213 lyx::support::top_build_dir_is_one_level_up);
215 // Start the real execution loop.
216 if (lyx_gui::use_gui)
217 return lyx_gui::exec(argc, argv);
219 return exec2(argc, argv);
223 int LyX::exec2(int & argc, char * argv[])
225 // check for any spurious extra arguments
226 // other than documents
227 for (int argi = 1; argi < argc ; ++argi) {
228 if (argv[argi][0] == '-') {
229 lyxerr << lyx::to_utf8(
230 bformat(_("Wrong command line option `%1$s'. Exiting."),
231 lyx::from_utf8(argv[argi]))) << endl;
236 // Initialization of LyX (reads lyxrc and more)
237 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
238 bool const success = init();
239 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
243 if (lyx_gui::use_gui)
244 lyx_gui::parse_lyxrc();
246 vector<string> files;
248 for (int argi = argc - 1; argi >= 1; --argi)
249 files.push_back(os::internal_path(argv[argi]));
252 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
254 // Execute batch commands if available
255 if (!batch_command.empty()) {
257 lyxerr[Debug::INIT] << "About to handle -x '"
258 << batch_command << '\'' << endl;
260 Buffer * last_loaded = 0;
262 vector<string>::const_iterator it = files.begin();
263 vector<string>::const_iterator end = files.end();
265 for (; it != end; ++it) {
266 // get absolute path of file and add ".lyx" to
267 // the filename if necessary
268 string s = fileSearch(string(), *it, "lyx");
270 Buffer * const b = newFile(*it, string(), true);
274 Buffer * buf = theApp->bufferList().newBuffer(s, false);
275 if (loadLyXFile(buf, s)) {
277 ErrorList const & el = buf->errorList("Parse");
279 for_each(el.begin(), el.end(),
280 boost::bind(&LyX::printError, this, _1));
283 theApp->bufferList().release(buf);
287 // try to dispatch to last loaded buffer first
289 bool success = false;
290 if (last_loaded->dispatch(batch_command, &success)) {
295 files.clear(); // the files are already loaded
298 if (lyx_gui::use_gui) {
299 // determine windows size and position, from lyxrc and/or session
301 unsigned int width = 690;
302 unsigned int height = 510;
303 bool maximize = false;
305 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
306 width = lyxrc.geometry_width;
307 height = lyxrc.geometry_height;
309 // if lyxrc returns (0,0), then use session info
311 string val = session().loadSessionInfo("WindowWidth");
313 width = convert<unsigned int>(val);
314 val = session().loadSessionInfo("WindowHeight");
316 height = convert<unsigned int>(val);
317 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
320 // if user wants to restore window position
323 if (lyxrc.geometry_xysaved) {
324 string val = session().loadSessionInfo("WindowPosX");
326 posx = convert<int>(val);
327 val = session().loadSessionInfo("WindowPosY");
329 posy = convert<int>(val);
332 if (geometryOption_) {
336 // create the main window
337 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
340 for_each(files.begin(), files.end(),
341 bind(&LyXView::loadLyXFile, view, _1, true));
343 // if a file is specified, I assume that user wants to edit *that* file
344 if (files.empty() && lyxrc.load_session) {
345 vector<string> const & lastopened = session_->lastOpenedFiles();
346 // do not add to the lastfile list since these files are restored from
347 // last seesion, and should be already there (regular files), or should
348 // not be added at all (help files).
349 for_each(lastopened.begin(), lastopened.end(),
350 bind(&LyXView::loadLyXFile, view, _1, false));
352 // clear this list to save a few bytes of RAM
353 session_->clearLastOpenedFiles();
355 return lyx_gui::start(view, batch_command);
357 // Something went wrong above
367 The SIGHUP signal does not exist on Windows and does not need to be handled.
369 Windows handles SIGFPE and SIGSEGV signals as expected.
371 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
372 cause a new thread to be spawned. This may well result in unexpected
373 behaviour by the single-threaded LyX.
375 SIGTERM signals will come only from another process actually sending
376 that signal using 'raise' in Windows' POSIX compatability layer. It will
377 not come from the general "terminate process" methods that everyone
378 actually uses (and which can't be trapped). Killing an app 'politely' on
379 Windows involves first sending a WM_CLOSE message, something that is
380 caught already by the Qt frontend.
382 For more information see:
384 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
385 ...signals are mostly useless on Windows for a variety of reasons that are
388 'UNIX Application Migration Guide, Chapter 9'
389 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
391 'How To Terminate an Application "Cleanly" in Win32'
392 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
396 static void error_handler(int err_sig)
398 // Throw away any signals other than the first one received.
399 static sig_atomic_t handling_error = false;
402 handling_error = true;
404 // We have received a signal indicating a fatal error, so
405 // try and save the data ASAP.
406 LyX::cref().emergencyCleanup();
408 // These lyxerr calls may or may not work:
410 // Signals are asynchronous, so the main program may be in a very
411 // fragile state when a signal is processed and thus while a signal
412 // handler function executes.
413 // In general, therefore, we should avoid performing any
414 // I/O operations or calling most library and system functions from
417 // This shouldn't matter here, however, as we've already invoked
422 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
426 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
429 lyxerr << "\nlyx: SIGSEGV signal caught\n"
430 "Sorry, you have found a bug in LyX. "
431 "Please read the bug-reporting instructions "
432 "in Help->Introduction and send us a bug report, "
433 "if necessary. Thanks !\nBye." << endl;
441 // Deinstall the signal handlers
443 signal(SIGHUP, SIG_DFL);
445 signal(SIGINT, SIG_DFL);
446 signal(SIGFPE, SIG_DFL);
447 signal(SIGSEGV, SIG_DFL);
448 signal(SIGTERM, SIG_DFL);
451 if (err_sig == SIGSEGV ||
452 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
454 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
456 lyx::support::abort();
463 void LyX::printError(ErrorItem const & ei)
465 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
467 std::cerr << lyx::to_utf8(tmp) << std::endl;
474 signal(SIGHUP, error_handler);
476 signal(SIGFPE, error_handler);
477 signal(SIGSEGV, error_handler);
478 signal(SIGINT, error_handler);
479 signal(SIGTERM, error_handler);
480 // SIGPIPE can be safely ignored.
482 lyxrc.tempdir_path = package().temp_dir();
483 lyxrc.document_path = package().document_dir();
485 if (lyxrc.template_path.empty()) {
486 lyxrc.template_path = addPath(package().system_support(),
490 if (lyxrc.roman_font_name.empty())
491 lyxrc.roman_font_name = lyx_gui::roman_font_name();
492 if (lyxrc.sans_font_name.empty())
493 lyxrc.sans_font_name = lyx_gui::sans_font_name();
494 if (lyxrc.typewriter_font_name.empty())
495 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
498 // Read configuration files
501 // This one may have been distributed along with LyX.
502 if (!readRcFile("lyxrc.dist"))
505 // Set the PATH correctly.
506 #if !defined (USE_POSIX_PACKAGING)
507 // Add the directory containing the LyX executable to the path
508 // so that LyX can find things like tex2lyx.
509 if (package().build_support().empty())
510 prependEnvPath("PATH", package().binary_dir());
512 if (!lyxrc.path_prefix.empty())
513 prependEnvPath("PATH", lyxrc.path_prefix);
515 // Check that user LyX directory is ok.
516 if (queryUserLyXDir(package().explicit_user_support()))
517 reconfigureUserLyXDir();
519 // no need for a splash when there is no GUI
520 if (!lyx_gui::use_gui) {
524 // This one is generated in user_support directory by lib/configure.py.
525 if (!readRcFile("lyxrc.defaults"))
528 // Query the OS to know what formats are viewed natively
529 formats.setAutoOpen();
531 system_lyxrc = lyxrc;
532 system_formats = formats;
533 system_converters = converters;
534 system_movers = movers;
535 system_lcolor = lcolor;
537 // This one is edited through the preferences dialog.
538 if (!readRcFile("preferences"))
541 if (!readEncodingsFile("encodings"))
543 if (!readLanguagesFile("languages"))
547 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
551 if (lyx_gui::use_gui) {
553 toplevel_keymap.reset(new kb_keymap);
554 defaultKeyBindings(toplevel_keymap.get());
555 toplevel_keymap->read(lyxrc.bind_file);
558 if (!readUIFile(lyxrc.ui_file))
562 if (lyxerr.debugging(Debug::LYXRC))
565 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
566 if (!lyxrc.path_prefix.empty())
567 prependEnvPath("PATH", lyxrc.path_prefix);
569 if (fs::exists(lyxrc.document_path) &&
570 fs::is_directory(lyxrc.document_path))
571 package().document_dir() = lyxrc.document_path;
573 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
574 if (package().temp_dir().empty()) {
575 Alert::error(_("Could not create temporary directory"),
576 bformat(_("Could not create a temporary directory in\n"
577 "%1$s. Make sure that this\n"
578 "path exists and is writable and try again."),
579 lyx::from_utf8(lyxrc.tempdir_path)));
580 // createLyXTmpDir() tries sufficiently hard to create a
581 // usable temp dir, so the probability to come here is
582 // close to zero. We therefore don't try to overcome this
583 // problem with e.g. asking the user for a new path and
584 // trying again but simply exit.
588 if (lyxerr.debugging(Debug::INIT)) {
589 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
592 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
593 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
598 void LyX::defaultKeyBindings(kb_keymap * kbmap)
600 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
601 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
602 kbmap->bind("Up", FuncRequest(LFUN_UP));
603 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
605 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
606 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
607 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
608 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
610 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
611 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
612 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
613 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
615 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
616 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
618 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
619 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
621 // kbmap->bindings to enable the use of the numeric keypad
623 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
624 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
625 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
626 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
627 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
628 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
629 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
630 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
631 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
632 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
639 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
640 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
641 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
642 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
643 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
644 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
645 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
646 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
650 void LyX::emergencyCleanup() const
652 // what to do about tmpfiles is non-obvious. we would
653 // like to delete any we find, but our lyxdir might
654 // contain documents etc. which might be helpful on
657 theApp->bufferList().emergencyWriteAll();
658 theApp->server().emergencyCleanup();
662 void LyX::deadKeyBindings(kb_keymap * kbmap)
664 // bindKeyings for transparent handling of deadkeys
665 // The keysyms are gotten from XFree86 X11R6
666 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
667 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
668 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
669 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
670 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
671 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
672 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
673 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
674 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
675 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
676 // nothing with this name
677 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
678 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
679 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
680 // nothing with this name either...
681 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
682 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
683 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
684 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
690 // return true if file does not exist or is older than configure.py.
691 bool needsUpdate(string const & file)
693 static string const configure_script =
694 addName(package().system_support(), "configure.py");
695 string const absfile =
696 addName(package().user_support(), file);
698 return (! fs::exists(absfile))
699 || (fs::last_write_time(configure_script)
700 > fs::last_write_time(absfile));
706 bool LyX::queryUserLyXDir(bool explicit_userdir)
708 // Does user directory exist?
709 if (fs::exists(package().user_support()) &&
710 fs::is_directory(package().user_support())) {
713 return needsUpdate("lyxrc.defaults")
714 || needsUpdate("textclass.lst")
715 || needsUpdate("packages.lst");
718 first_start = !explicit_userdir;
720 // If the user specified explicitly a directory, ask whether
721 // to create it. If the user says "no", then exit.
722 if (explicit_userdir &&
724 _("Missing user LyX directory"),
725 bformat(_("You have specified a non-existent user "
726 "LyX directory, %1$s.\n"
727 "It is needed to keep your own configuration."),
728 lyx::from_utf8(package().user_support())),
730 _("&Create directory"),
732 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
733 lyx_exit(EXIT_FAILURE);
736 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
737 lyx::from_utf8(package().user_support())))
740 if (!createDirectory(package().user_support(), 0755)) {
741 // Failed, so let's exit.
742 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
744 lyx_exit(EXIT_FAILURE);
751 bool LyX::readRcFile(string const & name)
753 lyxerr[Debug::INIT] << "About to read " << name << "... ";
755 string const lyxrc_path = libFileSearch(string(), name);
756 if (!lyxrc_path.empty()) {
758 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
760 if (lyxrc.read(lyxrc_path) < 0) {
765 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
771 // Read the ui file `name'
772 bool LyX::readUIFile(string const & name)
782 struct keyword_item uitags[ui_last - 1] = {
783 { "include", ui_include },
784 { "menuset", ui_menuset },
785 { "toolbar", ui_toolbar },
786 { "toolbars", ui_toolbars }
789 // Ensure that a file is read only once (prevents include loops)
790 static std::list<string> uifiles;
791 std::list<string>::const_iterator it = uifiles.begin();
792 std::list<string>::const_iterator end = uifiles.end();
793 it = std::find(it, end, name);
795 lyxerr[Debug::INIT] << "UI file '" << name
796 << "' has been read already. "
797 << "Is this an include loop?"
802 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
804 string const ui_path = libFileSearch("ui", name, "ui");
806 if (ui_path.empty()) {
807 lyxerr[Debug::INIT] << "Could not find " << name << endl;
811 uifiles.push_back(name);
813 lyxerr[Debug::INIT] << "Found " << name
814 << " in " << ui_path << endl;
815 LyXLex lex(uitags, ui_last - 1);
816 lex.setFile(ui_path);
818 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
822 if (lyxerr.debugging(Debug::PARSER))
823 lex.printTable(lyxerr);
829 string const file = lex.getString();
830 if (!readUIFile(file))
835 menubackend.read(lex);
839 toolbarbackend.read(lex);
843 toolbarbackend.readToolbars(lex);
847 if (!rtrim(lex.getString()).empty())
848 lex.printError("LyX::ReadUIFile: "
849 "Unknown menu tag: `$$Token'");
857 // Read the languages file `name'
858 bool LyX::readLanguagesFile(string const & name)
860 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
862 string const lang_path = libFileSearch(string(), name);
863 if (lang_path.empty()) {
867 languages.read(lang_path);
872 // Read the encodings file `name'
873 bool LyX::readEncodingsFile(string const & name)
875 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
877 string const enc_path = libFileSearch(string(), name);
878 if (enc_path.empty()) {
882 encodings.read(enc_path);
892 /// return the the number of arguments consumed
893 typedef boost::function<int(string const &, string const &)> cmd_helper;
895 int parse_dbg(string const & arg, string const &)
898 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
899 Debug::showTags(lyxerr);
902 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
904 lyxerr.level(Debug::value(arg));
905 Debug::showLevel(lyxerr, lyxerr.level());
910 int parse_help(string const &, string const &)
913 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
914 "Command line switches (case sensitive):\n"
915 "\t-help summarize LyX usage\n"
916 "\t-userdir dir set user directory to dir\n"
917 "\t-sysdir dir set system directory to dir\n"
918 "\t-geometry WxH+X+Y set geometry of the main window\n"
919 "\t-dbg feature[,feature]...\n"
920 " select the features to debug.\n"
921 " Type `lyx -dbg' to see the list of features\n"
922 "\t-x [--execute] command\n"
923 " where command is a lyx command.\n"
924 "\t-e [--export] fmt\n"
925 " where fmt is the export format of choice.\n"
926 "\t-i [--import] fmt file.xxx\n"
927 " where fmt is the import format of choice\n"
928 " and file.xxx is the file to be imported.\n"
929 "\t-version summarize version and build info\n"
930 "Check the LyX man page for more details.")) << endl;
935 int parse_version(string const &, string const &)
937 lyxerr << "LyX " << lyx_version
938 << " (" << lyx_release_date << ")" << endl;
939 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
941 lyxerr << lyx_version_info << endl;
946 int parse_sysdir(string const & arg, string const &)
949 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
952 cl_system_support = arg;
956 int parse_userdir(string const & arg, string const &)
959 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
962 cl_user_support = arg;
966 int parse_execute(string const & arg, string const &)
969 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
976 int parse_export(string const & type, string const &)
979 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
980 "--export switch")) << endl;
983 batch = "buffer-export " + type;
988 int parse_import(string const & type, string const & file)
991 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
992 "--import switch")) << endl;
996 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1000 batch = "buffer-import " + type + ' ' + file;
1007 bool LyX::easyParse(int & argc, char * argv[])
1009 std::map<string, cmd_helper> cmdmap;
1011 cmdmap["-dbg"] = parse_dbg;
1012 cmdmap["-help"] = parse_help;
1013 cmdmap["--help"] = parse_help;
1014 cmdmap["-version"] = parse_version;
1015 cmdmap["--version"] = parse_version;
1016 cmdmap["-sysdir"] = parse_sysdir;
1017 cmdmap["-userdir"] = parse_userdir;
1018 cmdmap["-x"] = parse_execute;
1019 cmdmap["--execute"] = parse_execute;
1020 cmdmap["-e"] = parse_export;
1021 cmdmap["--export"] = parse_export;
1022 cmdmap["-i"] = parse_import;
1023 cmdmap["--import"] = parse_import;
1025 for (int i = 1; i < argc; ++i) {
1026 std::map<string, cmd_helper>::const_iterator it
1027 = cmdmap.find(argv[i]);
1029 // check for X11 -geometry option
1030 if (lyx::support::compare(argv[i], "-geometry") == 0)
1031 geometryOption_ = true;
1033 // don't complain if not found - may be parsed later
1034 if (it == cmdmap.end())
1037 string arg((i + 1 < argc) ? argv[i + 1] : "");
1038 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1040 int const remove = 1 + it->second(arg, arg2);
1042 // Now, remove used arguments by shifting
1043 // the following ones remove places down.
1045 for (int j = i; j < argc; ++j)
1046 argv[j] = argv[j + remove];
1050 batch_command = batch;