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 may return and only schedule the exit
117 lyx_gui::exit(status);
122 void showFileError(string const & error)
124 Alert::warning(_("Could not read configuration file"),
125 bformat(_("Error while reading the configuration file\n%1$s.\n"
126 "Please check your installation."), error));
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 int 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 return 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();
173 : first_start(false), geometryOption_(false)
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(LyXView * 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 int 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 return lyx_gui::exec(argc, argv);
227 return exec2(argc, argv);
231 int 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;
245 bool const success = init();
246 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
250 if (lyx_gui::use_gui)
251 lyx_gui::parse_lyxrc();
253 vector<string> files;
255 for (int argi = argc - 1; argi >= 1; --argi)
256 files.push_back(os::internal_path(argv[argi]));
259 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
261 // if a file is specified, I assume that user wants to edit *that* file
262 if (files.empty() && lyxrc.load_session) {
263 vector<string> const & lastopened = session_->lastOpenedFiles();
264 files.insert(files.end(), lastopened.begin(), lastopened.end() );
266 // clear this list to save a few bytes of RAM
267 session_->clearLastOpenedFiles();
269 // Execute batch commands if available
270 if (!batch_command.empty()) {
272 lyxerr[Debug::INIT] << "About to handle -x '"
273 << batch_command << '\'' << endl;
275 Buffer * last_loaded = 0;
277 vector<string>::const_iterator it = files.begin();
278 vector<string>::const_iterator end = files.end();
280 for (; it != end; ++it) {
281 // get absolute path of file and add ".lyx" to
282 // the filename if necessary
283 string s = fileSearch(string(), *it, "lyx");
285 last_loaded = newFile(*it, string(), true);
287 Buffer * buf = bufferlist.newBuffer(s, false);
288 buf->error.connect(boost::bind(&LyX::printError, this, _1));
289 if (loadLyXFile(buf, s))
292 bufferlist.release(buf);
296 // try to dispatch to last loaded buffer first
298 bool success = false;
299 if (last_loaded->dispatch(batch_command, &success)) {
304 files.clear(); // the files are already loaded
307 if (lyx_gui::use_gui) {
308 // determine windows size and position, from lyxrc and/or session
310 unsigned int width = 690;
311 unsigned int height = 510;
312 bool maximize = false;
314 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
315 width = lyxrc.geometry_width;
316 height = lyxrc.geometry_height;
318 // if lyxrc returns (0,0), then use session info
320 string val = session().loadSessionInfo("WindowWidth");
322 width = convert<unsigned int>(val);
323 val = session().loadSessionInfo("WindowHeight");
325 height = convert<unsigned int>(val);
326 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
329 // if user wants to restore window position
332 if (lyxrc.geometry_xysaved) {
333 string val = session().loadSessionInfo("WindowPosX");
335 posx = convert<int>(val);
336 val = session().loadSessionInfo("WindowPosY");
338 posy = convert<int>(val);
341 if (geometryOption_) {
346 return lyx_gui::start(batch_command, files, width, height, posx, posy, maximize);
349 // Something went wrong above
359 The SIGHUP signal does not exist on Windows and does not need to be handled.
361 Windows handles SIGFPE and SIGSEGV signals as expected.
363 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
364 cause a new thread to be spawned. This may well result in unexpected
365 behaviour by the single-threaded LyX.
367 SIGTERM signals will come only from another process actually sending
368 that signal using 'raise' in Windows' POSIX compatability layer. It will
369 not come from the general "terminate process" methods that everyone
370 actually uses (and which can't be trapped). Killing an app 'politely' on
371 Windows involves first sending a WM_CLOSE message, something that is
372 caught already by the Qt frontend.
374 For more information see:
376 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
377 ...signals are mostly useless on Windows for a variety of reasons that are
380 'UNIX Application Migration Guide, Chapter 9'
381 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
383 'How To Terminate an Application "Cleanly" in Win32'
384 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
388 static void error_handler(int err_sig)
390 // Throw away any signals other than the first one received.
391 static sig_atomic_t handling_error = false;
394 handling_error = true;
396 // We have received a signal indicating a fatal error, so
397 // try and save the data ASAP.
398 LyX::cref().emergencyCleanup();
400 // These lyxerr calls may or may not work:
402 // Signals are asynchronous, so the main program may be in a very
403 // fragile state when a signal is processed and thus while a signal
404 // handler function executes.
405 // In general, therefore, we should avoid performing any
406 // I/O operations or calling most library and system functions from
409 // This shouldn't matter here, however, as we've already invoked
414 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
418 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
421 lyxerr << "\nlyx: SIGSEGV signal caught\n"
422 "Sorry, you have found a bug in LyX. "
423 "Please read the bug-reporting instructions "
424 "in Help->Introduction and send us a bug report, "
425 "if necessary. Thanks !\nBye." << endl;
433 // Deinstall the signal handlers
435 signal(SIGHUP, SIG_DFL);
437 signal(SIGINT, SIG_DFL);
438 signal(SIGFPE, SIG_DFL);
439 signal(SIGSEGV, SIG_DFL);
440 signal(SIGTERM, SIG_DFL);
443 if (err_sig == SIGSEGV ||
444 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
446 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
448 lyx::support::abort();
455 void LyX::printError(ErrorItem const & ei)
457 std::cerr << _("LyX: ") << ei.error
458 << ':' << ei.description << std::endl;
466 signal(SIGHUP, error_handler);
468 signal(SIGFPE, error_handler);
469 signal(SIGSEGV, error_handler);
470 signal(SIGINT, error_handler);
471 signal(SIGTERM, error_handler);
472 // SIGPIPE can be safely ignored.
474 lyxrc.tempdir_path = package().temp_dir();
475 lyxrc.document_path = package().document_dir();
477 if (lyxrc.template_path.empty()) {
478 lyxrc.template_path = addPath(package().system_support(),
482 if (lyxrc.roman_font_name.empty())
483 lyxrc.roman_font_name = lyx_gui::roman_font_name();
484 if (lyxrc.sans_font_name.empty())
485 lyxrc.sans_font_name = lyx_gui::sans_font_name();
486 if (lyxrc.typewriter_font_name.empty())
487 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
490 // Read configuration files
493 // This one may have been distributed along with LyX.
494 if (!readRcFile("lyxrc.dist"))
497 // Set the PATH correctly.
498 #if !defined (USE_POSIX_PACKAGING)
499 // Add the directory containing the LyX executable to the path
500 // so that LyX can find things like tex2lyx.
501 if (package().build_support().empty())
502 prependEnvPath("PATH", package().binary_dir());
504 if (!lyxrc.path_prefix.empty())
505 prependEnvPath("PATH", lyxrc.path_prefix);
507 // Check that user LyX directory is ok. We don't do that if
508 // running in batch mode.
509 if (lyx_gui::use_gui) {
510 if (queryUserLyXDir(package().explicit_user_support()))
511 reconfigureUserLyXDir();
516 // This one is generated in user_support directory by lib/configure.py.
517 if (!readRcFile("lyxrc.defaults"))
520 // Query the OS to know what formats are viewed natively
521 formats.setAutoOpen();
523 system_lyxrc = lyxrc;
524 system_formats = formats;
525 system_converters = converters;
526 system_movers = movers;
527 system_lcolor = lcolor;
529 // This one is edited through the preferences dialog.
530 if (!readRcFile("preferences"))
533 if (!readEncodingsFile("encodings"))
535 if (!readLanguagesFile("languages"))
539 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
543 if (lyx_gui::use_gui) {
545 toplevel_keymap.reset(new kb_keymap);
546 defaultKeyBindings(toplevel_keymap.get());
547 toplevel_keymap->read(lyxrc.bind_file);
550 if (!readUIFile(lyxrc.ui_file))
554 if (lyxerr.debugging(Debug::LYXRC))
557 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
558 if (!lyxrc.path_prefix.empty())
559 prependEnvPath("PATH", lyxrc.path_prefix);
561 if (fs::exists(lyxrc.document_path) &&
562 fs::is_directory(lyxrc.document_path))
563 package().document_dir() = lyxrc.document_path;
565 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
566 if (package().temp_dir().empty()) {
567 Alert::error(_("Could not create temporary directory"),
568 bformat(_("Could not create a temporary directory in\n"
569 "%1$s. Make sure that this\n"
570 "path exists and is writable and try again."),
571 lyxrc.tempdir_path));
572 // createLyXTmpDir() tries sufficiently hard to create a
573 // usable temp dir, so the probability to come here is
574 // close to zero. We therefore don't try to overcome this
575 // problem with e.g. asking the user for a new path and
576 // trying again but simply exit.
580 if (lyxerr.debugging(Debug::INIT)) {
581 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
584 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
585 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
590 void LyX::defaultKeyBindings(kb_keymap * kbmap)
592 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
593 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
594 kbmap->bind("Up", FuncRequest(LFUN_UP));
595 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
597 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
598 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
599 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
600 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
602 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
603 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
604 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
605 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
607 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
608 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
610 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
611 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
613 // kbmap->bindings to enable the use of the numeric keypad
615 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
616 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
617 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
618 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
619 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
620 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
621 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
622 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
623 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
624 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
625 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
626 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
627 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
628 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
629 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
630 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
631 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
632 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
633 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
634 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
635 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
636 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
637 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
638 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
642 void LyX::emergencyCleanup() const
644 // what to do about tmpfiles is non-obvious. we would
645 // like to delete any we find, but our lyxdir might
646 // contain documents etc. which might be helpful on
649 bufferlist.emergencyWriteAll();
651 lyxserver->emergencyCleanup();
655 void LyX::deadKeyBindings(kb_keymap * kbmap)
657 // bindKeyings for transparent handling of deadkeys
658 // The keysyms are gotten from XFree86 X11R6
659 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
660 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
661 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
662 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
663 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
664 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
665 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
666 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
667 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
668 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
669 // nothing with this name
670 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
671 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
672 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
673 // nothing with this name either...
674 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
675 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
676 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
677 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
683 // return true if file does not exist or is older than configure.py.
684 bool needsUpdate(string const & file)
686 static string const configure_script =
687 addName(package().system_support(), "configure.py");
688 string const absfile =
689 addName(package().user_support(), file);
691 return (! fs::exists(absfile))
692 || (fs::last_write_time(configure_script)
693 > fs::last_write_time(absfile));
699 bool LyX::queryUserLyXDir(bool explicit_userdir)
701 // Does user directory exist?
702 if (fs::exists(package().user_support()) &&
703 fs::is_directory(package().user_support())) {
706 return needsUpdate("lyxrc.defaults")
707 || needsUpdate("textclass.lst")
708 || needsUpdate("packages.lst");
711 first_start = !explicit_userdir;
713 // If the user specified explicitly a directory, ask whether
714 // to create it. If the user says "no", then exit.
715 if (explicit_userdir &&
717 _("Missing user LyX directory"),
718 bformat(_("You have specified a non-existent user "
719 "LyX directory, %1$s.\n"
720 "It is needed to keep your own configuration."),
721 package().user_support()),
723 _("&Create directory"),
725 lyxerr << _("No user LyX directory. Exiting.") << endl;
726 lyx_exit(EXIT_FAILURE);
729 lyxerr << bformat(_("LyX: Creating directory %1$s"),
730 package().user_support())
733 if (!createDirectory(package().user_support(), 0755)) {
734 // Failed, so let's exit.
735 lyxerr << _("Failed to create directory. Exiting.")
737 lyx_exit(EXIT_FAILURE);
744 bool LyX::readRcFile(string const & name)
746 lyxerr[Debug::INIT] << "About to read " << name << "... ";
748 string const lyxrc_path = libFileSearch(string(), name);
749 if (!lyxrc_path.empty()) {
751 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
753 if (lyxrc.read(lyxrc_path) < 0) {
758 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
764 // Read the ui file `name'
765 bool LyX::readUIFile(string const & name)
775 struct keyword_item uitags[ui_last - 1] = {
776 { "include", ui_include },
777 { "menuset", ui_menuset },
778 { "toolbar", ui_toolbar },
779 { "toolbars", ui_toolbars }
782 // Ensure that a file is read only once (prevents include loops)
783 static std::list<string> uifiles;
784 std::list<string>::const_iterator it = uifiles.begin();
785 std::list<string>::const_iterator end = uifiles.end();
786 it = std::find(it, end, name);
788 lyxerr[Debug::INIT] << "UI file '" << name
789 << "' has been read already. "
790 << "Is this an include loop?"
795 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
797 string const ui_path = libFileSearch("ui", name, "ui");
799 if (ui_path.empty()) {
800 lyxerr[Debug::INIT] << "Could not find " << name << endl;
804 uifiles.push_back(name);
806 lyxerr[Debug::INIT] << "Found " << name
807 << " in " << ui_path << endl;
808 LyXLex lex(uitags, ui_last - 1);
809 lex.setFile(ui_path);
811 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
815 if (lyxerr.debugging(Debug::PARSER))
816 lex.printTable(lyxerr);
822 string const file = lex.getString();
823 if (!readUIFile(file))
828 menubackend.read(lex);
832 toolbarbackend.read(lex);
836 toolbarbackend.readToolbars(lex);
840 if (!rtrim(lex.getString()).empty())
841 lex.printError("LyX::ReadUIFile: "
842 "Unknown menu tag: `$$Token'");
850 // Read the languages file `name'
851 bool LyX::readLanguagesFile(string const & name)
853 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
855 string const lang_path = libFileSearch(string(), name);
856 if (lang_path.empty()) {
860 languages.read(lang_path);
865 // Read the encodings file `name'
866 bool LyX::readEncodingsFile(string const & name)
868 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
870 string const enc_path = libFileSearch(string(), name);
871 if (enc_path.empty()) {
875 encodings.read(enc_path);
885 /// return the the number of arguments consumed
886 typedef boost::function<int(string const &, string const &)> cmd_helper;
888 int parse_dbg(string const & arg, string const &)
891 lyxerr << _("List of supported debug flags:") << endl;
892 Debug::showTags(lyxerr);
895 lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
897 lyxerr.level(Debug::value(arg));
898 Debug::showLevel(lyxerr, lyxerr.level());
903 int parse_help(string const &, string const &)
906 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
907 "Command line switches (case sensitive):\n"
908 "\t-help summarize LyX usage\n"
909 "\t-userdir dir set user directory to dir\n"
910 "\t-sysdir dir set system directory to dir\n"
911 "\t-geometry WxH+X+Y set geometry of the main window\n"
912 "\t-dbg feature[,feature]...\n"
913 " select the features to debug.\n"
914 " Type `lyx -dbg' to see the list of features\n"
915 "\t-x [--execute] command\n"
916 " where command is a lyx command.\n"
917 "\t-e [--export] fmt\n"
918 " where fmt is the export format of choice.\n"
919 "\t-i [--import] fmt file.xxx\n"
920 " where fmt is the import format of choice\n"
921 " and file.xxx is the file to be imported.\n"
922 "\t-version summarize version and build info\n"
923 "Check the LyX man page for more details.") << endl;
928 int parse_version(string const &, string const &)
930 lyxerr << "LyX " << lyx_version
931 << " of " << lyx_release_date << endl;
932 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
934 lyxerr << lyx_version_info << endl;
939 int parse_sysdir(string const & arg, string const &)
942 lyxerr << _("Missing directory for -sysdir switch") << endl;
945 cl_system_support = arg;
949 int parse_userdir(string const & arg, string const &)
952 lyxerr << _("Missing directory for -userdir switch") << endl;
955 cl_user_support = arg;
959 int parse_execute(string const & arg, string const &)
962 lyxerr << _("Missing command string after --execute switch") << endl;
969 int parse_export(string const & type, string const &)
972 lyxerr << _("Missing file type [eg latex, ps...] after "
973 "--export switch") << endl;
976 batch = "buffer-export " + type;
981 int parse_import(string const & type, string const & file)
984 lyxerr << _("Missing file type [eg latex, ps...] after "
985 "--import switch") << endl;
989 lyxerr << _("Missing filename for --import") << endl;
993 batch = "buffer-import " + type + ' ' + file;
1000 bool LyX::easyParse(int & argc, char * argv[])
1002 std::map<string, cmd_helper> cmdmap;
1004 cmdmap["-dbg"] = parse_dbg;
1005 cmdmap["-help"] = parse_help;
1006 cmdmap["--help"] = parse_help;
1007 cmdmap["-version"] = parse_version;
1008 cmdmap["--version"] = parse_version;
1009 cmdmap["-sysdir"] = parse_sysdir;
1010 cmdmap["-userdir"] = parse_userdir;
1011 cmdmap["-x"] = parse_execute;
1012 cmdmap["--execute"] = parse_execute;
1013 cmdmap["-e"] = parse_export;
1014 cmdmap["--export"] = parse_export;
1015 cmdmap["-i"] = parse_import;
1016 cmdmap["--import"] = parse_import;
1018 for (int i = 1; i < argc; ++i) {
1019 std::map<string, cmd_helper>::const_iterator it
1020 = cmdmap.find(argv[i]);
1022 // check for X11 -geometry option
1023 if (lyx::support::compare(argv[i], "-geometry") == 0)
1024 geometryOption_ = true;
1026 // don't complain if not found - may be parsed later
1027 if (it == cmdmap.end())
1030 string arg((i + 1 < argc) ? argv[i + 1] : "");
1031 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1033 int const remove = 1 + it->second(arg, arg2);
1035 // Now, remove used arguments by shifting
1036 // the following ones remove places down.
1038 for (int j = i; j < argc; ++j)
1039 argv[j] = argv[j + remove];
1043 batch_command = batch;