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 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 // Execute batch commands if available
262 if (!batch_command.empty()) {
264 lyxerr[Debug::INIT] << "About to handle -x '"
265 << batch_command << '\'' << endl;
267 Buffer * last_loaded = 0;
269 vector<string>::const_iterator it = files.begin();
270 vector<string>::const_iterator end = files.end();
272 for (; it != end; ++it) {
273 // get absolute path of file and add ".lyx" to
274 // the filename if necessary
275 string s = fileSearch(string(), *it, "lyx");
277 Buffer * const b = newFile(*it, string(), true);
281 Buffer * buf = theApp->bufferList().newBuffer(s, false);
282 if (loadLyXFile(buf, s)) {
284 ErrorList const & el = buf->errorList("Parse");
286 for_each(el.begin(), el.end(),
287 boost::bind(&LyX::printError, this, _1));
290 theApp->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;
310 bool maximize = false;
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);
339 if (geometryOption_) {
343 // create the main window
344 LyXView * view = &theApp->createView(width, height, posx, posy, maximize);
345 ref().addLyXView(view);
348 for_each(files.begin(), files.end(),
349 bind(&LyXView::loadLyXFile, view, _1, true));
351 // if a file is specified, I assume that user wants to edit *that* file
352 if (files.empty() && lyxrc.load_session) {
353 vector<string> const & lastopened = session_->lastOpenedFiles();
354 // do not add to the lastfile list since these files are restored from
355 // last seesion, and should be already there (regular files), or should
356 // not be added at all (help files).
357 for_each(lastopened.begin(), lastopened.end(),
358 bind(&LyXView::loadLyXFile, view, _1, false));
360 // clear this list to save a few bytes of RAM
361 session_->clearLastOpenedFiles();
363 return theApp->start(batch_command);
365 // Something went wrong above
375 The SIGHUP signal does not exist on Windows and does not need to be handled.
377 Windows handles SIGFPE and SIGSEGV signals as expected.
379 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
380 cause a new thread to be spawned. This may well result in unexpected
381 behaviour by the single-threaded LyX.
383 SIGTERM signals will come only from another process actually sending
384 that signal using 'raise' in Windows' POSIX compatability layer. It will
385 not come from the general "terminate process" methods that everyone
386 actually uses (and which can't be trapped). Killing an app 'politely' on
387 Windows involves first sending a WM_CLOSE message, something that is
388 caught already by the Qt frontend.
390 For more information see:
392 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
393 ...signals are mostly useless on Windows for a variety of reasons that are
396 'UNIX Application Migration Guide, Chapter 9'
397 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
399 'How To Terminate an Application "Cleanly" in Win32'
400 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
404 static void error_handler(int err_sig)
406 // Throw away any signals other than the first one received.
407 static sig_atomic_t handling_error = false;
410 handling_error = true;
412 // We have received a signal indicating a fatal error, so
413 // try and save the data ASAP.
414 LyX::cref().emergencyCleanup();
416 // These lyxerr calls may or may not work:
418 // Signals are asynchronous, so the main program may be in a very
419 // fragile state when a signal is processed and thus while a signal
420 // handler function executes.
421 // In general, therefore, we should avoid performing any
422 // I/O operations or calling most library and system functions from
425 // This shouldn't matter here, however, as we've already invoked
430 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
434 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
437 lyxerr << "\nlyx: SIGSEGV signal caught\n"
438 "Sorry, you have found a bug in LyX. "
439 "Please read the bug-reporting instructions "
440 "in Help->Introduction and send us a bug report, "
441 "if necessary. Thanks !\nBye." << endl;
449 // Deinstall the signal handlers
451 signal(SIGHUP, SIG_DFL);
453 signal(SIGINT, SIG_DFL);
454 signal(SIGFPE, SIG_DFL);
455 signal(SIGSEGV, SIG_DFL);
456 signal(SIGTERM, SIG_DFL);
459 if (err_sig == SIGSEGV ||
460 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
462 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
464 lyx::support::abort();
471 void LyX::printError(ErrorItem const & ei)
473 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
475 std::cerr << lyx::to_utf8(tmp) << std::endl;
482 signal(SIGHUP, error_handler);
484 signal(SIGFPE, error_handler);
485 signal(SIGSEGV, error_handler);
486 signal(SIGINT, error_handler);
487 signal(SIGTERM, error_handler);
488 // SIGPIPE can be safely ignored.
490 lyxrc.tempdir_path = package().temp_dir();
491 lyxrc.document_path = package().document_dir();
493 if (lyxrc.template_path.empty()) {
494 lyxrc.template_path = addPath(package().system_support(),
498 if (lyxrc.roman_font_name.empty())
499 lyxrc.roman_font_name =
500 lyx_gui::use_gui? theApp->romanFontName(): "serif";
502 if (lyxrc.sans_font_name.empty())
503 lyxrc.sans_font_name =
504 lyx_gui::use_gui? theApp->sansFontName(): "sans";
506 if (lyxrc.typewriter_font_name.empty())
507 lyxrc.typewriter_font_name =
508 lyx_gui::use_gui? theApp->typewriterFontName(): "monospace";
511 // Read configuration files
514 // This one may have been distributed along with LyX.
515 if (!readRcFile("lyxrc.dist"))
518 // Set the PATH correctly.
519 #if !defined (USE_POSIX_PACKAGING)
520 // Add the directory containing the LyX executable to the path
521 // so that LyX can find things like tex2lyx.
522 if (package().build_support().empty())
523 prependEnvPath("PATH", package().binary_dir());
525 if (!lyxrc.path_prefix.empty())
526 prependEnvPath("PATH", lyxrc.path_prefix);
528 // Check that user LyX directory is ok.
529 if (queryUserLyXDir(package().explicit_user_support()))
530 reconfigureUserLyXDir();
532 // no need for a splash when there is no GUI
533 if (!lyx_gui::use_gui) {
537 // This one is generated in user_support directory by lib/configure.py.
538 if (!readRcFile("lyxrc.defaults"))
541 // Query the OS to know what formats are viewed natively
542 formats.setAutoOpen();
544 system_lyxrc = lyxrc;
545 system_formats = formats;
546 system_converters = converters;
547 system_movers = movers;
548 system_lcolor = lcolor;
550 // This one is edited through the preferences dialog.
551 if (!readRcFile("preferences"))
554 if (!readEncodingsFile("encodings"))
556 if (!readLanguagesFile("languages"))
560 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
564 if (lyx_gui::use_gui) {
566 toplevel_keymap.reset(new kb_keymap);
567 defaultKeyBindings(toplevel_keymap.get());
568 toplevel_keymap->read(lyxrc.bind_file);
571 if (!readUIFile(lyxrc.ui_file))
575 if (lyxerr.debugging(Debug::LYXRC))
578 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
579 if (!lyxrc.path_prefix.empty())
580 prependEnvPath("PATH", lyxrc.path_prefix);
582 if (fs::exists(lyxrc.document_path) &&
583 fs::is_directory(lyxrc.document_path))
584 package().document_dir() = lyxrc.document_path;
586 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
587 if (package().temp_dir().empty()) {
588 Alert::error(_("Could not create temporary directory"),
589 bformat(_("Could not create a temporary directory in\n"
590 "%1$s. Make sure that this\n"
591 "path exists and is writable and try again."),
592 lyx::from_utf8(lyxrc.tempdir_path)));
593 // createLyXTmpDir() tries sufficiently hard to create a
594 // usable temp dir, so the probability to come here is
595 // close to zero. We therefore don't try to overcome this
596 // problem with e.g. asking the user for a new path and
597 // trying again but simply exit.
601 if (lyxerr.debugging(Debug::INIT)) {
602 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
605 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
606 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
611 void LyX::defaultKeyBindings(kb_keymap * kbmap)
613 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
614 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
615 kbmap->bind("Up", FuncRequest(LFUN_UP));
616 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
618 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
619 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
620 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
621 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
623 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
624 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
625 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
626 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
628 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
629 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
631 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
632 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
634 // kbmap->bindings to enable the use of the numeric keypad
636 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
638 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
639 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
647 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
648 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
649 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
650 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
651 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
652 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
653 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
654 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
655 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
656 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
657 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
658 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
659 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
663 void LyX::emergencyCleanup() const
665 // what to do about tmpfiles is non-obvious. we would
666 // like to delete any we find, but our lyxdir might
667 // contain documents etc. which might be helpful on
670 theApp->bufferList().emergencyWriteAll();
671 theApp->server().emergencyCleanup();
675 void LyX::deadKeyBindings(kb_keymap * kbmap)
677 // bindKeyings for transparent handling of deadkeys
678 // The keysyms are gotten from XFree86 X11R6
679 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
680 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
681 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
682 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
683 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
684 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
685 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
686 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
687 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
688 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
689 // nothing with this name
690 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
691 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
692 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
693 // nothing with this name either...
694 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
695 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
696 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
697 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
703 // return true if file does not exist or is older than configure.py.
704 bool needsUpdate(string const & file)
706 static string const configure_script =
707 addName(package().system_support(), "configure.py");
708 string const absfile =
709 addName(package().user_support(), file);
711 return (! fs::exists(absfile))
712 || (fs::last_write_time(configure_script)
713 > fs::last_write_time(absfile));
719 bool LyX::queryUserLyXDir(bool explicit_userdir)
721 // Does user directory exist?
722 if (fs::exists(package().user_support()) &&
723 fs::is_directory(package().user_support())) {
726 return needsUpdate("lyxrc.defaults")
727 || needsUpdate("textclass.lst")
728 || needsUpdate("packages.lst");
731 first_start = !explicit_userdir;
733 // If the user specified explicitly a directory, ask whether
734 // to create it. If the user says "no", then exit.
735 if (explicit_userdir &&
737 _("Missing user LyX directory"),
738 bformat(_("You have specified a non-existent user "
739 "LyX directory, %1$s.\n"
740 "It is needed to keep your own configuration."),
741 lyx::from_utf8(package().user_support())),
743 _("&Create directory"),
745 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
746 lyx_exit(EXIT_FAILURE);
749 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
750 lyx::from_utf8(package().user_support())))
753 if (!createDirectory(package().user_support(), 0755)) {
754 // Failed, so let's exit.
755 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
757 lyx_exit(EXIT_FAILURE);
764 bool LyX::readRcFile(string const & name)
766 lyxerr[Debug::INIT] << "About to read " << name << "... ";
768 string const lyxrc_path = libFileSearch(string(), name);
769 if (!lyxrc_path.empty()) {
771 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
773 if (lyxrc.read(lyxrc_path) < 0) {
778 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
784 // Read the ui file `name'
785 bool LyX::readUIFile(string const & name)
795 struct keyword_item uitags[ui_last - 1] = {
796 { "include", ui_include },
797 { "menuset", ui_menuset },
798 { "toolbar", ui_toolbar },
799 { "toolbars", ui_toolbars }
802 // Ensure that a file is read only once (prevents include loops)
803 static std::list<string> uifiles;
804 std::list<string>::const_iterator it = uifiles.begin();
805 std::list<string>::const_iterator end = uifiles.end();
806 it = std::find(it, end, name);
808 lyxerr[Debug::INIT] << "UI file '" << name
809 << "' has been read already. "
810 << "Is this an include loop?"
815 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
817 string const ui_path = libFileSearch("ui", name, "ui");
819 if (ui_path.empty()) {
820 lyxerr[Debug::INIT] << "Could not find " << name << endl;
824 uifiles.push_back(name);
826 lyxerr[Debug::INIT] << "Found " << name
827 << " in " << ui_path << endl;
828 LyXLex lex(uitags, ui_last - 1);
829 lex.setFile(ui_path);
831 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
835 if (lyxerr.debugging(Debug::PARSER))
836 lex.printTable(lyxerr);
842 string const file = lex.getString();
843 if (!readUIFile(file))
848 menubackend.read(lex);
852 toolbarbackend.read(lex);
856 toolbarbackend.readToolbars(lex);
860 if (!rtrim(lex.getString()).empty())
861 lex.printError("LyX::ReadUIFile: "
862 "Unknown menu tag: `$$Token'");
870 // Read the languages file `name'
871 bool LyX::readLanguagesFile(string const & name)
873 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
875 string const lang_path = libFileSearch(string(), name);
876 if (lang_path.empty()) {
880 languages.read(lang_path);
885 // Read the encodings file `name'
886 bool LyX::readEncodingsFile(string const & name)
888 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
890 string const enc_path = libFileSearch(string(), name);
891 if (enc_path.empty()) {
895 encodings.read(enc_path);
905 /// return the the number of arguments consumed
906 typedef boost::function<int(string const &, string const &)> cmd_helper;
908 int parse_dbg(string const & arg, string const &)
911 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
912 Debug::showTags(lyxerr);
915 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
917 lyxerr.level(Debug::value(arg));
918 Debug::showLevel(lyxerr, lyxerr.level());
923 int parse_help(string const &, string const &)
926 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
927 "Command line switches (case sensitive):\n"
928 "\t-help summarize LyX usage\n"
929 "\t-userdir dir set user directory to dir\n"
930 "\t-sysdir dir set system directory to dir\n"
931 "\t-geometry WxH+X+Y set geometry of the main window\n"
932 "\t-dbg feature[,feature]...\n"
933 " select the features to debug.\n"
934 " Type `lyx -dbg' to see the list of features\n"
935 "\t-x [--execute] command\n"
936 " where command is a lyx command.\n"
937 "\t-e [--export] fmt\n"
938 " where fmt is the export format of choice.\n"
939 "\t-i [--import] fmt file.xxx\n"
940 " where fmt is the import format of choice\n"
941 " and file.xxx is the file to be imported.\n"
942 "\t-version summarize version and build info\n"
943 "Check the LyX man page for more details.")) << endl;
948 int parse_version(string const &, string const &)
950 lyxerr << "LyX " << lyx_version
951 << " (" << lyx_release_date << ")" << endl;
952 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
954 lyxerr << lyx_version_info << endl;
959 int parse_sysdir(string const & arg, string const &)
962 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
965 cl_system_support = arg;
969 int parse_userdir(string const & arg, string const &)
972 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
975 cl_user_support = arg;
979 int parse_execute(string const & arg, string const &)
982 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
989 int parse_export(string const & type, string const &)
992 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
993 "--export switch")) << endl;
996 batch = "buffer-export " + type;
1001 int parse_import(string const & type, string const & file)
1004 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1005 "--import switch")) << endl;
1009 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1013 batch = "buffer-import " + type + ' ' + file;
1020 bool LyX::easyParse(int & argc, char * argv[])
1022 std::map<string, cmd_helper> cmdmap;
1024 cmdmap["-dbg"] = parse_dbg;
1025 cmdmap["-help"] = parse_help;
1026 cmdmap["--help"] = parse_help;
1027 cmdmap["-version"] = parse_version;
1028 cmdmap["--version"] = parse_version;
1029 cmdmap["-sysdir"] = parse_sysdir;
1030 cmdmap["-userdir"] = parse_userdir;
1031 cmdmap["-x"] = parse_execute;
1032 cmdmap["--execute"] = parse_execute;
1033 cmdmap["-e"] = parse_export;
1034 cmdmap["--export"] = parse_export;
1035 cmdmap["-i"] = parse_import;
1036 cmdmap["--import"] = parse_import;
1038 for (int i = 1; i < argc; ++i) {
1039 std::map<string, cmd_helper>::const_iterator it
1040 = cmdmap.find(argv[i]);
1042 // check for X11 -geometry option
1043 if (lyx::support::compare(argv[i], "-geometry") == 0)
1044 geometryOption_ = true;
1046 // don't complain if not found - may be parsed later
1047 if (it == cmdmap.end())
1050 string arg((i + 1 < argc) ? argv[i + 1] : "");
1051 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1053 int const remove = 1 + it->second(arg, arg2);
1055 // Now, remove used arguments by shifting
1056 // the following ones remove places down.
1058 for (int j = i; j < argc; ++j)
1059 argv[j] = argv[j + remove];
1063 batch_command = batch;