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 showFileError(string const & error)
112 Alert::warning(_("Could not read configuration file"),
113 bformat(_("Error while reading the configuration file\n%1$s.\n"
114 "Please check your installation."), error));
119 void reconfigureUserLyXDir()
121 string const configure_command = package().configure_command();
123 lyxerr << _("LyX: reconfiguring user directory") << endl;
124 Path p(package().user_support());
126 one.startscript(Systemcall::Wait, configure_command);
127 lyxerr << "LyX: " << _("Done!") << endl;
133 boost::scoped_ptr<LyX> LyX::singleton_;
135 void LyX::exec(int & argc, char * argv[])
137 BOOST_ASSERT(!singleton_.get());
138 // We must return from this before launching the gui so that
139 // other parts of the code can access singleton_ through
140 // LyX::ref and LyX::cref.
141 singleton_.reset(new LyX);
142 // Start the real execution loop.
143 singleton_->priv_exec(argc, argv);
149 BOOST_ASSERT(singleton_.get());
150 return *singleton_.get();
154 LyX const & LyX::cref()
156 BOOST_ASSERT(singleton_.get());
157 return *singleton_.get();
166 lyx::Session & LyX::session()
168 BOOST_ASSERT(session_.get());
169 return *session_.get();
173 lyx::Session const & LyX::session() const
175 BOOST_ASSERT(session_.get());
176 return *session_.get();
180 void LyX::addLyXView(boost::shared_ptr<LyXView> const & lyxview)
182 views_.push_back(lyxview);
186 Buffer const * const LyX::updateInset(InsetBase const * inset) const
191 Buffer const * buffer_ptr = 0;
192 ViewList::const_iterator it = views_.begin();
193 ViewList::const_iterator const end = views_.end();
194 for (; it != end; ++it) {
195 Buffer const * ptr = (*it)->updateInset(inset);
203 void LyX::priv_exec(int & argc, char * argv[])
205 // Here we need to parse the command line. At least
206 // we need to parse for "-dbg" and "-help"
207 bool const want_gui = easyParse(argc, argv);
209 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
210 lyx::support::top_build_dir_is_one_level_up);
213 lyx_gui::parse_init(argc, argv);
215 // check for any spurious extra arguments
216 // other than documents
217 for (int argi = 1; argi < argc ; ++argi) {
218 if (argv[argi][0] == '-') {
219 lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
225 // Initialization of LyX (reads lyxrc and more)
226 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
228 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
231 lyx_gui::parse_lyxrc();
233 vector<string> files;
235 for (int argi = argc - 1; argi >= 1; --argi)
236 files.push_back(os::internal_path(argv[argi]));
239 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
241 // if a file is specified, I assume that user wants to edit *that* file
242 if (files.empty() && lyxrc.load_session) {
243 vector<string> const & lastopened = session_->lastOpenedFiles();
244 files.insert(files.end(), lastopened.begin(), lastopened.end() );
246 // clear this list to save a few bytes of RAM
247 session_->clearLastOpenedFiles();
249 // Execute batch commands if available
250 if (!batch_command.empty()) {
252 lyxerr[Debug::INIT] << "About to handle -x '"
253 << batch_command << '\'' << endl;
255 Buffer * last_loaded = 0;
257 vector<string>::const_iterator it = files.begin();
258 vector<string>::const_iterator end = files.end();
260 for (; it != end; ++it) {
261 // get absolute path of file and add ".lyx" to
262 // the filename if necessary
263 string s = fileSearch(string(), *it, "lyx");
265 last_loaded = newFile(*it, string(), true);
267 Buffer * buf = bufferlist.newBuffer(s, false);
268 buf->error.connect(boost::bind(&LyX::printError, this, _1));
269 if (loadLyXFile(buf, s))
272 bufferlist.release(buf);
276 // try to dispatch to last loaded buffer first
278 bool success = false;
279 if (last_loaded->dispatch(batch_command, &success)) {
284 files.clear(); // the files are already loaded
288 // determine windows size and position, from lyxrc and/or session
290 unsigned int width = 690;
291 unsigned int height = 510;
293 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
294 width = lyxrc.geometry_width;
295 height = lyxrc.geometry_height;
297 // if lyxrc returns (0,0), then use session info
299 string val = LyX::ref().session().loadSessionInfo("WindowWidth");
301 width = convert<unsigned int>(val);
302 val = LyX::ref().session().loadSessionInfo("WindowHeight");
304 height = convert<unsigned int>(val);
306 // if user wants to restore window position
309 if (lyxrc.geometry_xysaved) {
310 string val = LyX::ref().session().loadSessionInfo("WindowPosX");
312 posx = convert<int>(val);
313 val = LyX::ref().session().loadSessionInfo("WindowPosY");
315 posy = convert<int>(val);
317 lyx_gui::start(batch_command, files, width, height, posx, posy);
319 // Something went wrong above
329 The SIGHUP signal does not exist on Windows and does not need to be handled.
331 Windows handles SIGFPE and SIGSEGV signals as expected.
333 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
334 cause a new thread to be spawned. This may well result in unexpected
335 behaviour by the single-threaded LyX.
337 SIGTERM signals will come only from another process actually sending
338 that signal using 'raise' in Windows' POSIX compatability layer. It will
339 not come from the general "terminate process" methods that everyone
340 actually uses (and which can't be trapped). Killing an app 'politely' on
341 Windows involves first sending a WM_CLOSE message, something that is
342 caught already by the Qt frontend.
344 For more information see:
346 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
347 ...signals are mostly useless on Windows for a variety of reasons that are
350 'UNIX Application Migration Guide, Chapter 9'
351 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
353 'How To Terminate an Application "Cleanly" in Win32'
354 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
358 static void error_handler(int err_sig)
360 // Throw away any signals other than the first one received.
361 static sig_atomic_t handling_error = false;
364 handling_error = true;
366 // We have received a signal indicating a fatal error, so
367 // try and save the data ASAP.
368 LyX::cref().emergencyCleanup();
370 // These lyxerr calls may or may not work:
372 // Signals are asynchronous, so the main program may be in a very
373 // fragile state when a signal is processed and thus while a signal
374 // handler function executes.
375 // In general, therefore, we should avoid performing any
376 // I/O operations or calling most library and system functions from
379 // This shouldn't matter here, however, as we've already invoked
384 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
388 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
391 lyxerr << "\nlyx: SIGSEGV signal caught\n"
392 "Sorry, you have found a bug in LyX. "
393 "Please read the bug-reporting instructions "
394 "in Help->Introduction and send us a bug report, "
395 "if necessary. Thanks !\nBye." << endl;
403 // Deinstall the signal handlers
405 signal(SIGHUP, SIG_DFL);
407 signal(SIGINT, SIG_DFL);
408 signal(SIGFPE, SIG_DFL);
409 signal(SIGSEGV, SIG_DFL);
410 signal(SIGTERM, SIG_DFL);
413 if (err_sig == SIGSEGV ||
414 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
416 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
418 lyx::support::abort();
425 void LyX::printError(ErrorItem const & ei)
427 std::cerr << _("LyX: ") << ei.error
428 << ':' << ei.description << std::endl;
433 void LyX::init(bool gui)
436 signal(SIGHUP, error_handler);
438 signal(SIGFPE, error_handler);
439 signal(SIGSEGV, error_handler);
440 signal(SIGINT, error_handler);
441 signal(SIGTERM, error_handler);
442 // SIGPIPE can be safely ignored.
444 // Disable gui when easyparse says so
445 lyx_gui::use_gui = gui;
447 lyxrc.tempdir_path = package().temp_dir();
448 lyxrc.document_path = package().document_dir();
450 if (lyxrc.template_path.empty()) {
451 lyxrc.template_path = addPath(package().system_support(),
455 if (lyxrc.roman_font_name.empty())
456 lyxrc.roman_font_name = lyx_gui::roman_font_name();
457 if (lyxrc.sans_font_name.empty())
458 lyxrc.sans_font_name = lyx_gui::sans_font_name();
459 if (lyxrc.typewriter_font_name.empty())
460 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
463 // Read configuration files
466 // This one may have been distributed along with LyX.
467 readRcFile("lyxrc.dist");
469 // Set the PATH correctly.
470 #if !defined (USE_POSIX_PACKAGING)
471 // Add the directory containing the LyX executable to the path
472 // so that LyX can find things like tex2lyx.
473 if (package().build_support().empty())
474 prependEnvPath("PATH", package().binary_dir());
476 if (!lyxrc.path_prefix.empty())
477 prependEnvPath("PATH", lyxrc.path_prefix);
479 // Check that user LyX directory is ok. We don't do that if
480 // running in batch mode.
482 if (queryUserLyXDir(package().explicit_user_support()))
483 reconfigureUserLyXDir();
488 // This one is generated in user_support directory by lib/configure.py.
489 readRcFile("lyxrc.defaults");
491 // Query the OS to know what formats are viewed natively
492 formats.setAutoOpen();
494 system_lyxrc = lyxrc;
495 system_formats = formats;
496 system_converters = converters;
497 system_movers = movers;
498 system_lcolor = lcolor;
500 // This one is edited through the preferences dialog.
501 readRcFile("preferences");
503 readEncodingsFile("encodings");
504 readLanguagesFile("languages");
507 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
512 toplevel_keymap.reset(new kb_keymap);
513 defaultKeyBindings(toplevel_keymap.get());
514 toplevel_keymap->read(lyxrc.bind_file);
517 readUIFile(lyxrc.ui_file);
520 if (lyxerr.debugging(Debug::LYXRC))
523 os::cygwin_path_fix(lyxrc.cygwin_path_fix);
524 if (!lyxrc.path_prefix.empty())
525 prependEnvPath("PATH", lyxrc.path_prefix);
527 if (fs::exists(lyxrc.document_path) &&
528 fs::is_directory(lyxrc.document_path))
529 package().document_dir() = lyxrc.document_path;
531 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
532 if (package().temp_dir().empty()) {
533 Alert::error(_("Could not create temporary directory"),
534 bformat(_("Could not create a temporary directory in\n"
535 "%1$s. Make sure that this\n"
536 "path exists and is writable and try again."),
537 lyxrc.tempdir_path));
538 // createLyXTmpDir() tries sufficiently hard to create a
539 // usable temp dir, so the probability to come here is
540 // close to zero. We therefore don't try to overcome this
541 // problem with e.g. asking the user for a new path and
542 // trying again but simply exit.
546 if (lyxerr.debugging(Debug::INIT)) {
547 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
550 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
551 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
555 void LyX::defaultKeyBindings(kb_keymap * kbmap)
557 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
558 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
559 kbmap->bind("Up", FuncRequest(LFUN_UP));
560 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
562 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
563 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
564 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
565 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
567 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
568 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
569 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
570 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
572 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
573 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
575 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
576 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
578 // kbmap->bindings to enable the use of the numeric keypad
580 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
581 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
582 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
583 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
584 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
585 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
586 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
587 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
588 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
589 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
590 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
591 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
592 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
593 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
594 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
595 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
596 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
597 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
598 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
599 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
600 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
601 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
602 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
603 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
607 void LyX::emergencyCleanup() const
609 // what to do about tmpfiles is non-obvious. we would
610 // like to delete any we find, but our lyxdir might
611 // contain documents etc. which might be helpful on
614 bufferlist.emergencyWriteAll();
616 lyxserver->emergencyCleanup();
620 void LyX::deadKeyBindings(kb_keymap * kbmap)
622 // bindKeyings for transparent handling of deadkeys
623 // The keysyms are gotten from XFree86 X11R6
624 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
625 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
626 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
627 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
628 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
629 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
630 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
631 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
632 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
633 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
634 // nothing with this name
635 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
636 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
637 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
638 // nothing with this name either...
639 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
640 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
641 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
642 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
648 // return true if file does not exist or is older than configure.py.
649 bool needsUpdate(string const & file)
651 static string const configure_script =
652 addName(package().system_support(), "configure.py");
653 string const absfile =
654 addName(package().user_support(), file);
656 return (! fs::exists(absfile))
657 || (fs::last_write_time(configure_script)
658 > fs::last_write_time(absfile));
664 bool LyX::queryUserLyXDir(bool explicit_userdir)
666 // Does user directory exist?
667 if (fs::exists(package().user_support()) &&
668 fs::is_directory(package().user_support())) {
671 return needsUpdate("lyxrc.defaults")
672 || needsUpdate("textclass.lst")
673 || needsUpdate("packages.lst");
676 first_start = !explicit_userdir;
678 // If the user specified explicitly a directory, ask whether
679 // to create it. If the user says "no", then exit.
680 if (explicit_userdir &&
682 _("Missing user LyX directory"),
683 bformat(_("You have specified a non-existent user "
684 "LyX directory, %1$s.\n"
685 "It is needed to keep your own configuration."),
686 package().user_support()),
688 _("&Create directory"),
690 lyxerr << _("No user LyX directory. Exiting.") << endl;
694 lyxerr << bformat(_("LyX: Creating directory %1$s"),
695 package().user_support())
698 if (!createDirectory(package().user_support(), 0755)) {
699 // Failed, so let's exit.
700 lyxerr << _("Failed to create directory. Exiting.")
709 void LyX::readRcFile(string const & name)
711 lyxerr[Debug::INIT] << "About to read " << name << "... ";
713 string const lyxrc_path = libFileSearch(string(), name);
714 if (!lyxrc_path.empty()) {
716 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
718 if (lyxrc.read(lyxrc_path) < 0)
721 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
726 // Read the ui file `name'
727 void LyX::readUIFile(string const & name)
737 struct keyword_item uitags[ui_last - 1] = {
738 { "include", ui_include },
739 { "menuset", ui_menuset },
740 { "toolbar", ui_toolbar },
741 { "toolbars", ui_toolbars }
744 // Ensure that a file is read only once (prevents include loops)
745 static std::list<string> uifiles;
746 std::list<string>::const_iterator it = uifiles.begin();
747 std::list<string>::const_iterator end = uifiles.end();
748 it = std::find(it, end, name);
750 lyxerr[Debug::INIT] << "UI file '" << name
751 << "' has been read already. "
752 << "Is this an include loop?"
757 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
759 string const ui_path = libFileSearch("ui", name, "ui");
761 if (ui_path.empty()) {
762 lyxerr[Debug::INIT] << "Could not find " << name << endl;
766 uifiles.push_back(name);
768 lyxerr[Debug::INIT] << "Found " << name
769 << " in " << ui_path << endl;
770 LyXLex lex(uitags, ui_last - 1);
771 lex.setFile(ui_path);
773 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
777 if (lyxerr.debugging(Debug::PARSER))
778 lex.printTable(lyxerr);
784 string const file = lex.getString();
789 menubackend.read(lex);
793 toolbarbackend.read(lex);
797 toolbarbackend.readToolbars(lex);
801 if (!rtrim(lex.getString()).empty())
802 lex.printError("LyX::ReadUIFile: "
803 "Unknown menu tag: `$$Token'");
810 // Read the languages file `name'
811 void LyX::readLanguagesFile(string const & name)
813 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
815 string const lang_path = libFileSearch(string(), name);
816 if (lang_path.empty()) {
820 languages.read(lang_path);
824 // Read the encodings file `name'
825 void LyX::readEncodingsFile(string const & name)
827 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
829 string const enc_path = libFileSearch(string(), name);
830 if (enc_path.empty()) {
834 encodings.read(enc_path);
843 /// return the the number of arguments consumed
844 typedef boost::function<int(string const &, string const &)> cmd_helper;
846 int parse_dbg(string const & arg, string const &)
849 lyxerr << _("List of supported debug flags:") << endl;
850 Debug::showTags(lyxerr);
853 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
855 lyxerr.level(Debug::value(arg));
856 Debug::showLevel(lyxerr, lyxerr.level());
861 int parse_help(string const &, string const &)
864 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
865 "Command line switches (case sensitive):\n"
866 "\t-help summarize LyX usage\n"
867 "\t-userdir dir set user directory to dir\n"
868 "\t-sysdir dir set system directory to dir\n"
869 "\t-geometry WxH+X+Y set geometry of the main window\n"
870 "\t-dbg feature[,feature]...\n"
871 " select the features to debug.\n"
872 " Type `lyx -dbg' to see the list of features\n"
873 "\t-x [--execute] command\n"
874 " where command is a lyx command.\n"
875 "\t-e [--export] fmt\n"
876 " where fmt is the export format of choice.\n"
877 "\t-i [--import] fmt file.xxx\n"
878 " where fmt is the import format of choice\n"
879 " and file.xxx is the file to be imported.\n"
880 "\t-version summarize version and build info\n"
881 "Check the LyX man page for more details.") << endl;
886 int parse_version(string const &, string const &)
888 lyxerr << "LyX " << lyx_version
889 << " of " << lyx_release_date << endl;
890 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
892 lyxerr << lyx_version_info << endl;
897 int parse_sysdir(string const & arg, string const &)
900 lyxerr << _("Missing directory for -sysdir switch") << endl;
903 cl_system_support = arg;
907 int parse_userdir(string const & arg, string const &)
910 lyxerr << _("Missing directory for -userdir switch") << endl;
913 cl_user_support = arg;
917 int parse_execute(string const & arg, string const &)
920 lyxerr << _("Missing command string after --execute switch") << endl;
927 int parse_export(string const & type, string const &)
930 lyxerr << _("Missing file type [eg latex, ps...] after "
931 "--export switch") << endl;
934 batch = "buffer-export " + type;
939 int parse_import(string const & type, string const & file)
942 lyxerr << _("Missing file type [eg latex, ps...] after "
943 "--import switch") << endl;
947 lyxerr << _("Missing filename for --import") << endl;
951 batch = "buffer-import " + type + ' ' + file;
958 bool LyX::easyParse(int & argc, char * argv[])
960 std::map<string, cmd_helper> cmdmap;
962 cmdmap["-dbg"] = parse_dbg;
963 cmdmap["-help"] = parse_help;
964 cmdmap["--help"] = parse_help;
965 cmdmap["-version"] = parse_version;
966 cmdmap["--version"] = parse_version;
967 cmdmap["-sysdir"] = parse_sysdir;
968 cmdmap["-userdir"] = parse_userdir;
969 cmdmap["-x"] = parse_execute;
970 cmdmap["--execute"] = parse_execute;
971 cmdmap["-e"] = parse_export;
972 cmdmap["--export"] = parse_export;
973 cmdmap["-i"] = parse_import;
974 cmdmap["--import"] = parse_import;
976 for (int i = 1; i < argc; ++i) {
977 std::map<string, cmd_helper>::const_iterator it
978 = cmdmap.find(argv[i]);
980 // don't complain if not found - may be parsed later
981 if (it == cmdmap.end())
984 string arg((i + 1 < argc) ? argv[i + 1] : "");
985 string arg2((i + 2 < argc) ? argv[i + 2] : "");
987 int const remove = 1 + it->second(arg, arg2);
989 // Now, remove used arguments by shifting
990 // the following ones remove places down.
992 for (int j = i; j < argc; ++j)
993 argv[j] = argv[j + remove];
997 batch_command = batch;