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;
312 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
313 width = lyxrc.geometry_width;
314 height = lyxrc.geometry_height;
316 // if lyxrc returns (0,0), then use session info
318 string val = session().loadSessionInfo("WindowWidth");
320 width = convert<unsigned int>(val);
321 val = session().loadSessionInfo("WindowHeight");
323 height = convert<unsigned int>(val);
324 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
327 // if user wants to restore window position
330 if (lyxrc.geometry_xysaved) {
331 string val = session().loadSessionInfo("WindowPosX");
333 posx = convert<int>(val);
334 val = session().loadSessionInfo("WindowPosY");
336 posy = convert<int>(val);
338 lyx_gui::start(batch_command, files, width, height, posx, posy, isMax);
340 // Something went wrong above
342 lyx_exit(EXIT_FAILURE);
350 The SIGHUP signal does not exist on Windows and does not need to be handled.
352 Windows handles SIGFPE and SIGSEGV signals as expected.
354 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
355 cause a new thread to be spawned. This may well result in unexpected
356 behaviour by the single-threaded LyX.
358 SIGTERM signals will come only from another process actually sending
359 that signal using 'raise' in Windows' POSIX compatability layer. It will
360 not come from the general "terminate process" methods that everyone
361 actually uses (and which can't be trapped). Killing an app 'politely' on
362 Windows involves first sending a WM_CLOSE message, something that is
363 caught already by the Qt frontend.
365 For more information see:
367 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
368 ...signals are mostly useless on Windows for a variety of reasons that are
371 'UNIX Application Migration Guide, Chapter 9'
372 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
374 'How To Terminate an Application "Cleanly" in Win32'
375 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
379 static void error_handler(int err_sig)
381 // Throw away any signals other than the first one received.
382 static sig_atomic_t handling_error = false;
385 handling_error = true;
387 // We have received a signal indicating a fatal error, so
388 // try and save the data ASAP.
389 LyX::cref().emergencyCleanup();
391 // These lyxerr calls may or may not work:
393 // Signals are asynchronous, so the main program may be in a very
394 // fragile state when a signal is processed and thus while a signal
395 // handler function executes.
396 // In general, therefore, we should avoid performing any
397 // I/O operations or calling most library and system functions from
400 // This shouldn't matter here, however, as we've already invoked
405 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
409 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
412 lyxerr << "\nlyx: SIGSEGV signal caught\n"
413 "Sorry, you have found a bug in LyX. "
414 "Please read the bug-reporting instructions "
415 "in Help->Introduction and send us a bug report, "
416 "if necessary. Thanks !\nBye." << endl;
424 // Deinstall the signal handlers
426 signal(SIGHUP, SIG_DFL);
428 signal(SIGINT, SIG_DFL);
429 signal(SIGFPE, SIG_DFL);
430 signal(SIGSEGV, SIG_DFL);
431 signal(SIGTERM, SIG_DFL);
434 if (err_sig == SIGSEGV ||
435 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
437 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
439 lyx::support::abort();
446 void LyX::printError(ErrorItem const & ei)
448 std::cerr << _("LyX: ") << ei.error
449 << ':' << ei.description << std::endl;
457 signal(SIGHUP, error_handler);
459 signal(SIGFPE, error_handler);
460 signal(SIGSEGV, error_handler);
461 signal(SIGINT, error_handler);
462 signal(SIGTERM, error_handler);
463 // SIGPIPE can be safely ignored.
465 lyxrc.tempdir_path = package().temp_dir();
466 lyxrc.document_path = package().document_dir();
468 if (lyxrc.template_path.empty()) {
469 lyxrc.template_path = addPath(package().system_support(),
473 if (lyxrc.roman_font_name.empty())
474 lyxrc.roman_font_name = lyx_gui::roman_font_name();
475 if (lyxrc.sans_font_name.empty())
476 lyxrc.sans_font_name = lyx_gui::sans_font_name();
477 if (lyxrc.typewriter_font_name.empty())
478 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
481 // Read configuration files
484 // This one may have been distributed along with LyX.
485 readRcFile("lyxrc.dist");
487 // Set the PATH correctly.
488 #if !defined (USE_POSIX_PACKAGING)
489 // Add the directory containing the LyX executable to the path
490 // so that LyX can find things like tex2lyx.
491 if (package().build_support().empty())
492 prependEnvPath("PATH", package().binary_dir());
494 if (!lyxrc.path_prefix.empty())
495 prependEnvPath("PATH", lyxrc.path_prefix);
497 // Check that user LyX directory is ok. We don't do that if
498 // running in batch mode.
499 if (lyx_gui::use_gui) {
500 if (queryUserLyXDir(package().explicit_user_support()))
501 reconfigureUserLyXDir();
506 // This one is generated in user_support directory by lib/configure.py.
507 readRcFile("lyxrc.defaults");
509 // Query the OS to know what formats are viewed natively
510 formats.setAutoOpen();
512 system_lyxrc = lyxrc;
513 system_formats = formats;
514 system_converters = converters;
515 system_movers = movers;
516 system_lcolor = lcolor;
518 // This one is edited through the preferences dialog.
519 readRcFile("preferences");
521 readEncodingsFile("encodings");
522 readLanguagesFile("languages");
525 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
528 if (lyx_gui::use_gui) {
530 toplevel_keymap.reset(new kb_keymap);
531 defaultKeyBindings(toplevel_keymap.get());
532 toplevel_keymap->read(lyxrc.bind_file);
535 readUIFile(lyxrc.ui_file);
538 if (lyxerr.debugging(Debug::LYXRC))
541 os::cygwin_path_fix(lyxrc.cygwin_path_fix);
542 if (!lyxrc.path_prefix.empty())
543 prependEnvPath("PATH", lyxrc.path_prefix);
545 if (fs::exists(lyxrc.document_path) &&
546 fs::is_directory(lyxrc.document_path))
547 package().document_dir() = lyxrc.document_path;
549 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
550 if (package().temp_dir().empty()) {
551 Alert::error(_("Could not create temporary directory"),
552 bformat(_("Could not create a temporary directory in\n"
553 "%1$s. Make sure that this\n"
554 "path exists and is writable and try again."),
555 lyxrc.tempdir_path));
556 // createLyXTmpDir() tries sufficiently hard to create a
557 // usable temp dir, so the probability to come here is
558 // close to zero. We therefore don't try to overcome this
559 // problem with e.g. asking the user for a new path and
560 // trying again but simply exit.
561 lyx_exit(EXIT_FAILURE);
564 if (lyxerr.debugging(Debug::INIT)) {
565 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
568 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
569 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
573 void LyX::defaultKeyBindings(kb_keymap * kbmap)
575 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
576 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
577 kbmap->bind("Up", FuncRequest(LFUN_UP));
578 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
580 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
581 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
582 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
583 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
585 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
586 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
587 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
588 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
590 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
591 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
593 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
594 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
596 // kbmap->bindings to enable the use of the numeric keypad
598 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
599 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
600 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
601 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
602 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
603 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
604 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
605 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
606 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
607 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
608 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
609 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
610 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
611 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
612 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
613 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
614 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
615 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
616 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
617 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
618 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
619 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
620 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
621 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
625 void LyX::emergencyCleanup() const
627 // what to do about tmpfiles is non-obvious. we would
628 // like to delete any we find, but our lyxdir might
629 // contain documents etc. which might be helpful on
632 bufferlist.emergencyWriteAll();
634 lyxserver->emergencyCleanup();
638 void LyX::deadKeyBindings(kb_keymap * kbmap)
640 // bindKeyings for transparent handling of deadkeys
641 // The keysyms are gotten from XFree86 X11R6
642 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
643 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
644 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
645 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
646 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
647 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
648 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
649 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
650 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
651 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
652 // nothing with this name
653 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
654 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
655 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
656 // nothing with this name either...
657 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
658 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
659 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
660 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
666 // return true if file does not exist or is older than configure.py.
667 bool needsUpdate(string const & file)
669 static string const configure_script =
670 addName(package().system_support(), "configure.py");
671 string const absfile =
672 addName(package().user_support(), file);
674 return (! fs::exists(absfile))
675 || (fs::last_write_time(configure_script)
676 > fs::last_write_time(absfile));
682 bool LyX::queryUserLyXDir(bool explicit_userdir)
684 // Does user directory exist?
685 if (fs::exists(package().user_support()) &&
686 fs::is_directory(package().user_support())) {
689 return needsUpdate("lyxrc.defaults")
690 || needsUpdate("textclass.lst")
691 || needsUpdate("packages.lst");
694 first_start = !explicit_userdir;
696 // If the user specified explicitly a directory, ask whether
697 // to create it. If the user says "no", then exit.
698 if (explicit_userdir &&
700 _("Missing user LyX directory"),
701 bformat(_("You have specified a non-existent user "
702 "LyX directory, %1$s.\n"
703 "It is needed to keep your own configuration."),
704 package().user_support()),
706 _("&Create directory"),
708 lyxerr << _("No user LyX directory. Exiting.") << endl;
709 lyx_exit(EXIT_FAILURE);
712 lyxerr << bformat(_("LyX: Creating directory %1$s"),
713 package().user_support())
716 if (!createDirectory(package().user_support(), 0755)) {
717 // Failed, so let's exit.
718 lyxerr << _("Failed to create directory. Exiting.")
720 lyx_exit(EXIT_FAILURE);
727 void LyX::readRcFile(string const & name)
729 lyxerr[Debug::INIT] << "About to read " << name << "... ";
731 string const lyxrc_path = libFileSearch(string(), name);
732 if (!lyxrc_path.empty()) {
734 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
736 if (lyxrc.read(lyxrc_path) < 0)
739 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
744 // Read the ui file `name'
745 void LyX::readUIFile(string const & name)
755 struct keyword_item uitags[ui_last - 1] = {
756 { "include", ui_include },
757 { "menuset", ui_menuset },
758 { "toolbar", ui_toolbar },
759 { "toolbars", ui_toolbars }
762 // Ensure that a file is read only once (prevents include loops)
763 static std::list<string> uifiles;
764 std::list<string>::const_iterator it = uifiles.begin();
765 std::list<string>::const_iterator end = uifiles.end();
766 it = std::find(it, end, name);
768 lyxerr[Debug::INIT] << "UI file '" << name
769 << "' has been read already. "
770 << "Is this an include loop?"
775 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
777 string const ui_path = libFileSearch("ui", name, "ui");
779 if (ui_path.empty()) {
780 lyxerr[Debug::INIT] << "Could not find " << name << endl;
784 uifiles.push_back(name);
786 lyxerr[Debug::INIT] << "Found " << name
787 << " in " << ui_path << endl;
788 LyXLex lex(uitags, ui_last - 1);
789 lex.setFile(ui_path);
791 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
795 if (lyxerr.debugging(Debug::PARSER))
796 lex.printTable(lyxerr);
802 string const file = lex.getString();
807 menubackend.read(lex);
811 toolbarbackend.read(lex);
815 toolbarbackend.readToolbars(lex);
819 if (!rtrim(lex.getString()).empty())
820 lex.printError("LyX::ReadUIFile: "
821 "Unknown menu tag: `$$Token'");
828 // Read the languages file `name'
829 void LyX::readLanguagesFile(string const & name)
831 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
833 string const lang_path = libFileSearch(string(), name);
834 if (lang_path.empty()) {
838 languages.read(lang_path);
842 // Read the encodings file `name'
843 void LyX::readEncodingsFile(string const & name)
845 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
847 string const enc_path = libFileSearch(string(), name);
848 if (enc_path.empty()) {
852 encodings.read(enc_path);
861 /// return the the number of arguments consumed
862 typedef boost::function<int(string const &, string const &)> cmd_helper;
864 int parse_dbg(string const & arg, string const &)
867 lyxerr << _("List of supported debug flags:") << endl;
868 Debug::showTags(lyxerr);
871 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
873 lyxerr.level(Debug::value(arg));
874 Debug::showLevel(lyxerr, lyxerr.level());
879 int parse_help(string const &, string const &)
882 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
883 "Command line switches (case sensitive):\n"
884 "\t-help summarize LyX usage\n"
885 "\t-userdir dir set user directory to dir\n"
886 "\t-sysdir dir set system directory to dir\n"
887 "\t-geometry WxH+X+Y set geometry of the main window\n"
888 "\t-dbg feature[,feature]...\n"
889 " select the features to debug.\n"
890 " Type `lyx -dbg' to see the list of features\n"
891 "\t-x [--execute] command\n"
892 " where command is a lyx command.\n"
893 "\t-e [--export] fmt\n"
894 " where fmt is the export format of choice.\n"
895 "\t-i [--import] fmt file.xxx\n"
896 " where fmt is the import format of choice\n"
897 " and file.xxx is the file to be imported.\n"
898 "\t-version summarize version and build info\n"
899 "Check the LyX man page for more details.") << endl;
904 int parse_version(string const &, string const &)
906 lyxerr << "LyX " << lyx_version
907 << " of " << lyx_release_date << endl;
908 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
910 lyxerr << lyx_version_info << endl;
915 int parse_sysdir(string const & arg, string const &)
918 lyxerr << _("Missing directory for -sysdir switch") << endl;
921 cl_system_support = arg;
925 int parse_userdir(string const & arg, string const &)
928 lyxerr << _("Missing directory for -userdir switch") << endl;
931 cl_user_support = arg;
935 int parse_execute(string const & arg, string const &)
938 lyxerr << _("Missing command string after --execute switch") << endl;
945 int parse_export(string const & type, string const &)
948 lyxerr << _("Missing file type [eg latex, ps...] after "
949 "--export switch") << endl;
952 batch = "buffer-export " + type;
957 int parse_import(string const & type, string const & file)
960 lyxerr << _("Missing file type [eg latex, ps...] after "
961 "--import switch") << endl;
965 lyxerr << _("Missing filename for --import") << endl;
969 batch = "buffer-import " + type + ' ' + file;
976 bool LyX::easyParse(int & argc, char * argv[])
978 std::map<string, cmd_helper> cmdmap;
980 cmdmap["-dbg"] = parse_dbg;
981 cmdmap["-help"] = parse_help;
982 cmdmap["--help"] = parse_help;
983 cmdmap["-version"] = parse_version;
984 cmdmap["--version"] = parse_version;
985 cmdmap["-sysdir"] = parse_sysdir;
986 cmdmap["-userdir"] = parse_userdir;
987 cmdmap["-x"] = parse_execute;
988 cmdmap["--execute"] = parse_execute;
989 cmdmap["-e"] = parse_export;
990 cmdmap["--export"] = parse_export;
991 cmdmap["-i"] = parse_import;
992 cmdmap["--import"] = parse_import;
994 for (int i = 1; i < argc; ++i) {
995 std::map<string, cmd_helper>::const_iterator it
996 = cmdmap.find(argv[i]);
998 // don't complain if not found - may be parsed later
999 if (it == cmdmap.end())
1002 string arg((i + 1 < argc) ? argv[i + 1] : "");
1003 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1005 int const remove = 1 + it->second(arg, arg2);
1007 // Now, remove used arguments by shifting
1008 // the following ones remove places down.
1010 for (int j = i; j < argc; ++j)
1011 argv[j] = argv[j + remove];
1015 batch_command = batch;