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 Alert = lyx::frontend::Alert;
81 namespace os = lyx::support::os;
82 namespace fs = boost::filesystem;
89 #ifndef CXX_GLOBAL_CSTD
96 // convenient to have it here.
97 boost::scoped_ptr<kb_keymap> toplevel_keymap;
101 // Filled with the command line arguments "foo" of "-sysdir foo" or
103 string cl_system_support;
104 string cl_user_support;
107 void lyx_exit(int status)
109 // FIXME: We should not directly call exit(), since it only
110 // guarantees a return to the system, no application cleanup.
111 // This may cause troubles with not executed destructors.
112 if (lyx_gui::use_gui) {
113 theApp->exit(status);
114 // Restore original font resources after Application is destroyed.
115 lyx::support::restoreFontResources();
122 void showFileError(string const & error)
124 Alert::warning(_("Could not read configuration file"),
125 bformat(_("Error while reading the configuration file\n%1$s.\n"
126 "Please check your installation."), lyx::from_utf8(error)));
130 void reconfigureUserLyXDir()
132 string const configure_command = package().configure_command();
134 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
135 lyx::support::Path p(package().user_support());
137 one.startscript(Systemcall::Wait, configure_command);
138 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
144 boost::scoped_ptr<LyX> LyX::singleton_;
146 int LyX::exec(int & argc, char * argv[])
148 BOOST_ASSERT(!singleton_.get());
149 // We must return from this before launching the gui so that
150 // other parts of the code can access singleton_ through
151 // LyX::ref and LyX::cref.
152 singleton_.reset(new LyX);
153 // Start the real execution loop.
154 return singleton_->priv_exec(argc, argv);
160 BOOST_ASSERT(singleton_.get());
161 return *singleton_.get();
165 LyX const & LyX::cref()
167 BOOST_ASSERT(singleton_.get());
168 return *singleton_.get();
172 BufferList & theBufferList()
174 return LyX::ref().bufferList();
179 : first_start(false), geometryOption_(false)
181 buffer_list_.reset(new BufferList);
185 BufferList & LyX::bufferList()
187 return *buffer_list_.get();
191 BufferList const & LyX::bufferList() const
193 return *buffer_list_.get();
197 lyx::Session & LyX::session()
199 BOOST_ASSERT(session_.get());
200 return *session_.get();
204 lyx::Session const & LyX::session() const
206 BOOST_ASSERT(session_.get());
207 return *session_.get();
211 void LyX::addLyXView(LyXView * lyxview)
213 views_.push_back(lyxview);
217 Buffer const * const LyX::updateInset(InsetBase const * inset) const
222 Buffer const * buffer_ptr = 0;
223 ViewList::const_iterator it = views_.begin();
224 ViewList::const_iterator const end = views_.end();
225 for (; it != end; ++it) {
226 Buffer const * ptr = (*it)->updateInset(inset);
234 int LyX::priv_exec(int & argc, char * argv[])
236 // Here we need to parse the command line. At least
237 // we need to parse for "-dbg" and "-help"
238 lyx_gui::use_gui = easyParse(argc, argv);
240 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
241 lyx::support::top_build_dir_is_one_level_up);
243 // Start the real execution loop.
244 if (lyx_gui::use_gui) {
245 // Force adding of font path _before_ Application is initialized
246 lyx::support::addFontResources();
247 return lyx_gui::exec(argc, argv);
250 return exec2(argc, argv);
254 int LyX::exec2(int & argc, char * argv[])
256 // check for any spurious extra arguments
257 // other than documents
258 for (int argi = 1; argi < argc ; ++argi) {
259 if (argv[argi][0] == '-') {
260 lyxerr << lyx::to_utf8(
261 bformat(_("Wrong command line option `%1$s'. Exiting."),
262 lyx::from_utf8(argv[argi]))) << endl;
267 // Initialization of LyX (reads lyxrc and more)
268 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
269 bool const success = init();
270 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
274 vector<string> files;
276 for (int argi = argc - 1; argi >= 1; --argi)
277 files.push_back(os::internal_path(argv[argi]));
280 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
282 // Execute batch commands if available
283 if (!batch_command.empty()) {
285 lyxerr[Debug::INIT] << "About to handle -x '"
286 << batch_command << '\'' << endl;
288 Buffer * last_loaded = 0;
290 vector<string>::const_iterator it = files.begin();
291 vector<string>::const_iterator end = files.end();
293 for (; it != end; ++it) {
294 // get absolute path of file and add ".lyx" to
295 // the filename if necessary
296 string s = fileSearch(string(), *it, "lyx");
298 Buffer * const b = newFile(*it, string(), true);
302 Buffer * buf = theBufferList().newBuffer(s, false);
303 if (loadLyXFile(buf, s)) {
305 ErrorList const & el = buf->errorList("Parse");
307 for_each(el.begin(), el.end(),
308 boost::bind(&LyX::printError, this, _1));
311 theBufferList().release(buf);
315 // try to dispatch to last loaded buffer first
317 bool success = false;
318 if (last_loaded->dispatch(batch_command, &success)) {
323 files.clear(); // the files are already loaded
326 if (lyx_gui::use_gui) {
327 // determine windows size and position, from lyxrc and/or session
329 unsigned int width = 690;
330 unsigned int height = 510;
331 bool maximize = false;
333 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
334 width = lyxrc.geometry_width;
335 height = lyxrc.geometry_height;
337 // if lyxrc returns (0,0), then use session info
339 string val = session().loadSessionInfo("WindowWidth");
341 width = convert<unsigned int>(val);
342 val = session().loadSessionInfo("WindowHeight");
344 height = convert<unsigned int>(val);
345 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
348 // if user wants to restore window position
351 if (lyxrc.geometry_xysaved) {
352 string val = session().loadSessionInfo("WindowPosX");
354 posx = convert<int>(val);
355 val = session().loadSessionInfo("WindowPosY");
357 posy = convert<int>(val);
360 if (geometryOption_) {
364 // create the main window
365 LyXView * view = &theApp->createView(width, height, posx, posy, maximize);
366 ref().addLyXView(view);
369 for_each(files.begin(), files.end(),
370 bind(&LyXView::loadLyXFile, view, _1, true));
372 // if a file is specified, I assume that user wants to edit *that* file
373 if (files.empty() && lyxrc.load_session) {
374 vector<string> const & lastopened = session_->lastOpenedFiles();
375 // do not add to the lastfile list since these files are restored from
376 // last seesion, and should be already there (regular files), or should
377 // not be added at all (help files).
378 for_each(lastopened.begin(), lastopened.end(),
379 bind(&LyXView::loadLyXFile, view, _1, false));
381 // clear this list to save a few bytes of RAM
382 session_->clearLastOpenedFiles();
384 return theApp->start(batch_command);
386 // Something went wrong above
396 The SIGHUP signal does not exist on Windows and does not need to be handled.
398 Windows handles SIGFPE and SIGSEGV signals as expected.
400 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
401 cause a new thread to be spawned. This may well result in unexpected
402 behaviour by the single-threaded LyX.
404 SIGTERM signals will come only from another process actually sending
405 that signal using 'raise' in Windows' POSIX compatability layer. It will
406 not come from the general "terminate process" methods that everyone
407 actually uses (and which can't be trapped). Killing an app 'politely' on
408 Windows involves first sending a WM_CLOSE message, something that is
409 caught already by the Qt frontend.
411 For more information see:
413 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
414 ...signals are mostly useless on Windows for a variety of reasons that are
417 'UNIX Application Migration Guide, Chapter 9'
418 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
420 'How To Terminate an Application "Cleanly" in Win32'
421 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
425 static void error_handler(int err_sig)
427 // Throw away any signals other than the first one received.
428 static sig_atomic_t handling_error = false;
431 handling_error = true;
433 // We have received a signal indicating a fatal error, so
434 // try and save the data ASAP.
435 LyX::cref().emergencyCleanup();
437 // These lyxerr calls may or may not work:
439 // Signals are asynchronous, so the main program may be in a very
440 // fragile state when a signal is processed and thus while a signal
441 // handler function executes.
442 // In general, therefore, we should avoid performing any
443 // I/O operations or calling most library and system functions from
446 // This shouldn't matter here, however, as we've already invoked
451 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
455 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
458 lyxerr << "\nlyx: SIGSEGV signal caught\n"
459 "Sorry, you have found a bug in LyX. "
460 "Please read the bug-reporting instructions "
461 "in Help->Introduction and send us a bug report, "
462 "if necessary. Thanks !\nBye." << endl;
470 // Deinstall the signal handlers
472 signal(SIGHUP, SIG_DFL);
474 signal(SIGINT, SIG_DFL);
475 signal(SIGFPE, SIG_DFL);
476 signal(SIGSEGV, SIG_DFL);
477 signal(SIGTERM, SIG_DFL);
480 if (err_sig == SIGSEGV ||
481 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
483 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
485 lyx::support::abort();
492 void LyX::printError(ErrorItem const & ei)
494 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
496 std::cerr << lyx::to_utf8(tmp) << std::endl;
503 signal(SIGHUP, error_handler);
505 signal(SIGFPE, error_handler);
506 signal(SIGSEGV, error_handler);
507 signal(SIGINT, error_handler);
508 signal(SIGTERM, error_handler);
509 // SIGPIPE can be safely ignored.
511 lyxrc.tempdir_path = package().temp_dir();
512 lyxrc.document_path = package().document_dir();
514 if (lyxrc.template_path.empty()) {
515 lyxrc.template_path = addPath(package().system_support(),
519 if (lyxrc.roman_font_name.empty())
520 lyxrc.roman_font_name =
521 lyx_gui::use_gui? theApp->romanFontName(): "serif";
523 if (lyxrc.sans_font_name.empty())
524 lyxrc.sans_font_name =
525 lyx_gui::use_gui? theApp->sansFontName(): "sans";
527 if (lyxrc.typewriter_font_name.empty())
528 lyxrc.typewriter_font_name =
529 lyx_gui::use_gui? theApp->typewriterFontName(): "monospace";
532 // Read configuration files
535 // This one may have been distributed along with LyX.
536 if (!readRcFile("lyxrc.dist"))
539 // Set the PATH correctly.
540 #if !defined (USE_POSIX_PACKAGING)
541 // Add the directory containing the LyX executable to the path
542 // so that LyX can find things like tex2lyx.
543 if (package().build_support().empty())
544 prependEnvPath("PATH", package().binary_dir());
546 if (!lyxrc.path_prefix.empty())
547 prependEnvPath("PATH", lyxrc.path_prefix);
549 // Check that user LyX directory is ok.
550 if (queryUserLyXDir(package().explicit_user_support()))
551 reconfigureUserLyXDir();
553 // no need for a splash when there is no GUI
554 if (!lyx_gui::use_gui) {
558 // This one is generated in user_support directory by lib/configure.py.
559 if (!readRcFile("lyxrc.defaults"))
562 // Query the OS to know what formats are viewed natively
563 formats.setAutoOpen();
565 system_lyxrc = lyxrc;
566 system_formats = formats;
567 system_converters = converters;
568 system_movers = movers;
569 system_lcolor = lcolor;
571 // This one is edited through the preferences dialog.
572 if (!readRcFile("preferences"))
575 if (!readEncodingsFile("encodings"))
577 if (!readLanguagesFile("languages"))
581 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
585 if (lyx_gui::use_gui) {
587 toplevel_keymap.reset(new kb_keymap);
588 defaultKeyBindings(toplevel_keymap.get());
589 toplevel_keymap->read(lyxrc.bind_file);
592 if (!readUIFile(lyxrc.ui_file))
596 if (lyxerr.debugging(Debug::LYXRC))
599 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
600 if (!lyxrc.path_prefix.empty())
601 prependEnvPath("PATH", lyxrc.path_prefix);
603 if (fs::exists(lyxrc.document_path) &&
604 fs::is_directory(lyxrc.document_path))
605 package().document_dir() = lyxrc.document_path;
607 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
608 if (package().temp_dir().empty()) {
609 Alert::error(_("Could not create temporary directory"),
610 bformat(_("Could not create a temporary directory in\n"
611 "%1$s. Make sure that this\n"
612 "path exists and is writable and try again."),
613 lyx::from_utf8(lyxrc.tempdir_path)));
614 // createLyXTmpDir() tries sufficiently hard to create a
615 // usable temp dir, so the probability to come here is
616 // close to zero. We therefore don't try to overcome this
617 // problem with e.g. asking the user for a new path and
618 // trying again but simply exit.
622 if (lyxerr.debugging(Debug::INIT)) {
623 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
626 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
627 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
632 void LyX::defaultKeyBindings(kb_keymap * kbmap)
634 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
635 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
636 kbmap->bind("Up", FuncRequest(LFUN_UP));
637 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
639 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
640 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
641 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
642 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
644 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
645 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
646 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
647 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
649 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
650 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
652 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
653 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
655 // kbmap->bindings to enable the use of the numeric keypad
657 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
658 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
659 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
660 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
661 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
662 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
663 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
664 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
665 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
666 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
667 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
668 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
669 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
670 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
671 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
672 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
673 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
674 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
675 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
676 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
677 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
678 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
679 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
680 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
684 void LyX::emergencyCleanup() const
686 // what to do about tmpfiles is non-obvious. we would
687 // like to delete any we find, but our lyxdir might
688 // contain documents etc. which might be helpful on
691 theBufferList().emergencyWriteAll();
692 theApp->server().emergencyCleanup();
696 void LyX::deadKeyBindings(kb_keymap * kbmap)
698 // bindKeyings for transparent handling of deadkeys
699 // The keysyms are gotten from XFree86 X11R6
700 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
701 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
702 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
703 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
704 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
705 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
706 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
707 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
708 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
709 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
710 // nothing with this name
711 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
712 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
713 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
714 // nothing with this name either...
715 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
716 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
717 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
718 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
724 // return true if file does not exist or is older than configure.py.
725 bool needsUpdate(string const & file)
727 static string const configure_script =
728 addName(package().system_support(), "configure.py");
729 string const absfile =
730 addName(package().user_support(), file);
732 return (! fs::exists(absfile))
733 || (fs::last_write_time(configure_script)
734 > fs::last_write_time(absfile));
740 bool LyX::queryUserLyXDir(bool explicit_userdir)
742 // Does user directory exist?
743 if (fs::exists(package().user_support()) &&
744 fs::is_directory(package().user_support())) {
747 return needsUpdate("lyxrc.defaults")
748 || needsUpdate("textclass.lst")
749 || needsUpdate("packages.lst");
752 first_start = !explicit_userdir;
754 // If the user specified explicitly a directory, ask whether
755 // to create it. If the user says "no", then exit.
756 if (explicit_userdir &&
758 _("Missing user LyX directory"),
759 bformat(_("You have specified a non-existent user "
760 "LyX directory, %1$s.\n"
761 "It is needed to keep your own configuration."),
762 lyx::from_utf8(package().user_support())),
764 _("&Create directory"),
766 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
767 lyx_exit(EXIT_FAILURE);
770 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
771 lyx::from_utf8(package().user_support())))
774 if (!createDirectory(package().user_support(), 0755)) {
775 // Failed, so let's exit.
776 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
778 lyx_exit(EXIT_FAILURE);
785 bool LyX::readRcFile(string const & name)
787 lyxerr[Debug::INIT] << "About to read " << name << "... ";
789 string const lyxrc_path = libFileSearch(string(), name);
790 if (!lyxrc_path.empty()) {
792 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
794 if (lyxrc.read(lyxrc_path) < 0) {
799 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
805 // Read the ui file `name'
806 bool LyX::readUIFile(string const & name)
816 struct keyword_item uitags[ui_last - 1] = {
817 { "include", ui_include },
818 { "menuset", ui_menuset },
819 { "toolbar", ui_toolbar },
820 { "toolbars", ui_toolbars }
823 // Ensure that a file is read only once (prevents include loops)
824 static std::list<string> uifiles;
825 std::list<string>::const_iterator it = uifiles.begin();
826 std::list<string>::const_iterator end = uifiles.end();
827 it = std::find(it, end, name);
829 lyxerr[Debug::INIT] << "UI file '" << name
830 << "' has been read already. "
831 << "Is this an include loop?"
836 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
838 string const ui_path = libFileSearch("ui", name, "ui");
840 if (ui_path.empty()) {
841 lyxerr[Debug::INIT] << "Could not find " << name << endl;
845 uifiles.push_back(name);
847 lyxerr[Debug::INIT] << "Found " << name
848 << " in " << ui_path << endl;
849 LyXLex lex(uitags, ui_last - 1);
850 lex.setFile(ui_path);
852 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
856 if (lyxerr.debugging(Debug::PARSER))
857 lex.printTable(lyxerr);
863 string const file = lex.getString();
864 if (!readUIFile(file))
869 menubackend.read(lex);
873 toolbarbackend.read(lex);
877 toolbarbackend.readToolbars(lex);
881 if (!rtrim(lex.getString()).empty())
882 lex.printError("LyX::ReadUIFile: "
883 "Unknown menu tag: `$$Token'");
891 // Read the languages file `name'
892 bool LyX::readLanguagesFile(string const & name)
894 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
896 string const lang_path = libFileSearch(string(), name);
897 if (lang_path.empty()) {
901 languages.read(lang_path);
906 // Read the encodings file `name'
907 bool LyX::readEncodingsFile(string const & name)
909 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
911 string const enc_path = libFileSearch(string(), name);
912 if (enc_path.empty()) {
916 encodings.read(enc_path);
926 /// return the the number of arguments consumed
927 typedef boost::function<int(string const &, string const &)> cmd_helper;
929 int parse_dbg(string const & arg, string const &)
932 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
933 Debug::showTags(lyxerr);
936 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
938 lyxerr.level(Debug::value(arg));
939 Debug::showLevel(lyxerr, lyxerr.level());
944 int parse_help(string const &, string const &)
947 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
948 "Command line switches (case sensitive):\n"
949 "\t-help summarize LyX usage\n"
950 "\t-userdir dir set user directory to dir\n"
951 "\t-sysdir dir set system directory to dir\n"
952 "\t-geometry WxH+X+Y set geometry of the main window\n"
953 "\t-dbg feature[,feature]...\n"
954 " select the features to debug.\n"
955 " Type `lyx -dbg' to see the list of features\n"
956 "\t-x [--execute] command\n"
957 " where command is a lyx command.\n"
958 "\t-e [--export] fmt\n"
959 " where fmt is the export format of choice.\n"
960 "\t-i [--import] fmt file.xxx\n"
961 " where fmt is the import format of choice\n"
962 " and file.xxx is the file to be imported.\n"
963 "\t-version summarize version and build info\n"
964 "Check the LyX man page for more details.")) << endl;
969 int parse_version(string const &, string const &)
971 lyxerr << "LyX " << lyx_version
972 << " (" << lyx_release_date << ")" << endl;
973 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
975 lyxerr << lyx_version_info << endl;
980 int parse_sysdir(string const & arg, string const &)
983 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
986 cl_system_support = arg;
990 int parse_userdir(string const & arg, string const &)
993 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
996 cl_user_support = arg;
1000 int parse_execute(string const & arg, string const &)
1003 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
1010 int parse_export(string const & type, string const &)
1013 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1014 "--export switch")) << endl;
1017 batch = "buffer-export " + type;
1022 int parse_import(string const & type, string const & file)
1025 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1026 "--import switch")) << endl;
1030 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1034 batch = "buffer-import " + type + ' ' + file;
1041 bool LyX::easyParse(int & argc, char * argv[])
1043 std::map<string, cmd_helper> cmdmap;
1045 cmdmap["-dbg"] = parse_dbg;
1046 cmdmap["-help"] = parse_help;
1047 cmdmap["--help"] = parse_help;
1048 cmdmap["-version"] = parse_version;
1049 cmdmap["--version"] = parse_version;
1050 cmdmap["-sysdir"] = parse_sysdir;
1051 cmdmap["-userdir"] = parse_userdir;
1052 cmdmap["-x"] = parse_execute;
1053 cmdmap["--execute"] = parse_execute;
1054 cmdmap["-e"] = parse_export;
1055 cmdmap["--export"] = parse_export;
1056 cmdmap["-i"] = parse_import;
1057 cmdmap["--import"] = parse_import;
1059 for (int i = 1; i < argc; ++i) {
1060 std::map<string, cmd_helper>::const_iterator it
1061 = cmdmap.find(argv[i]);
1063 // check for X11 -geometry option
1064 if (lyx::support::compare(argv[i], "-geometry") == 0)
1065 geometryOption_ = true;
1067 // don't complain if not found - may be parsed later
1068 if (it == cmdmap.end())
1071 string arg((i + 1 < argc) ? argv[i + 1] : "");
1072 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1074 int const remove = 1 + it->second(arg, arg2);
1076 // Now, remove used arguments by shifting
1077 // the following ones remove places down.
1079 for (int j = i; j < argc; ++j)
1080 argv[j] = argv[j + remove];
1084 batch_command = batch;