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 // if a file is specified, I assume that user wants to edit *that* file
263 if (files.empty() && lyxrc.load_session) {
264 vector<string> const & lastopened = session_->lastOpenedFiles();
265 files.insert(files.end(), lastopened.begin(), lastopened.end() );
267 // clear this list to save a few bytes of RAM
268 session_->clearLastOpenedFiles();
270 // Execute batch commands if available
271 if (!batch_command.empty()) {
273 lyxerr[Debug::INIT] << "About to handle -x '"
274 << batch_command << '\'' << endl;
276 Buffer * last_loaded = 0;
278 vector<string>::const_iterator it = files.begin();
279 vector<string>::const_iterator end = files.end();
281 for (; it != end; ++it) {
282 // get absolute path of file and add ".lyx" to
283 // the filename if necessary
284 string s = fileSearch(string(), *it, "lyx");
286 Buffer * const b = newFile(*it, string(), true);
290 Buffer * buf = bufferlist.newBuffer(s, false);
291 if (loadLyXFile(buf, s))
294 bufferlist.release(buf);
296 ErrorList const & el = buf->getErrorList();
298 // There should be a way to use the following but I (abdel) don't know
299 // how to make it compile on MSVC2005.
300 //for_each(el.begin(), el.end(), mem_fun_ref(&LyX::printError));
301 for (ErrorList::const_iterator it = el.begin();
302 it != el.end(); ++it) {
309 // try to dispatch to last loaded buffer first
311 bool success = false;
312 if (last_loaded->dispatch(batch_command, &success)) {
317 files.clear(); // the files are already loaded
320 if (lyx_gui::use_gui) {
321 // determine windows size and position, from lyxrc and/or session
323 unsigned int width = 690;
324 unsigned int height = 510;
325 bool maximize = false;
327 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
328 width = lyxrc.geometry_width;
329 height = lyxrc.geometry_height;
331 // if lyxrc returns (0,0), then use session info
333 string val = session().loadSessionInfo("WindowWidth");
335 width = convert<unsigned int>(val);
336 val = session().loadSessionInfo("WindowHeight");
338 height = convert<unsigned int>(val);
339 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
342 // if user wants to restore window position
345 if (lyxrc.geometry_xysaved) {
346 string val = session().loadSessionInfo("WindowPosX");
348 posx = convert<int>(val);
349 val = session().loadSessionInfo("WindowPosY");
351 posy = convert<int>(val);
354 if (geometryOption_) {
359 return lyx_gui::start(batch_command, files, width, height, posx, posy, maximize);
362 // Something went wrong above
372 The SIGHUP signal does not exist on Windows and does not need to be handled.
374 Windows handles SIGFPE and SIGSEGV signals as expected.
376 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
377 cause a new thread to be spawned. This may well result in unexpected
378 behaviour by the single-threaded LyX.
380 SIGTERM signals will come only from another process actually sending
381 that signal using 'raise' in Windows' POSIX compatability layer. It will
382 not come from the general "terminate process" methods that everyone
383 actually uses (and which can't be trapped). Killing an app 'politely' on
384 Windows involves first sending a WM_CLOSE message, something that is
385 caught already by the Qt frontend.
387 For more information see:
389 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
390 ...signals are mostly useless on Windows for a variety of reasons that are
393 'UNIX Application Migration Guide, Chapter 9'
394 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
396 'How To Terminate an Application "Cleanly" in Win32'
397 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
401 static void error_handler(int err_sig)
403 // Throw away any signals other than the first one received.
404 static sig_atomic_t handling_error = false;
407 handling_error = true;
409 // We have received a signal indicating a fatal error, so
410 // try and save the data ASAP.
411 LyX::cref().emergencyCleanup();
413 // These lyxerr calls may or may not work:
415 // Signals are asynchronous, so the main program may be in a very
416 // fragile state when a signal is processed and thus while a signal
417 // handler function executes.
418 // In general, therefore, we should avoid performing any
419 // I/O operations or calling most library and system functions from
422 // This shouldn't matter here, however, as we've already invoked
427 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
431 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
434 lyxerr << "\nlyx: SIGSEGV signal caught\n"
435 "Sorry, you have found a bug in LyX. "
436 "Please read the bug-reporting instructions "
437 "in Help->Introduction and send us a bug report, "
438 "if necessary. Thanks !\nBye." << endl;
446 // Deinstall the signal handlers
448 signal(SIGHUP, SIG_DFL);
450 signal(SIGINT, SIG_DFL);
451 signal(SIGFPE, SIG_DFL);
452 signal(SIGSEGV, SIG_DFL);
453 signal(SIGTERM, SIG_DFL);
456 if (err_sig == SIGSEGV ||
457 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
459 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
461 lyx::support::abort();
468 void LyX::printError(ErrorItem const & ei)
470 std::cerr << _("LyX: ") << ei.error
471 << ':' << ei.description << std::endl;
479 signal(SIGHUP, error_handler);
481 signal(SIGFPE, error_handler);
482 signal(SIGSEGV, error_handler);
483 signal(SIGINT, error_handler);
484 signal(SIGTERM, error_handler);
485 // SIGPIPE can be safely ignored.
487 lyxrc.tempdir_path = package().temp_dir();
488 lyxrc.document_path = package().document_dir();
490 if (lyxrc.template_path.empty()) {
491 lyxrc.template_path = addPath(package().system_support(),
495 if (lyxrc.roman_font_name.empty())
496 lyxrc.roman_font_name = lyx_gui::roman_font_name();
497 if (lyxrc.sans_font_name.empty())
498 lyxrc.sans_font_name = lyx_gui::sans_font_name();
499 if (lyxrc.typewriter_font_name.empty())
500 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
503 // Read configuration files
506 // This one may have been distributed along with LyX.
507 if (!readRcFile("lyxrc.dist"))
510 // Set the PATH correctly.
511 #if !defined (USE_POSIX_PACKAGING)
512 // Add the directory containing the LyX executable to the path
513 // so that LyX can find things like tex2lyx.
514 if (package().build_support().empty())
515 prependEnvPath("PATH", package().binary_dir());
517 if (!lyxrc.path_prefix.empty())
518 prependEnvPath("PATH", lyxrc.path_prefix);
520 // Check that user LyX directory is ok. We don't do that if
521 // running in batch mode.
522 if (lyx_gui::use_gui) {
523 if (queryUserLyXDir(package().explicit_user_support()))
524 reconfigureUserLyXDir();
529 // This one is generated in user_support directory by lib/configure.py.
530 if (!readRcFile("lyxrc.defaults"))
533 // Query the OS to know what formats are viewed natively
534 formats.setAutoOpen();
536 system_lyxrc = lyxrc;
537 system_formats = formats;
538 system_converters = converters;
539 system_movers = movers;
540 system_lcolor = lcolor;
542 // This one is edited through the preferences dialog.
543 if (!readRcFile("preferences"))
546 if (!readEncodingsFile("encodings"))
548 if (!readLanguagesFile("languages"))
552 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
556 if (lyx_gui::use_gui) {
558 toplevel_keymap.reset(new kb_keymap);
559 defaultKeyBindings(toplevel_keymap.get());
560 toplevel_keymap->read(lyxrc.bind_file);
563 if (!readUIFile(lyxrc.ui_file))
567 if (lyxerr.debugging(Debug::LYXRC))
570 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
571 if (!lyxrc.path_prefix.empty())
572 prependEnvPath("PATH", lyxrc.path_prefix);
574 if (fs::exists(lyxrc.document_path) &&
575 fs::is_directory(lyxrc.document_path))
576 package().document_dir() = lyxrc.document_path;
578 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
579 if (package().temp_dir().empty()) {
580 Alert::error(_("Could not create temporary directory"),
581 bformat(_("Could not create a temporary directory in\n"
582 "%1$s. Make sure that this\n"
583 "path exists and is writable and try again."),
584 lyxrc.tempdir_path));
585 // createLyXTmpDir() tries sufficiently hard to create a
586 // usable temp dir, so the probability to come here is
587 // close to zero. We therefore don't try to overcome this
588 // problem with e.g. asking the user for a new path and
589 // trying again but simply exit.
593 if (lyxerr.debugging(Debug::INIT)) {
594 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
597 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
598 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
603 void LyX::defaultKeyBindings(kb_keymap * kbmap)
605 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
606 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
607 kbmap->bind("Up", FuncRequest(LFUN_UP));
608 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
610 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
611 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
612 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
613 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
615 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
616 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
617 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
618 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
620 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
621 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
623 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
624 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
626 // kbmap->bindings to enable the use of the numeric keypad
628 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
629 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
630 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
631 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
632 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
644 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
645 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
646 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
647 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
648 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
649 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
650 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
651 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
655 void LyX::emergencyCleanup() const
657 // what to do about tmpfiles is non-obvious. we would
658 // like to delete any we find, but our lyxdir might
659 // contain documents etc. which might be helpful on
662 bufferlist.emergencyWriteAll();
664 lyxserver->emergencyCleanup();
668 void LyX::deadKeyBindings(kb_keymap * kbmap)
670 // bindKeyings for transparent handling of deadkeys
671 // The keysyms are gotten from XFree86 X11R6
672 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
673 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
674 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
675 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
676 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
677 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
678 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
679 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
680 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
681 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
682 // nothing with this name
683 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
684 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
685 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
686 // nothing with this name either...
687 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
688 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
689 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
690 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
696 // return true if file does not exist or is older than configure.py.
697 bool needsUpdate(string const & file)
699 static string const configure_script =
700 addName(package().system_support(), "configure.py");
701 string const absfile =
702 addName(package().user_support(), file);
704 return (! fs::exists(absfile))
705 || (fs::last_write_time(configure_script)
706 > fs::last_write_time(absfile));
712 bool LyX::queryUserLyXDir(bool explicit_userdir)
714 // Does user directory exist?
715 if (fs::exists(package().user_support()) &&
716 fs::is_directory(package().user_support())) {
719 return needsUpdate("lyxrc.defaults")
720 || needsUpdate("textclass.lst")
721 || needsUpdate("packages.lst");
724 first_start = !explicit_userdir;
726 // If the user specified explicitly a directory, ask whether
727 // to create it. If the user says "no", then exit.
728 if (explicit_userdir &&
730 _("Missing user LyX directory"),
731 bformat(_("You have specified a non-existent user "
732 "LyX directory, %1$s.\n"
733 "It is needed to keep your own configuration."),
734 package().user_support()),
736 _("&Create directory"),
738 lyxerr << _("No user LyX directory. Exiting.") << endl;
739 lyx_exit(EXIT_FAILURE);
742 lyxerr << bformat(_("LyX: Creating directory %1$s"),
743 package().user_support())
746 if (!createDirectory(package().user_support(), 0755)) {
747 // Failed, so let's exit.
748 lyxerr << _("Failed to create directory. Exiting.")
750 lyx_exit(EXIT_FAILURE);
757 bool LyX::readRcFile(string const & name)
759 lyxerr[Debug::INIT] << "About to read " << name << "... ";
761 string const lyxrc_path = libFileSearch(string(), name);
762 if (!lyxrc_path.empty()) {
764 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
766 if (lyxrc.read(lyxrc_path) < 0) {
771 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
777 // Read the ui file `name'
778 bool LyX::readUIFile(string const & name)
788 struct keyword_item uitags[ui_last - 1] = {
789 { "include", ui_include },
790 { "menuset", ui_menuset },
791 { "toolbar", ui_toolbar },
792 { "toolbars", ui_toolbars }
795 // Ensure that a file is read only once (prevents include loops)
796 static std::list<string> uifiles;
797 std::list<string>::const_iterator it = uifiles.begin();
798 std::list<string>::const_iterator end = uifiles.end();
799 it = std::find(it, end, name);
801 lyxerr[Debug::INIT] << "UI file '" << name
802 << "' has been read already. "
803 << "Is this an include loop?"
808 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
810 string const ui_path = libFileSearch("ui", name, "ui");
812 if (ui_path.empty()) {
813 lyxerr[Debug::INIT] << "Could not find " << name << endl;
817 uifiles.push_back(name);
819 lyxerr[Debug::INIT] << "Found " << name
820 << " in " << ui_path << endl;
821 LyXLex lex(uitags, ui_last - 1);
822 lex.setFile(ui_path);
824 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
828 if (lyxerr.debugging(Debug::PARSER))
829 lex.printTable(lyxerr);
835 string const file = lex.getString();
836 if (!readUIFile(file))
841 menubackend.read(lex);
845 toolbarbackend.read(lex);
849 toolbarbackend.readToolbars(lex);
853 if (!rtrim(lex.getString()).empty())
854 lex.printError("LyX::ReadUIFile: "
855 "Unknown menu tag: `$$Token'");
863 // Read the languages file `name'
864 bool LyX::readLanguagesFile(string const & name)
866 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
868 string const lang_path = libFileSearch(string(), name);
869 if (lang_path.empty()) {
873 languages.read(lang_path);
878 // Read the encodings file `name'
879 bool LyX::readEncodingsFile(string const & name)
881 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
883 string const enc_path = libFileSearch(string(), name);
884 if (enc_path.empty()) {
888 encodings.read(enc_path);
898 /// return the the number of arguments consumed
899 typedef boost::function<int(string const &, string const &)> cmd_helper;
901 int parse_dbg(string const & arg, string const &)
904 lyxerr << _("List of supported debug flags:") << endl;
905 Debug::showTags(lyxerr);
908 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
910 lyxerr.level(Debug::value(arg));
911 Debug::showLevel(lyxerr, lyxerr.level());
916 int parse_help(string const &, string const &)
919 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
920 "Command line switches (case sensitive):\n"
921 "\t-help summarize LyX usage\n"
922 "\t-userdir dir set user directory to dir\n"
923 "\t-sysdir dir set system directory to dir\n"
924 "\t-geometry WxH+X+Y set geometry of the main window\n"
925 "\t-dbg feature[,feature]...\n"
926 " select the features to debug.\n"
927 " Type `lyx -dbg' to see the list of features\n"
928 "\t-x [--execute] command\n"
929 " where command is a lyx command.\n"
930 "\t-e [--export] fmt\n"
931 " where fmt is the export format of choice.\n"
932 "\t-i [--import] fmt file.xxx\n"
933 " where fmt is the import format of choice\n"
934 " and file.xxx is the file to be imported.\n"
935 "\t-version summarize version and build info\n"
936 "Check the LyX man page for more details.") << endl;
941 int parse_version(string const &, string const &)
943 lyxerr << "LyX " << lyx_version
944 << " of " << lyx_release_date << endl;
945 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
947 lyxerr << lyx_version_info << endl;
952 int parse_sysdir(string const & arg, string const &)
955 lyxerr << _("Missing directory for -sysdir switch") << endl;
958 cl_system_support = arg;
962 int parse_userdir(string const & arg, string const &)
965 lyxerr << _("Missing directory for -userdir switch") << endl;
968 cl_user_support = arg;
972 int parse_execute(string const & arg, string const &)
975 lyxerr << _("Missing command string after --execute switch") << endl;
982 int parse_export(string const & type, string const &)
985 lyxerr << _("Missing file type [eg latex, ps...] after "
986 "--export switch") << endl;
989 batch = "buffer-export " + type;
994 int parse_import(string const & type, string const & file)
997 lyxerr << _("Missing file type [eg latex, ps...] after "
998 "--import switch") << endl;
1002 lyxerr << _("Missing filename for --import") << endl;
1006 batch = "buffer-import " + type + ' ' + file;
1013 bool LyX::easyParse(int & argc, char * argv[])
1015 std::map<string, cmd_helper> cmdmap;
1017 cmdmap["-dbg"] = parse_dbg;
1018 cmdmap["-help"] = parse_help;
1019 cmdmap["--help"] = parse_help;
1020 cmdmap["-version"] = parse_version;
1021 cmdmap["--version"] = parse_version;
1022 cmdmap["-sysdir"] = parse_sysdir;
1023 cmdmap["-userdir"] = parse_userdir;
1024 cmdmap["-x"] = parse_execute;
1025 cmdmap["--execute"] = parse_execute;
1026 cmdmap["-e"] = parse_export;
1027 cmdmap["--export"] = parse_export;
1028 cmdmap["-i"] = parse_import;
1029 cmdmap["--import"] = parse_import;
1031 for (int i = 1; i < argc; ++i) {
1032 std::map<string, cmd_helper>::const_iterator it
1033 = cmdmap.find(argv[i]);
1035 // check for X11 -geometry option
1036 if (lyx::support::compare(argv[i], "-geometry") == 0)
1037 geometryOption_ = true;
1039 // don't complain if not found - may be parsed later
1040 if (it == cmdmap.end())
1043 string arg((i + 1 < argc) ? argv[i + 1] : "");
1044 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1046 int const remove = 1 + it->second(arg, arg2);
1048 // Now, remove used arguments by shifting
1049 // the following ones remove places down.
1051 for (int j = i; j < argc; ++j)
1052 argv[j] = argv[j + remove];
1056 batch_command = batch;