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 Alert = lyx::frontend::Alert;
81 namespace os = lyx::support::os;
82 namespace fs = boost::filesystem;
89 #ifndef CXX_GLOBAL_CSTD
96 // convenient to have it here.
97 boost::scoped_ptr<kb_keymap> toplevel_keymap;
101 // Filled with the command line arguments "foo" of "-sysdir foo" or
103 string cl_system_support;
104 string cl_user_support;
107 void lyx_exit(int status)
109 // FIXME: We should not directly call exit(), since it only
110 // guarantees a return to the system, no application cleanup.
111 // This may cause troubles with not executed destructors.
112 if (lyx_gui::use_gui) {
113 theApp->exit(status);
114 // Restore original font resources after Application is destroyed.
115 lyx::support::restoreFontResources();
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."), lyx::from_utf8(error)));
130 void reconfigureUserLyXDir()
132 string const configure_command = package().configure_command();
134 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
135 lyx::support::Path p(package().user_support());
137 one.startscript(Systemcall::Wait, configure_command);
138 lyxerr << "LyX: " << lyx::to_utf8(_("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 // Force adding of font path _before_ Application is initialized
226 lyx::support::addFontResources();
227 return lyx_gui::exec(argc, argv);
230 return exec2(argc, argv);
234 int LyX::exec2(int & argc, char * argv[])
236 // check for any spurious extra arguments
237 // other than documents
238 for (int argi = 1; argi < argc ; ++argi) {
239 if (argv[argi][0] == '-') {
240 lyxerr << lyx::to_utf8(
241 bformat(_("Wrong command line option `%1$s'. Exiting."),
242 lyx::from_utf8(argv[argi]))) << endl;
247 // Initialization of LyX (reads lyxrc and more)
248 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
249 bool const success = init();
250 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
254 vector<string> files;
256 for (int argi = argc - 1; argi >= 1; --argi)
257 files.push_back(os::internal_path(argv[argi]));
260 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
262 // Execute batch commands if available
263 if (!batch_command.empty()) {
265 lyxerr[Debug::INIT] << "About to handle -x '"
266 << batch_command << '\'' << endl;
268 Buffer * last_loaded = 0;
270 vector<string>::const_iterator it = files.begin();
271 vector<string>::const_iterator end = files.end();
273 for (; it != end; ++it) {
274 // get absolute path of file and add ".lyx" to
275 // the filename if necessary
276 string s = fileSearch(string(), *it, "lyx");
278 Buffer * const b = newFile(*it, string(), true);
282 Buffer * buf = theApp->bufferList().newBuffer(s, false);
283 if (loadLyXFile(buf, s)) {
285 ErrorList const & el = buf->errorList("Parse");
287 for_each(el.begin(), el.end(),
288 boost::bind(&LyX::printError, this, _1));
291 theApp->bufferList().release(buf);
295 // try to dispatch to last loaded buffer first
297 bool success = false;
298 if (last_loaded->dispatch(batch_command, &success)) {
303 files.clear(); // the files are already loaded
306 if (lyx_gui::use_gui) {
307 // determine windows size and position, from lyxrc and/or session
309 unsigned int width = 690;
310 unsigned int height = 510;
311 bool maximize = false;
313 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
314 width = lyxrc.geometry_width;
315 height = lyxrc.geometry_height;
317 // if lyxrc returns (0,0), then use session info
319 string val = session().loadSessionInfo("WindowWidth");
321 width = convert<unsigned int>(val);
322 val = session().loadSessionInfo("WindowHeight");
324 height = convert<unsigned int>(val);
325 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
328 // if user wants to restore window position
331 if (lyxrc.geometry_xysaved) {
332 string val = session().loadSessionInfo("WindowPosX");
334 posx = convert<int>(val);
335 val = session().loadSessionInfo("WindowPosY");
337 posy = convert<int>(val);
340 if (geometryOption_) {
344 // create the main window
345 LyXView * view = &theApp->createView(width, height, posx, posy, maximize);
346 ref().addLyXView(view);
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 theApp->start(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 =
501 lyx_gui::use_gui? theApp->romanFontName(): "serif";
503 if (lyxrc.sans_font_name.empty())
504 lyxrc.sans_font_name =
505 lyx_gui::use_gui? theApp->sansFontName(): "sans";
507 if (lyxrc.typewriter_font_name.empty())
508 lyxrc.typewriter_font_name =
509 lyx_gui::use_gui? theApp->typewriterFontName(): "monospace";
512 // Read configuration files
515 // This one may have been distributed along with LyX.
516 if (!readRcFile("lyxrc.dist"))
519 // Set the PATH correctly.
520 #if !defined (USE_POSIX_PACKAGING)
521 // Add the directory containing the LyX executable to the path
522 // so that LyX can find things like tex2lyx.
523 if (package().build_support().empty())
524 prependEnvPath("PATH", package().binary_dir());
526 if (!lyxrc.path_prefix.empty())
527 prependEnvPath("PATH", lyxrc.path_prefix);
529 // Check that user LyX directory is ok.
530 if (queryUserLyXDir(package().explicit_user_support()))
531 reconfigureUserLyXDir();
533 // no need for a splash when there is no GUI
534 if (!lyx_gui::use_gui) {
538 // This one is generated in user_support directory by lib/configure.py.
539 if (!readRcFile("lyxrc.defaults"))
542 // Query the OS to know what formats are viewed natively
543 formats.setAutoOpen();
545 system_lyxrc = lyxrc;
546 system_formats = formats;
547 system_converters = converters;
548 system_movers = movers;
549 system_lcolor = lcolor;
551 // This one is edited through the preferences dialog.
552 if (!readRcFile("preferences"))
555 if (!readEncodingsFile("encodings"))
557 if (!readLanguagesFile("languages"))
561 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
565 if (lyx_gui::use_gui) {
567 toplevel_keymap.reset(new kb_keymap);
568 defaultKeyBindings(toplevel_keymap.get());
569 toplevel_keymap->read(lyxrc.bind_file);
572 if (!readUIFile(lyxrc.ui_file))
576 if (lyxerr.debugging(Debug::LYXRC))
579 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
580 if (!lyxrc.path_prefix.empty())
581 prependEnvPath("PATH", lyxrc.path_prefix);
583 if (fs::exists(lyxrc.document_path) &&
584 fs::is_directory(lyxrc.document_path))
585 package().document_dir() = lyxrc.document_path;
587 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
588 if (package().temp_dir().empty()) {
589 Alert::error(_("Could not create temporary directory"),
590 bformat(_("Could not create a temporary directory in\n"
591 "%1$s. Make sure that this\n"
592 "path exists and is writable and try again."),
593 lyx::from_utf8(lyxrc.tempdir_path)));
594 // createLyXTmpDir() tries sufficiently hard to create a
595 // usable temp dir, so the probability to come here is
596 // close to zero. We therefore don't try to overcome this
597 // problem with e.g. asking the user for a new path and
598 // trying again but simply exit.
602 if (lyxerr.debugging(Debug::INIT)) {
603 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
606 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
607 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
612 void LyX::defaultKeyBindings(kb_keymap * kbmap)
614 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
615 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
616 kbmap->bind("Up", FuncRequest(LFUN_UP));
617 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
619 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
620 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
621 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
622 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
624 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
625 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
626 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
627 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
629 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
630 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
632 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
633 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
635 // kbmap->bindings to enable the use of the numeric keypad
637 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
639 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
640 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
647 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
648 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
649 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
650 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
651 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
652 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
653 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
654 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
655 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
656 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
657 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
658 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
659 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
660 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
664 void LyX::emergencyCleanup() const
666 // what to do about tmpfiles is non-obvious. we would
667 // like to delete any we find, but our lyxdir might
668 // contain documents etc. which might be helpful on
671 theApp->bufferList().emergencyWriteAll();
672 theApp->server().emergencyCleanup();
676 void LyX::deadKeyBindings(kb_keymap * kbmap)
678 // bindKeyings for transparent handling of deadkeys
679 // The keysyms are gotten from XFree86 X11R6
680 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
681 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
682 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
683 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
684 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
685 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
686 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
687 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
688 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
689 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
690 // nothing with this name
691 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
692 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
693 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
694 // nothing with this name either...
695 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
696 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
697 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
698 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
704 // return true if file does not exist or is older than configure.py.
705 bool needsUpdate(string const & file)
707 static string const configure_script =
708 addName(package().system_support(), "configure.py");
709 string const absfile =
710 addName(package().user_support(), file);
712 return (! fs::exists(absfile))
713 || (fs::last_write_time(configure_script)
714 > fs::last_write_time(absfile));
720 bool LyX::queryUserLyXDir(bool explicit_userdir)
722 // Does user directory exist?
723 if (fs::exists(package().user_support()) &&
724 fs::is_directory(package().user_support())) {
727 return needsUpdate("lyxrc.defaults")
728 || needsUpdate("textclass.lst")
729 || needsUpdate("packages.lst");
732 first_start = !explicit_userdir;
734 // If the user specified explicitly a directory, ask whether
735 // to create it. If the user says "no", then exit.
736 if (explicit_userdir &&
738 _("Missing user LyX directory"),
739 bformat(_("You have specified a non-existent user "
740 "LyX directory, %1$s.\n"
741 "It is needed to keep your own configuration."),
742 lyx::from_utf8(package().user_support())),
744 _("&Create directory"),
746 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
747 lyx_exit(EXIT_FAILURE);
750 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
751 lyx::from_utf8(package().user_support())))
754 if (!createDirectory(package().user_support(), 0755)) {
755 // Failed, so let's exit.
756 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
758 lyx_exit(EXIT_FAILURE);
765 bool LyX::readRcFile(string const & name)
767 lyxerr[Debug::INIT] << "About to read " << name << "... ";
769 string const lyxrc_path = libFileSearch(string(), name);
770 if (!lyxrc_path.empty()) {
772 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
774 if (lyxrc.read(lyxrc_path) < 0) {
779 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
785 // Read the ui file `name'
786 bool LyX::readUIFile(string const & name)
796 struct keyword_item uitags[ui_last - 1] = {
797 { "include", ui_include },
798 { "menuset", ui_menuset },
799 { "toolbar", ui_toolbar },
800 { "toolbars", ui_toolbars }
803 // Ensure that a file is read only once (prevents include loops)
804 static std::list<string> uifiles;
805 std::list<string>::const_iterator it = uifiles.begin();
806 std::list<string>::const_iterator end = uifiles.end();
807 it = std::find(it, end, name);
809 lyxerr[Debug::INIT] << "UI file '" << name
810 << "' has been read already. "
811 << "Is this an include loop?"
816 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
818 string const ui_path = libFileSearch("ui", name, "ui");
820 if (ui_path.empty()) {
821 lyxerr[Debug::INIT] << "Could not find " << name << endl;
825 uifiles.push_back(name);
827 lyxerr[Debug::INIT] << "Found " << name
828 << " in " << ui_path << endl;
829 LyXLex lex(uitags, ui_last - 1);
830 lex.setFile(ui_path);
832 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
836 if (lyxerr.debugging(Debug::PARSER))
837 lex.printTable(lyxerr);
843 string const file = lex.getString();
844 if (!readUIFile(file))
849 menubackend.read(lex);
853 toolbarbackend.read(lex);
857 toolbarbackend.readToolbars(lex);
861 if (!rtrim(lex.getString()).empty())
862 lex.printError("LyX::ReadUIFile: "
863 "Unknown menu tag: `$$Token'");
871 // Read the languages file `name'
872 bool LyX::readLanguagesFile(string const & name)
874 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
876 string const lang_path = libFileSearch(string(), name);
877 if (lang_path.empty()) {
881 languages.read(lang_path);
886 // Read the encodings file `name'
887 bool LyX::readEncodingsFile(string const & name)
889 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
891 string const enc_path = libFileSearch(string(), name);
892 if (enc_path.empty()) {
896 encodings.read(enc_path);
906 /// return the the number of arguments consumed
907 typedef boost::function<int(string const &, string const &)> cmd_helper;
909 int parse_dbg(string const & arg, string const &)
912 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
913 Debug::showTags(lyxerr);
916 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
918 lyxerr.level(Debug::value(arg));
919 Debug::showLevel(lyxerr, lyxerr.level());
924 int parse_help(string const &, string const &)
927 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
928 "Command line switches (case sensitive):\n"
929 "\t-help summarize LyX usage\n"
930 "\t-userdir dir set user directory to dir\n"
931 "\t-sysdir dir set system directory to dir\n"
932 "\t-geometry WxH+X+Y set geometry of the main window\n"
933 "\t-dbg feature[,feature]...\n"
934 " select the features to debug.\n"
935 " Type `lyx -dbg' to see the list of features\n"
936 "\t-x [--execute] command\n"
937 " where command is a lyx command.\n"
938 "\t-e [--export] fmt\n"
939 " where fmt is the export format of choice.\n"
940 "\t-i [--import] fmt file.xxx\n"
941 " where fmt is the import format of choice\n"
942 " and file.xxx is the file to be imported.\n"
943 "\t-version summarize version and build info\n"
944 "Check the LyX man page for more details.")) << endl;
949 int parse_version(string const &, string const &)
951 lyxerr << "LyX " << lyx_version
952 << " (" << lyx_release_date << ")" << endl;
953 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
955 lyxerr << lyx_version_info << endl;
960 int parse_sysdir(string const & arg, string const &)
963 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
966 cl_system_support = arg;
970 int parse_userdir(string const & arg, string const &)
973 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
976 cl_user_support = arg;
980 int parse_execute(string const & arg, string const &)
983 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
990 int parse_export(string const & type, string const &)
993 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
994 "--export switch")) << endl;
997 batch = "buffer-export " + type;
1002 int parse_import(string const & type, string const & file)
1005 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1006 "--import switch")) << endl;
1010 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1014 batch = "buffer-import " + type + ' ' + file;
1021 bool LyX::easyParse(int & argc, char * argv[])
1023 std::map<string, cmd_helper> cmdmap;
1025 cmdmap["-dbg"] = parse_dbg;
1026 cmdmap["-help"] = parse_help;
1027 cmdmap["--help"] = parse_help;
1028 cmdmap["-version"] = parse_version;
1029 cmdmap["--version"] = parse_version;
1030 cmdmap["-sysdir"] = parse_sysdir;
1031 cmdmap["-userdir"] = parse_userdir;
1032 cmdmap["-x"] = parse_execute;
1033 cmdmap["--execute"] = parse_execute;
1034 cmdmap["-e"] = parse_export;
1035 cmdmap["--export"] = parse_export;
1036 cmdmap["-i"] = parse_import;
1037 cmdmap["--import"] = parse_import;
1039 for (int i = 1; i < argc; ++i) {
1040 std::map<string, cmd_helper>::const_iterator it
1041 = cmdmap.find(argv[i]);
1043 // check for X11 -geometry option
1044 if (lyx::support::compare(argv[i], "-geometry") == 0)
1045 geometryOption_ = true;
1047 // don't complain if not found - may be parsed later
1048 if (it == cmdmap.end())
1051 string arg((i + 1 < argc) ? argv[i + 1] : "");
1052 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1054 int const remove = 1 + it->second(arg, arg2);
1056 // Now, remove used arguments by shifting
1057 // the following ones remove places down.
1059 for (int j = i; j < argc; ++j)
1060 argv[j] = argv[j + remove];
1064 batch_command = batch;