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::rtrim;
77 using lyx::support::Systemcall;
81 namespace os = lyx::support::os;
82 namespace fs = boost::filesystem;
88 #ifndef CXX_GLOBAL_CSTD
95 extern LyXServer * lyxserver;
97 // This is the global bufferlist object
98 BufferList bufferlist;
100 // convenient to have it here.
101 boost::scoped_ptr<kb_keymap> toplevel_keymap;
105 // Filled with the command line arguments "foo" of "-sysdir foo" or
107 string cl_system_support;
108 string cl_user_support;
111 void lyx_exit(int status)
113 // FIXME: We should not directly call exit(), since it only
114 // guarantees a return to the system, no application cleanup.
115 // This may cause troubles with not executed destructors.
116 if (lyx_gui::use_gui)
117 // lyx_gui::exit may return and only schedule the exit
118 lyx_gui::exit(status);
123 void showFileError(string const & error)
125 Alert::warning(_("Could not read configuration file"),
126 bformat(_("Error while reading the configuration file\n%1$s.\n"
127 "Please check your installation."), lyx::from_utf8(error)));
131 void reconfigureUserLyXDir()
133 string const configure_command = package().configure_command();
135 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
136 Path p(package().user_support());
138 one.startscript(Systemcall::Wait, configure_command);
139 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
145 boost::scoped_ptr<LyX> LyX::singleton_;
147 int LyX::exec(int & argc, char * argv[])
149 BOOST_ASSERT(!singleton_.get());
150 // We must return from this before launching the gui so that
151 // other parts of the code can access singleton_ through
152 // LyX::ref and LyX::cref.
153 singleton_.reset(new LyX);
154 // Start the real execution loop.
155 return singleton_->priv_exec(argc, argv);
161 BOOST_ASSERT(singleton_.get());
162 return *singleton_.get();
166 LyX const & LyX::cref()
168 BOOST_ASSERT(singleton_.get());
169 return *singleton_.get();
174 : first_start(false), geometryOption_(false)
178 lyx::Session & LyX::session()
180 BOOST_ASSERT(session_.get());
181 return *session_.get();
185 lyx::Session const & LyX::session() const
187 BOOST_ASSERT(session_.get());
188 return *session_.get();
192 void LyX::addLyXView(LyXView * lyxview)
194 views_.push_back(lyxview);
198 Buffer const * const LyX::updateInset(InsetBase const * inset) const
203 Buffer const * buffer_ptr = 0;
204 ViewList::const_iterator it = views_.begin();
205 ViewList::const_iterator const end = views_.end();
206 for (; it != end; ++it) {
207 Buffer const * ptr = (*it)->updateInset(inset);
215 int LyX::priv_exec(int & argc, char * argv[])
217 // Here we need to parse the command line. At least
218 // we need to parse for "-dbg" and "-help"
219 lyx_gui::use_gui = easyParse(argc, argv);
221 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
222 lyx::support::top_build_dir_is_one_level_up);
224 // Start the real execution loop.
225 if (lyx_gui::use_gui)
226 return lyx_gui::exec(argc, argv);
228 return exec2(argc, argv);
232 int LyX::exec2(int & argc, char * argv[])
234 // check for any spurious extra arguments
235 // other than documents
236 for (int argi = 1; argi < argc ; ++argi) {
237 if (argv[argi][0] == '-') {
238 lyxerr << lyx::to_utf8(
239 bformat(_("Wrong command line option `%1$s'. Exiting."),
240 lyx::from_utf8(argv[argi]))) << endl;
245 // Initialization of LyX (reads lyxrc and more)
246 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
247 bool const success = init();
248 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
252 if (lyx_gui::use_gui)
253 lyx_gui::parse_lyxrc();
255 vector<string> files;
257 for (int argi = argc - 1; argi >= 1; --argi)
258 files.push_back(os::internal_path(argv[argi]));
261 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
263 // Execute batch commands if available
264 if (!batch_command.empty()) {
266 lyxerr[Debug::INIT] << "About to handle -x '"
267 << batch_command << '\'' << endl;
269 Buffer * last_loaded = 0;
271 vector<string>::const_iterator it = files.begin();
272 vector<string>::const_iterator end = files.end();
274 for (; it != end; ++it) {
275 // get absolute path of file and add ".lyx" to
276 // the filename if necessary
277 string s = fileSearch(string(), *it, "lyx");
279 Buffer * const b = newFile(*it, string(), true);
283 Buffer * buf = bufferlist.newBuffer(s, false);
284 if (loadLyXFile(buf, s)) {
286 ErrorList const & el = buf->errorList("Parse");
288 for_each(el.begin(), el.end(),
289 boost::bind(&LyX::printError, this, _1));
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_) {
345 // create the main window
346 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
349 for_each(files.begin(), files.end(),
350 bind(&LyXView::loadLyXFile, view, _1, true));
352 // if a file is specified, I assume that user wants to edit *that* file
353 if (files.empty() && lyxrc.load_session) {
354 vector<string> const & lastopened = session_->lastOpenedFiles();
355 // do not add to the lastfile list since these files are restored from
356 // last seesion, and should be already there (regular files), or should
357 // not be added at all (help files).
358 for_each(lastopened.begin(), lastopened.end(),
359 bind(&LyXView::loadLyXFile, view, _1, false));
361 // clear this list to save a few bytes of RAM
362 session_->clearLastOpenedFiles();
364 return lyx_gui::start(view, batch_command);
366 // Something went wrong above
376 The SIGHUP signal does not exist on Windows and does not need to be handled.
378 Windows handles SIGFPE and SIGSEGV signals as expected.
380 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
381 cause a new thread to be spawned. This may well result in unexpected
382 behaviour by the single-threaded LyX.
384 SIGTERM signals will come only from another process actually sending
385 that signal using 'raise' in Windows' POSIX compatability layer. It will
386 not come from the general "terminate process" methods that everyone
387 actually uses (and which can't be trapped). Killing an app 'politely' on
388 Windows involves first sending a WM_CLOSE message, something that is
389 caught already by the Qt frontend.
391 For more information see:
393 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
394 ...signals are mostly useless on Windows for a variety of reasons that are
397 'UNIX Application Migration Guide, Chapter 9'
398 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
400 'How To Terminate an Application "Cleanly" in Win32'
401 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
405 static void error_handler(int err_sig)
407 // Throw away any signals other than the first one received.
408 static sig_atomic_t handling_error = false;
411 handling_error = true;
413 // We have received a signal indicating a fatal error, so
414 // try and save the data ASAP.
415 LyX::cref().emergencyCleanup();
417 // These lyxerr calls may or may not work:
419 // Signals are asynchronous, so the main program may be in a very
420 // fragile state when a signal is processed and thus while a signal
421 // handler function executes.
422 // In general, therefore, we should avoid performing any
423 // I/O operations or calling most library and system functions from
426 // This shouldn't matter here, however, as we've already invoked
431 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
435 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
438 lyxerr << "\nlyx: SIGSEGV signal caught\n"
439 "Sorry, you have found a bug in LyX. "
440 "Please read the bug-reporting instructions "
441 "in Help->Introduction and send us a bug report, "
442 "if necessary. Thanks !\nBye." << endl;
450 // Deinstall the signal handlers
452 signal(SIGHUP, SIG_DFL);
454 signal(SIGINT, SIG_DFL);
455 signal(SIGFPE, SIG_DFL);
456 signal(SIGSEGV, SIG_DFL);
457 signal(SIGTERM, SIG_DFL);
460 if (err_sig == SIGSEGV ||
461 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
463 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
465 lyx::support::abort();
472 void LyX::printError(ErrorItem const & ei)
474 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
476 std::cerr << lyx::to_utf8(tmp) << std::endl;
483 signal(SIGHUP, error_handler);
485 signal(SIGFPE, error_handler);
486 signal(SIGSEGV, error_handler);
487 signal(SIGINT, error_handler);
488 signal(SIGTERM, error_handler);
489 // SIGPIPE can be safely ignored.
491 lyxrc.tempdir_path = package().temp_dir();
492 lyxrc.document_path = package().document_dir();
494 if (lyxrc.template_path.empty()) {
495 lyxrc.template_path = addPath(package().system_support(),
499 if (lyxrc.roman_font_name.empty())
500 lyxrc.roman_font_name = lyx_gui::roman_font_name();
501 if (lyxrc.sans_font_name.empty())
502 lyxrc.sans_font_name = lyx_gui::sans_font_name();
503 if (lyxrc.typewriter_font_name.empty())
504 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
507 // Read configuration files
510 // This one may have been distributed along with LyX.
511 if (!readRcFile("lyxrc.dist"))
514 // Set the PATH correctly.
515 #if !defined (USE_POSIX_PACKAGING)
516 // Add the directory containing the LyX executable to the path
517 // so that LyX can find things like tex2lyx.
518 if (package().build_support().empty())
519 prependEnvPath("PATH", package().binary_dir());
521 if (!lyxrc.path_prefix.empty())
522 prependEnvPath("PATH", lyxrc.path_prefix);
524 // Check that user LyX directory is ok.
525 if (queryUserLyXDir(package().explicit_user_support()))
526 reconfigureUserLyXDir();
528 // no need for a splash when there is no GUI
529 if (!lyx_gui::use_gui) {
533 // This one is generated in user_support directory by lib/configure.py.
534 if (!readRcFile("lyxrc.defaults"))
537 // Query the OS to know what formats are viewed natively
538 formats.setAutoOpen();
540 system_lyxrc = lyxrc;
541 system_formats = formats;
542 system_converters = converters;
543 system_movers = movers;
544 system_lcolor = lcolor;
546 // This one is edited through the preferences dialog.
547 if (!readRcFile("preferences"))
550 if (!readEncodingsFile("encodings"))
552 if (!readLanguagesFile("languages"))
556 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
560 if (lyx_gui::use_gui) {
562 toplevel_keymap.reset(new kb_keymap);
563 defaultKeyBindings(toplevel_keymap.get());
564 toplevel_keymap->read(lyxrc.bind_file);
567 if (!readUIFile(lyxrc.ui_file))
571 if (lyxerr.debugging(Debug::LYXRC))
574 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
575 if (!lyxrc.path_prefix.empty())
576 prependEnvPath("PATH", lyxrc.path_prefix);
578 if (fs::exists(lyxrc.document_path) &&
579 fs::is_directory(lyxrc.document_path))
580 package().document_dir() = lyxrc.document_path;
582 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
583 if (package().temp_dir().empty()) {
584 Alert::error(_("Could not create temporary directory"),
585 bformat(_("Could not create a temporary directory in\n"
586 "%1$s. Make sure that this\n"
587 "path exists and is writable and try again."),
588 lyx::from_utf8(lyxrc.tempdir_path)));
589 // createLyXTmpDir() tries sufficiently hard to create a
590 // usable temp dir, so the probability to come here is
591 // close to zero. We therefore don't try to overcome this
592 // problem with e.g. asking the user for a new path and
593 // trying again but simply exit.
597 if (lyxerr.debugging(Debug::INIT)) {
598 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
601 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
602 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
607 void LyX::defaultKeyBindings(kb_keymap * kbmap)
609 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
610 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
611 kbmap->bind("Up", FuncRequest(LFUN_UP));
612 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
614 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
615 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
616 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
617 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
619 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
620 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
621 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
622 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
624 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
625 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
627 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
628 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
630 // kbmap->bindings to enable the use of the numeric keypad
632 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
634 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
635 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
647 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
648 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
649 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
650 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
651 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
652 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
653 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
654 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
655 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
659 void LyX::emergencyCleanup() const
661 // what to do about tmpfiles is non-obvious. we would
662 // like to delete any we find, but our lyxdir might
663 // contain documents etc. which might be helpful on
666 bufferlist.emergencyWriteAll();
668 lyxserver->emergencyCleanup();
672 void LyX::deadKeyBindings(kb_keymap * kbmap)
674 // bindKeyings for transparent handling of deadkeys
675 // The keysyms are gotten from XFree86 X11R6
676 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
677 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
678 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
679 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
680 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
681 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
682 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
683 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
684 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
685 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
686 // nothing with this name
687 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
688 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
689 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
690 // nothing with this name either...
691 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
692 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
693 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
694 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
700 // return true if file does not exist or is older than configure.py.
701 bool needsUpdate(string const & file)
703 static string const configure_script =
704 addName(package().system_support(), "configure.py");
705 string const absfile =
706 addName(package().user_support(), file);
708 return (! fs::exists(absfile))
709 || (fs::last_write_time(configure_script)
710 > fs::last_write_time(absfile));
716 bool LyX::queryUserLyXDir(bool explicit_userdir)
718 // Does user directory exist?
719 if (fs::exists(package().user_support()) &&
720 fs::is_directory(package().user_support())) {
723 return needsUpdate("lyxrc.defaults")
724 || needsUpdate("textclass.lst")
725 || needsUpdate("packages.lst");
728 first_start = !explicit_userdir;
730 // If the user specified explicitly a directory, ask whether
731 // to create it. If the user says "no", then exit.
732 if (explicit_userdir &&
734 _("Missing user LyX directory"),
735 bformat(_("You have specified a non-existent user "
736 "LyX directory, %1$s.\n"
737 "It is needed to keep your own configuration."),
738 lyx::from_utf8(package().user_support())),
740 _("&Create directory"),
742 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
743 lyx_exit(EXIT_FAILURE);
746 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
747 lyx::from_utf8(package().user_support())))
750 if (!createDirectory(package().user_support(), 0755)) {
751 // Failed, so let's exit.
752 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
754 lyx_exit(EXIT_FAILURE);
761 bool LyX::readRcFile(string const & name)
763 lyxerr[Debug::INIT] << "About to read " << name << "... ";
765 string const lyxrc_path = libFileSearch(string(), name);
766 if (!lyxrc_path.empty()) {
768 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
770 if (lyxrc.read(lyxrc_path) < 0) {
775 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
781 // Read the ui file `name'
782 bool LyX::readUIFile(string const & name)
792 struct keyword_item uitags[ui_last - 1] = {
793 { "include", ui_include },
794 { "menuset", ui_menuset },
795 { "toolbar", ui_toolbar },
796 { "toolbars", ui_toolbars }
799 // Ensure that a file is read only once (prevents include loops)
800 static std::list<string> uifiles;
801 std::list<string>::const_iterator it = uifiles.begin();
802 std::list<string>::const_iterator end = uifiles.end();
803 it = std::find(it, end, name);
805 lyxerr[Debug::INIT] << "UI file '" << name
806 << "' has been read already. "
807 << "Is this an include loop?"
812 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
814 string const ui_path = libFileSearch("ui", name, "ui");
816 if (ui_path.empty()) {
817 lyxerr[Debug::INIT] << "Could not find " << name << endl;
821 uifiles.push_back(name);
823 lyxerr[Debug::INIT] << "Found " << name
824 << " in " << ui_path << endl;
825 LyXLex lex(uitags, ui_last - 1);
826 lex.setFile(ui_path);
828 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
832 if (lyxerr.debugging(Debug::PARSER))
833 lex.printTable(lyxerr);
839 string const file = lex.getString();
840 if (!readUIFile(file))
845 menubackend.read(lex);
849 toolbarbackend.read(lex);
853 toolbarbackend.readToolbars(lex);
857 if (!rtrim(lex.getString()).empty())
858 lex.printError("LyX::ReadUIFile: "
859 "Unknown menu tag: `$$Token'");
867 // Read the languages file `name'
868 bool LyX::readLanguagesFile(string const & name)
870 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
872 string const lang_path = libFileSearch(string(), name);
873 if (lang_path.empty()) {
877 languages.read(lang_path);
882 // Read the encodings file `name'
883 bool LyX::readEncodingsFile(string const & name)
885 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
887 string const enc_path = libFileSearch(string(), name);
888 if (enc_path.empty()) {
892 encodings.read(enc_path);
902 /// return the the number of arguments consumed
903 typedef boost::function<int(string const &, string const &)> cmd_helper;
905 int parse_dbg(string const & arg, string const &)
908 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
909 Debug::showTags(lyxerr);
912 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
914 lyxerr.level(Debug::value(arg));
915 Debug::showLevel(lyxerr, lyxerr.level());
920 int parse_help(string const &, string const &)
923 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
924 "Command line switches (case sensitive):\n"
925 "\t-help summarize LyX usage\n"
926 "\t-userdir dir set user directory to dir\n"
927 "\t-sysdir dir set system directory to dir\n"
928 "\t-geometry WxH+X+Y set geometry of the main window\n"
929 "\t-dbg feature[,feature]...\n"
930 " select the features to debug.\n"
931 " Type `lyx -dbg' to see the list of features\n"
932 "\t-x [--execute] command\n"
933 " where command is a lyx command.\n"
934 "\t-e [--export] fmt\n"
935 " where fmt is the export format of choice.\n"
936 "\t-i [--import] fmt file.xxx\n"
937 " where fmt is the import format of choice\n"
938 " and file.xxx is the file to be imported.\n"
939 "\t-version summarize version and build info\n"
940 "Check the LyX man page for more details.")) << endl;
945 int parse_version(string const &, string const &)
947 lyxerr << "LyX " << lyx_version
948 << " (" << lyx_release_date << ")" << endl;
949 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
951 lyxerr << lyx_version_info << endl;
956 int parse_sysdir(string const & arg, string const &)
959 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
962 cl_system_support = arg;
966 int parse_userdir(string const & arg, string const &)
969 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
972 cl_user_support = arg;
976 int parse_execute(string const & arg, string const &)
979 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
986 int parse_export(string const & type, string const &)
989 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
990 "--export switch")) << endl;
993 batch = "buffer-export " + type;
998 int parse_import(string const & type, string const & file)
1001 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1002 "--import switch")) << endl;
1006 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1010 batch = "buffer-import " + type + ' ' + file;
1017 bool LyX::easyParse(int & argc, char * argv[])
1019 std::map<string, cmd_helper> cmdmap;
1021 cmdmap["-dbg"] = parse_dbg;
1022 cmdmap["-help"] = parse_help;
1023 cmdmap["--help"] = parse_help;
1024 cmdmap["-version"] = parse_version;
1025 cmdmap["--version"] = parse_version;
1026 cmdmap["-sysdir"] = parse_sysdir;
1027 cmdmap["-userdir"] = parse_userdir;
1028 cmdmap["-x"] = parse_execute;
1029 cmdmap["--execute"] = parse_execute;
1030 cmdmap["-e"] = parse_export;
1031 cmdmap["--export"] = parse_export;
1032 cmdmap["-i"] = parse_import;
1033 cmdmap["--import"] = parse_import;
1035 for (int i = 1; i < argc; ++i) {
1036 std::map<string, cmd_helper>::const_iterator it
1037 = cmdmap.find(argv[i]);
1039 // check for X11 -geometry option
1040 if (lyx::support::compare(argv[i], "-geometry") == 0)
1041 geometryOption_ = true;
1043 // don't complain if not found - may be parsed later
1044 if (it == cmdmap.end())
1047 string arg((i + 1 < argc) ? argv[i + 1] : "");
1048 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1050 int const remove = 1 + it->second(arg, arg2);
1052 // Now, remove used arguments by shifting
1053 // the following ones remove places down.
1055 for (int j = i; j < argc; ++j)
1056 argv[j] = argv[j + remove];
1060 batch_command = batch;