3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
21 #include "buffer_funcs.h"
22 #include "bufferlist.h"
23 #include "converter.h"
26 #include "errorlist.h"
37 #include "lyxtextclasslist.h"
38 #include "lyxserver.h"
39 #include "MenuBackend.h"
41 #include "ToolbarBackend.h"
43 #include "mathed/math_inset.h"
45 #include "frontends/Alert.h"
46 #include "frontends/lyx_gui.h"
47 #include "frontends/LyXView.h"
49 #include "support/environment.h"
50 #include "support/filetools.h"
51 #include "support/lyxlib.h"
52 #include "support/convert.h"
53 #include "support/os.h"
54 #include "support/package.h"
55 #include "support/path.h"
56 #include "support/systemcall.h"
58 #include <boost/bind.hpp>
59 #include <boost/filesystem/operations.hpp>
64 using lyx::support::addName;
65 using lyx::support::addPath;
66 using lyx::support::bformat;
67 using lyx::support::createDirectory;
68 using lyx::support::createLyXTmpDir;
69 using lyx::support::fileSearch;
70 using lyx::support::getEnv;
71 using lyx::support::i18nLibFileSearch;
72 using lyx::support::libFileSearch;
73 using lyx::support::package;
74 using lyx::support::Path;
75 using lyx::support::prependEnvPath;
76 using lyx::support::quoteName;
77 using lyx::support::rtrim;
78 using lyx::support::Systemcall;
80 namespace os = lyx::support::os;
81 namespace fs = boost::filesystem;
87 #ifndef CXX_GLOBAL_CSTD
94 extern LyXServer * lyxserver;
96 // This is the global bufferlist object
97 BufferList bufferlist;
99 // convenient to have it here.
100 boost::scoped_ptr<kb_keymap> toplevel_keymap;
104 // Filled with the command line arguments "foo" of "-sysdir foo" or
106 string cl_system_support;
107 string cl_user_support;
110 void lyx_exit(int status)
112 // FIXME: We should not directly call exit(), since it only
113 // guarantees a return to the system, no application cleanup.
114 // This may cause troubles with not executed destructors.
115 if (lyx_gui::use_gui)
116 lyx_gui::exit(status);
121 void showFileError(string const & error)
123 Alert::warning(_("Could not read configuration file"),
124 bformat(_("Error while reading the configuration file\n%1$s.\n"
125 "Please check your installation."), error));
126 lyx_exit(EXIT_FAILURE);
130 void reconfigureUserLyXDir()
132 string const configure_command = package().configure_command();
134 lyxerr << _("LyX: reconfiguring user directory") << endl;
135 Path p(package().user_support());
137 one.startscript(Systemcall::Wait, configure_command);
138 lyxerr << "LyX: " << _("Done!") << endl;
144 boost::scoped_ptr<LyX> LyX::singleton_;
146 void LyX::exec(int & argc, char * argv[])
148 BOOST_ASSERT(!singleton_.get());
149 // We must return from this before launching the gui so that
150 // other parts of the code can access singleton_ through
151 // LyX::ref and LyX::cref.
152 singleton_.reset(new LyX);
153 // Start the real execution loop.
154 singleton_->priv_exec(argc, argv);
160 BOOST_ASSERT(singleton_.get());
161 return *singleton_.get();
165 LyX const & LyX::cref()
167 BOOST_ASSERT(singleton_.get());
168 return *singleton_.get();
177 lyx::Session & LyX::session()
179 BOOST_ASSERT(session_.get());
180 return *session_.get();
184 lyx::Session const & LyX::session() const
186 BOOST_ASSERT(session_.get());
187 return *session_.get();
191 void LyX::addLyXView(boost::shared_ptr<LyXView> const & lyxview)
193 views_.push_back(lyxview);
197 Buffer const * const LyX::updateInset(InsetBase const * inset) const
202 Buffer const * buffer_ptr = 0;
203 ViewList::const_iterator it = views_.begin();
204 ViewList::const_iterator const end = views_.end();
205 for (; it != end; ++it) {
206 Buffer const * ptr = (*it)->updateInset(inset);
214 void LyX::priv_exec(int & argc, char * argv[])
216 // Here we need to parse the command line. At least
217 // we need to parse for "-dbg" and "-help"
218 lyx_gui::use_gui = easyParse(argc, argv);
220 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
221 lyx::support::top_build_dir_is_one_level_up);
223 // Start the real execution loop.
224 if (lyx_gui::use_gui)
225 lyx_gui::exec(argc, argv);
231 void LyX::exec2(int & argc, char * argv[])
233 // check for any spurious extra arguments
234 // other than documents
235 for (int argi = 1; argi < argc ; ++argi) {
236 if (argv[argi][0] == '-') {
237 lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
243 // Initialization of LyX (reads lyxrc and more)
244 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
246 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
248 if (lyx_gui::use_gui)
249 lyx_gui::parse_lyxrc();
251 vector<string> files;
253 for (int argi = argc - 1; argi >= 1; --argi)
254 files.push_back(os::internal_path(argv[argi]));
257 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
259 // if a file is specified, I assume that user wants to edit *that* file
260 if (files.empty() && lyxrc.load_session) {
261 vector<string> const & lastopened = session_->lastOpenedFiles();
262 files.insert(files.end(), lastopened.begin(), lastopened.end() );
264 // clear this list to save a few bytes of RAM
265 session_->clearLastOpenedFiles();
267 // Execute batch commands if available
268 if (!batch_command.empty()) {
270 lyxerr[Debug::INIT] << "About to handle -x '"
271 << batch_command << '\'' << endl;
273 Buffer * last_loaded = 0;
275 vector<string>::const_iterator it = files.begin();
276 vector<string>::const_iterator end = files.end();
278 for (; it != end; ++it) {
279 // get absolute path of file and add ".lyx" to
280 // the filename if necessary
281 string s = fileSearch(string(), *it, "lyx");
283 last_loaded = newFile(*it, string(), true);
285 Buffer * buf = bufferlist.newBuffer(s, false);
286 buf->error.connect(boost::bind(&LyX::printError, this, _1));
287 if (loadLyXFile(buf, s))
290 bufferlist.release(buf);
294 // try to dispatch to last loaded buffer first
296 bool success = false;
297 if (last_loaded->dispatch(batch_command, &success)) {
302 files.clear(); // the files are already loaded
305 if (lyx_gui::use_gui) {
306 // determine windows size and position, from lyxrc and/or session
308 unsigned int width = 690;
309 unsigned int height = 510;
311 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
312 width = lyxrc.geometry_width;
313 height = lyxrc.geometry_height;
315 // if lyxrc returns (0,0), then use session info
317 string val = session().loadSessionInfo("WindowWidth");
319 width = convert<unsigned int>(val);
320 val = session().loadSessionInfo("WindowHeight");
322 height = convert<unsigned int>(val);
324 // if user wants to restore window position
327 if (lyxrc.geometry_xysaved) {
328 string val = session().loadSessionInfo("WindowPosX");
330 posx = convert<int>(val);
331 val = session().loadSessionInfo("WindowPosY");
333 posy = convert<int>(val);
335 lyx_gui::start(batch_command, files, width, height, posx, posy);
337 // Something went wrong above
339 lyx_exit(EXIT_FAILURE);
347 The SIGHUP signal does not exist on Windows and does not need to be handled.
349 Windows handles SIGFPE and SIGSEGV signals as expected.
351 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
352 cause a new thread to be spawned. This may well result in unexpected
353 behaviour by the single-threaded LyX.
355 SIGTERM signals will come only from another process actually sending
356 that signal using 'raise' in Windows' POSIX compatability layer. It will
357 not come from the general "terminate process" methods that everyone
358 actually uses (and which can't be trapped). Killing an app 'politely' on
359 Windows involves first sending a WM_CLOSE message, something that is
360 caught already by the Qt frontend.
362 For more information see:
364 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
365 ...signals are mostly useless on Windows for a variety of reasons that are
368 'UNIX Application Migration Guide, Chapter 9'
369 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
371 'How To Terminate an Application "Cleanly" in Win32'
372 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
376 static void error_handler(int err_sig)
378 // Throw away any signals other than the first one received.
379 static sig_atomic_t handling_error = false;
382 handling_error = true;
384 // We have received a signal indicating a fatal error, so
385 // try and save the data ASAP.
386 LyX::cref().emergencyCleanup();
388 // These lyxerr calls may or may not work:
390 // Signals are asynchronous, so the main program may be in a very
391 // fragile state when a signal is processed and thus while a signal
392 // handler function executes.
393 // In general, therefore, we should avoid performing any
394 // I/O operations or calling most library and system functions from
397 // This shouldn't matter here, however, as we've already invoked
402 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
406 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
409 lyxerr << "\nlyx: SIGSEGV signal caught\n"
410 "Sorry, you have found a bug in LyX. "
411 "Please read the bug-reporting instructions "
412 "in Help->Introduction and send us a bug report, "
413 "if necessary. Thanks !\nBye." << endl;
421 // Deinstall the signal handlers
423 signal(SIGHUP, SIG_DFL);
425 signal(SIGINT, SIG_DFL);
426 signal(SIGFPE, SIG_DFL);
427 signal(SIGSEGV, SIG_DFL);
428 signal(SIGTERM, SIG_DFL);
431 if (err_sig == SIGSEGV ||
432 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
434 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
436 lyx::support::abort();
443 void LyX::printError(ErrorItem const & ei)
445 std::cerr << _("LyX: ") << ei.error
446 << ':' << ei.description << std::endl;
454 signal(SIGHUP, error_handler);
456 signal(SIGFPE, error_handler);
457 signal(SIGSEGV, error_handler);
458 signal(SIGINT, error_handler);
459 signal(SIGTERM, error_handler);
460 // SIGPIPE can be safely ignored.
462 lyxrc.tempdir_path = package().temp_dir();
463 lyxrc.document_path = package().document_dir();
465 if (lyxrc.template_path.empty()) {
466 lyxrc.template_path = addPath(package().system_support(),
470 if (lyxrc.roman_font_name.empty())
471 lyxrc.roman_font_name = lyx_gui::roman_font_name();
472 if (lyxrc.sans_font_name.empty())
473 lyxrc.sans_font_name = lyx_gui::sans_font_name();
474 if (lyxrc.typewriter_font_name.empty())
475 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
478 // Read configuration files
481 // This one may have been distributed along with LyX.
482 readRcFile("lyxrc.dist");
484 // Set the PATH correctly.
485 #if !defined (USE_POSIX_PACKAGING)
486 // Add the directory containing the LyX executable to the path
487 // so that LyX can find things like tex2lyx.
488 if (package().build_support().empty())
489 prependEnvPath("PATH", package().binary_dir());
491 if (!lyxrc.path_prefix.empty())
492 prependEnvPath("PATH", lyxrc.path_prefix);
494 // Check that user LyX directory is ok. We don't do that if
495 // running in batch mode.
496 if (lyx_gui::use_gui) {
497 if (queryUserLyXDir(package().explicit_user_support()))
498 reconfigureUserLyXDir();
503 // This one is generated in user_support directory by lib/configure.py.
504 readRcFile("lyxrc.defaults");
506 // Query the OS to know what formats are viewed natively
507 formats.setAutoOpen();
509 system_lyxrc = lyxrc;
510 system_formats = formats;
511 system_converters = converters;
512 system_movers = movers;
513 system_lcolor = lcolor;
515 // This one is edited through the preferences dialog.
516 readRcFile("preferences");
518 readEncodingsFile("encodings");
519 readLanguagesFile("languages");
522 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
525 if (lyx_gui::use_gui) {
527 toplevel_keymap.reset(new kb_keymap);
528 defaultKeyBindings(toplevel_keymap.get());
529 toplevel_keymap->read(lyxrc.bind_file);
532 readUIFile(lyxrc.ui_file);
535 if (lyxerr.debugging(Debug::LYXRC))
538 os::cygwin_path_fix(lyxrc.cygwin_path_fix);
539 if (!lyxrc.path_prefix.empty())
540 prependEnvPath("PATH", lyxrc.path_prefix);
542 if (fs::exists(lyxrc.document_path) &&
543 fs::is_directory(lyxrc.document_path))
544 package().document_dir() = lyxrc.document_path;
546 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
547 if (package().temp_dir().empty()) {
548 Alert::error(_("Could not create temporary directory"),
549 bformat(_("Could not create a temporary directory in\n"
550 "%1$s. Make sure that this\n"
551 "path exists and is writable and try again."),
552 lyxrc.tempdir_path));
553 // createLyXTmpDir() tries sufficiently hard to create a
554 // usable temp dir, so the probability to come here is
555 // close to zero. We therefore don't try to overcome this
556 // problem with e.g. asking the user for a new path and
557 // trying again but simply exit.
558 lyx_exit(EXIT_FAILURE);
561 if (lyxerr.debugging(Debug::INIT)) {
562 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
565 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
566 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
570 void LyX::defaultKeyBindings(kb_keymap * kbmap)
572 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
573 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
574 kbmap->bind("Up", FuncRequest(LFUN_UP));
575 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
577 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
578 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
579 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
580 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
582 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
583 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
584 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
585 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
587 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
588 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
590 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
591 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
593 // kbmap->bindings to enable the use of the numeric keypad
595 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
596 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
597 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
598 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
599 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
600 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
601 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
602 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
603 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
604 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
605 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
606 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
607 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
608 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
609 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
610 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
611 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
612 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
613 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
614 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
615 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
616 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
617 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
618 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
622 void LyX::emergencyCleanup() const
624 // what to do about tmpfiles is non-obvious. we would
625 // like to delete any we find, but our lyxdir might
626 // contain documents etc. which might be helpful on
629 bufferlist.emergencyWriteAll();
631 lyxserver->emergencyCleanup();
635 void LyX::deadKeyBindings(kb_keymap * kbmap)
637 // bindKeyings for transparent handling of deadkeys
638 // The keysyms are gotten from XFree86 X11R6
639 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
640 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
641 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
642 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
643 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
644 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
645 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
646 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
647 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
648 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
649 // nothing with this name
650 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
651 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
652 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
653 // nothing with this name either...
654 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
655 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
656 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
657 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
663 // return true if file does not exist or is older than configure.py.
664 bool needsUpdate(string const & file)
666 static string const configure_script =
667 addName(package().system_support(), "configure.py");
668 string const absfile =
669 addName(package().user_support(), file);
671 return (! fs::exists(absfile))
672 || (fs::last_write_time(configure_script)
673 > fs::last_write_time(absfile));
679 bool LyX::queryUserLyXDir(bool explicit_userdir)
681 // Does user directory exist?
682 if (fs::exists(package().user_support()) &&
683 fs::is_directory(package().user_support())) {
686 return needsUpdate("lyxrc.defaults")
687 || needsUpdate("textclass.lst")
688 || needsUpdate("packages.lst");
691 first_start = !explicit_userdir;
693 // If the user specified explicitly a directory, ask whether
694 // to create it. If the user says "no", then exit.
695 if (explicit_userdir &&
697 _("Missing user LyX directory"),
698 bformat(_("You have specified a non-existent user "
699 "LyX directory, %1$s.\n"
700 "It is needed to keep your own configuration."),
701 package().user_support()),
703 _("&Create directory"),
705 lyxerr << _("No user LyX directory. Exiting.") << endl;
706 lyx_exit(EXIT_FAILURE);
709 lyxerr << bformat(_("LyX: Creating directory %1$s"),
710 package().user_support())
713 if (!createDirectory(package().user_support(), 0755)) {
714 // Failed, so let's exit.
715 lyxerr << _("Failed to create directory. Exiting.")
717 lyx_exit(EXIT_FAILURE);
724 void LyX::readRcFile(string const & name)
726 lyxerr[Debug::INIT] << "About to read " << name << "... ";
728 string const lyxrc_path = libFileSearch(string(), name);
729 if (!lyxrc_path.empty()) {
731 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
733 if (lyxrc.read(lyxrc_path) < 0)
736 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
741 // Read the ui file `name'
742 void LyX::readUIFile(string const & name)
752 struct keyword_item uitags[ui_last - 1] = {
753 { "include", ui_include },
754 { "menuset", ui_menuset },
755 { "toolbar", ui_toolbar },
756 { "toolbars", ui_toolbars }
759 // Ensure that a file is read only once (prevents include loops)
760 static std::list<string> uifiles;
761 std::list<string>::const_iterator it = uifiles.begin();
762 std::list<string>::const_iterator end = uifiles.end();
763 it = std::find(it, end, name);
765 lyxerr[Debug::INIT] << "UI file '" << name
766 << "' has been read already. "
767 << "Is this an include loop?"
772 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
774 string const ui_path = libFileSearch("ui", name, "ui");
776 if (ui_path.empty()) {
777 lyxerr[Debug::INIT] << "Could not find " << name << endl;
781 uifiles.push_back(name);
783 lyxerr[Debug::INIT] << "Found " << name
784 << " in " << ui_path << endl;
785 LyXLex lex(uitags, ui_last - 1);
786 lex.setFile(ui_path);
788 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
792 if (lyxerr.debugging(Debug::PARSER))
793 lex.printTable(lyxerr);
799 string const file = lex.getString();
804 menubackend.read(lex);
808 toolbarbackend.read(lex);
812 toolbarbackend.readToolbars(lex);
816 if (!rtrim(lex.getString()).empty())
817 lex.printError("LyX::ReadUIFile: "
818 "Unknown menu tag: `$$Token'");
825 // Read the languages file `name'
826 void LyX::readLanguagesFile(string const & name)
828 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
830 string const lang_path = libFileSearch(string(), name);
831 if (lang_path.empty()) {
835 languages.read(lang_path);
839 // Read the encodings file `name'
840 void LyX::readEncodingsFile(string const & name)
842 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
844 string const enc_path = libFileSearch(string(), name);
845 if (enc_path.empty()) {
849 encodings.read(enc_path);
858 /// return the the number of arguments consumed
859 typedef boost::function<int(string const &, string const &)> cmd_helper;
861 int parse_dbg(string const & arg, string const &)
864 lyxerr << _("List of supported debug flags:") << endl;
865 Debug::showTags(lyxerr);
868 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
870 lyxerr.level(Debug::value(arg));
871 Debug::showLevel(lyxerr, lyxerr.level());
876 int parse_help(string const &, string const &)
879 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
880 "Command line switches (case sensitive):\n"
881 "\t-help summarize LyX usage\n"
882 "\t-userdir dir set user directory to dir\n"
883 "\t-sysdir dir set system directory to dir\n"
884 "\t-geometry WxH+X+Y set geometry of the main window\n"
885 "\t-dbg feature[,feature]...\n"
886 " select the features to debug.\n"
887 " Type `lyx -dbg' to see the list of features\n"
888 "\t-x [--execute] command\n"
889 " where command is a lyx command.\n"
890 "\t-e [--export] fmt\n"
891 " where fmt is the export format of choice.\n"
892 "\t-i [--import] fmt file.xxx\n"
893 " where fmt is the import format of choice\n"
894 " and file.xxx is the file to be imported.\n"
895 "\t-version summarize version and build info\n"
896 "Check the LyX man page for more details.") << endl;
901 int parse_version(string const &, string const &)
903 lyxerr << "LyX " << lyx_version
904 << " of " << lyx_release_date << endl;
905 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
907 lyxerr << lyx_version_info << endl;
912 int parse_sysdir(string const & arg, string const &)
915 lyxerr << _("Missing directory for -sysdir switch") << endl;
918 cl_system_support = arg;
922 int parse_userdir(string const & arg, string const &)
925 lyxerr << _("Missing directory for -userdir switch") << endl;
928 cl_user_support = arg;
932 int parse_execute(string const & arg, string const &)
935 lyxerr << _("Missing command string after --execute switch") << endl;
942 int parse_export(string const & type, string const &)
945 lyxerr << _("Missing file type [eg latex, ps...] after "
946 "--export switch") << endl;
949 batch = "buffer-export " + type;
954 int parse_import(string const & type, string const & file)
957 lyxerr << _("Missing file type [eg latex, ps...] after "
958 "--import switch") << endl;
962 lyxerr << _("Missing filename for --import") << endl;
966 batch = "buffer-import " + type + ' ' + file;
973 bool LyX::easyParse(int & argc, char * argv[])
975 std::map<string, cmd_helper> cmdmap;
977 cmdmap["-dbg"] = parse_dbg;
978 cmdmap["-help"] = parse_help;
979 cmdmap["--help"] = parse_help;
980 cmdmap["-version"] = parse_version;
981 cmdmap["--version"] = parse_version;
982 cmdmap["-sysdir"] = parse_sysdir;
983 cmdmap["-userdir"] = parse_userdir;
984 cmdmap["-x"] = parse_execute;
985 cmdmap["--execute"] = parse_execute;
986 cmdmap["-e"] = parse_export;
987 cmdmap["--export"] = parse_export;
988 cmdmap["-i"] = parse_import;
989 cmdmap["--import"] = parse_import;
991 for (int i = 1; i < argc; ++i) {
992 std::map<string, cmd_helper>::const_iterator it
993 = cmdmap.find(argv[i]);
995 // don't complain if not found - may be parsed later
996 if (it == cmdmap.end())
999 string arg((i + 1 < argc) ? argv[i + 1] : "");
1000 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1002 int const remove = 1 + it->second(arg, arg2);
1004 // Now, remove used arguments by shifting
1005 // the following ones remove places down.
1007 for (int j = i; j < argc; ++j)
1008 argv[j] = argv[j + remove];
1012 batch_command = batch;