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 "lyxserver.h"
38 #include "lyxtextclasslist.h"
39 #include "MenuBackend.h"
41 #include "ToolbarBackend.h"
43 #include "frontends/Alert.h"
44 #include "frontends/Application.h"
45 #include "frontends/lyx_gui.h"
46 #include "frontends/LyXView.h"
48 #include "support/environment.h"
49 #include "support/filetools.h"
50 #include "support/fontutils.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::prependEnvPath;
75 using lyx::support::rtrim;
76 using lyx::support::Systemcall;
80 namespace os = lyx::support::os;
81 namespace fs = boost::filesystem;
88 #ifndef CXX_GLOBAL_CSTD
95 // convenient to have it here.
96 boost::scoped_ptr<kb_keymap> toplevel_keymap;
100 // Filled with the command line arguments "foo" of "-sysdir foo" or
102 string cl_system_support;
103 string cl_user_support;
106 void lyx_exit(int status)
108 // FIXME: We should not directly call exit(), since it only
109 // guarantees a return to the system, no application cleanup.
110 // This may cause troubles with not executed destructors.
111 if (lyx_gui::use_gui) {
112 theApp->exit(status);
113 // Restore original font resources after Application is destroyed.
114 lyx::support::restoreFontResources();
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."), lyx::from_utf8(error)));
129 void reconfigureUserLyXDir()
131 string const configure_command = package().configure_command();
133 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
134 lyx::support::Path p(package().user_support());
136 one.startscript(Systemcall::Wait, configure_command);
137 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
143 boost::scoped_ptr<LyX> LyX::singleton_;
145 int LyX::exec(int & argc, char * argv[])
147 BOOST_ASSERT(!singleton_.get());
148 // We must return from this before launching the gui so that
149 // other parts of the code can access singleton_ through
150 // LyX::ref and LyX::cref.
151 singleton_.reset(new LyX);
152 // Start the real execution loop.
153 return singleton_->priv_exec(argc, argv);
159 BOOST_ASSERT(singleton_.get());
160 return *singleton_.get();
164 LyX const & LyX::cref()
166 BOOST_ASSERT(singleton_.get());
167 return *singleton_.get();
172 : first_start(false), geometryOption_(false)
176 lyx::Session & LyX::session()
178 BOOST_ASSERT(session_.get());
179 return *session_.get();
183 lyx::Session const & LyX::session() const
185 BOOST_ASSERT(session_.get());
186 return *session_.get();
190 void LyX::addLyXView(LyXView * lyxview)
192 views_.push_back(lyxview);
196 Buffer const * const LyX::updateInset(InsetBase const * inset) const
201 Buffer const * buffer_ptr = 0;
202 ViewList::const_iterator it = views_.begin();
203 ViewList::const_iterator const end = views_.end();
204 for (; it != end; ++it) {
205 Buffer const * ptr = (*it)->updateInset(inset);
213 int LyX::priv_exec(int & argc, char * argv[])
215 // Here we need to parse the command line. At least
216 // we need to parse for "-dbg" and "-help"
217 lyx_gui::use_gui = easyParse(argc, argv);
219 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
220 lyx::support::top_build_dir_is_one_level_up);
222 // Start the real execution loop.
223 if (lyx_gui::use_gui) {
224 // Force adding of font path _before_ Application is initialized
225 lyx::support::addFontResources();
226 return lyx_gui::exec(argc, argv);
229 return exec2(argc, argv);
233 int LyX::exec2(int & argc, char * argv[])
235 // check for any spurious extra arguments
236 // other than documents
237 for (int argi = 1; argi < argc ; ++argi) {
238 if (argv[argi][0] == '-') {
239 lyxerr << lyx::to_utf8(
240 bformat(_("Wrong command line option `%1$s'. Exiting."),
241 lyx::from_utf8(argv[argi]))) << endl;
246 // Initialization of LyX (reads lyxrc and more)
247 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
248 bool const success = init();
249 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
253 if (lyx_gui::use_gui)
254 lyx_gui::parse_lyxrc();
256 vector<string> files;
258 for (int argi = argc - 1; argi >= 1; --argi)
259 files.push_back(os::internal_path(argv[argi]));
262 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
264 // Execute batch commands if available
265 if (!batch_command.empty()) {
267 lyxerr[Debug::INIT] << "About to handle -x '"
268 << batch_command << '\'' << endl;
270 Buffer * last_loaded = 0;
272 vector<string>::const_iterator it = files.begin();
273 vector<string>::const_iterator end = files.end();
275 for (; it != end; ++it) {
276 // get absolute path of file and add ".lyx" to
277 // the filename if necessary
278 string s = fileSearch(string(), *it, "lyx");
280 Buffer * const b = newFile(*it, string(), true);
284 Buffer * buf = theApp->bufferList().newBuffer(s, false);
285 if (loadLyXFile(buf, s)) {
287 ErrorList const & el = buf->errorList("Parse");
289 for_each(el.begin(), el.end(),
290 boost::bind(&LyX::printError, this, _1));
293 theApp->bufferList().release(buf);
297 // try to dispatch to last loaded buffer first
299 bool success = false;
300 if (last_loaded->dispatch(batch_command, &success)) {
305 files.clear(); // the files are already loaded
308 if (lyx_gui::use_gui) {
309 // determine windows size and position, from lyxrc and/or session
311 unsigned int width = 690;
312 unsigned int height = 510;
313 bool maximize = false;
315 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
316 width = lyxrc.geometry_width;
317 height = lyxrc.geometry_height;
319 // if lyxrc returns (0,0), then use session info
321 string val = session().loadSessionInfo("WindowWidth");
323 width = convert<unsigned int>(val);
324 val = session().loadSessionInfo("WindowHeight");
326 height = convert<unsigned int>(val);
327 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
330 // if user wants to restore window position
333 if (lyxrc.geometry_xysaved) {
334 string val = session().loadSessionInfo("WindowPosX");
336 posx = convert<int>(val);
337 val = session().loadSessionInfo("WindowPosY");
339 posy = convert<int>(val);
342 if (geometryOption_) {
346 // create the main window
347 LyXView * view = &theApp->createView(width, height, posx, posy, maximize);
348 ref().addLyXView(view);
351 for_each(files.begin(), files.end(),
352 bind(&LyXView::loadLyXFile, view, _1, true));
354 // if a file is specified, I assume that user wants to edit *that* file
355 if (files.empty() && lyxrc.load_session) {
356 vector<string> const & lastopened = session_->lastOpenedFiles();
357 // do not add to the lastfile list since these files are restored from
358 // last seesion, and should be already there (regular files), or should
359 // not be added at all (help files).
360 for_each(lastopened.begin(), lastopened.end(),
361 bind(&LyXView::loadLyXFile, view, _1, false));
363 // clear this list to save a few bytes of RAM
364 session_->clearLastOpenedFiles();
366 return theApp->start(batch_command);
368 // Something went wrong above
378 The SIGHUP signal does not exist on Windows and does not need to be handled.
380 Windows handles SIGFPE and SIGSEGV signals as expected.
382 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
383 cause a new thread to be spawned. This may well result in unexpected
384 behaviour by the single-threaded LyX.
386 SIGTERM signals will come only from another process actually sending
387 that signal using 'raise' in Windows' POSIX compatability layer. It will
388 not come from the general "terminate process" methods that everyone
389 actually uses (and which can't be trapped). Killing an app 'politely' on
390 Windows involves first sending a WM_CLOSE message, something that is
391 caught already by the Qt frontend.
393 For more information see:
395 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
396 ...signals are mostly useless on Windows for a variety of reasons that are
399 'UNIX Application Migration Guide, Chapter 9'
400 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
402 'How To Terminate an Application "Cleanly" in Win32'
403 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
407 static void error_handler(int err_sig)
409 // Throw away any signals other than the first one received.
410 static sig_atomic_t handling_error = false;
413 handling_error = true;
415 // We have received a signal indicating a fatal error, so
416 // try and save the data ASAP.
417 LyX::cref().emergencyCleanup();
419 // These lyxerr calls may or may not work:
421 // Signals are asynchronous, so the main program may be in a very
422 // fragile state when a signal is processed and thus while a signal
423 // handler function executes.
424 // In general, therefore, we should avoid performing any
425 // I/O operations or calling most library and system functions from
428 // This shouldn't matter here, however, as we've already invoked
433 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
437 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
440 lyxerr << "\nlyx: SIGSEGV signal caught\n"
441 "Sorry, you have found a bug in LyX. "
442 "Please read the bug-reporting instructions "
443 "in Help->Introduction and send us a bug report, "
444 "if necessary. Thanks !\nBye." << endl;
452 // Deinstall the signal handlers
454 signal(SIGHUP, SIG_DFL);
456 signal(SIGINT, SIG_DFL);
457 signal(SIGFPE, SIG_DFL);
458 signal(SIGSEGV, SIG_DFL);
459 signal(SIGTERM, SIG_DFL);
462 if (err_sig == SIGSEGV ||
463 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
465 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
467 lyx::support::abort();
474 void LyX::printError(ErrorItem const & ei)
476 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
478 std::cerr << lyx::to_utf8(tmp) << std::endl;
485 signal(SIGHUP, error_handler);
487 signal(SIGFPE, error_handler);
488 signal(SIGSEGV, error_handler);
489 signal(SIGINT, error_handler);
490 signal(SIGTERM, error_handler);
491 // SIGPIPE can be safely ignored.
493 lyxrc.tempdir_path = package().temp_dir();
494 lyxrc.document_path = package().document_dir();
496 if (lyxrc.template_path.empty()) {
497 lyxrc.template_path = addPath(package().system_support(),
501 if (lyxrc.roman_font_name.empty())
502 lyxrc.roman_font_name = lyx_gui::roman_font_name();
503 if (lyxrc.sans_font_name.empty())
504 lyxrc.sans_font_name = lyx_gui::sans_font_name();
505 if (lyxrc.typewriter_font_name.empty())
506 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
509 // Read configuration files
512 // This one may have been distributed along with LyX.
513 if (!readRcFile("lyxrc.dist"))
516 // Set the PATH correctly.
517 #if !defined (USE_POSIX_PACKAGING)
518 // Add the directory containing the LyX executable to the path
519 // so that LyX can find things like tex2lyx.
520 if (package().build_support().empty())
521 prependEnvPath("PATH", package().binary_dir());
523 if (!lyxrc.path_prefix.empty())
524 prependEnvPath("PATH", lyxrc.path_prefix);
526 // Check that user LyX directory is ok.
527 if (queryUserLyXDir(package().explicit_user_support()))
528 reconfigureUserLyXDir();
530 // no need for a splash when there is no GUI
531 if (!lyx_gui::use_gui) {
535 // This one is generated in user_support directory by lib/configure.py.
536 if (!readRcFile("lyxrc.defaults"))
539 // Query the OS to know what formats are viewed natively
540 formats.setAutoOpen();
542 system_lyxrc = lyxrc;
543 system_formats = formats;
544 system_converters = converters;
545 system_movers = movers;
546 system_lcolor = lcolor;
548 // This one is edited through the preferences dialog.
549 if (!readRcFile("preferences"))
552 if (!readEncodingsFile("encodings"))
554 if (!readLanguagesFile("languages"))
558 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
562 if (lyx_gui::use_gui) {
564 toplevel_keymap.reset(new kb_keymap);
565 defaultKeyBindings(toplevel_keymap.get());
566 toplevel_keymap->read(lyxrc.bind_file);
569 if (!readUIFile(lyxrc.ui_file))
573 if (lyxerr.debugging(Debug::LYXRC))
576 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
577 if (!lyxrc.path_prefix.empty())
578 prependEnvPath("PATH", lyxrc.path_prefix);
580 if (fs::exists(lyxrc.document_path) &&
581 fs::is_directory(lyxrc.document_path))
582 package().document_dir() = lyxrc.document_path;
584 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
585 if (package().temp_dir().empty()) {
586 Alert::error(_("Could not create temporary directory"),
587 bformat(_("Could not create a temporary directory in\n"
588 "%1$s. Make sure that this\n"
589 "path exists and is writable and try again."),
590 lyx::from_utf8(lyxrc.tempdir_path)));
591 // createLyXTmpDir() tries sufficiently hard to create a
592 // usable temp dir, so the probability to come here is
593 // close to zero. We therefore don't try to overcome this
594 // problem with e.g. asking the user for a new path and
595 // trying again but simply exit.
599 if (lyxerr.debugging(Debug::INIT)) {
600 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
603 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
604 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
609 void LyX::defaultKeyBindings(kb_keymap * kbmap)
611 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
612 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
613 kbmap->bind("Up", FuncRequest(LFUN_UP));
614 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
616 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
617 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
618 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
619 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
621 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
622 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
623 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
624 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
626 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
627 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
629 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
630 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
632 // kbmap->bindings to enable the use of the numeric keypad
634 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
636 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
637 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
647 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
648 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
649 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
650 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
651 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
652 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
653 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
654 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
655 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
656 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
657 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
661 void LyX::emergencyCleanup() const
663 // what to do about tmpfiles is non-obvious. we would
664 // like to delete any we find, but our lyxdir might
665 // contain documents etc. which might be helpful on
668 theApp->bufferList().emergencyWriteAll();
669 theApp->server().emergencyCleanup();
673 void LyX::deadKeyBindings(kb_keymap * kbmap)
675 // bindKeyings for transparent handling of deadkeys
676 // The keysyms are gotten from XFree86 X11R6
677 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
678 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
679 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
680 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
681 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
682 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
683 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
684 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
685 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
686 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
687 // nothing with this name
688 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
689 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
690 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
691 // nothing with this name either...
692 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
693 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
694 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
695 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
701 // return true if file does not exist or is older than configure.py.
702 bool needsUpdate(string const & file)
704 static string const configure_script =
705 addName(package().system_support(), "configure.py");
706 string const absfile =
707 addName(package().user_support(), file);
709 return (! fs::exists(absfile))
710 || (fs::last_write_time(configure_script)
711 > fs::last_write_time(absfile));
717 bool LyX::queryUserLyXDir(bool explicit_userdir)
719 // Does user directory exist?
720 if (fs::exists(package().user_support()) &&
721 fs::is_directory(package().user_support())) {
724 return needsUpdate("lyxrc.defaults")
725 || needsUpdate("textclass.lst")
726 || needsUpdate("packages.lst");
729 first_start = !explicit_userdir;
731 // If the user specified explicitly a directory, ask whether
732 // to create it. If the user says "no", then exit.
733 if (explicit_userdir &&
735 _("Missing user LyX directory"),
736 bformat(_("You have specified a non-existent user "
737 "LyX directory, %1$s.\n"
738 "It is needed to keep your own configuration."),
739 lyx::from_utf8(package().user_support())),
741 _("&Create directory"),
743 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
744 lyx_exit(EXIT_FAILURE);
747 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
748 lyx::from_utf8(package().user_support())))
751 if (!createDirectory(package().user_support(), 0755)) {
752 // Failed, so let's exit.
753 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
755 lyx_exit(EXIT_FAILURE);
762 bool LyX::readRcFile(string const & name)
764 lyxerr[Debug::INIT] << "About to read " << name << "... ";
766 string const lyxrc_path = libFileSearch(string(), name);
767 if (!lyxrc_path.empty()) {
769 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
771 if (lyxrc.read(lyxrc_path) < 0) {
776 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
782 // Read the ui file `name'
783 bool LyX::readUIFile(string const & name)
793 struct keyword_item uitags[ui_last - 1] = {
794 { "include", ui_include },
795 { "menuset", ui_menuset },
796 { "toolbar", ui_toolbar },
797 { "toolbars", ui_toolbars }
800 // Ensure that a file is read only once (prevents include loops)
801 static std::list<string> uifiles;
802 std::list<string>::const_iterator it = uifiles.begin();
803 std::list<string>::const_iterator end = uifiles.end();
804 it = std::find(it, end, name);
806 lyxerr[Debug::INIT] << "UI file '" << name
807 << "' has been read already. "
808 << "Is this an include loop?"
813 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
815 string const ui_path = libFileSearch("ui", name, "ui");
817 if (ui_path.empty()) {
818 lyxerr[Debug::INIT] << "Could not find " << name << endl;
822 uifiles.push_back(name);
824 lyxerr[Debug::INIT] << "Found " << name
825 << " in " << ui_path << endl;
826 LyXLex lex(uitags, ui_last - 1);
827 lex.setFile(ui_path);
829 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
833 if (lyxerr.debugging(Debug::PARSER))
834 lex.printTable(lyxerr);
840 string const file = lex.getString();
841 if (!readUIFile(file))
846 menubackend.read(lex);
850 toolbarbackend.read(lex);
854 toolbarbackend.readToolbars(lex);
858 if (!rtrim(lex.getString()).empty())
859 lex.printError("LyX::ReadUIFile: "
860 "Unknown menu tag: `$$Token'");
868 // Read the languages file `name'
869 bool LyX::readLanguagesFile(string const & name)
871 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
873 string const lang_path = libFileSearch(string(), name);
874 if (lang_path.empty()) {
878 languages.read(lang_path);
883 // Read the encodings file `name'
884 bool LyX::readEncodingsFile(string const & name)
886 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
888 string const enc_path = libFileSearch(string(), name);
889 if (enc_path.empty()) {
893 encodings.read(enc_path);
903 /// return the the number of arguments consumed
904 typedef boost::function<int(string const &, string const &)> cmd_helper;
906 int parse_dbg(string const & arg, string const &)
909 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
910 Debug::showTags(lyxerr);
913 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
915 lyxerr.level(Debug::value(arg));
916 Debug::showLevel(lyxerr, lyxerr.level());
921 int parse_help(string const &, string const &)
924 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
925 "Command line switches (case sensitive):\n"
926 "\t-help summarize LyX usage\n"
927 "\t-userdir dir set user directory to dir\n"
928 "\t-sysdir dir set system directory to dir\n"
929 "\t-geometry WxH+X+Y set geometry of the main window\n"
930 "\t-dbg feature[,feature]...\n"
931 " select the features to debug.\n"
932 " Type `lyx -dbg' to see the list of features\n"
933 "\t-x [--execute] command\n"
934 " where command is a lyx command.\n"
935 "\t-e [--export] fmt\n"
936 " where fmt is the export format of choice.\n"
937 "\t-i [--import] fmt file.xxx\n"
938 " where fmt is the import format of choice\n"
939 " and file.xxx is the file to be imported.\n"
940 "\t-version summarize version and build info\n"
941 "Check the LyX man page for more details.")) << endl;
946 int parse_version(string const &, string const &)
948 lyxerr << "LyX " << lyx_version
949 << " (" << lyx_release_date << ")" << endl;
950 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
952 lyxerr << lyx_version_info << endl;
957 int parse_sysdir(string const & arg, string const &)
960 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
963 cl_system_support = arg;
967 int parse_userdir(string const & arg, string const &)
970 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
973 cl_user_support = arg;
977 int parse_execute(string const & arg, string const &)
980 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
987 int parse_export(string const & type, string const &)
990 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
991 "--export switch")) << endl;
994 batch = "buffer-export " + type;
999 int parse_import(string const & type, string const & file)
1002 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1003 "--import switch")) << endl;
1007 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1011 batch = "buffer-import " + type + ' ' + file;
1018 bool LyX::easyParse(int & argc, char * argv[])
1020 std::map<string, cmd_helper> cmdmap;
1022 cmdmap["-dbg"] = parse_dbg;
1023 cmdmap["-help"] = parse_help;
1024 cmdmap["--help"] = parse_help;
1025 cmdmap["-version"] = parse_version;
1026 cmdmap["--version"] = parse_version;
1027 cmdmap["-sysdir"] = parse_sysdir;
1028 cmdmap["-userdir"] = parse_userdir;
1029 cmdmap["-x"] = parse_execute;
1030 cmdmap["--execute"] = parse_execute;
1031 cmdmap["-e"] = parse_export;
1032 cmdmap["--export"] = parse_export;
1033 cmdmap["-i"] = parse_import;
1034 cmdmap["--import"] = parse_import;
1036 for (int i = 1; i < argc; ++i) {
1037 std::map<string, cmd_helper>::const_iterator it
1038 = cmdmap.find(argv[i]);
1040 // check for X11 -geometry option
1041 if (lyx::support::compare(argv[i], "-geometry") == 0)
1042 geometryOption_ = true;
1044 // don't complain if not found - may be parsed later
1045 if (it == cmdmap.end())
1048 string arg((i + 1 < argc) ? argv[i + 1] : "");
1049 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1051 int const remove = 1 + it->second(arg, arg2);
1053 // Now, remove used arguments by shifting
1054 // the following ones remove places down.
1056 for (int j = i; j < argc; ++j)
1057 argv[j] = argv[j + remove];
1061 batch_command = batch;