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