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/os.h"
53 #include "support/package.h"
54 #include "support/path.h"
55 #include "support/systemcall.h"
57 #include <boost/bind.hpp>
58 #include <boost/filesystem/operations.hpp>
63 using lyx::support::addName;
64 using lyx::support::addPath;
65 using lyx::support::bformat;
66 using lyx::support::createDirectory;
67 using lyx::support::createLyXTmpDir;
68 using lyx::support::fileSearch;
69 using lyx::support::getEnv;
70 using lyx::support::i18nLibFileSearch;
71 using lyx::support::libFileSearch;
72 using lyx::support::package;
73 using lyx::support::Path;
74 using lyx::support::prependEnvPath;
75 using lyx::support::quoteName;
76 using lyx::support::rtrim;
77 using lyx::support::Systemcall;
79 namespace os = lyx::support::os;
80 namespace fs = boost::filesystem;
86 #ifndef CXX_GLOBAL_CSTD
93 extern LyXServer * lyxserver;
95 // This is the global bufferlist object
96 BufferList bufferlist;
98 // convenient to have it here.
99 boost::scoped_ptr<kb_keymap> toplevel_keymap;
103 // Filled with the command line arguments "foo" of "-sysdir foo" or
105 string cl_system_support;
106 string cl_user_support;
109 void showFileError(string const & error)
111 Alert::warning(_("Could not read configuration file"),
112 bformat(_("Error while reading the configuration file\n%1$s.\n"
113 "Please check your installation."), error));
118 void reconfigureUserLyXDir()
120 string const configure_command = package().configure_command();
122 lyxerr << _("LyX: reconfiguring user directory") << endl;
123 Path p(package().user_support());
125 one.startscript(Systemcall::Wait, configure_command);
126 lyxerr << "LyX: " << _("Done!") << endl;
132 boost::scoped_ptr<LyX> LyX::singleton_;
134 void LyX::exec(int & argc, char * argv[])
136 BOOST_ASSERT(!singleton_.get());
137 // We must return from this before launching the gui so that
138 // other parts of the code can access singleton_ through
139 // LyX::ref and LyX::cref.
140 singleton_.reset(new LyX);
141 // Start the real execution loop.
142 singleton_->priv_exec(argc, argv);
148 BOOST_ASSERT(singleton_.get());
149 return *singleton_.get();
153 LyX const & LyX::cref()
155 BOOST_ASSERT(singleton_.get());
156 return *singleton_.get();
165 lyx::Session & LyX::session()
167 BOOST_ASSERT(session_.get());
168 return *session_.get();
172 lyx::Session const & LyX::session() const
174 BOOST_ASSERT(session_.get());
175 return *session_.get();
179 void LyX::addLyXView(boost::shared_ptr<LyXView> const & lyxview)
181 views_.push_back(lyxview);
185 Buffer const * const LyX::updateInset(InsetBase const * inset) const
190 Buffer const * buffer_ptr = 0;
191 ViewList::const_iterator it = views_.begin();
192 ViewList::const_iterator const end = views_.end();
193 for (; it != end; ++it) {
194 Buffer const * ptr = (*it)->updateInset(inset);
202 void LyX::priv_exec(int & argc, char * argv[])
204 // Here we need to parse the command line. At least
205 // we need to parse for "-dbg" and "-help"
206 bool const want_gui = easyParse(argc, argv);
208 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
209 lyx::support::top_build_dir_is_one_level_up);
212 lyx_gui::parse_init(argc, argv);
214 // check for any spurious extra arguments
215 // other than documents
216 for (int argi = 1; argi < argc ; ++argi) {
217 if (argv[argi][0] == '-') {
218 lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
224 // Initialization of LyX (reads lyxrc and more)
225 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
227 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
230 lyx_gui::parse_lyxrc();
232 vector<string> files;
234 for (int argi = argc - 1; argi >= 1; --argi)
235 files.push_back(os::internal_path(argv[argi]));
238 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
240 // if a file is specified, I assume that user wants to edit *that* file
241 if (files.empty() && lyxrc.load_session) {
242 vector<string> const & lastopened = session_->lastOpenedFiles();
243 files.insert(files.end(), lastopened.begin(), lastopened.end() );
245 // clear this list to save a few bytes of RAM
246 session_->clearLastOpenedFiles();
248 // Execute batch commands if available
249 if (!batch_command.empty()) {
251 lyxerr[Debug::INIT] << "About to handle -x '"
252 << batch_command << '\'' << endl;
254 Buffer * last_loaded = 0;
256 vector<string>::const_iterator it = files.begin();
257 vector<string>::const_iterator end = files.end();
259 for (; it != end; ++it) {
260 // get absolute path of file and add ".lyx" to
261 // the filename if necessary
262 string s = fileSearch(string(), *it, "lyx");
264 last_loaded = newFile(*it, string(), true);
266 Buffer * buf = bufferlist.newBuffer(s, false);
267 buf->error.connect(boost::bind(&LyX::printError, this, _1));
268 if (loadLyXFile(buf, s))
271 bufferlist.release(buf);
275 // try to dispatch to last loaded buffer first
277 bool success = false;
278 if (last_loaded->dispatch(batch_command, &success)) {
283 files.clear(); // the files are already loaded
287 lyx_gui::start(batch_command, files);
289 // Something went wrong above
299 The SIGHUP signal does not exist on Windows and does not need to be handled.
301 Windows handles SIGFPE and SIGSEGV signals as expected.
303 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
304 cause a new thread to be spawned. This may well result in unexpected
305 behaviour by the single-threaded LyX.
307 SIGTERM signals will come only from another process actually sending
308 that signal using 'raise' in Windows' POSIX compatability layer. It will
309 not come from the general "terminate process" methods that everyone
310 actually uses (and which can't be trapped). Killing an app 'politely' on
311 Windows involves first sending a WM_CLOSE message, something that is
312 caught already by the Qt frontend.
314 For more information see:
316 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
317 ...signals are mostly useless on Windows for a variety of reasons that are
320 'UNIX Application Migration Guide, Chapter 9'
321 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
323 'How To Terminate an Application "Cleanly" in Win32'
324 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
328 static void error_handler(int err_sig)
330 // Throw away any signals other than the first one received.
331 static sig_atomic_t handling_error = false;
334 handling_error = true;
336 // We have received a signal indicating a fatal error, so
337 // try and save the data ASAP.
338 LyX::cref().emergencyCleanup();
340 // These lyxerr calls may or may not work:
342 // Signals are asynchronous, so the main program may be in a very
343 // fragile state when a signal is processed and thus while a signal
344 // handler function executes.
345 // In general, therefore, we should avoid performing any
346 // I/O operations or calling most library and system functions from
349 // This shouldn't matter here, however, as we've already invoked
354 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
358 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
361 lyxerr << "\nlyx: SIGSEGV signal caught\n"
362 "Sorry, you have found a bug in LyX. "
363 "Please read the bug-reporting instructions "
364 "in Help->Introduction and send us a bug report, "
365 "if necessary. Thanks !\nBye." << endl;
373 // Deinstall the signal handlers
375 signal(SIGHUP, SIG_DFL);
377 signal(SIGINT, SIG_DFL);
378 signal(SIGFPE, SIG_DFL);
379 signal(SIGSEGV, SIG_DFL);
380 signal(SIGTERM, SIG_DFL);
383 if (err_sig == SIGSEGV ||
384 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
386 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
388 lyx::support::abort();
395 void LyX::printError(ErrorItem const & ei)
397 std::cerr << _("LyX: ") << ei.error
398 << ':' << ei.description << std::endl;
403 void LyX::init(bool gui)
406 signal(SIGHUP, error_handler);
408 signal(SIGFPE, error_handler);
409 signal(SIGSEGV, error_handler);
410 signal(SIGINT, error_handler);
411 signal(SIGTERM, error_handler);
412 // SIGPIPE can be safely ignored.
414 // Disable gui when easyparse says so
415 lyx_gui::use_gui = gui;
417 lyxrc.tempdir_path = package().temp_dir();
418 lyxrc.document_path = package().document_dir();
420 if (lyxrc.template_path.empty()) {
421 lyxrc.template_path = addPath(package().system_support(),
425 if (lyxrc.roman_font_name.empty())
426 lyxrc.roman_font_name = lyx_gui::roman_font_name();
427 if (lyxrc.sans_font_name.empty())
428 lyxrc.sans_font_name = lyx_gui::sans_font_name();
429 if (lyxrc.typewriter_font_name.empty())
430 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
433 // Read configuration files
436 // This one may have been distributed along with LyX.
437 readRcFile("lyxrc.dist");
439 // Set the PATH correctly.
440 #if !defined (USE_POSIX_PACKAGING)
441 // Add the directory containing the LyX executable to the path
442 // so that LyX can find things like tex2lyx.
443 if (package().build_support().empty())
444 prependEnvPath("PATH", package().binary_dir());
446 if (!lyxrc.path_prefix.empty())
447 prependEnvPath("PATH", lyxrc.path_prefix);
449 // Check that user LyX directory is ok. We don't do that if
450 // running in batch mode.
452 if (queryUserLyXDir(package().explicit_user_support()))
453 reconfigureUserLyXDir();
458 // This one is generated in user_support directory by lib/configure.py.
459 readRcFile("lyxrc.defaults");
461 // Query the OS to know what formats are viewed natively
462 formats.setAutoOpen();
464 system_lyxrc = lyxrc;
465 system_formats = formats;
466 system_converters = converters;
467 system_movers = movers;
468 system_lcolor = lcolor;
470 // This one is edited through the preferences dialog.
471 readRcFile("preferences");
473 readEncodingsFile("encodings");
474 readLanguagesFile("languages");
477 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
482 toplevel_keymap.reset(new kb_keymap);
483 defaultKeyBindings(toplevel_keymap.get());
484 toplevel_keymap->read(lyxrc.bind_file);
487 readUIFile(lyxrc.ui_file);
490 if (lyxerr.debugging(Debug::LYXRC))
493 os::cygwin_path_fix(lyxrc.cygwin_path_fix);
494 if (!lyxrc.path_prefix.empty())
495 prependEnvPath("PATH", lyxrc.path_prefix);
497 if (fs::exists(lyxrc.document_path) &&
498 fs::is_directory(lyxrc.document_path))
499 package().document_dir() = lyxrc.document_path;
501 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
502 if (package().temp_dir().empty()) {
503 Alert::error(_("Could not create temporary directory"),
504 bformat(_("Could not create a temporary directory in\n"
505 "%1$s. Make sure that this\n"
506 "path exists and is writable and try again."),
507 lyxrc.tempdir_path));
508 // createLyXTmpDir() tries sufficiently hard to create a
509 // usable temp dir, so the probability to come here is
510 // close to zero. We therefore don't try to overcome this
511 // problem with e.g. asking the user for a new path and
512 // trying again but simply exit.
516 if (lyxerr.debugging(Debug::INIT)) {
517 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
520 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
521 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
525 void LyX::defaultKeyBindings(kb_keymap * kbmap)
527 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
528 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
529 kbmap->bind("Up", FuncRequest(LFUN_UP));
530 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
532 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
533 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
534 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
535 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
537 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
538 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
539 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
540 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
542 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
543 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
545 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
546 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
548 // kbmap->bindings to enable the use of the numeric keypad
550 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
551 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
552 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
553 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
554 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
555 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
556 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
557 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
558 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
559 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
560 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
561 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
562 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
563 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
564 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
565 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
566 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
567 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
568 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
569 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
570 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
571 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
572 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
573 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
577 void LyX::emergencyCleanup() const
579 // what to do about tmpfiles is non-obvious. we would
580 // like to delete any we find, but our lyxdir might
581 // contain documents etc. which might be helpful on
584 bufferlist.emergencyWriteAll();
586 lyxserver->emergencyCleanup();
590 void LyX::deadKeyBindings(kb_keymap * kbmap)
592 // bindKeyings for transparent handling of deadkeys
593 // The keysyms are gotten from XFree86 X11R6
594 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
595 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
596 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
597 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
598 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
599 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
600 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
601 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
602 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
603 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
604 // nothing with this name
605 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
606 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
607 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
608 // nothing with this name either...
609 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
610 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
611 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
612 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
618 // return true if file does not exist or is older than configure.py.
619 bool needsUpdate(string const & file)
621 static string const configure_script =
622 addName(package().system_support(), "configure.py");
623 string const absfile =
624 addName(package().user_support(), file);
626 return (! fs::exists(absfile))
627 || (fs::last_write_time(configure_script)
628 > fs::last_write_time(absfile));
634 bool LyX::queryUserLyXDir(bool explicit_userdir)
636 // Does user directory exist?
637 if (fs::exists(package().user_support()) &&
638 fs::is_directory(package().user_support())) {
641 return needsUpdate("lyxrc.defaults")
642 || needsUpdate("textclass.lst")
643 || needsUpdate("packages.lst");
646 first_start = !explicit_userdir;
648 // If the user specified explicitly a directory, ask whether
649 // to create it. If the user says "no", then exit.
650 if (explicit_userdir &&
652 _("Missing user LyX directory"),
653 bformat(_("You have specified a non-existent user "
654 "LyX directory, %1$s.\n"
655 "It is needed to keep your own configuration."),
656 package().user_support()),
658 _("&Create directory"),
660 lyxerr << _("No user LyX directory. Exiting.") << endl;
664 lyxerr << bformat(_("LyX: Creating directory %1$s"),
665 package().user_support())
668 if (!createDirectory(package().user_support(), 0755)) {
669 // Failed, so let's exit.
670 lyxerr << _("Failed to create directory. Exiting.")
679 void LyX::readRcFile(string const & name)
681 lyxerr[Debug::INIT] << "About to read " << name << "... ";
683 string const lyxrc_path = libFileSearch(string(), name);
684 if (!lyxrc_path.empty()) {
686 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
688 if (lyxrc.read(lyxrc_path) < 0)
691 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
696 // Read the ui file `name'
697 void LyX::readUIFile(string const & name)
707 struct keyword_item uitags[ui_last - 1] = {
708 { "include", ui_include },
709 { "menuset", ui_menuset },
710 { "toolbar", ui_toolbar },
711 { "toolbars", ui_toolbars }
714 // Ensure that a file is read only once (prevents include loops)
715 static std::list<string> uifiles;
716 std::list<string>::const_iterator it = uifiles.begin();
717 std::list<string>::const_iterator end = uifiles.end();
718 it = std::find(it, end, name);
720 lyxerr[Debug::INIT] << "UI file '" << name
721 << "' has been read already. "
722 << "Is this an include loop?"
727 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
729 string const ui_path = libFileSearch("ui", name, "ui");
731 if (ui_path.empty()) {
732 lyxerr[Debug::INIT] << "Could not find " << name << endl;
736 uifiles.push_back(name);
738 lyxerr[Debug::INIT] << "Found " << name
739 << " in " << ui_path << endl;
740 LyXLex lex(uitags, ui_last - 1);
741 lex.setFile(ui_path);
743 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
747 if (lyxerr.debugging(Debug::PARSER))
748 lex.printTable(lyxerr);
754 string const file = lex.getString();
759 menubackend.read(lex);
763 toolbarbackend.read(lex);
767 toolbarbackend.readToolbars(lex);
771 if (!rtrim(lex.getString()).empty())
772 lex.printError("LyX::ReadUIFile: "
773 "Unknown menu tag: `$$Token'");
780 // Read the languages file `name'
781 void LyX::readLanguagesFile(string const & name)
783 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
785 string const lang_path = libFileSearch(string(), name);
786 if (lang_path.empty()) {
790 languages.read(lang_path);
794 // Read the encodings file `name'
795 void LyX::readEncodingsFile(string const & name)
797 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
799 string const enc_path = libFileSearch(string(), name);
800 if (enc_path.empty()) {
804 encodings.read(enc_path);
813 /// return the the number of arguments consumed
814 typedef boost::function<int(string const &, string const &)> cmd_helper;
816 int parse_dbg(string const & arg, string const &)
819 lyxerr << _("List of supported debug flags:") << endl;
820 Debug::showTags(lyxerr);
823 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
825 lyxerr.level(Debug::value(arg));
826 Debug::showLevel(lyxerr, lyxerr.level());
831 int parse_help(string const &, string const &)
834 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
835 "Command line switches (case sensitive):\n"
836 "\t-help summarize LyX usage\n"
837 "\t-userdir dir set user directory to dir\n"
838 "\t-sysdir dir set system directory to dir\n"
839 "\t-geometry WxH+X+Y set geometry of the main window\n"
840 "\t-dbg feature[,feature]...\n"
841 " select the features to debug.\n"
842 " Type `lyx -dbg' to see the list of features\n"
843 "\t-x [--execute] command\n"
844 " where command is a lyx command.\n"
845 "\t-e [--export] fmt\n"
846 " where fmt is the export format of choice.\n"
847 "\t-i [--import] fmt file.xxx\n"
848 " where fmt is the import format of choice\n"
849 " and file.xxx is the file to be imported.\n"
850 "\t-version summarize version and build info\n"
851 "Check the LyX man page for more details.") << endl;
856 int parse_version(string const &, string const &)
858 lyxerr << "LyX " << lyx_version
859 << " of " << lyx_release_date << endl;
860 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
862 lyxerr << lyx_version_info << endl;
867 int parse_sysdir(string const & arg, string const &)
870 lyxerr << _("Missing directory for -sysdir switch") << endl;
873 cl_system_support = arg;
877 int parse_userdir(string const & arg, string const &)
880 lyxerr << _("Missing directory for -userdir switch") << endl;
883 cl_user_support = arg;
887 int parse_execute(string const & arg, string const &)
890 lyxerr << _("Missing command string after --execute switch") << endl;
897 int parse_export(string const & type, string const &)
900 lyxerr << _("Missing file type [eg latex, ps...] after "
901 "--export switch") << endl;
904 batch = "buffer-export " + type;
909 int parse_import(string const & type, string const & file)
912 lyxerr << _("Missing file type [eg latex, ps...] after "
913 "--import switch") << endl;
917 lyxerr << _("Missing filename for --import") << endl;
921 batch = "buffer-import " + type + ' ' + file;
928 bool LyX::easyParse(int & argc, char * argv[])
930 std::map<string, cmd_helper> cmdmap;
932 cmdmap["-dbg"] = parse_dbg;
933 cmdmap["-help"] = parse_help;
934 cmdmap["--help"] = parse_help;
935 cmdmap["-version"] = parse_version;
936 cmdmap["--version"] = parse_version;
937 cmdmap["-sysdir"] = parse_sysdir;
938 cmdmap["-userdir"] = parse_userdir;
939 cmdmap["-x"] = parse_execute;
940 cmdmap["--execute"] = parse_execute;
941 cmdmap["-e"] = parse_export;
942 cmdmap["--export"] = parse_export;
943 cmdmap["-i"] = parse_import;
944 cmdmap["--import"] = parse_import;
946 for (int i = 1; i < argc; ++i) {
947 std::map<string, cmd_helper>::const_iterator it
948 = cmdmap.find(argv[i]);
950 // don't complain if not found - may be parsed later
951 if (it == cmdmap.end())
954 string arg((i + 1 < argc) ? argv[i + 1] : "");
955 string arg2((i + 2 < argc) ? argv[i + 2] : "");
957 int const remove = 1 + it->second(arg, arg2);
959 // Now, remove used arguments by shifting
960 // the following ones remove places down.
962 for (int j = i; j < argc; ++j)
963 argv[j] = argv[j + remove];
967 batch_command = batch;