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/LyXView.h"
47 #include "support/environment.h"
48 #include "support/filetools.h"
49 #include "support/fontutils.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 Alert = lyx::frontend::Alert;
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;
99 lyx::frontend::Application * theApp;
103 /// are we using the GUI at all?
105 * We default to true and this is changed to false when the export feature is used.
113 // Filled with the command line arguments "foo" of "-sysdir foo" or
115 string cl_system_support;
116 string cl_user_support;
119 void lyx_exit(int status)
121 // FIXME: We should not directly call exit(), since it only
122 // guarantees a return to the system, no application cleanup.
123 // This may cause troubles with not executed destructors.
125 theApp->exit(status);
126 // Restore original font resources after Application is destroyed.
127 lyx::support::restoreFontResources();
134 void showFileError(string const & error)
136 Alert::warning(_("Could not read configuration file"),
137 bformat(_("Error while reading the configuration file\n%1$s.\n"
138 "Please check your installation."), lyx::from_utf8(error)));
142 void reconfigureUserLyXDir()
144 string const configure_command = package().configure_command();
146 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
147 lyx::support::Path p(package().user_support());
149 one.startscript(Systemcall::Wait, configure_command);
150 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
156 boost::scoped_ptr<LyX> LyX::singleton_;
158 int LyX::exec(int & argc, char * argv[])
160 BOOST_ASSERT(!singleton_.get());
161 // We must return from this before launching the gui so that
162 // other parts of the code can access singleton_ through
163 // LyX::ref and LyX::cref.
164 singleton_.reset(new LyX);
165 // Start the real execution loop.
166 return singleton_->priv_exec(argc, argv);
172 BOOST_ASSERT(singleton_.get());
173 return *singleton_.get();
177 LyX const & LyX::cref()
179 BOOST_ASSERT(singleton_.get());
180 return *singleton_.get();
184 BufferList & theBufferList()
186 return LyX::ref().bufferList();
191 : first_start(false), geometryOption_(false)
193 buffer_list_.reset(new BufferList);
197 BufferList & LyX::bufferList()
199 return *buffer_list_.get();
203 BufferList const & LyX::bufferList() const
205 return *buffer_list_.get();
209 lyx::Session & LyX::session()
211 BOOST_ASSERT(session_.get());
212 return *session_.get();
216 lyx::Session const & LyX::session() const
218 BOOST_ASSERT(session_.get());
219 return *session_.get();
223 void LyX::addLyXView(LyXView * lyxview)
225 views_.push_back(lyxview);
229 Buffer const * const LyX::updateInset(InsetBase const * inset) const
234 Buffer const * buffer_ptr = 0;
235 ViewList::const_iterator it = views_.begin();
236 ViewList::const_iterator const end = views_.end();
237 for (; it != end; ++it) {
238 Buffer const * ptr = (*it)->updateInset(inset);
246 int LyX::priv_exec(int & argc, char * argv[])
248 // Here we need to parse the command line. At least
249 // we need to parse for "-dbg" and "-help"
250 easyParse(argc, argv);
252 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
253 lyx::support::top_build_dir_is_one_level_up);
255 // Start the real execution loop.
257 // Force adding of font path _before_ Application is initialized
258 lyx::support::addFontResources();
259 application_.reset(lyx::createApplication(argc, argv));
260 theApp = application_.get();
263 // FIXME: create a ConsoleApplication
267 return exec2(argc, argv);
271 int LyX::exec2(int & argc, char * argv[])
273 // check for any spurious extra arguments
274 // other than documents
275 for (int argi = 1; argi < argc ; ++argi) {
276 if (argv[argi][0] == '-') {
277 lyxerr << lyx::to_utf8(
278 bformat(_("Wrong command line option `%1$s'. Exiting."),
279 lyx::from_utf8(argv[argi]))) << endl;
284 // Initialization of LyX (reads lyxrc and more)
285 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
286 bool const success = init();
287 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
291 vector<string> files;
293 for (int argi = argc - 1; argi >= 1; --argi)
294 files.push_back(os::internal_path(argv[argi]));
297 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
299 // Execute batch commands if available
300 if (!batch_command.empty()) {
302 lyxerr[Debug::INIT] << "About to handle -x '"
303 << batch_command << '\'' << endl;
305 Buffer * last_loaded = 0;
307 vector<string>::const_iterator it = files.begin();
308 vector<string>::const_iterator end = files.end();
310 for (; it != end; ++it) {
311 // get absolute path of file and add ".lyx" to
312 // the filename if necessary
313 string s = fileSearch(string(), *it, "lyx");
315 Buffer * const b = newFile(*it, string(), true);
319 Buffer * buf = theBufferList().newBuffer(s, false);
320 if (loadLyXFile(buf, s)) {
322 ErrorList const & el = buf->errorList("Parse");
324 for_each(el.begin(), el.end(),
325 boost::bind(&LyX::printError, this, _1));
328 theBufferList().release(buf);
332 // try to dispatch to last loaded buffer first
334 bool success = false;
335 if (last_loaded->dispatch(batch_command, &success)) {
340 files.clear(); // the files are already loaded
344 // determine windows size and position, from lyxrc and/or session
346 unsigned int width = 690;
347 unsigned int height = 510;
348 bool maximize = false;
350 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
351 width = lyxrc.geometry_width;
352 height = lyxrc.geometry_height;
354 // if lyxrc returns (0,0), then use session info
356 string val = session().loadSessionInfo("WindowWidth");
358 width = convert<unsigned int>(val);
359 val = session().loadSessionInfo("WindowHeight");
361 height = convert<unsigned int>(val);
362 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
365 // if user wants to restore window position
368 if (lyxrc.geometry_xysaved) {
369 string val = session().loadSessionInfo("WindowPosX");
371 posx = convert<int>(val);
372 val = session().loadSessionInfo("WindowPosY");
374 posy = convert<int>(val);
377 if (geometryOption_) {
381 // create the main window
382 LyXView * view = &application_->createView(width, height, posx, posy, maximize);
383 ref().addLyXView(view);
386 for_each(files.begin(), files.end(),
387 bind(&LyXView::loadLyXFile, view, _1, true));
389 // if a file is specified, I assume that user wants to edit *that* file
390 if (files.empty() && lyxrc.load_session) {
391 vector<string> const & lastopened = session_->lastOpenedFiles();
392 // do not add to the lastfile list since these files are restored from
393 // last seesion, and should be already there (regular files), or should
394 // not be added at all (help files).
395 for_each(lastopened.begin(), lastopened.end(),
396 bind(&LyXView::loadLyXFile, view, _1, false));
398 // clear this list to save a few bytes of RAM
399 session_->clearLastOpenedFiles();
401 return application_->start(batch_command);
403 // Something went wrong above
413 The SIGHUP signal does not exist on Windows and does not need to be handled.
415 Windows handles SIGFPE and SIGSEGV signals as expected.
417 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
418 cause a new thread to be spawned. This may well result in unexpected
419 behaviour by the single-threaded LyX.
421 SIGTERM signals will come only from another process actually sending
422 that signal using 'raise' in Windows' POSIX compatability layer. It will
423 not come from the general "terminate process" methods that everyone
424 actually uses (and which can't be trapped). Killing an app 'politely' on
425 Windows involves first sending a WM_CLOSE message, something that is
426 caught already by the Qt frontend.
428 For more information see:
430 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
431 ...signals are mostly useless on Windows for a variety of reasons that are
434 'UNIX Application Migration Guide, Chapter 9'
435 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
437 'How To Terminate an Application "Cleanly" in Win32'
438 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
442 static void error_handler(int err_sig)
444 // Throw away any signals other than the first one received.
445 static sig_atomic_t handling_error = false;
448 handling_error = true;
450 // We have received a signal indicating a fatal error, so
451 // try and save the data ASAP.
452 LyX::cref().emergencyCleanup();
454 // These lyxerr calls may or may not work:
456 // Signals are asynchronous, so the main program may be in a very
457 // fragile state when a signal is processed and thus while a signal
458 // handler function executes.
459 // In general, therefore, we should avoid performing any
460 // I/O operations or calling most library and system functions from
463 // This shouldn't matter here, however, as we've already invoked
468 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
472 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
475 lyxerr << "\nlyx: SIGSEGV signal caught\n"
476 "Sorry, you have found a bug in LyX. "
477 "Please read the bug-reporting instructions "
478 "in Help->Introduction and send us a bug report, "
479 "if necessary. Thanks !\nBye." << endl;
487 // Deinstall the signal handlers
489 signal(SIGHUP, SIG_DFL);
491 signal(SIGINT, SIG_DFL);
492 signal(SIGFPE, SIG_DFL);
493 signal(SIGSEGV, SIG_DFL);
494 signal(SIGTERM, SIG_DFL);
497 if (err_sig == SIGSEGV ||
498 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
500 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
502 lyx::support::abort();
509 void LyX::printError(ErrorItem const & ei)
511 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
513 std::cerr << lyx::to_utf8(tmp) << std::endl;
520 signal(SIGHUP, error_handler);
522 signal(SIGFPE, error_handler);
523 signal(SIGSEGV, error_handler);
524 signal(SIGINT, error_handler);
525 signal(SIGTERM, error_handler);
526 // SIGPIPE can be safely ignored.
528 lyxrc.tempdir_path = package().temp_dir();
529 lyxrc.document_path = package().document_dir();
531 if (lyxrc.template_path.empty()) {
532 lyxrc.template_path = addPath(package().system_support(),
536 if (lyxrc.roman_font_name.empty())
537 lyxrc.roman_font_name =
538 lyx::use_gui? application_->romanFontName(): "serif";
540 if (lyxrc.sans_font_name.empty())
541 lyxrc.sans_font_name =
542 lyx::use_gui? application_->sansFontName(): "sans";
544 if (lyxrc.typewriter_font_name.empty())
545 lyxrc.typewriter_font_name =
546 lyx::use_gui? application_->typewriterFontName(): "monospace";
549 // Read configuration files
552 // This one may have been distributed along with LyX.
553 if (!readRcFile("lyxrc.dist"))
556 // Set the PATH correctly.
557 #if !defined (USE_POSIX_PACKAGING)
558 // Add the directory containing the LyX executable to the path
559 // so that LyX can find things like tex2lyx.
560 if (package().build_support().empty())
561 prependEnvPath("PATH", package().binary_dir());
563 if (!lyxrc.path_prefix.empty())
564 prependEnvPath("PATH", lyxrc.path_prefix);
566 // Check that user LyX directory is ok.
567 if (queryUserLyXDir(package().explicit_user_support()))
568 reconfigureUserLyXDir();
570 // no need for a splash when there is no GUI
575 // This one is generated in user_support directory by lib/configure.py.
576 if (!readRcFile("lyxrc.defaults"))
579 // Query the OS to know what formats are viewed natively
580 formats.setAutoOpen();
582 system_lyxrc = lyxrc;
583 system_formats = formats;
584 system_converters = converters;
585 system_movers = movers;
586 system_lcolor = lcolor;
588 // This one is edited through the preferences dialog.
589 if (!readRcFile("preferences"))
592 if (!readEncodingsFile("encodings"))
594 if (!readLanguagesFile("languages"))
598 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
604 toplevel_keymap.reset(new kb_keymap);
605 defaultKeyBindings(toplevel_keymap.get());
606 toplevel_keymap->read(lyxrc.bind_file);
609 if (!readUIFile(lyxrc.ui_file))
613 if (lyxerr.debugging(Debug::LYXRC))
616 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
617 if (!lyxrc.path_prefix.empty())
618 prependEnvPath("PATH", lyxrc.path_prefix);
620 if (fs::exists(lyxrc.document_path) &&
621 fs::is_directory(lyxrc.document_path))
622 package().document_dir() = lyxrc.document_path;
624 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
625 if (package().temp_dir().empty()) {
626 Alert::error(_("Could not create temporary directory"),
627 bformat(_("Could not create a temporary directory in\n"
628 "%1$s. Make sure that this\n"
629 "path exists and is writable and try again."),
630 lyx::from_utf8(lyxrc.tempdir_path)));
631 // createLyXTmpDir() tries sufficiently hard to create a
632 // usable temp dir, so the probability to come here is
633 // close to zero. We therefore don't try to overcome this
634 // problem with e.g. asking the user for a new path and
635 // trying again but simply exit.
639 if (lyxerr.debugging(Debug::INIT)) {
640 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
643 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
644 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
649 void LyX::defaultKeyBindings(kb_keymap * kbmap)
651 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
652 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
653 kbmap->bind("Up", FuncRequest(LFUN_UP));
654 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
656 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
657 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
658 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
659 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
661 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
662 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
663 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
664 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
666 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
667 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
669 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
670 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
672 // kbmap->bindings to enable the use of the numeric keypad
674 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
675 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
676 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
677 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
678 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
679 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
680 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
681 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
682 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
683 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
684 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
685 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
686 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
687 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
688 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
689 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
690 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
691 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
692 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
693 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
694 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
695 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
696 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
697 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
701 void LyX::emergencyCleanup() const
703 // what to do about tmpfiles is non-obvious. we would
704 // like to delete any we find, but our lyxdir might
705 // contain documents etc. which might be helpful on
708 theBufferList().emergencyWriteAll();
709 application_->server().emergencyCleanup();
713 void LyX::deadKeyBindings(kb_keymap * kbmap)
715 // bindKeyings for transparent handling of deadkeys
716 // The keysyms are gotten from XFree86 X11R6
717 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
718 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
719 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
720 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
721 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
722 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
723 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
724 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
725 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
726 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
727 // nothing with this name
728 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
729 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
730 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
731 // nothing with this name either...
732 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
733 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
734 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
735 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
741 // return true if file does not exist or is older than configure.py.
742 bool needsUpdate(string const & file)
744 static string const configure_script =
745 addName(package().system_support(), "configure.py");
746 string const absfile =
747 addName(package().user_support(), file);
749 return (! fs::exists(absfile))
750 || (fs::last_write_time(configure_script)
751 > fs::last_write_time(absfile));
757 bool LyX::queryUserLyXDir(bool explicit_userdir)
759 // Does user directory exist?
760 if (fs::exists(package().user_support()) &&
761 fs::is_directory(package().user_support())) {
764 return needsUpdate("lyxrc.defaults")
765 || needsUpdate("textclass.lst")
766 || needsUpdate("packages.lst");
769 first_start = !explicit_userdir;
771 // If the user specified explicitly a directory, ask whether
772 // to create it. If the user says "no", then exit.
773 if (explicit_userdir &&
775 _("Missing user LyX directory"),
776 bformat(_("You have specified a non-existent user "
777 "LyX directory, %1$s.\n"
778 "It is needed to keep your own configuration."),
779 lyx::from_utf8(package().user_support())),
781 _("&Create directory"),
783 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
784 lyx_exit(EXIT_FAILURE);
787 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
788 lyx::from_utf8(package().user_support())))
791 if (!createDirectory(package().user_support(), 0755)) {
792 // Failed, so let's exit.
793 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
795 lyx_exit(EXIT_FAILURE);
802 bool LyX::readRcFile(string const & name)
804 lyxerr[Debug::INIT] << "About to read " << name << "... ";
806 string const lyxrc_path = libFileSearch(string(), name);
807 if (!lyxrc_path.empty()) {
809 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
811 if (lyxrc.read(lyxrc_path) < 0) {
816 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
822 // Read the ui file `name'
823 bool LyX::readUIFile(string const & name)
833 struct keyword_item uitags[ui_last - 1] = {
834 { "include", ui_include },
835 { "menuset", ui_menuset },
836 { "toolbar", ui_toolbar },
837 { "toolbars", ui_toolbars }
840 // Ensure that a file is read only once (prevents include loops)
841 static std::list<string> uifiles;
842 std::list<string>::const_iterator it = uifiles.begin();
843 std::list<string>::const_iterator end = uifiles.end();
844 it = std::find(it, end, name);
846 lyxerr[Debug::INIT] << "UI file '" << name
847 << "' has been read already. "
848 << "Is this an include loop?"
853 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
855 string const ui_path = libFileSearch("ui", name, "ui");
857 if (ui_path.empty()) {
858 lyxerr[Debug::INIT] << "Could not find " << name << endl;
862 uifiles.push_back(name);
864 lyxerr[Debug::INIT] << "Found " << name
865 << " in " << ui_path << endl;
866 LyXLex lex(uitags, ui_last - 1);
867 lex.setFile(ui_path);
869 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
873 if (lyxerr.debugging(Debug::PARSER))
874 lex.printTable(lyxerr);
880 string const file = lex.getString();
881 if (!readUIFile(file))
886 menubackend.read(lex);
890 toolbarbackend.read(lex);
894 toolbarbackend.readToolbars(lex);
898 if (!rtrim(lex.getString()).empty())
899 lex.printError("LyX::ReadUIFile: "
900 "Unknown menu tag: `$$Token'");
908 // Read the languages file `name'
909 bool LyX::readLanguagesFile(string const & name)
911 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
913 string const lang_path = libFileSearch(string(), name);
914 if (lang_path.empty()) {
918 languages.read(lang_path);
923 // Read the encodings file `name'
924 bool LyX::readEncodingsFile(string const & name)
926 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
928 string const enc_path = libFileSearch(string(), name);
929 if (enc_path.empty()) {
933 encodings.read(enc_path);
942 /// return the the number of arguments consumed
943 typedef boost::function<int(string const &, string const &)> cmd_helper;
945 int parse_dbg(string const & arg, string const &)
948 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
949 Debug::showTags(lyxerr);
952 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
954 lyxerr.level(Debug::value(arg));
955 Debug::showLevel(lyxerr, lyxerr.level());
960 int parse_help(string const &, string const &)
963 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
964 "Command line switches (case sensitive):\n"
965 "\t-help summarize LyX usage\n"
966 "\t-userdir dir set user directory to dir\n"
967 "\t-sysdir dir set system directory to dir\n"
968 "\t-geometry WxH+X+Y set geometry of the main window\n"
969 "\t-dbg feature[,feature]...\n"
970 " select the features to debug.\n"
971 " Type `lyx -dbg' to see the list of features\n"
972 "\t-x [--execute] command\n"
973 " where command is a lyx command.\n"
974 "\t-e [--export] fmt\n"
975 " where fmt is the export format of choice.\n"
976 "\t-i [--import] fmt file.xxx\n"
977 " where fmt is the import format of choice\n"
978 " and file.xxx is the file to be imported.\n"
979 "\t-version summarize version and build info\n"
980 "Check the LyX man page for more details.")) << endl;
985 int parse_version(string const &, string const &)
987 lyxerr << "LyX " << lyx_version
988 << " (" << lyx_release_date << ")" << endl;
989 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
991 lyxerr << lyx_version_info << endl;
996 int parse_sysdir(string const & arg, string const &)
999 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
1002 cl_system_support = arg;
1006 int parse_userdir(string const & arg, string const &)
1009 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
1012 cl_user_support = arg;
1016 int parse_execute(string const & arg, string const &)
1019 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
1026 int parse_export(string const & type, string const &)
1029 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1030 "--export switch")) << endl;
1033 batch = "buffer-export " + type;
1034 lyx::use_gui = true;
1038 int parse_import(string const & type, string const & file)
1041 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1042 "--import switch")) << endl;
1046 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1050 batch = "buffer-import " + type + ' ' + file;
1057 void LyX::easyParse(int & argc, char * argv[])
1059 std::map<string, cmd_helper> cmdmap;
1061 cmdmap["-dbg"] = parse_dbg;
1062 cmdmap["-help"] = parse_help;
1063 cmdmap["--help"] = parse_help;
1064 cmdmap["-version"] = parse_version;
1065 cmdmap["--version"] = parse_version;
1066 cmdmap["-sysdir"] = parse_sysdir;
1067 cmdmap["-userdir"] = parse_userdir;
1068 cmdmap["-x"] = parse_execute;
1069 cmdmap["--execute"] = parse_execute;
1070 cmdmap["-e"] = parse_export;
1071 cmdmap["--export"] = parse_export;
1072 cmdmap["-i"] = parse_import;
1073 cmdmap["--import"] = parse_import;
1075 for (int i = 1; i < argc; ++i) {
1076 std::map<string, cmd_helper>::const_iterator it
1077 = cmdmap.find(argv[i]);
1079 // check for X11 -geometry option
1080 if (lyx::support::compare(argv[i], "-geometry") == 0)
1081 geometryOption_ = true;
1083 // don't complain if not found - may be parsed later
1084 if (it == cmdmap.end())
1087 string arg((i + 1 < argc) ? argv[i + 1] : "");
1088 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1090 int const remove = 1 + it->second(arg, arg2);
1092 // Now, remove used arguments by shifting
1093 // the following ones remove places down.
1095 for (int j = i; j < argc; ++j)
1096 argv[j] = argv[j + remove];
1100 batch_command = batch;