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/lyxlib.h"
51 #include "support/convert.h"
52 #include "support/os.h"
53 #include "support/package.h"
54 #include "support/path.h"
55 #include "support/systemcall.h"
57 #include <boost/bind.hpp>
58 #include <boost/filesystem/operations.hpp>
63 using lyx::support::addName;
64 using lyx::support::addPath;
65 using lyx::support::bformat;
66 using lyx::support::createDirectory;
67 using lyx::support::createLyXTmpDir;
68 using lyx::support::fileSearch;
69 using lyx::support::getEnv;
70 using lyx::support::i18nLibFileSearch;
71 using lyx::support::libFileSearch;
72 using lyx::support::package;
73 using lyx::support::prependEnvPath;
74 using lyx::support::rtrim;
75 using lyx::support::Systemcall;
79 namespace os = lyx::support::os;
80 namespace fs = boost::filesystem;
87 #ifndef CXX_GLOBAL_CSTD
94 // convenient to have it here.
95 boost::scoped_ptr<kb_keymap> toplevel_keymap;
99 // Filled with the command line arguments "foo" of "-sysdir foo" or
101 string cl_system_support;
102 string cl_user_support;
105 void lyx_exit(int status)
107 // FIXME: We should not directly call exit(), since it only
108 // guarantees a return to the system, no application cleanup.
109 // This may cause troubles with not executed destructors.
110 if (lyx_gui::use_gui)
111 // lyx_gui::exit may return and only schedule the exit
112 lyx_gui::exit(status);
117 void showFileError(string const & error)
119 Alert::warning(_("Could not read configuration file"),
120 bformat(_("Error while reading the configuration file\n%1$s.\n"
121 "Please check your installation."), lyx::from_utf8(error)));
125 void reconfigureUserLyXDir()
127 string const configure_command = package().configure_command();
129 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
130 lyx::support::Path p(package().user_support());
132 one.startscript(Systemcall::Wait, configure_command);
133 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
139 boost::scoped_ptr<LyX> LyX::singleton_;
141 int LyX::exec(int & argc, char * argv[])
143 BOOST_ASSERT(!singleton_.get());
144 // We must return from this before launching the gui so that
145 // other parts of the code can access singleton_ through
146 // LyX::ref and LyX::cref.
147 singleton_.reset(new LyX);
148 // Start the real execution loop.
149 return singleton_->priv_exec(argc, argv);
155 BOOST_ASSERT(singleton_.get());
156 return *singleton_.get();
160 LyX const & LyX::cref()
162 BOOST_ASSERT(singleton_.get());
163 return *singleton_.get();
168 : first_start(false), geometryOption_(false)
172 lyx::Session & LyX::session()
174 BOOST_ASSERT(session_.get());
175 return *session_.get();
179 lyx::Session const & LyX::session() const
181 BOOST_ASSERT(session_.get());
182 return *session_.get();
186 void LyX::addLyXView(LyXView * lyxview)
188 views_.push_back(lyxview);
192 Buffer const * const LyX::updateInset(InsetBase const * inset) const
197 Buffer const * buffer_ptr = 0;
198 ViewList::const_iterator it = views_.begin();
199 ViewList::const_iterator const end = views_.end();
200 for (; it != end; ++it) {
201 Buffer const * ptr = (*it)->updateInset(inset);
209 int LyX::priv_exec(int & argc, char * argv[])
211 // Here we need to parse the command line. At least
212 // we need to parse for "-dbg" and "-help"
213 lyx_gui::use_gui = easyParse(argc, argv);
215 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
216 lyx::support::top_build_dir_is_one_level_up);
218 // Start the real execution loop.
219 if (lyx_gui::use_gui)
220 return lyx_gui::exec(argc, argv);
222 return exec2(argc, argv);
226 int LyX::exec2(int & argc, char * argv[])
228 // check for any spurious extra arguments
229 // other than documents
230 for (int argi = 1; argi < argc ; ++argi) {
231 if (argv[argi][0] == '-') {
232 lyxerr << lyx::to_utf8(
233 bformat(_("Wrong command line option `%1$s'. Exiting."),
234 lyx::from_utf8(argv[argi]))) << endl;
239 // Initialization of LyX (reads lyxrc and more)
240 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
241 bool const success = init();
242 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
246 if (lyx_gui::use_gui)
247 lyx_gui::parse_lyxrc();
249 vector<string> files;
251 for (int argi = argc - 1; argi >= 1; --argi)
252 files.push_back(os::internal_path(argv[argi]));
255 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
257 // Execute batch commands if available
258 if (!batch_command.empty()) {
260 lyxerr[Debug::INIT] << "About to handle -x '"
261 << batch_command << '\'' << endl;
263 Buffer * last_loaded = 0;
265 vector<string>::const_iterator it = files.begin();
266 vector<string>::const_iterator end = files.end();
268 for (; it != end; ++it) {
269 // get absolute path of file and add ".lyx" to
270 // the filename if necessary
271 string s = fileSearch(string(), *it, "lyx");
273 Buffer * const b = newFile(*it, string(), true);
277 Buffer * buf = theApp->bufferList().newBuffer(s, false);
278 if (loadLyXFile(buf, s)) {
280 ErrorList const & el = buf->errorList("Parse");
282 for_each(el.begin(), el.end(),
283 boost::bind(&LyX::printError, this, _1));
286 theApp->bufferList().release(buf);
290 // try to dispatch to last loaded buffer first
292 bool success = false;
293 if (last_loaded->dispatch(batch_command, &success)) {
298 files.clear(); // the files are already loaded
301 if (lyx_gui::use_gui) {
302 // determine windows size and position, from lyxrc and/or session
304 unsigned int width = 690;
305 unsigned int height = 510;
306 bool maximize = false;
308 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
309 width = lyxrc.geometry_width;
310 height = lyxrc.geometry_height;
312 // if lyxrc returns (0,0), then use session info
314 string val = session().loadSessionInfo("WindowWidth");
316 width = convert<unsigned int>(val);
317 val = session().loadSessionInfo("WindowHeight");
319 height = convert<unsigned int>(val);
320 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
323 // if user wants to restore window position
326 if (lyxrc.geometry_xysaved) {
327 string val = session().loadSessionInfo("WindowPosX");
329 posx = convert<int>(val);
330 val = session().loadSessionInfo("WindowPosY");
332 posy = convert<int>(val);
335 if (geometryOption_) {
339 // create the main window
340 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
343 for_each(files.begin(), files.end(),
344 bind(&LyXView::loadLyXFile, view, _1, true));
346 // if a file is specified, I assume that user wants to edit *that* file
347 if (files.empty() && lyxrc.load_session) {
348 vector<string> const & lastopened = session_->lastOpenedFiles();
349 // do not add to the lastfile list since these files are restored from
350 // last seesion, and should be already there (regular files), or should
351 // not be added at all (help files).
352 for_each(lastopened.begin(), lastopened.end(),
353 bind(&LyXView::loadLyXFile, view, _1, false));
355 // clear this list to save a few bytes of RAM
356 session_->clearLastOpenedFiles();
358 return lyx_gui::start(view, batch_command);
360 // Something went wrong above
370 The SIGHUP signal does not exist on Windows and does not need to be handled.
372 Windows handles SIGFPE and SIGSEGV signals as expected.
374 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
375 cause a new thread to be spawned. This may well result in unexpected
376 behaviour by the single-threaded LyX.
378 SIGTERM signals will come only from another process actually sending
379 that signal using 'raise' in Windows' POSIX compatability layer. It will
380 not come from the general "terminate process" methods that everyone
381 actually uses (and which can't be trapped). Killing an app 'politely' on
382 Windows involves first sending a WM_CLOSE message, something that is
383 caught already by the Qt frontend.
385 For more information see:
387 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
388 ...signals are mostly useless on Windows for a variety of reasons that are
391 'UNIX Application Migration Guide, Chapter 9'
392 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
394 'How To Terminate an Application "Cleanly" in Win32'
395 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
399 static void error_handler(int err_sig)
401 // Throw away any signals other than the first one received.
402 static sig_atomic_t handling_error = false;
405 handling_error = true;
407 // We have received a signal indicating a fatal error, so
408 // try and save the data ASAP.
409 LyX::cref().emergencyCleanup();
411 // These lyxerr calls may or may not work:
413 // Signals are asynchronous, so the main program may be in a very
414 // fragile state when a signal is processed and thus while a signal
415 // handler function executes.
416 // In general, therefore, we should avoid performing any
417 // I/O operations or calling most library and system functions from
420 // This shouldn't matter here, however, as we've already invoked
425 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
429 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
432 lyxerr << "\nlyx: SIGSEGV signal caught\n"
433 "Sorry, you have found a bug in LyX. "
434 "Please read the bug-reporting instructions "
435 "in Help->Introduction and send us a bug report, "
436 "if necessary. Thanks !\nBye." << endl;
444 // Deinstall the signal handlers
446 signal(SIGHUP, SIG_DFL);
448 signal(SIGINT, SIG_DFL);
449 signal(SIGFPE, SIG_DFL);
450 signal(SIGSEGV, SIG_DFL);
451 signal(SIGTERM, SIG_DFL);
454 if (err_sig == SIGSEGV ||
455 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
457 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
459 lyx::support::abort();
466 void LyX::printError(ErrorItem const & ei)
468 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
470 std::cerr << lyx::to_utf8(tmp) << std::endl;
477 signal(SIGHUP, error_handler);
479 signal(SIGFPE, error_handler);
480 signal(SIGSEGV, error_handler);
481 signal(SIGINT, error_handler);
482 signal(SIGTERM, error_handler);
483 // SIGPIPE can be safely ignored.
485 lyxrc.tempdir_path = package().temp_dir();
486 lyxrc.document_path = package().document_dir();
488 if (lyxrc.template_path.empty()) {
489 lyxrc.template_path = addPath(package().system_support(),
493 if (lyxrc.roman_font_name.empty())
494 lyxrc.roman_font_name = lyx_gui::roman_font_name();
495 if (lyxrc.sans_font_name.empty())
496 lyxrc.sans_font_name = lyx_gui::sans_font_name();
497 if (lyxrc.typewriter_font_name.empty())
498 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
501 // Read configuration files
504 // This one may have been distributed along with LyX.
505 if (!readRcFile("lyxrc.dist"))
508 // Set the PATH correctly.
509 #if !defined (USE_POSIX_PACKAGING)
510 // Add the directory containing the LyX executable to the path
511 // so that LyX can find things like tex2lyx.
512 if (package().build_support().empty())
513 prependEnvPath("PATH", package().binary_dir());
515 if (!lyxrc.path_prefix.empty())
516 prependEnvPath("PATH", lyxrc.path_prefix);
518 // Check that user LyX directory is ok.
519 if (queryUserLyXDir(package().explicit_user_support()))
520 reconfigureUserLyXDir();
522 // no need for a splash when there is no GUI
523 if (!lyx_gui::use_gui) {
527 // This one is generated in user_support directory by lib/configure.py.
528 if (!readRcFile("lyxrc.defaults"))
531 // Query the OS to know what formats are viewed natively
532 formats.setAutoOpen();
534 system_lyxrc = lyxrc;
535 system_formats = formats;
536 system_converters = converters;
537 system_movers = movers;
538 system_lcolor = lcolor;
540 // This one is edited through the preferences dialog.
541 if (!readRcFile("preferences"))
544 if (!readEncodingsFile("encodings"))
546 if (!readLanguagesFile("languages"))
550 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
554 if (lyx_gui::use_gui) {
556 toplevel_keymap.reset(new kb_keymap);
557 defaultKeyBindings(toplevel_keymap.get());
558 toplevel_keymap->read(lyxrc.bind_file);
561 if (!readUIFile(lyxrc.ui_file))
565 if (lyxerr.debugging(Debug::LYXRC))
568 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
569 if (!lyxrc.path_prefix.empty())
570 prependEnvPath("PATH", lyxrc.path_prefix);
572 if (fs::exists(lyxrc.document_path) &&
573 fs::is_directory(lyxrc.document_path))
574 package().document_dir() = lyxrc.document_path;
576 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
577 if (package().temp_dir().empty()) {
578 Alert::error(_("Could not create temporary directory"),
579 bformat(_("Could not create a temporary directory in\n"
580 "%1$s. Make sure that this\n"
581 "path exists and is writable and try again."),
582 lyx::from_utf8(lyxrc.tempdir_path)));
583 // createLyXTmpDir() tries sufficiently hard to create a
584 // usable temp dir, so the probability to come here is
585 // close to zero. We therefore don't try to overcome this
586 // problem with e.g. asking the user for a new path and
587 // trying again but simply exit.
591 if (lyxerr.debugging(Debug::INIT)) {
592 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
595 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
596 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
601 void LyX::defaultKeyBindings(kb_keymap * kbmap)
603 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
604 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
605 kbmap->bind("Up", FuncRequest(LFUN_UP));
606 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
608 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
609 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
610 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
611 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
613 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
614 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
615 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
616 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
618 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
619 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
621 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
622 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
624 // kbmap->bindings to enable the use of the numeric keypad
626 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
627 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
628 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
629 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
630 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
631 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
632 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
642 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
643 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
644 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
645 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
646 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
647 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
648 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
649 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
653 void LyX::emergencyCleanup() const
655 // what to do about tmpfiles is non-obvious. we would
656 // like to delete any we find, but our lyxdir might
657 // contain documents etc. which might be helpful on
660 theApp->bufferList().emergencyWriteAll();
661 theApp->server().emergencyCleanup();
665 void LyX::deadKeyBindings(kb_keymap * kbmap)
667 // bindKeyings for transparent handling of deadkeys
668 // The keysyms are gotten from XFree86 X11R6
669 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
670 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
671 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
672 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
673 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
674 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
675 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
676 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
677 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
678 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
679 // nothing with this name
680 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
681 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
682 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
683 // nothing with this name either...
684 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
685 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
686 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
687 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
693 // return true if file does not exist or is older than configure.py.
694 bool needsUpdate(string const & file)
696 static string const configure_script =
697 addName(package().system_support(), "configure.py");
698 string const absfile =
699 addName(package().user_support(), file);
701 return (! fs::exists(absfile))
702 || (fs::last_write_time(configure_script)
703 > fs::last_write_time(absfile));
709 bool LyX::queryUserLyXDir(bool explicit_userdir)
711 // Does user directory exist?
712 if (fs::exists(package().user_support()) &&
713 fs::is_directory(package().user_support())) {
716 return needsUpdate("lyxrc.defaults")
717 || needsUpdate("textclass.lst")
718 || needsUpdate("packages.lst");
721 first_start = !explicit_userdir;
723 // If the user specified explicitly a directory, ask whether
724 // to create it. If the user says "no", then exit.
725 if (explicit_userdir &&
727 _("Missing user LyX directory"),
728 bformat(_("You have specified a non-existent user "
729 "LyX directory, %1$s.\n"
730 "It is needed to keep your own configuration."),
731 lyx::from_utf8(package().user_support())),
733 _("&Create directory"),
735 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
736 lyx_exit(EXIT_FAILURE);
739 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
740 lyx::from_utf8(package().user_support())))
743 if (!createDirectory(package().user_support(), 0755)) {
744 // Failed, so let's exit.
745 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
747 lyx_exit(EXIT_FAILURE);
754 bool LyX::readRcFile(string const & name)
756 lyxerr[Debug::INIT] << "About to read " << name << "... ";
758 string const lyxrc_path = libFileSearch(string(), name);
759 if (!lyxrc_path.empty()) {
761 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
763 if (lyxrc.read(lyxrc_path) < 0) {
768 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
774 // Read the ui file `name'
775 bool LyX::readUIFile(string const & name)
785 struct keyword_item uitags[ui_last - 1] = {
786 { "include", ui_include },
787 { "menuset", ui_menuset },
788 { "toolbar", ui_toolbar },
789 { "toolbars", ui_toolbars }
792 // Ensure that a file is read only once (prevents include loops)
793 static std::list<string> uifiles;
794 std::list<string>::const_iterator it = uifiles.begin();
795 std::list<string>::const_iterator end = uifiles.end();
796 it = std::find(it, end, name);
798 lyxerr[Debug::INIT] << "UI file '" << name
799 << "' has been read already. "
800 << "Is this an include loop?"
805 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
807 string const ui_path = libFileSearch("ui", name, "ui");
809 if (ui_path.empty()) {
810 lyxerr[Debug::INIT] << "Could not find " << name << endl;
814 uifiles.push_back(name);
816 lyxerr[Debug::INIT] << "Found " << name
817 << " in " << ui_path << endl;
818 LyXLex lex(uitags, ui_last - 1);
819 lex.setFile(ui_path);
821 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
825 if (lyxerr.debugging(Debug::PARSER))
826 lex.printTable(lyxerr);
832 string const file = lex.getString();
833 if (!readUIFile(file))
838 menubackend.read(lex);
842 toolbarbackend.read(lex);
846 toolbarbackend.readToolbars(lex);
850 if (!rtrim(lex.getString()).empty())
851 lex.printError("LyX::ReadUIFile: "
852 "Unknown menu tag: `$$Token'");
860 // Read the languages file `name'
861 bool LyX::readLanguagesFile(string const & name)
863 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
865 string const lang_path = libFileSearch(string(), name);
866 if (lang_path.empty()) {
870 languages.read(lang_path);
875 // Read the encodings file `name'
876 bool LyX::readEncodingsFile(string const & name)
878 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
880 string const enc_path = libFileSearch(string(), name);
881 if (enc_path.empty()) {
885 encodings.read(enc_path);
895 /// return the the number of arguments consumed
896 typedef boost::function<int(string const &, string const &)> cmd_helper;
898 int parse_dbg(string const & arg, string const &)
901 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
902 Debug::showTags(lyxerr);
905 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
907 lyxerr.level(Debug::value(arg));
908 Debug::showLevel(lyxerr, lyxerr.level());
913 int parse_help(string const &, string const &)
916 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
917 "Command line switches (case sensitive):\n"
918 "\t-help summarize LyX usage\n"
919 "\t-userdir dir set user directory to dir\n"
920 "\t-sysdir dir set system directory to dir\n"
921 "\t-geometry WxH+X+Y set geometry of the main window\n"
922 "\t-dbg feature[,feature]...\n"
923 " select the features to debug.\n"
924 " Type `lyx -dbg' to see the list of features\n"
925 "\t-x [--execute] command\n"
926 " where command is a lyx command.\n"
927 "\t-e [--export] fmt\n"
928 " where fmt is the export format of choice.\n"
929 "\t-i [--import] fmt file.xxx\n"
930 " where fmt is the import format of choice\n"
931 " and file.xxx is the file to be imported.\n"
932 "\t-version summarize version and build info\n"
933 "Check the LyX man page for more details.")) << endl;
938 int parse_version(string const &, string const &)
940 lyxerr << "LyX " << lyx_version
941 << " (" << lyx_release_date << ")" << endl;
942 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
944 lyxerr << lyx_version_info << endl;
949 int parse_sysdir(string const & arg, string const &)
952 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
955 cl_system_support = arg;
959 int parse_userdir(string const & arg, string const &)
962 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
965 cl_user_support = arg;
969 int parse_execute(string const & arg, string const &)
972 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
979 int parse_export(string const & type, string const &)
982 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
983 "--export switch")) << endl;
986 batch = "buffer-export " + type;
991 int parse_import(string const & type, string const & file)
994 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
995 "--import switch")) << endl;
999 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1003 batch = "buffer-import " + type + ' ' + file;
1010 bool LyX::easyParse(int & argc, char * argv[])
1012 std::map<string, cmd_helper> cmdmap;
1014 cmdmap["-dbg"] = parse_dbg;
1015 cmdmap["-help"] = parse_help;
1016 cmdmap["--help"] = parse_help;
1017 cmdmap["-version"] = parse_version;
1018 cmdmap["--version"] = parse_version;
1019 cmdmap["-sysdir"] = parse_sysdir;
1020 cmdmap["-userdir"] = parse_userdir;
1021 cmdmap["-x"] = parse_execute;
1022 cmdmap["--execute"] = parse_execute;
1023 cmdmap["-e"] = parse_export;
1024 cmdmap["--export"] = parse_export;
1025 cmdmap["-i"] = parse_import;
1026 cmdmap["--import"] = parse_import;
1028 for (int i = 1; i < argc; ++i) {
1029 std::map<string, cmd_helper>::const_iterator it
1030 = cmdmap.find(argv[i]);
1032 // check for X11 -geometry option
1033 if (lyx::support::compare(argv[i], "-geometry") == 0)
1034 geometryOption_ = true;
1036 // don't complain if not found - may be parsed later
1037 if (it == cmdmap.end())
1040 string arg((i + 1 < argc) ? argv[i + 1] : "");
1041 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1043 int const remove = 1 + it->second(arg, arg2);
1045 // Now, remove used arguments by shifting
1046 // the following ones remove places down.
1048 for (int j = i; j < argc; ++j)
1049 argv[j] = argv[j + remove];
1053 batch_command = batch;