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;
86 using std::mem_fun_ref;
88 #ifndef CXX_GLOBAL_CSTD
95 extern LyXServer * lyxserver;
97 // This is the global bufferlist object
98 BufferList bufferlist;
100 // convenient to have it here.
101 boost::scoped_ptr<kb_keymap> toplevel_keymap;
105 // Filled with the command line arguments "foo" of "-sysdir foo" or
107 string cl_system_support;
108 string cl_user_support;
111 void lyx_exit(int status)
113 // FIXME: We should not directly call exit(), since it only
114 // guarantees a return to the system, no application cleanup.
115 // This may cause troubles with not executed destructors.
116 if (lyx_gui::use_gui)
117 // lyx_gui::exit may return and only schedule the exit
118 lyx_gui::exit(status);
123 void showFileError(string const & error)
125 Alert::warning(_("Could not read configuration file"),
126 bformat(_("Error while reading the configuration file\n%1$s.\n"
127 "Please check your installation."), error));
131 void reconfigureUserLyXDir()
133 string const configure_command = package().configure_command();
135 lyxerr << _("LyX: reconfiguring user directory") << endl;
136 Path p(package().user_support());
138 one.startscript(Systemcall::Wait, configure_command);
139 lyxerr << "LyX: " << _("Done!") << endl;
145 boost::scoped_ptr<LyX> LyX::singleton_;
147 int LyX::exec(int & argc, char * argv[])
149 BOOST_ASSERT(!singleton_.get());
150 // We must return from this before launching the gui so that
151 // other parts of the code can access singleton_ through
152 // LyX::ref and LyX::cref.
153 singleton_.reset(new LyX);
154 // Start the real execution loop.
155 return singleton_->priv_exec(argc, argv);
161 BOOST_ASSERT(singleton_.get());
162 return *singleton_.get();
166 LyX const & LyX::cref()
168 BOOST_ASSERT(singleton_.get());
169 return *singleton_.get();
174 : first_start(false), geometryOption_(false)
178 lyx::Session & LyX::session()
180 BOOST_ASSERT(session_.get());
181 return *session_.get();
185 lyx::Session const & LyX::session() const
187 BOOST_ASSERT(session_.get());
188 return *session_.get();
192 void LyX::addLyXView(LyXView * lyxview)
194 views_.push_back(lyxview);
198 Buffer const * const LyX::updateInset(InsetBase const * inset) const
203 Buffer const * buffer_ptr = 0;
204 ViewList::const_iterator it = views_.begin();
205 ViewList::const_iterator const end = views_.end();
206 for (; it != end; ++it) {
207 Buffer const * ptr = (*it)->updateInset(inset);
215 int LyX::priv_exec(int & argc, char * argv[])
217 // Here we need to parse the command line. At least
218 // we need to parse for "-dbg" and "-help"
219 lyx_gui::use_gui = easyParse(argc, argv);
221 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
222 lyx::support::top_build_dir_is_one_level_up);
224 // Start the real execution loop.
225 if (lyx_gui::use_gui)
226 return lyx_gui::exec(argc, argv);
228 return exec2(argc, argv);
232 int LyX::exec2(int & argc, char * argv[])
234 // check for any spurious extra arguments
235 // other than documents
236 for (int argi = 1; argi < argc ; ++argi) {
237 if (argv[argi][0] == '-') {
238 lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
244 // Initialization of LyX (reads lyxrc and more)
245 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
246 bool const success = init();
247 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
251 if (lyx_gui::use_gui)
252 lyx_gui::parse_lyxrc();
254 vector<string> files;
256 for (int argi = argc - 1; argi >= 1; --argi)
257 files.push_back(os::internal_path(argv[argi]));
260 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
262 // Execute batch commands if available
263 if (!batch_command.empty()) {
265 lyxerr[Debug::INIT] << "About to handle -x '"
266 << batch_command << '\'' << endl;
268 Buffer * last_loaded = 0;
270 vector<string>::const_iterator it = files.begin();
271 vector<string>::const_iterator end = files.end();
273 for (; it != end; ++it) {
274 // get absolute path of file and add ".lyx" to
275 // the filename if necessary
276 string s = fileSearch(string(), *it, "lyx");
278 Buffer * const b = newFile(*it, string(), true);
282 Buffer * buf = bufferlist.newBuffer(s, false);
283 if (loadLyXFile(buf, s))
286 bufferlist.release(buf);
288 ErrorList const & el = buf->getErrorList();
290 // There should be a way to use the following but I (abdel) don't know
291 // how to make it compile on MSVC2005.
292 //for_each(el.begin(), el.end(), mem_fun_ref(&LyX::printError));
293 for (ErrorList::const_iterator it = el.begin();
294 it != el.end(); ++it) {
301 // try to dispatch to last loaded buffer first
303 bool success = false;
304 if (last_loaded->dispatch(batch_command, &success)) {
309 files.clear(); // the files are already loaded
312 if (lyx_gui::use_gui) {
313 // determine windows size and position, from lyxrc and/or session
315 unsigned int width = 690;
316 unsigned int height = 510;
317 bool maximize = false;
319 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
320 width = lyxrc.geometry_width;
321 height = lyxrc.geometry_height;
323 // if lyxrc returns (0,0), then use session info
325 string val = session().loadSessionInfo("WindowWidth");
327 width = convert<unsigned int>(val);
328 val = session().loadSessionInfo("WindowHeight");
330 height = convert<unsigned int>(val);
331 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
334 // if user wants to restore window position
337 if (lyxrc.geometry_xysaved) {
338 string val = session().loadSessionInfo("WindowPosX");
340 posx = convert<int>(val);
341 val = session().loadSessionInfo("WindowPosY");
343 posy = convert<int>(val);
346 if (geometryOption_) {
350 // create the main window
351 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
354 for_each(files.begin(), files.end(),
355 bind(&LyXView::loadLyXFile, view, _1, true));
357 // if a file is specified, I assume that user wants to edit *that* file
358 if (files.empty() && lyxrc.load_session) {
359 vector<string> const & lastopened = session_->lastOpenedFiles();
360 // do not add to the lastfile list since these files are restored from
361 // last seesion, and should be already there (regular files), or should
362 // not be added at all (help files).
363 for_each(lastopened.begin(), lastopened.end(),
364 bind(&LyXView::loadLyXFile, view, _1, false));
366 // clear this list to save a few bytes of RAM
367 session_->clearLastOpenedFiles();
369 return lyx_gui::start(view, batch_command);
371 // Something went wrong above
381 The SIGHUP signal does not exist on Windows and does not need to be handled.
383 Windows handles SIGFPE and SIGSEGV signals as expected.
385 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
386 cause a new thread to be spawned. This may well result in unexpected
387 behaviour by the single-threaded LyX.
389 SIGTERM signals will come only from another process actually sending
390 that signal using 'raise' in Windows' POSIX compatability layer. It will
391 not come from the general "terminate process" methods that everyone
392 actually uses (and which can't be trapped). Killing an app 'politely' on
393 Windows involves first sending a WM_CLOSE message, something that is
394 caught already by the Qt frontend.
396 For more information see:
398 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
399 ...signals are mostly useless on Windows for a variety of reasons that are
402 'UNIX Application Migration Guide, Chapter 9'
403 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
405 'How To Terminate an Application "Cleanly" in Win32'
406 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
410 static void error_handler(int err_sig)
412 // Throw away any signals other than the first one received.
413 static sig_atomic_t handling_error = false;
416 handling_error = true;
418 // We have received a signal indicating a fatal error, so
419 // try and save the data ASAP.
420 LyX::cref().emergencyCleanup();
422 // These lyxerr calls may or may not work:
424 // Signals are asynchronous, so the main program may be in a very
425 // fragile state when a signal is processed and thus while a signal
426 // handler function executes.
427 // In general, therefore, we should avoid performing any
428 // I/O operations or calling most library and system functions from
431 // This shouldn't matter here, however, as we've already invoked
436 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
440 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
443 lyxerr << "\nlyx: SIGSEGV signal caught\n"
444 "Sorry, you have found a bug in LyX. "
445 "Please read the bug-reporting instructions "
446 "in Help->Introduction and send us a bug report, "
447 "if necessary. Thanks !\nBye." << endl;
455 // Deinstall the signal handlers
457 signal(SIGHUP, SIG_DFL);
459 signal(SIGINT, SIG_DFL);
460 signal(SIGFPE, SIG_DFL);
461 signal(SIGSEGV, SIG_DFL);
462 signal(SIGTERM, SIG_DFL);
465 if (err_sig == SIGSEGV ||
466 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
468 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
470 lyx::support::abort();
477 void LyX::printError(ErrorItem const & ei)
479 std::cerr << _("LyX: ") << ei.error
480 << ':' << ei.description << std::endl;
488 signal(SIGHUP, error_handler);
490 signal(SIGFPE, error_handler);
491 signal(SIGSEGV, error_handler);
492 signal(SIGINT, error_handler);
493 signal(SIGTERM, error_handler);
494 // SIGPIPE can be safely ignored.
496 lyxrc.tempdir_path = package().temp_dir();
497 lyxrc.document_path = package().document_dir();
499 if (lyxrc.template_path.empty()) {
500 lyxrc.template_path = addPath(package().system_support(),
504 if (lyxrc.roman_font_name.empty())
505 lyxrc.roman_font_name = lyx_gui::roman_font_name();
506 if (lyxrc.sans_font_name.empty())
507 lyxrc.sans_font_name = lyx_gui::sans_font_name();
508 if (lyxrc.typewriter_font_name.empty())
509 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
512 // Read configuration files
515 // This one may have been distributed along with LyX.
516 if (!readRcFile("lyxrc.dist"))
519 // Set the PATH correctly.
520 #if !defined (USE_POSIX_PACKAGING)
521 // Add the directory containing the LyX executable to the path
522 // so that LyX can find things like tex2lyx.
523 if (package().build_support().empty())
524 prependEnvPath("PATH", package().binary_dir());
526 if (!lyxrc.path_prefix.empty())
527 prependEnvPath("PATH", lyxrc.path_prefix);
529 // Check that user LyX directory is ok.
530 if (queryUserLyXDir(package().explicit_user_support()))
531 reconfigureUserLyXDir();
533 // no need for a splash when there is no GUI
534 if (!lyx_gui::use_gui) {
538 // This one is generated in user_support directory by lib/configure.py.
539 if (!readRcFile("lyxrc.defaults"))
542 // Query the OS to know what formats are viewed natively
543 formats.setAutoOpen();
545 system_lyxrc = lyxrc;
546 system_formats = formats;
547 system_converters = converters;
548 system_movers = movers;
549 system_lcolor = lcolor;
551 // This one is edited through the preferences dialog.
552 if (!readRcFile("preferences"))
555 if (!readEncodingsFile("encodings"))
557 if (!readLanguagesFile("languages"))
561 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
565 if (lyx_gui::use_gui) {
567 toplevel_keymap.reset(new kb_keymap);
568 defaultKeyBindings(toplevel_keymap.get());
569 toplevel_keymap->read(lyxrc.bind_file);
572 if (!readUIFile(lyxrc.ui_file))
576 if (lyxerr.debugging(Debug::LYXRC))
579 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
580 if (!lyxrc.path_prefix.empty())
581 prependEnvPath("PATH", lyxrc.path_prefix);
583 if (fs::exists(lyxrc.document_path) &&
584 fs::is_directory(lyxrc.document_path))
585 package().document_dir() = lyxrc.document_path;
587 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
588 if (package().temp_dir().empty()) {
589 Alert::error(_("Could not create temporary directory"),
590 bformat(_("Could not create a temporary directory in\n"
591 "%1$s. Make sure that this\n"
592 "path exists and is writable and try again."),
593 lyxrc.tempdir_path));
594 // createLyXTmpDir() tries sufficiently hard to create a
595 // usable temp dir, so the probability to come here is
596 // close to zero. We therefore don't try to overcome this
597 // problem with e.g. asking the user for a new path and
598 // trying again but simply exit.
602 if (lyxerr.debugging(Debug::INIT)) {
603 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
606 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
607 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
612 void LyX::defaultKeyBindings(kb_keymap * kbmap)
614 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
615 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
616 kbmap->bind("Up", FuncRequest(LFUN_UP));
617 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
619 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
620 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
621 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
622 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
624 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
625 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
626 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
627 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
629 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
630 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
632 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
633 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
635 // kbmap->bindings to enable the use of the numeric keypad
637 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
639 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
640 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
647 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
648 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
649 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
650 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
651 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
652 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
653 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
654 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
655 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
656 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
657 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
658 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
659 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
660 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
664 void LyX::emergencyCleanup() const
666 // what to do about tmpfiles is non-obvious. we would
667 // like to delete any we find, but our lyxdir might
668 // contain documents etc. which might be helpful on
671 bufferlist.emergencyWriteAll();
673 lyxserver->emergencyCleanup();
677 void LyX::deadKeyBindings(kb_keymap * kbmap)
679 // bindKeyings for transparent handling of deadkeys
680 // The keysyms are gotten from XFree86 X11R6
681 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
682 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
683 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
684 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
685 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
686 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
687 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
688 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
689 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
690 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
691 // nothing with this name
692 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
693 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
694 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
695 // nothing with this name either...
696 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
697 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
698 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
699 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
705 // return true if file does not exist or is older than configure.py.
706 bool needsUpdate(string const & file)
708 static string const configure_script =
709 addName(package().system_support(), "configure.py");
710 string const absfile =
711 addName(package().user_support(), file);
713 return (! fs::exists(absfile))
714 || (fs::last_write_time(configure_script)
715 > fs::last_write_time(absfile));
721 bool LyX::queryUserLyXDir(bool explicit_userdir)
723 // Does user directory exist?
724 if (fs::exists(package().user_support()) &&
725 fs::is_directory(package().user_support())) {
728 return needsUpdate("lyxrc.defaults")
729 || needsUpdate("textclass.lst")
730 || needsUpdate("packages.lst");
733 first_start = !explicit_userdir;
735 // If the user specified explicitly a directory, ask whether
736 // to create it. If the user says "no", then exit.
737 if (explicit_userdir &&
739 _("Missing user LyX directory"),
740 bformat(_("You have specified a non-existent user "
741 "LyX directory, %1$s.\n"
742 "It is needed to keep your own configuration."),
743 package().user_support()),
745 _("&Create directory"),
747 lyxerr << _("No user LyX directory. Exiting.") << endl;
748 lyx_exit(EXIT_FAILURE);
751 lyxerr << bformat(_("LyX: Creating directory %1$s"),
752 package().user_support())
755 if (!createDirectory(package().user_support(), 0755)) {
756 // Failed, so let's exit.
757 lyxerr << _("Failed to create directory. Exiting.")
759 lyx_exit(EXIT_FAILURE);
766 bool LyX::readRcFile(string const & name)
768 lyxerr[Debug::INIT] << "About to read " << name << "... ";
770 string const lyxrc_path = libFileSearch(string(), name);
771 if (!lyxrc_path.empty()) {
773 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
775 if (lyxrc.read(lyxrc_path) < 0) {
780 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
786 // Read the ui file `name'
787 bool LyX::readUIFile(string const & name)
797 struct keyword_item uitags[ui_last - 1] = {
798 { "include", ui_include },
799 { "menuset", ui_menuset },
800 { "toolbar", ui_toolbar },
801 { "toolbars", ui_toolbars }
804 // Ensure that a file is read only once (prevents include loops)
805 static std::list<string> uifiles;
806 std::list<string>::const_iterator it = uifiles.begin();
807 std::list<string>::const_iterator end = uifiles.end();
808 it = std::find(it, end, name);
810 lyxerr[Debug::INIT] << "UI file '" << name
811 << "' has been read already. "
812 << "Is this an include loop?"
817 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
819 string const ui_path = libFileSearch("ui", name, "ui");
821 if (ui_path.empty()) {
822 lyxerr[Debug::INIT] << "Could not find " << name << endl;
826 uifiles.push_back(name);
828 lyxerr[Debug::INIT] << "Found " << name
829 << " in " << ui_path << endl;
830 LyXLex lex(uitags, ui_last - 1);
831 lex.setFile(ui_path);
833 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
837 if (lyxerr.debugging(Debug::PARSER))
838 lex.printTable(lyxerr);
844 string const file = lex.getString();
845 if (!readUIFile(file))
850 menubackend.read(lex);
854 toolbarbackend.read(lex);
858 toolbarbackend.readToolbars(lex);
862 if (!rtrim(lex.getString()).empty())
863 lex.printError("LyX::ReadUIFile: "
864 "Unknown menu tag: `$$Token'");
872 // Read the languages file `name'
873 bool LyX::readLanguagesFile(string const & name)
875 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
877 string const lang_path = libFileSearch(string(), name);
878 if (lang_path.empty()) {
882 languages.read(lang_path);
887 // Read the encodings file `name'
888 bool LyX::readEncodingsFile(string const & name)
890 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
892 string const enc_path = libFileSearch(string(), name);
893 if (enc_path.empty()) {
897 encodings.read(enc_path);
907 /// return the the number of arguments consumed
908 typedef boost::function<int(string const &, string const &)> cmd_helper;
910 int parse_dbg(string const & arg, string const &)
913 lyxerr << _("List of supported debug flags:") << endl;
914 Debug::showTags(lyxerr);
917 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
919 lyxerr.level(Debug::value(arg));
920 Debug::showLevel(lyxerr, lyxerr.level());
925 int parse_help(string const &, string const &)
928 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
929 "Command line switches (case sensitive):\n"
930 "\t-help summarize LyX usage\n"
931 "\t-userdir dir set user directory to dir\n"
932 "\t-sysdir dir set system directory to dir\n"
933 "\t-geometry WxH+X+Y set geometry of the main window\n"
934 "\t-dbg feature[,feature]...\n"
935 " select the features to debug.\n"
936 " Type `lyx -dbg' to see the list of features\n"
937 "\t-x [--execute] command\n"
938 " where command is a lyx command.\n"
939 "\t-e [--export] fmt\n"
940 " where fmt is the export format of choice.\n"
941 "\t-i [--import] fmt file.xxx\n"
942 " where fmt is the import format of choice\n"
943 " and file.xxx is the file to be imported.\n"
944 "\t-version summarize version and build info\n"
945 "Check the LyX man page for more details.") << endl;
950 int parse_version(string const &, string const &)
952 lyxerr << "LyX " << lyx_version
953 << " of " << lyx_release_date << endl;
954 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
956 lyxerr << lyx_version_info << endl;
961 int parse_sysdir(string const & arg, string const &)
964 lyxerr << _("Missing directory for -sysdir switch") << endl;
967 cl_system_support = arg;
971 int parse_userdir(string const & arg, string const &)
974 lyxerr << _("Missing directory for -userdir switch") << endl;
977 cl_user_support = arg;
981 int parse_execute(string const & arg, string const &)
984 lyxerr << _("Missing command string after --execute switch") << endl;
991 int parse_export(string const & type, string const &)
994 lyxerr << _("Missing file type [eg latex, ps...] after "
995 "--export switch") << endl;
998 batch = "buffer-export " + type;
1003 int parse_import(string const & type, string const & file)
1006 lyxerr << _("Missing file type [eg latex, ps...] after "
1007 "--import switch") << endl;
1011 lyxerr << _("Missing filename for --import") << endl;
1015 batch = "buffer-import " + type + ' ' + file;
1022 bool LyX::easyParse(int & argc, char * argv[])
1024 std::map<string, cmd_helper> cmdmap;
1026 cmdmap["-dbg"] = parse_dbg;
1027 cmdmap["-help"] = parse_help;
1028 cmdmap["--help"] = parse_help;
1029 cmdmap["-version"] = parse_version;
1030 cmdmap["--version"] = parse_version;
1031 cmdmap["-sysdir"] = parse_sysdir;
1032 cmdmap["-userdir"] = parse_userdir;
1033 cmdmap["-x"] = parse_execute;
1034 cmdmap["--execute"] = parse_execute;
1035 cmdmap["-e"] = parse_export;
1036 cmdmap["--export"] = parse_export;
1037 cmdmap["-i"] = parse_import;
1038 cmdmap["--import"] = parse_import;
1040 for (int i = 1; i < argc; ++i) {
1041 std::map<string, cmd_helper>::const_iterator it
1042 = cmdmap.find(argv[i]);
1044 // check for X11 -geometry option
1045 if (lyx::support::compare(argv[i], "-geometry") == 0)
1046 geometryOption_ = true;
1048 // don't complain if not found - may be parsed later
1049 if (it == cmdmap.end())
1052 string arg((i + 1 < argc) ? argv[i + 1] : "");
1053 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1055 int const remove = 1 + it->second(arg, arg2);
1057 // Now, remove used arguments by shifting
1058 // the following ones remove places down.
1060 for (int j = i; j < argc; ++j)
1061 argv[j] = argv[j + remove];
1065 batch_command = batch;