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 int exit_status = exec2(argc, argv);
270 application_.reset();
276 int LyX::exec2(int & argc, char * argv[])
278 // check for any spurious extra arguments
279 // other than documents
280 for (int argi = 1; argi < argc ; ++argi) {
281 if (argv[argi][0] == '-') {
282 lyxerr << lyx::to_utf8(
283 bformat(_("Wrong command line option `%1$s'. Exiting."),
284 lyx::from_utf8(argv[argi]))) << endl;
289 // Initialization of LyX (reads lyxrc and more)
290 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
291 bool const success = init();
292 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
296 vector<string> files;
298 for (int argi = argc - 1; argi >= 1; --argi)
299 files.push_back(os::internal_path(argv[argi]));
302 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
304 // Execute batch commands if available
305 if (!batch_command.empty()) {
307 lyxerr[Debug::INIT] << "About to handle -x '"
308 << batch_command << '\'' << endl;
310 Buffer * last_loaded = 0;
312 vector<string>::const_iterator it = files.begin();
313 vector<string>::const_iterator end = files.end();
315 for (; it != end; ++it) {
316 // get absolute path of file and add ".lyx" to
317 // the filename if necessary
318 string s = fileSearch(string(), *it, "lyx");
320 Buffer * const b = newFile(*it, string(), true);
324 Buffer * buf = theBufferList().newBuffer(s, false);
325 if (loadLyXFile(buf, s)) {
327 ErrorList const & el = buf->errorList("Parse");
329 for_each(el.begin(), el.end(),
330 boost::bind(&LyX::printError, this, _1));
333 theBufferList().release(buf);
337 // try to dispatch to last loaded buffer first
339 bool success = false;
340 if (last_loaded->dispatch(batch_command, &success)) {
345 files.clear(); // the files are already loaded
349 // determine windows size and position, from lyxrc and/or session
351 unsigned int width = 690;
352 unsigned int height = 510;
353 bool maximize = false;
355 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
356 width = lyxrc.geometry_width;
357 height = lyxrc.geometry_height;
359 // if lyxrc returns (0,0), then use session info
361 string val = session().loadSessionInfo("WindowWidth");
363 width = convert<unsigned int>(val);
364 val = session().loadSessionInfo("WindowHeight");
366 height = convert<unsigned int>(val);
367 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
370 // if user wants to restore window position
373 if (lyxrc.geometry_xysaved) {
374 string val = session().loadSessionInfo("WindowPosX");
376 posx = convert<int>(val);
377 val = session().loadSessionInfo("WindowPosY");
379 posy = convert<int>(val);
382 if (geometryOption_) {
386 // create the main window
387 LyXView * view = &application_->createView(width, height, posx, posy, maximize);
388 ref().addLyXView(view);
391 for_each(files.begin(), files.end(),
392 bind(&LyXView::loadLyXFile, view, _1, true));
394 // if a file is specified, I assume that user wants to edit *that* file
395 if (files.empty() && lyxrc.load_session) {
396 vector<string> const & lastopened = session_->lastOpenedFiles();
397 // do not add to the lastfile list since these files are restored from
398 // last seesion, and should be already there (regular files), or should
399 // not be added at all (help files).
400 for_each(lastopened.begin(), lastopened.end(),
401 bind(&LyXView::loadLyXFile, view, _1, false));
403 // clear this list to save a few bytes of RAM
404 session_->clearLastOpenedFiles();
406 return application_->start(batch_command);
408 // Something went wrong above
418 The SIGHUP signal does not exist on Windows and does not need to be handled.
420 Windows handles SIGFPE and SIGSEGV signals as expected.
422 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
423 cause a new thread to be spawned. This may well result in unexpected
424 behaviour by the single-threaded LyX.
426 SIGTERM signals will come only from another process actually sending
427 that signal using 'raise' in Windows' POSIX compatability layer. It will
428 not come from the general "terminate process" methods that everyone
429 actually uses (and which can't be trapped). Killing an app 'politely' on
430 Windows involves first sending a WM_CLOSE message, something that is
431 caught already by the Qt frontend.
433 For more information see:
435 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
436 ...signals are mostly useless on Windows for a variety of reasons that are
439 'UNIX Application Migration Guide, Chapter 9'
440 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
442 'How To Terminate an Application "Cleanly" in Win32'
443 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
447 static void error_handler(int err_sig)
449 // Throw away any signals other than the first one received.
450 static sig_atomic_t handling_error = false;
453 handling_error = true;
455 // We have received a signal indicating a fatal error, so
456 // try and save the data ASAP.
457 LyX::cref().emergencyCleanup();
459 // These lyxerr calls may or may not work:
461 // Signals are asynchronous, so the main program may be in a very
462 // fragile state when a signal is processed and thus while a signal
463 // handler function executes.
464 // In general, therefore, we should avoid performing any
465 // I/O operations or calling most library and system functions from
468 // This shouldn't matter here, however, as we've already invoked
473 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
477 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
480 lyxerr << "\nlyx: SIGSEGV signal caught\n"
481 "Sorry, you have found a bug in LyX. "
482 "Please read the bug-reporting instructions "
483 "in Help->Introduction and send us a bug report, "
484 "if necessary. Thanks !\nBye." << endl;
492 // Deinstall the signal handlers
494 signal(SIGHUP, SIG_DFL);
496 signal(SIGINT, SIG_DFL);
497 signal(SIGFPE, SIG_DFL);
498 signal(SIGSEGV, SIG_DFL);
499 signal(SIGTERM, SIG_DFL);
502 if (err_sig == SIGSEGV ||
503 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
505 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
507 lyx::support::abort();
514 void LyX::printError(ErrorItem const & ei)
516 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
518 std::cerr << lyx::to_utf8(tmp) << std::endl;
525 signal(SIGHUP, error_handler);
527 signal(SIGFPE, error_handler);
528 signal(SIGSEGV, error_handler);
529 signal(SIGINT, error_handler);
530 signal(SIGTERM, error_handler);
531 // SIGPIPE can be safely ignored.
533 lyxrc.tempdir_path = package().temp_dir();
534 lyxrc.document_path = package().document_dir();
536 if (lyxrc.template_path.empty()) {
537 lyxrc.template_path = addPath(package().system_support(),
541 if (lyxrc.roman_font_name.empty())
542 lyxrc.roman_font_name =
543 lyx::use_gui? application_->romanFontName(): "serif";
545 if (lyxrc.sans_font_name.empty())
546 lyxrc.sans_font_name =
547 lyx::use_gui? application_->sansFontName(): "sans";
549 if (lyxrc.typewriter_font_name.empty())
550 lyxrc.typewriter_font_name =
551 lyx::use_gui? application_->typewriterFontName(): "monospace";
554 // Read configuration files
557 // This one may have been distributed along with LyX.
558 if (!readRcFile("lyxrc.dist"))
561 // Set the PATH correctly.
562 #if !defined (USE_POSIX_PACKAGING)
563 // Add the directory containing the LyX executable to the path
564 // so that LyX can find things like tex2lyx.
565 if (package().build_support().empty())
566 prependEnvPath("PATH", package().binary_dir());
568 if (!lyxrc.path_prefix.empty())
569 prependEnvPath("PATH", lyxrc.path_prefix);
571 // Check that user LyX directory is ok.
572 if (queryUserLyXDir(package().explicit_user_support()))
573 reconfigureUserLyXDir();
575 // no need for a splash when there is no GUI
580 // This one is generated in user_support directory by lib/configure.py.
581 if (!readRcFile("lyxrc.defaults"))
584 // Query the OS to know what formats are viewed natively
585 formats.setAutoOpen();
587 system_lyxrc = lyxrc;
588 system_formats = formats;
589 system_converters = converters;
590 system_movers = movers;
591 system_lcolor = lcolor;
593 // This one is edited through the preferences dialog.
594 if (!readRcFile("preferences"))
597 if (!readEncodingsFile("encodings"))
599 if (!readLanguagesFile("languages"))
603 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
609 toplevel_keymap.reset(new kb_keymap);
610 defaultKeyBindings(toplevel_keymap.get());
611 toplevel_keymap->read(lyxrc.bind_file);
614 if (!readUIFile(lyxrc.ui_file))
618 if (lyxerr.debugging(Debug::LYXRC))
621 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
622 if (!lyxrc.path_prefix.empty())
623 prependEnvPath("PATH", lyxrc.path_prefix);
625 if (fs::exists(lyxrc.document_path) &&
626 fs::is_directory(lyxrc.document_path))
627 package().document_dir() = lyxrc.document_path;
629 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
630 if (package().temp_dir().empty()) {
631 Alert::error(_("Could not create temporary directory"),
632 bformat(_("Could not create a temporary directory in\n"
633 "%1$s. Make sure that this\n"
634 "path exists and is writable and try again."),
635 lyx::from_utf8(lyxrc.tempdir_path)));
636 // createLyXTmpDir() tries sufficiently hard to create a
637 // usable temp dir, so the probability to come here is
638 // close to zero. We therefore don't try to overcome this
639 // problem with e.g. asking the user for a new path and
640 // trying again but simply exit.
644 if (lyxerr.debugging(Debug::INIT)) {
645 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
648 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
649 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
654 void LyX::defaultKeyBindings(kb_keymap * kbmap)
656 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
657 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
658 kbmap->bind("Up", FuncRequest(LFUN_UP));
659 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
661 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
662 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
663 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
664 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
666 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
667 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
668 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
669 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
671 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
672 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
674 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
675 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
677 // kbmap->bindings to enable the use of the numeric keypad
679 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
680 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
681 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
682 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
683 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
684 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
685 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
686 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
687 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
688 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
689 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
690 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
691 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
692 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
693 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
694 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
695 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
696 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
697 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
698 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
699 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
700 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
701 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
702 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
706 void LyX::emergencyCleanup() const
708 // what to do about tmpfiles is non-obvious. we would
709 // like to delete any we find, but our lyxdir might
710 // contain documents etc. which might be helpful on
713 theBufferList().emergencyWriteAll();
714 application_->server().emergencyCleanup();
718 void LyX::deadKeyBindings(kb_keymap * kbmap)
720 // bindKeyings for transparent handling of deadkeys
721 // The keysyms are gotten from XFree86 X11R6
722 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
723 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
724 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
725 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
726 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
727 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
728 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
729 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
730 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
731 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
732 // nothing with this name
733 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
734 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
735 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
736 // nothing with this name either...
737 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
738 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
739 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
740 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
746 // return true if file does not exist or is older than configure.py.
747 bool needsUpdate(string const & file)
749 static string const configure_script =
750 addName(package().system_support(), "configure.py");
751 string const absfile =
752 addName(package().user_support(), file);
754 return (! fs::exists(absfile))
755 || (fs::last_write_time(configure_script)
756 > fs::last_write_time(absfile));
762 bool LyX::queryUserLyXDir(bool explicit_userdir)
764 // Does user directory exist?
765 if (fs::exists(package().user_support()) &&
766 fs::is_directory(package().user_support())) {
769 return needsUpdate("lyxrc.defaults")
770 || needsUpdate("textclass.lst")
771 || needsUpdate("packages.lst");
774 first_start = !explicit_userdir;
776 // If the user specified explicitly a directory, ask whether
777 // to create it. If the user says "no", then exit.
778 if (explicit_userdir &&
780 _("Missing user LyX directory"),
781 bformat(_("You have specified a non-existent user "
782 "LyX directory, %1$s.\n"
783 "It is needed to keep your own configuration."),
784 lyx::from_utf8(package().user_support())),
786 _("&Create directory"),
788 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
789 lyx_exit(EXIT_FAILURE);
792 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
793 lyx::from_utf8(package().user_support())))
796 if (!createDirectory(package().user_support(), 0755)) {
797 // Failed, so let's exit.
798 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
800 lyx_exit(EXIT_FAILURE);
807 bool LyX::readRcFile(string const & name)
809 lyxerr[Debug::INIT] << "About to read " << name << "... ";
811 string const lyxrc_path = libFileSearch(string(), name);
812 if (!lyxrc_path.empty()) {
814 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
816 if (lyxrc.read(lyxrc_path) < 0) {
821 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
827 // Read the ui file `name'
828 bool LyX::readUIFile(string const & name)
838 struct keyword_item uitags[ui_last - 1] = {
839 { "include", ui_include },
840 { "menuset", ui_menuset },
841 { "toolbar", ui_toolbar },
842 { "toolbars", ui_toolbars }
845 // Ensure that a file is read only once (prevents include loops)
846 static std::list<string> uifiles;
847 std::list<string>::const_iterator it = uifiles.begin();
848 std::list<string>::const_iterator end = uifiles.end();
849 it = std::find(it, end, name);
851 lyxerr[Debug::INIT] << "UI file '" << name
852 << "' has been read already. "
853 << "Is this an include loop?"
858 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
860 string const ui_path = libFileSearch("ui", name, "ui");
862 if (ui_path.empty()) {
863 lyxerr[Debug::INIT] << "Could not find " << name << endl;
867 uifiles.push_back(name);
869 lyxerr[Debug::INIT] << "Found " << name
870 << " in " << ui_path << endl;
871 LyXLex lex(uitags, ui_last - 1);
872 lex.setFile(ui_path);
874 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
878 if (lyxerr.debugging(Debug::PARSER))
879 lex.printTable(lyxerr);
885 string const file = lex.getString();
886 if (!readUIFile(file))
891 menubackend.read(lex);
895 toolbarbackend.read(lex);
899 toolbarbackend.readToolbars(lex);
903 if (!rtrim(lex.getString()).empty())
904 lex.printError("LyX::ReadUIFile: "
905 "Unknown menu tag: `$$Token'");
913 // Read the languages file `name'
914 bool LyX::readLanguagesFile(string const & name)
916 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
918 string const lang_path = libFileSearch(string(), name);
919 if (lang_path.empty()) {
923 languages.read(lang_path);
928 // Read the encodings file `name'
929 bool LyX::readEncodingsFile(string const & name)
931 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
933 string const enc_path = libFileSearch(string(), name);
934 if (enc_path.empty()) {
938 encodings.read(enc_path);
947 /// return the the number of arguments consumed
948 typedef boost::function<int(string const &, string const &)> cmd_helper;
950 int parse_dbg(string const & arg, string const &)
953 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
954 Debug::showTags(lyxerr);
957 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
959 lyxerr.level(Debug::value(arg));
960 Debug::showLevel(lyxerr, lyxerr.level());
965 int parse_help(string const &, string const &)
968 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
969 "Command line switches (case sensitive):\n"
970 "\t-help summarize LyX usage\n"
971 "\t-userdir dir set user directory to dir\n"
972 "\t-sysdir dir set system directory to dir\n"
973 "\t-geometry WxH+X+Y set geometry of the main window\n"
974 "\t-dbg feature[,feature]...\n"
975 " select the features to debug.\n"
976 " Type `lyx -dbg' to see the list of features\n"
977 "\t-x [--execute] command\n"
978 " where command is a lyx command.\n"
979 "\t-e [--export] fmt\n"
980 " where fmt is the export format of choice.\n"
981 "\t-i [--import] fmt file.xxx\n"
982 " where fmt is the import format of choice\n"
983 " and file.xxx is the file to be imported.\n"
984 "\t-version summarize version and build info\n"
985 "Check the LyX man page for more details.")) << endl;
990 int parse_version(string const &, string const &)
992 lyxerr << "LyX " << lyx_version
993 << " (" << lyx_release_date << ")" << endl;
994 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
996 lyxerr << lyx_version_info << endl;
1001 int parse_sysdir(string const & arg, string const &)
1004 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
1007 cl_system_support = arg;
1011 int parse_userdir(string const & arg, string const &)
1014 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
1017 cl_user_support = arg;
1021 int parse_execute(string const & arg, string const &)
1024 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
1031 int parse_export(string const & type, string const &)
1034 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1035 "--export switch")) << endl;
1038 batch = "buffer-export " + type;
1039 lyx::use_gui = false;
1043 int parse_import(string const & type, string const & file)
1046 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1047 "--import switch")) << endl;
1051 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1055 batch = "buffer-import " + type + ' ' + file;
1062 void LyX::easyParse(int & argc, char * argv[])
1064 std::map<string, cmd_helper> cmdmap;
1066 cmdmap["-dbg"] = parse_dbg;
1067 cmdmap["-help"] = parse_help;
1068 cmdmap["--help"] = parse_help;
1069 cmdmap["-version"] = parse_version;
1070 cmdmap["--version"] = parse_version;
1071 cmdmap["-sysdir"] = parse_sysdir;
1072 cmdmap["-userdir"] = parse_userdir;
1073 cmdmap["-x"] = parse_execute;
1074 cmdmap["--execute"] = parse_execute;
1075 cmdmap["-e"] = parse_export;
1076 cmdmap["--export"] = parse_export;
1077 cmdmap["-i"] = parse_import;
1078 cmdmap["--import"] = parse_import;
1080 for (int i = 1; i < argc; ++i) {
1081 std::map<string, cmd_helper>::const_iterator it
1082 = cmdmap.find(argv[i]);
1084 // check for X11 -geometry option
1085 if (lyx::support::compare(argv[i], "-geometry") == 0)
1086 geometryOption_ = true;
1088 // don't complain if not found - may be parsed later
1089 if (it == cmdmap.end())
1092 string arg((i + 1 < argc) ? argv[i + 1] : "");
1093 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1095 int const remove = 1 + it->second(arg, arg2);
1097 // Now, remove used arguments by shifting
1098 // the following ones remove places down.
1100 for (int j = i; j < argc; ++j)
1101 argv[j] = argv[j + remove];
1105 batch_command = batch;