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);
341 ref().addLyXView(view);
344 for_each(files.begin(), files.end(),
345 bind(&LyXView::loadLyXFile, view, _1, true));
347 // if a file is specified, I assume that user wants to edit *that* file
348 if (files.empty() && lyxrc.load_session) {
349 vector<string> const & lastopened = session_->lastOpenedFiles();
350 // do not add to the lastfile list since these files are restored from
351 // last seesion, and should be already there (regular files), or should
352 // not be added at all (help files).
353 for_each(lastopened.begin(), lastopened.end(),
354 bind(&LyXView::loadLyXFile, view, _1, false));
356 // clear this list to save a few bytes of RAM
357 session_->clearLastOpenedFiles();
359 return lyx_gui::start(view, batch_command);
361 // Something went wrong above
371 The SIGHUP signal does not exist on Windows and does not need to be handled.
373 Windows handles SIGFPE and SIGSEGV signals as expected.
375 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
376 cause a new thread to be spawned. This may well result in unexpected
377 behaviour by the single-threaded LyX.
379 SIGTERM signals will come only from another process actually sending
380 that signal using 'raise' in Windows' POSIX compatability layer. It will
381 not come from the general "terminate process" methods that everyone
382 actually uses (and which can't be trapped). Killing an app 'politely' on
383 Windows involves first sending a WM_CLOSE message, something that is
384 caught already by the Qt frontend.
386 For more information see:
388 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
389 ...signals are mostly useless on Windows for a variety of reasons that are
392 'UNIX Application Migration Guide, Chapter 9'
393 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
395 'How To Terminate an Application "Cleanly" in Win32'
396 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
400 static void error_handler(int err_sig)
402 // Throw away any signals other than the first one received.
403 static sig_atomic_t handling_error = false;
406 handling_error = true;
408 // We have received a signal indicating a fatal error, so
409 // try and save the data ASAP.
410 LyX::cref().emergencyCleanup();
412 // These lyxerr calls may or may not work:
414 // Signals are asynchronous, so the main program may be in a very
415 // fragile state when a signal is processed and thus while a signal
416 // handler function executes.
417 // In general, therefore, we should avoid performing any
418 // I/O operations or calling most library and system functions from
421 // This shouldn't matter here, however, as we've already invoked
426 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
430 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
433 lyxerr << "\nlyx: SIGSEGV signal caught\n"
434 "Sorry, you have found a bug in LyX. "
435 "Please read the bug-reporting instructions "
436 "in Help->Introduction and send us a bug report, "
437 "if necessary. Thanks !\nBye." << endl;
445 // Deinstall the signal handlers
447 signal(SIGHUP, SIG_DFL);
449 signal(SIGINT, SIG_DFL);
450 signal(SIGFPE, SIG_DFL);
451 signal(SIGSEGV, SIG_DFL);
452 signal(SIGTERM, SIG_DFL);
455 if (err_sig == SIGSEGV ||
456 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
458 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
460 lyx::support::abort();
467 void LyX::printError(ErrorItem const & ei)
469 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
471 std::cerr << lyx::to_utf8(tmp) << std::endl;
478 signal(SIGHUP, error_handler);
480 signal(SIGFPE, error_handler);
481 signal(SIGSEGV, error_handler);
482 signal(SIGINT, error_handler);
483 signal(SIGTERM, error_handler);
484 // SIGPIPE can be safely ignored.
486 lyxrc.tempdir_path = package().temp_dir();
487 lyxrc.document_path = package().document_dir();
489 if (lyxrc.template_path.empty()) {
490 lyxrc.template_path = addPath(package().system_support(),
494 if (lyxrc.roman_font_name.empty())
495 lyxrc.roman_font_name = lyx_gui::roman_font_name();
496 if (lyxrc.sans_font_name.empty())
497 lyxrc.sans_font_name = lyx_gui::sans_font_name();
498 if (lyxrc.typewriter_font_name.empty())
499 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
502 // Read configuration files
505 // This one may have been distributed along with LyX.
506 if (!readRcFile("lyxrc.dist"))
509 // Set the PATH correctly.
510 #if !defined (USE_POSIX_PACKAGING)
511 // Add the directory containing the LyX executable to the path
512 // so that LyX can find things like tex2lyx.
513 if (package().build_support().empty())
514 prependEnvPath("PATH", package().binary_dir());
516 if (!lyxrc.path_prefix.empty())
517 prependEnvPath("PATH", lyxrc.path_prefix);
519 // Check that user LyX directory is ok.
520 if (queryUserLyXDir(package().explicit_user_support()))
521 reconfigureUserLyXDir();
523 // no need for a splash when there is no GUI
524 if (!lyx_gui::use_gui) {
528 // This one is generated in user_support directory by lib/configure.py.
529 if (!readRcFile("lyxrc.defaults"))
532 // Query the OS to know what formats are viewed natively
533 formats.setAutoOpen();
535 system_lyxrc = lyxrc;
536 system_formats = formats;
537 system_converters = converters;
538 system_movers = movers;
539 system_lcolor = lcolor;
541 // This one is edited through the preferences dialog.
542 if (!readRcFile("preferences"))
545 if (!readEncodingsFile("encodings"))
547 if (!readLanguagesFile("languages"))
551 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
555 if (lyx_gui::use_gui) {
557 toplevel_keymap.reset(new kb_keymap);
558 defaultKeyBindings(toplevel_keymap.get());
559 toplevel_keymap->read(lyxrc.bind_file);
562 if (!readUIFile(lyxrc.ui_file))
566 if (lyxerr.debugging(Debug::LYXRC))
569 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
570 if (!lyxrc.path_prefix.empty())
571 prependEnvPath("PATH", lyxrc.path_prefix);
573 if (fs::exists(lyxrc.document_path) &&
574 fs::is_directory(lyxrc.document_path))
575 package().document_dir() = lyxrc.document_path;
577 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
578 if (package().temp_dir().empty()) {
579 Alert::error(_("Could not create temporary directory"),
580 bformat(_("Could not create a temporary directory in\n"
581 "%1$s. Make sure that this\n"
582 "path exists and is writable and try again."),
583 lyx::from_utf8(lyxrc.tempdir_path)));
584 // createLyXTmpDir() tries sufficiently hard to create a
585 // usable temp dir, so the probability to come here is
586 // close to zero. We therefore don't try to overcome this
587 // problem with e.g. asking the user for a new path and
588 // trying again but simply exit.
592 if (lyxerr.debugging(Debug::INIT)) {
593 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
596 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
597 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
602 void LyX::defaultKeyBindings(kb_keymap * kbmap)
604 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
605 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
606 kbmap->bind("Up", FuncRequest(LFUN_UP));
607 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
609 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
610 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
611 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
612 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
614 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
615 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
616 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
617 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
619 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
620 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
622 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
623 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
625 // kbmap->bindings to enable the use of the numeric keypad
627 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
628 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
629 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
630 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
631 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
632 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
633 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
634 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
643 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
644 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
645 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
646 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
647 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
648 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
649 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
650 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
654 void LyX::emergencyCleanup() const
656 // what to do about tmpfiles is non-obvious. we would
657 // like to delete any we find, but our lyxdir might
658 // contain documents etc. which might be helpful on
661 theApp->bufferList().emergencyWriteAll();
662 theApp->server().emergencyCleanup();
666 void LyX::deadKeyBindings(kb_keymap * kbmap)
668 // bindKeyings for transparent handling of deadkeys
669 // The keysyms are gotten from XFree86 X11R6
670 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
671 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
672 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
673 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
674 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
675 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
676 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
677 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
678 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
679 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
680 // nothing with this name
681 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
682 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
683 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
684 // nothing with this name either...
685 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
686 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
687 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
688 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
694 // return true if file does not exist or is older than configure.py.
695 bool needsUpdate(string const & file)
697 static string const configure_script =
698 addName(package().system_support(), "configure.py");
699 string const absfile =
700 addName(package().user_support(), file);
702 return (! fs::exists(absfile))
703 || (fs::last_write_time(configure_script)
704 > fs::last_write_time(absfile));
710 bool LyX::queryUserLyXDir(bool explicit_userdir)
712 // Does user directory exist?
713 if (fs::exists(package().user_support()) &&
714 fs::is_directory(package().user_support())) {
717 return needsUpdate("lyxrc.defaults")
718 || needsUpdate("textclass.lst")
719 || needsUpdate("packages.lst");
722 first_start = !explicit_userdir;
724 // If the user specified explicitly a directory, ask whether
725 // to create it. If the user says "no", then exit.
726 if (explicit_userdir &&
728 _("Missing user LyX directory"),
729 bformat(_("You have specified a non-existent user "
730 "LyX directory, %1$s.\n"
731 "It is needed to keep your own configuration."),
732 lyx::from_utf8(package().user_support())),
734 _("&Create directory"),
736 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
737 lyx_exit(EXIT_FAILURE);
740 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
741 lyx::from_utf8(package().user_support())))
744 if (!createDirectory(package().user_support(), 0755)) {
745 // Failed, so let's exit.
746 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
748 lyx_exit(EXIT_FAILURE);
755 bool LyX::readRcFile(string const & name)
757 lyxerr[Debug::INIT] << "About to read " << name << "... ";
759 string const lyxrc_path = libFileSearch(string(), name);
760 if (!lyxrc_path.empty()) {
762 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
764 if (lyxrc.read(lyxrc_path) < 0) {
769 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
775 // Read the ui file `name'
776 bool LyX::readUIFile(string const & name)
786 struct keyword_item uitags[ui_last - 1] = {
787 { "include", ui_include },
788 { "menuset", ui_menuset },
789 { "toolbar", ui_toolbar },
790 { "toolbars", ui_toolbars }
793 // Ensure that a file is read only once (prevents include loops)
794 static std::list<string> uifiles;
795 std::list<string>::const_iterator it = uifiles.begin();
796 std::list<string>::const_iterator end = uifiles.end();
797 it = std::find(it, end, name);
799 lyxerr[Debug::INIT] << "UI file '" << name
800 << "' has been read already. "
801 << "Is this an include loop?"
806 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
808 string const ui_path = libFileSearch("ui", name, "ui");
810 if (ui_path.empty()) {
811 lyxerr[Debug::INIT] << "Could not find " << name << endl;
815 uifiles.push_back(name);
817 lyxerr[Debug::INIT] << "Found " << name
818 << " in " << ui_path << endl;
819 LyXLex lex(uitags, ui_last - 1);
820 lex.setFile(ui_path);
822 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
826 if (lyxerr.debugging(Debug::PARSER))
827 lex.printTable(lyxerr);
833 string const file = lex.getString();
834 if (!readUIFile(file))
839 menubackend.read(lex);
843 toolbarbackend.read(lex);
847 toolbarbackend.readToolbars(lex);
851 if (!rtrim(lex.getString()).empty())
852 lex.printError("LyX::ReadUIFile: "
853 "Unknown menu tag: `$$Token'");
861 // Read the languages file `name'
862 bool LyX::readLanguagesFile(string const & name)
864 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
866 string const lang_path = libFileSearch(string(), name);
867 if (lang_path.empty()) {
871 languages.read(lang_path);
876 // Read the encodings file `name'
877 bool LyX::readEncodingsFile(string const & name)
879 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
881 string const enc_path = libFileSearch(string(), name);
882 if (enc_path.empty()) {
886 encodings.read(enc_path);
896 /// return the the number of arguments consumed
897 typedef boost::function<int(string const &, string const &)> cmd_helper;
899 int parse_dbg(string const & arg, string const &)
902 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
903 Debug::showTags(lyxerr);
906 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
908 lyxerr.level(Debug::value(arg));
909 Debug::showLevel(lyxerr, lyxerr.level());
914 int parse_help(string const &, string const &)
917 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
918 "Command line switches (case sensitive):\n"
919 "\t-help summarize LyX usage\n"
920 "\t-userdir dir set user directory to dir\n"
921 "\t-sysdir dir set system directory to dir\n"
922 "\t-geometry WxH+X+Y set geometry of the main window\n"
923 "\t-dbg feature[,feature]...\n"
924 " select the features to debug.\n"
925 " Type `lyx -dbg' to see the list of features\n"
926 "\t-x [--execute] command\n"
927 " where command is a lyx command.\n"
928 "\t-e [--export] fmt\n"
929 " where fmt is the export format of choice.\n"
930 "\t-i [--import] fmt file.xxx\n"
931 " where fmt is the import format of choice\n"
932 " and file.xxx is the file to be imported.\n"
933 "\t-version summarize version and build info\n"
934 "Check the LyX man page for more details.")) << endl;
939 int parse_version(string const &, string const &)
941 lyxerr << "LyX " << lyx_version
942 << " (" << lyx_release_date << ")" << endl;
943 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
945 lyxerr << lyx_version_info << endl;
950 int parse_sysdir(string const & arg, string const &)
953 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
956 cl_system_support = arg;
960 int parse_userdir(string const & arg, string const &)
963 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
966 cl_user_support = arg;
970 int parse_execute(string const & arg, string const &)
973 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
980 int parse_export(string const & type, string const &)
983 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
984 "--export switch")) << endl;
987 batch = "buffer-export " + type;
992 int parse_import(string const & type, string const & file)
995 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
996 "--import switch")) << endl;
1000 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1004 batch = "buffer-import " + type + ' ' + file;
1011 bool LyX::easyParse(int & argc, char * argv[])
1013 std::map<string, cmd_helper> cmdmap;
1015 cmdmap["-dbg"] = parse_dbg;
1016 cmdmap["-help"] = parse_help;
1017 cmdmap["--help"] = parse_help;
1018 cmdmap["-version"] = parse_version;
1019 cmdmap["--version"] = parse_version;
1020 cmdmap["-sysdir"] = parse_sysdir;
1021 cmdmap["-userdir"] = parse_userdir;
1022 cmdmap["-x"] = parse_execute;
1023 cmdmap["--execute"] = parse_execute;
1024 cmdmap["-e"] = parse_export;
1025 cmdmap["--export"] = parse_export;
1026 cmdmap["-i"] = parse_import;
1027 cmdmap["--import"] = parse_import;
1029 for (int i = 1; i < argc; ++i) {
1030 std::map<string, cmd_helper>::const_iterator it
1031 = cmdmap.find(argv[i]);
1033 // check for X11 -geometry option
1034 if (lyx::support::compare(argv[i], "-geometry") == 0)
1035 geometryOption_ = true;
1037 // don't complain if not found - may be parsed later
1038 if (it == cmdmap.end())
1041 string arg((i + 1 < argc) ? argv[i + 1] : "");
1042 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1044 int const remove = 1 + it->second(arg, arg2);
1046 // Now, remove used arguments by shifting
1047 // the following ones remove places down.
1049 for (int j = i; j < argc; ++j)
1050 argv[j] = argv[j + remove];
1054 batch_command = batch;