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;
85 #ifndef CXX_GLOBAL_CSTD
92 // convenient to have it here.
93 boost::scoped_ptr<kb_keymap> toplevel_keymap;
97 // Filled with the command line arguments "foo" of "-sysdir foo" or
99 string cl_system_support;
100 string cl_user_support;
103 void lyx_exit(int status)
105 // FIXME: We should not directly call exit(), since it only
106 // guarantees a return to the system, no application cleanup.
107 // This may cause troubles with not executed destructors.
108 if (lyx_gui::use_gui)
109 // lyx_gui::exit may return and only schedule the exit
110 lyx_gui::exit(status);
115 void showFileError(string const & error)
117 Alert::warning(_("Could not read configuration file"),
118 bformat(_("Error while reading the configuration file\n%1$s.\n"
119 "Please check your installation."), lyx::from_utf8(error)));
123 void reconfigureUserLyXDir()
125 string const configure_command = package().configure_command();
127 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
128 lyx::support::Path p(package().user_support());
130 one.startscript(Systemcall::Wait, configure_command);
131 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
137 boost::scoped_ptr<LyX> LyX::singleton_;
139 int LyX::exec(int & argc, char * argv[])
141 BOOST_ASSERT(!singleton_.get());
142 // We must return from this before launching the gui so that
143 // other parts of the code can access singleton_ through
144 // LyX::ref and LyX::cref.
145 singleton_.reset(new LyX);
146 // Start the real execution loop.
147 return singleton_->priv_exec(argc, argv);
153 BOOST_ASSERT(singleton_.get());
154 return *singleton_.get();
158 LyX const & LyX::cref()
160 BOOST_ASSERT(singleton_.get());
161 return *singleton_.get();
166 : first_start(false), geometryOption_(false)
170 lyx::Session & LyX::session()
172 BOOST_ASSERT(session_.get());
173 return *session_.get();
177 lyx::Session const & LyX::session() const
179 BOOST_ASSERT(session_.get());
180 return *session_.get();
184 void LyX::addLyXView(LyXView * lyxview)
186 views_.push_back(lyxview);
190 Buffer const * const LyX::updateInset(InsetBase const * inset) const
195 Buffer const * buffer_ptr = 0;
196 ViewList::const_iterator it = views_.begin();
197 ViewList::const_iterator const end = views_.end();
198 for (; it != end; ++it) {
199 Buffer const * ptr = (*it)->updateInset(inset);
207 int LyX::priv_exec(int & argc, char * argv[])
209 // Here we need to parse the command line. At least
210 // we need to parse for "-dbg" and "-help"
211 lyx_gui::use_gui = easyParse(argc, argv);
213 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
214 lyx::support::top_build_dir_is_one_level_up);
216 // Start the real execution loop.
217 if (lyx_gui::use_gui)
218 return lyx_gui::exec(argc, argv);
220 return exec2(argc, argv);
224 int LyX::exec2(int & argc, char * argv[])
226 // check for any spurious extra arguments
227 // other than documents
228 for (int argi = 1; argi < argc ; ++argi) {
229 if (argv[argi][0] == '-') {
230 lyxerr << lyx::to_utf8(
231 bformat(_("Wrong command line option `%1$s'. Exiting."),
232 lyx::from_utf8(argv[argi]))) << endl;
237 // Initialization of LyX (reads lyxrc and more)
238 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
239 bool const success = init();
240 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
244 if (lyx_gui::use_gui)
245 lyx_gui::parse_lyxrc();
247 vector<string> files;
249 for (int argi = argc - 1; argi >= 1; --argi)
250 files.push_back(os::internal_path(argv[argi]));
253 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
255 // Execute batch commands if available
256 if (!batch_command.empty()) {
258 lyxerr[Debug::INIT] << "About to handle -x '"
259 << batch_command << '\'' << endl;
261 Buffer * last_loaded = 0;
263 vector<string>::const_iterator it = files.begin();
264 vector<string>::const_iterator end = files.end();
266 for (; it != end; ++it) {
267 // get absolute path of file and add ".lyx" to
268 // the filename if necessary
269 string s = fileSearch(string(), *it, "lyx");
271 Buffer * const b = newFile(*it, string(), true);
275 Buffer * buf = theApp->bufferList().newBuffer(s, false);
276 if (loadLyXFile(buf, s)) {
278 ErrorList const & el = buf->errorList("Parse");
280 for_each(el.begin(), el.end(),
281 boost::bind(&LyX::printError, this, _1));
284 theApp->bufferList().release(buf);
288 // try to dispatch to last loaded buffer first
290 bool success = false;
291 if (last_loaded->dispatch(batch_command, &success)) {
296 files.clear(); // the files are already loaded
299 if (lyx_gui::use_gui) {
300 // determine windows size and position, from lyxrc and/or session
302 unsigned int width = 690;
303 unsigned int height = 510;
304 bool maximize = false;
306 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
307 width = lyxrc.geometry_width;
308 height = lyxrc.geometry_height;
310 // if lyxrc returns (0,0), then use session info
312 string val = session().loadSessionInfo("WindowWidth");
314 width = convert<unsigned int>(val);
315 val = session().loadSessionInfo("WindowHeight");
317 height = convert<unsigned int>(val);
318 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
321 // if user wants to restore window position
324 if (lyxrc.geometry_xysaved) {
325 string val = session().loadSessionInfo("WindowPosX");
327 posx = convert<int>(val);
328 val = session().loadSessionInfo("WindowPosY");
330 posy = convert<int>(val);
333 if (geometryOption_) {
337 // create the main window
338 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
341 for_each(files.begin(), files.end(),
342 bind(&LyXView::loadLyXFile, view, _1, true));
344 // if a file is specified, I assume that user wants to edit *that* file
345 if (files.empty() && lyxrc.load_session) {
346 vector<string> const & lastopened = session_->lastOpenedFiles();
347 // do not add to the lastfile list since these files are restored from
348 // last seesion, and should be already there (regular files), or should
349 // not be added at all (help files).
350 for_each(lastopened.begin(), lastopened.end(),
351 bind(&LyXView::loadLyXFile, view, _1, false));
353 // clear this list to save a few bytes of RAM
354 session_->clearLastOpenedFiles();
356 return lyx_gui::start(view, batch_command);
358 // Something went wrong above
368 The SIGHUP signal does not exist on Windows and does not need to be handled.
370 Windows handles SIGFPE and SIGSEGV signals as expected.
372 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
373 cause a new thread to be spawned. This may well result in unexpected
374 behaviour by the single-threaded LyX.
376 SIGTERM signals will come only from another process actually sending
377 that signal using 'raise' in Windows' POSIX compatability layer. It will
378 not come from the general "terminate process" methods that everyone
379 actually uses (and which can't be trapped). Killing an app 'politely' on
380 Windows involves first sending a WM_CLOSE message, something that is
381 caught already by the Qt frontend.
383 For more information see:
385 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
386 ...signals are mostly useless on Windows for a variety of reasons that are
389 'UNIX Application Migration Guide, Chapter 9'
390 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
392 'How To Terminate an Application "Cleanly" in Win32'
393 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
397 static void error_handler(int err_sig)
399 // Throw away any signals other than the first one received.
400 static sig_atomic_t handling_error = false;
403 handling_error = true;
405 // We have received a signal indicating a fatal error, so
406 // try and save the data ASAP.
407 LyX::cref().emergencyCleanup();
409 // These lyxerr calls may or may not work:
411 // Signals are asynchronous, so the main program may be in a very
412 // fragile state when a signal is processed and thus while a signal
413 // handler function executes.
414 // In general, therefore, we should avoid performing any
415 // I/O operations or calling most library and system functions from
418 // This shouldn't matter here, however, as we've already invoked
423 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
427 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
430 lyxerr << "\nlyx: SIGSEGV signal caught\n"
431 "Sorry, you have found a bug in LyX. "
432 "Please read the bug-reporting instructions "
433 "in Help->Introduction and send us a bug report, "
434 "if necessary. Thanks !\nBye." << endl;
442 // Deinstall the signal handlers
444 signal(SIGHUP, SIG_DFL);
446 signal(SIGINT, SIG_DFL);
447 signal(SIGFPE, SIG_DFL);
448 signal(SIGSEGV, SIG_DFL);
449 signal(SIGTERM, SIG_DFL);
452 if (err_sig == SIGSEGV ||
453 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
455 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
457 lyx::support::abort();
464 void LyX::printError(ErrorItem const & ei)
466 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
468 std::cerr << lyx::to_utf8(tmp) << std::endl;
475 signal(SIGHUP, error_handler);
477 signal(SIGFPE, error_handler);
478 signal(SIGSEGV, error_handler);
479 signal(SIGINT, error_handler);
480 signal(SIGTERM, error_handler);
481 // SIGPIPE can be safely ignored.
483 lyxrc.tempdir_path = package().temp_dir();
484 lyxrc.document_path = package().document_dir();
486 if (lyxrc.template_path.empty()) {
487 lyxrc.template_path = addPath(package().system_support(),
491 if (lyxrc.roman_font_name.empty())
492 lyxrc.roman_font_name = lyx_gui::roman_font_name();
493 if (lyxrc.sans_font_name.empty())
494 lyxrc.sans_font_name = lyx_gui::sans_font_name();
495 if (lyxrc.typewriter_font_name.empty())
496 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
499 // Read configuration files
502 // This one may have been distributed along with LyX.
503 if (!readRcFile("lyxrc.dist"))
506 // Set the PATH correctly.
507 #if !defined (USE_POSIX_PACKAGING)
508 // Add the directory containing the LyX executable to the path
509 // so that LyX can find things like tex2lyx.
510 if (package().build_support().empty())
511 prependEnvPath("PATH", package().binary_dir());
513 if (!lyxrc.path_prefix.empty())
514 prependEnvPath("PATH", lyxrc.path_prefix);
516 // Check that user LyX directory is ok.
517 if (queryUserLyXDir(package().explicit_user_support()))
518 reconfigureUserLyXDir();
520 // no need for a splash when there is no GUI
521 if (!lyx_gui::use_gui) {
525 // This one is generated in user_support directory by lib/configure.py.
526 if (!readRcFile("lyxrc.defaults"))
529 // Query the OS to know what formats are viewed natively
530 formats.setAutoOpen();
532 system_lyxrc = lyxrc;
533 system_formats = formats;
534 system_converters = converters;
535 system_movers = movers;
536 system_lcolor = lcolor;
538 // This one is edited through the preferences dialog.
539 if (!readRcFile("preferences"))
542 if (!readEncodingsFile("encodings"))
544 if (!readLanguagesFile("languages"))
548 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
552 if (lyx_gui::use_gui) {
554 toplevel_keymap.reset(new kb_keymap);
555 defaultKeyBindings(toplevel_keymap.get());
556 toplevel_keymap->read(lyxrc.bind_file);
559 if (!readUIFile(lyxrc.ui_file))
563 if (lyxerr.debugging(Debug::LYXRC))
566 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
567 if (!lyxrc.path_prefix.empty())
568 prependEnvPath("PATH", lyxrc.path_prefix);
570 if (fs::exists(lyxrc.document_path) &&
571 fs::is_directory(lyxrc.document_path))
572 package().document_dir() = lyxrc.document_path;
574 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
575 if (package().temp_dir().empty()) {
576 Alert::error(_("Could not create temporary directory"),
577 bformat(_("Could not create a temporary directory in\n"
578 "%1$s. Make sure that this\n"
579 "path exists and is writable and try again."),
580 lyx::from_utf8(lyxrc.tempdir_path)));
581 // createLyXTmpDir() tries sufficiently hard to create a
582 // usable temp dir, so the probability to come here is
583 // close to zero. We therefore don't try to overcome this
584 // problem with e.g. asking the user for a new path and
585 // trying again but simply exit.
589 if (lyxerr.debugging(Debug::INIT)) {
590 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
593 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
594 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
599 void LyX::defaultKeyBindings(kb_keymap * kbmap)
601 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
602 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
603 kbmap->bind("Up", FuncRequest(LFUN_UP));
604 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
606 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
607 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
608 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
609 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
611 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
612 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
613 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
614 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
616 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
617 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
619 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
620 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
622 // kbmap->bindings to enable the use of the numeric keypad
624 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
625 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
626 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
627 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
628 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
629 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
630 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
631 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
632 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
640 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
641 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
642 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
643 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
644 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
645 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
646 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
647 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
651 void LyX::emergencyCleanup() const
653 // what to do about tmpfiles is non-obvious. we would
654 // like to delete any we find, but our lyxdir might
655 // contain documents etc. which might be helpful on
658 theApp->bufferList().emergencyWriteAll();
659 theApp->server().emergencyCleanup();
663 void LyX::deadKeyBindings(kb_keymap * kbmap)
665 // bindKeyings for transparent handling of deadkeys
666 // The keysyms are gotten from XFree86 X11R6
667 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
668 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
669 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
670 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
671 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
672 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
673 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
674 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
675 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
676 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
677 // nothing with this name
678 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
679 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
680 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
681 // nothing with this name either...
682 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
683 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
684 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
685 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
691 // return true if file does not exist or is older than configure.py.
692 bool needsUpdate(string const & file)
694 static string const configure_script =
695 addName(package().system_support(), "configure.py");
696 string const absfile =
697 addName(package().user_support(), file);
699 return (! fs::exists(absfile))
700 || (fs::last_write_time(configure_script)
701 > fs::last_write_time(absfile));
707 bool LyX::queryUserLyXDir(bool explicit_userdir)
709 // Does user directory exist?
710 if (fs::exists(package().user_support()) &&
711 fs::is_directory(package().user_support())) {
714 return needsUpdate("lyxrc.defaults")
715 || needsUpdate("textclass.lst")
716 || needsUpdate("packages.lst");
719 first_start = !explicit_userdir;
721 // If the user specified explicitly a directory, ask whether
722 // to create it. If the user says "no", then exit.
723 if (explicit_userdir &&
725 _("Missing user LyX directory"),
726 bformat(_("You have specified a non-existent user "
727 "LyX directory, %1$s.\n"
728 "It is needed to keep your own configuration."),
729 lyx::from_utf8(package().user_support())),
731 _("&Create directory"),
733 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
734 lyx_exit(EXIT_FAILURE);
737 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
738 lyx::from_utf8(package().user_support())))
741 if (!createDirectory(package().user_support(), 0755)) {
742 // Failed, so let's exit.
743 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
745 lyx_exit(EXIT_FAILURE);
752 bool LyX::readRcFile(string const & name)
754 lyxerr[Debug::INIT] << "About to read " << name << "... ";
756 string const lyxrc_path = libFileSearch(string(), name);
757 if (!lyxrc_path.empty()) {
759 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
761 if (lyxrc.read(lyxrc_path) < 0) {
766 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
772 // Read the ui file `name'
773 bool LyX::readUIFile(string const & name)
783 struct keyword_item uitags[ui_last - 1] = {
784 { "include", ui_include },
785 { "menuset", ui_menuset },
786 { "toolbar", ui_toolbar },
787 { "toolbars", ui_toolbars }
790 // Ensure that a file is read only once (prevents include loops)
791 static std::list<string> uifiles;
792 std::list<string>::const_iterator it = uifiles.begin();
793 std::list<string>::const_iterator end = uifiles.end();
794 it = std::find(it, end, name);
796 lyxerr[Debug::INIT] << "UI file '" << name
797 << "' has been read already. "
798 << "Is this an include loop?"
803 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
805 string const ui_path = libFileSearch("ui", name, "ui");
807 if (ui_path.empty()) {
808 lyxerr[Debug::INIT] << "Could not find " << name << endl;
812 uifiles.push_back(name);
814 lyxerr[Debug::INIT] << "Found " << name
815 << " in " << ui_path << endl;
816 LyXLex lex(uitags, ui_last - 1);
817 lex.setFile(ui_path);
819 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
823 if (lyxerr.debugging(Debug::PARSER))
824 lex.printTable(lyxerr);
830 string const file = lex.getString();
831 if (!readUIFile(file))
836 menubackend.read(lex);
840 toolbarbackend.read(lex);
844 toolbarbackend.readToolbars(lex);
848 if (!rtrim(lex.getString()).empty())
849 lex.printError("LyX::ReadUIFile: "
850 "Unknown menu tag: `$$Token'");
858 // Read the languages file `name'
859 bool LyX::readLanguagesFile(string const & name)
861 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
863 string const lang_path = libFileSearch(string(), name);
864 if (lang_path.empty()) {
868 languages.read(lang_path);
873 // Read the encodings file `name'
874 bool LyX::readEncodingsFile(string const & name)
876 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
878 string const enc_path = libFileSearch(string(), name);
879 if (enc_path.empty()) {
883 encodings.read(enc_path);
893 /// return the the number of arguments consumed
894 typedef boost::function<int(string const &, string const &)> cmd_helper;
896 int parse_dbg(string const & arg, string const &)
899 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
900 Debug::showTags(lyxerr);
903 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
905 lyxerr.level(Debug::value(arg));
906 Debug::showLevel(lyxerr, lyxerr.level());
911 int parse_help(string const &, string const &)
914 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
915 "Command line switches (case sensitive):\n"
916 "\t-help summarize LyX usage\n"
917 "\t-userdir dir set user directory to dir\n"
918 "\t-sysdir dir set system directory to dir\n"
919 "\t-geometry WxH+X+Y set geometry of the main window\n"
920 "\t-dbg feature[,feature]...\n"
921 " select the features to debug.\n"
922 " Type `lyx -dbg' to see the list of features\n"
923 "\t-x [--execute] command\n"
924 " where command is a lyx command.\n"
925 "\t-e [--export] fmt\n"
926 " where fmt is the export format of choice.\n"
927 "\t-i [--import] fmt file.xxx\n"
928 " where fmt is the import format of choice\n"
929 " and file.xxx is the file to be imported.\n"
930 "\t-version summarize version and build info\n"
931 "Check the LyX man page for more details.")) << endl;
936 int parse_version(string const &, string const &)
938 lyxerr << "LyX " << lyx_version
939 << " (" << lyx_release_date << ")" << endl;
940 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
942 lyxerr << lyx_version_info << endl;
947 int parse_sysdir(string const & arg, string const &)
950 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
953 cl_system_support = arg;
957 int parse_userdir(string const & arg, string const &)
960 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
963 cl_user_support = arg;
967 int parse_execute(string const & arg, string const &)
970 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
977 int parse_export(string const & type, string const &)
980 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
981 "--export switch")) << endl;
984 batch = "buffer-export " + type;
989 int parse_import(string const & type, string const & file)
992 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
993 "--import switch")) << endl;
997 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1001 batch = "buffer-import " + type + ' ' + file;
1008 bool LyX::easyParse(int & argc, char * argv[])
1010 std::map<string, cmd_helper> cmdmap;
1012 cmdmap["-dbg"] = parse_dbg;
1013 cmdmap["-help"] = parse_help;
1014 cmdmap["--help"] = parse_help;
1015 cmdmap["-version"] = parse_version;
1016 cmdmap["--version"] = parse_version;
1017 cmdmap["-sysdir"] = parse_sysdir;
1018 cmdmap["-userdir"] = parse_userdir;
1019 cmdmap["-x"] = parse_execute;
1020 cmdmap["--execute"] = parse_execute;
1021 cmdmap["-e"] = parse_export;
1022 cmdmap["--export"] = parse_export;
1023 cmdmap["-i"] = parse_import;
1024 cmdmap["--import"] = parse_import;
1026 for (int i = 1; i < argc; ++i) {
1027 std::map<string, cmd_helper>::const_iterator it
1028 = cmdmap.find(argv[i]);
1030 // check for X11 -geometry option
1031 if (lyx::support::compare(argv[i], "-geometry") == 0)
1032 geometryOption_ = true;
1034 // don't complain if not found - may be parsed later
1035 if (it == cmdmap.end())
1038 string arg((i + 1 < argc) ? argv[i + 1] : "");
1039 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1041 int const remove = 1 + it->second(arg, arg2);
1043 // Now, remove used arguments by shifting
1044 // the following ones remove places down.
1046 for (int j = i; j < argc; ++j)
1047 argv[j] = argv[j + remove];
1051 batch_command = batch;