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 // lyx_gui::exit may return and only schedule the exit
113 lyx_gui::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();
173 : first_start(false), geometryOption_(false)
177 lyx::Session & LyX::session()
179 BOOST_ASSERT(session_.get());
180 return *session_.get();
184 lyx::Session const & LyX::session() const
186 BOOST_ASSERT(session_.get());
187 return *session_.get();
191 void LyX::addLyXView(LyXView * lyxview)
193 views_.push_back(lyxview);
197 Buffer const * const LyX::updateInset(InsetBase const * inset) const
202 Buffer const * buffer_ptr = 0;
203 ViewList::const_iterator it = views_.begin();
204 ViewList::const_iterator const end = views_.end();
205 for (; it != end; ++it) {
206 Buffer const * ptr = (*it)->updateInset(inset);
214 int LyX::priv_exec(int & argc, char * argv[])
216 // Here we need to parse the command line. At least
217 // we need to parse for "-dbg" and "-help"
218 lyx_gui::use_gui = easyParse(argc, argv);
220 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
221 lyx::support::top_build_dir_is_one_level_up);
223 // Start the real execution loop.
224 if (lyx_gui::use_gui) {
225 // Force adding of font path _before_ Application is initialized
226 lyx::support::addFontResources();
227 return lyx_gui::exec(argc, argv);
230 return exec2(argc, argv);
234 int LyX::exec2(int & argc, char * argv[])
236 // check for any spurious extra arguments
237 // other than documents
238 for (int argi = 1; argi < argc ; ++argi) {
239 if (argv[argi][0] == '-') {
240 lyxerr << lyx::to_utf8(
241 bformat(_("Wrong command line option `%1$s'. Exiting."),
242 lyx::from_utf8(argv[argi]))) << endl;
247 // Initialization of LyX (reads lyxrc and more)
248 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
249 bool const success = init();
250 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
254 if (lyx_gui::use_gui)
255 lyx_gui::parse_lyxrc();
257 vector<string> files;
259 for (int argi = argc - 1; argi >= 1; --argi)
260 files.push_back(os::internal_path(argv[argi]));
263 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
265 // Execute batch commands if available
266 if (!batch_command.empty()) {
268 lyxerr[Debug::INIT] << "About to handle -x '"
269 << batch_command << '\'' << endl;
271 Buffer * last_loaded = 0;
273 vector<string>::const_iterator it = files.begin();
274 vector<string>::const_iterator end = files.end();
276 for (; it != end; ++it) {
277 // get absolute path of file and add ".lyx" to
278 // the filename if necessary
279 string s = fileSearch(string(), *it, "lyx");
281 Buffer * const b = newFile(*it, string(), true);
285 Buffer * buf = theApp->bufferList().newBuffer(s, false);
286 if (loadLyXFile(buf, s)) {
288 ErrorList const & el = buf->errorList("Parse");
290 for_each(el.begin(), el.end(),
291 boost::bind(&LyX::printError, this, _1));
294 theApp->bufferList().release(buf);
298 // try to dispatch to last loaded buffer first
300 bool success = false;
301 if (last_loaded->dispatch(batch_command, &success)) {
306 files.clear(); // the files are already loaded
309 if (lyx_gui::use_gui) {
310 // determine windows size and position, from lyxrc and/or session
312 unsigned int width = 690;
313 unsigned int height = 510;
314 bool maximize = false;
316 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
317 width = lyxrc.geometry_width;
318 height = lyxrc.geometry_height;
320 // if lyxrc returns (0,0), then use session info
322 string val = session().loadSessionInfo("WindowWidth");
324 width = convert<unsigned int>(val);
325 val = session().loadSessionInfo("WindowHeight");
327 height = convert<unsigned int>(val);
328 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
331 // if user wants to restore window position
334 if (lyxrc.geometry_xysaved) {
335 string val = session().loadSessionInfo("WindowPosX");
337 posx = convert<int>(val);
338 val = session().loadSessionInfo("WindowPosY");
340 posy = convert<int>(val);
343 if (geometryOption_) {
347 // create the main window
348 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
349 ref().addLyXView(view);
352 for_each(files.begin(), files.end(),
353 bind(&LyXView::loadLyXFile, view, _1, true));
355 // if a file is specified, I assume that user wants to edit *that* file
356 if (files.empty() && lyxrc.load_session) {
357 vector<string> const & lastopened = session_->lastOpenedFiles();
358 // do not add to the lastfile list since these files are restored from
359 // last seesion, and should be already there (regular files), or should
360 // not be added at all (help files).
361 for_each(lastopened.begin(), lastopened.end(),
362 bind(&LyXView::loadLyXFile, view, _1, false));
364 // clear this list to save a few bytes of RAM
365 session_->clearLastOpenedFiles();
367 return lyx_gui::start(view, batch_command);
369 // Something went wrong above
379 The SIGHUP signal does not exist on Windows and does not need to be handled.
381 Windows handles SIGFPE and SIGSEGV signals as expected.
383 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
384 cause a new thread to be spawned. This may well result in unexpected
385 behaviour by the single-threaded LyX.
387 SIGTERM signals will come only from another process actually sending
388 that signal using 'raise' in Windows' POSIX compatability layer. It will
389 not come from the general "terminate process" methods that everyone
390 actually uses (and which can't be trapped). Killing an app 'politely' on
391 Windows involves first sending a WM_CLOSE message, something that is
392 caught already by the Qt frontend.
394 For more information see:
396 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
397 ...signals are mostly useless on Windows for a variety of reasons that are
400 'UNIX Application Migration Guide, Chapter 9'
401 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
403 'How To Terminate an Application "Cleanly" in Win32'
404 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
408 static void error_handler(int err_sig)
410 // Throw away any signals other than the first one received.
411 static sig_atomic_t handling_error = false;
414 handling_error = true;
416 // We have received a signal indicating a fatal error, so
417 // try and save the data ASAP.
418 LyX::cref().emergencyCleanup();
420 // These lyxerr calls may or may not work:
422 // Signals are asynchronous, so the main program may be in a very
423 // fragile state when a signal is processed and thus while a signal
424 // handler function executes.
425 // In general, therefore, we should avoid performing any
426 // I/O operations or calling most library and system functions from
429 // This shouldn't matter here, however, as we've already invoked
434 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
438 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
441 lyxerr << "\nlyx: SIGSEGV signal caught\n"
442 "Sorry, you have found a bug in LyX. "
443 "Please read the bug-reporting instructions "
444 "in Help->Introduction and send us a bug report, "
445 "if necessary. Thanks !\nBye." << endl;
453 // Deinstall the signal handlers
455 signal(SIGHUP, SIG_DFL);
457 signal(SIGINT, SIG_DFL);
458 signal(SIGFPE, SIG_DFL);
459 signal(SIGSEGV, SIG_DFL);
460 signal(SIGTERM, SIG_DFL);
463 if (err_sig == SIGSEGV ||
464 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
466 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
468 lyx::support::abort();
475 void LyX::printError(ErrorItem const & ei)
477 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
479 std::cerr << lyx::to_utf8(tmp) << std::endl;
486 signal(SIGHUP, error_handler);
488 signal(SIGFPE, error_handler);
489 signal(SIGSEGV, error_handler);
490 signal(SIGINT, error_handler);
491 signal(SIGTERM, error_handler);
492 // SIGPIPE can be safely ignored.
494 lyxrc.tempdir_path = package().temp_dir();
495 lyxrc.document_path = package().document_dir();
497 if (lyxrc.template_path.empty()) {
498 lyxrc.template_path = addPath(package().system_support(),
502 if (lyxrc.roman_font_name.empty())
503 lyxrc.roman_font_name = lyx_gui::roman_font_name();
504 if (lyxrc.sans_font_name.empty())
505 lyxrc.sans_font_name = lyx_gui::sans_font_name();
506 if (lyxrc.typewriter_font_name.empty())
507 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
510 // Read configuration files
513 // This one may have been distributed along with LyX.
514 if (!readRcFile("lyxrc.dist"))
517 // Set the PATH correctly.
518 #if !defined (USE_POSIX_PACKAGING)
519 // Add the directory containing the LyX executable to the path
520 // so that LyX can find things like tex2lyx.
521 if (package().build_support().empty())
522 prependEnvPath("PATH", package().binary_dir());
524 if (!lyxrc.path_prefix.empty())
525 prependEnvPath("PATH", lyxrc.path_prefix);
527 // Check that user LyX directory is ok.
528 if (queryUserLyXDir(package().explicit_user_support()))
529 reconfigureUserLyXDir();
531 // no need for a splash when there is no GUI
532 if (!lyx_gui::use_gui) {
536 // This one is generated in user_support directory by lib/configure.py.
537 if (!readRcFile("lyxrc.defaults"))
540 // Query the OS to know what formats are viewed natively
541 formats.setAutoOpen();
543 system_lyxrc = lyxrc;
544 system_formats = formats;
545 system_converters = converters;
546 system_movers = movers;
547 system_lcolor = lcolor;
549 // This one is edited through the preferences dialog.
550 if (!readRcFile("preferences"))
553 if (!readEncodingsFile("encodings"))
555 if (!readLanguagesFile("languages"))
559 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
563 if (lyx_gui::use_gui) {
565 toplevel_keymap.reset(new kb_keymap);
566 defaultKeyBindings(toplevel_keymap.get());
567 toplevel_keymap->read(lyxrc.bind_file);
570 if (!readUIFile(lyxrc.ui_file))
574 if (lyxerr.debugging(Debug::LYXRC))
577 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
578 if (!lyxrc.path_prefix.empty())
579 prependEnvPath("PATH", lyxrc.path_prefix);
581 if (fs::exists(lyxrc.document_path) &&
582 fs::is_directory(lyxrc.document_path))
583 package().document_dir() = lyxrc.document_path;
585 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
586 if (package().temp_dir().empty()) {
587 Alert::error(_("Could not create temporary directory"),
588 bformat(_("Could not create a temporary directory in\n"
589 "%1$s. Make sure that this\n"
590 "path exists and is writable and try again."),
591 lyx::from_utf8(lyxrc.tempdir_path)));
592 // createLyXTmpDir() tries sufficiently hard to create a
593 // usable temp dir, so the probability to come here is
594 // close to zero. We therefore don't try to overcome this
595 // problem with e.g. asking the user for a new path and
596 // trying again but simply exit.
600 if (lyxerr.debugging(Debug::INIT)) {
601 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
604 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
605 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
610 void LyX::defaultKeyBindings(kb_keymap * kbmap)
612 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
613 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
614 kbmap->bind("Up", FuncRequest(LFUN_UP));
615 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
617 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
618 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
619 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
620 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
622 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
623 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
624 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
625 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
627 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
628 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
630 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
631 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
633 // kbmap->bindings to enable the use of the numeric keypad
635 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
637 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
638 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
647 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
648 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
649 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
650 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
651 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
652 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
653 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
654 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
655 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
656 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
657 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
658 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
662 void LyX::emergencyCleanup() const
664 // what to do about tmpfiles is non-obvious. we would
665 // like to delete any we find, but our lyxdir might
666 // contain documents etc. which might be helpful on
669 theApp->bufferList().emergencyWriteAll();
670 theApp->server().emergencyCleanup();
674 void LyX::deadKeyBindings(kb_keymap * kbmap)
676 // bindKeyings for transparent handling of deadkeys
677 // The keysyms are gotten from XFree86 X11R6
678 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
679 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
680 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
681 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
682 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
683 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
684 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
685 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
686 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
687 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
688 // nothing with this name
689 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
690 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
691 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
692 // nothing with this name either...
693 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
694 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
695 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
696 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
702 // return true if file does not exist or is older than configure.py.
703 bool needsUpdate(string const & file)
705 static string const configure_script =
706 addName(package().system_support(), "configure.py");
707 string const absfile =
708 addName(package().user_support(), file);
710 return (! fs::exists(absfile))
711 || (fs::last_write_time(configure_script)
712 > fs::last_write_time(absfile));
718 bool LyX::queryUserLyXDir(bool explicit_userdir)
720 // Does user directory exist?
721 if (fs::exists(package().user_support()) &&
722 fs::is_directory(package().user_support())) {
725 return needsUpdate("lyxrc.defaults")
726 || needsUpdate("textclass.lst")
727 || needsUpdate("packages.lst");
730 first_start = !explicit_userdir;
732 // If the user specified explicitly a directory, ask whether
733 // to create it. If the user says "no", then exit.
734 if (explicit_userdir &&
736 _("Missing user LyX directory"),
737 bformat(_("You have specified a non-existent user "
738 "LyX directory, %1$s.\n"
739 "It is needed to keep your own configuration."),
740 lyx::from_utf8(package().user_support())),
742 _("&Create directory"),
744 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
745 lyx_exit(EXIT_FAILURE);
748 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
749 lyx::from_utf8(package().user_support())))
752 if (!createDirectory(package().user_support(), 0755)) {
753 // Failed, so let's exit.
754 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
756 lyx_exit(EXIT_FAILURE);
763 bool LyX::readRcFile(string const & name)
765 lyxerr[Debug::INIT] << "About to read " << name << "... ";
767 string const lyxrc_path = libFileSearch(string(), name);
768 if (!lyxrc_path.empty()) {
770 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
772 if (lyxrc.read(lyxrc_path) < 0) {
777 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
783 // Read the ui file `name'
784 bool LyX::readUIFile(string const & name)
794 struct keyword_item uitags[ui_last - 1] = {
795 { "include", ui_include },
796 { "menuset", ui_menuset },
797 { "toolbar", ui_toolbar },
798 { "toolbars", ui_toolbars }
801 // Ensure that a file is read only once (prevents include loops)
802 static std::list<string> uifiles;
803 std::list<string>::const_iterator it = uifiles.begin();
804 std::list<string>::const_iterator end = uifiles.end();
805 it = std::find(it, end, name);
807 lyxerr[Debug::INIT] << "UI file '" << name
808 << "' has been read already. "
809 << "Is this an include loop?"
814 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
816 string const ui_path = libFileSearch("ui", name, "ui");
818 if (ui_path.empty()) {
819 lyxerr[Debug::INIT] << "Could not find " << name << endl;
823 uifiles.push_back(name);
825 lyxerr[Debug::INIT] << "Found " << name
826 << " in " << ui_path << endl;
827 LyXLex lex(uitags, ui_last - 1);
828 lex.setFile(ui_path);
830 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
834 if (lyxerr.debugging(Debug::PARSER))
835 lex.printTable(lyxerr);
841 string const file = lex.getString();
842 if (!readUIFile(file))
847 menubackend.read(lex);
851 toolbarbackend.read(lex);
855 toolbarbackend.readToolbars(lex);
859 if (!rtrim(lex.getString()).empty())
860 lex.printError("LyX::ReadUIFile: "
861 "Unknown menu tag: `$$Token'");
869 // Read the languages file `name'
870 bool LyX::readLanguagesFile(string const & name)
872 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
874 string const lang_path = libFileSearch(string(), name);
875 if (lang_path.empty()) {
879 languages.read(lang_path);
884 // Read the encodings file `name'
885 bool LyX::readEncodingsFile(string const & name)
887 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
889 string const enc_path = libFileSearch(string(), name);
890 if (enc_path.empty()) {
894 encodings.read(enc_path);
904 /// return the the number of arguments consumed
905 typedef boost::function<int(string const &, string const &)> cmd_helper;
907 int parse_dbg(string const & arg, string const &)
910 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
911 Debug::showTags(lyxerr);
914 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
916 lyxerr.level(Debug::value(arg));
917 Debug::showLevel(lyxerr, lyxerr.level());
922 int parse_help(string const &, string const &)
925 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
926 "Command line switches (case sensitive):\n"
927 "\t-help summarize LyX usage\n"
928 "\t-userdir dir set user directory to dir\n"
929 "\t-sysdir dir set system directory to dir\n"
930 "\t-geometry WxH+X+Y set geometry of the main window\n"
931 "\t-dbg feature[,feature]...\n"
932 " select the features to debug.\n"
933 " Type `lyx -dbg' to see the list of features\n"
934 "\t-x [--execute] command\n"
935 " where command is a lyx command.\n"
936 "\t-e [--export] fmt\n"
937 " where fmt is the export format of choice.\n"
938 "\t-i [--import] fmt file.xxx\n"
939 " where fmt is the import format of choice\n"
940 " and file.xxx is the file to be imported.\n"
941 "\t-version summarize version and build info\n"
942 "Check the LyX man page for more details.")) << endl;
947 int parse_version(string const &, string const &)
949 lyxerr << "LyX " << lyx_version
950 << " (" << lyx_release_date << ")" << endl;
951 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
953 lyxerr << lyx_version_info << endl;
958 int parse_sysdir(string const & arg, string const &)
961 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
964 cl_system_support = arg;
968 int parse_userdir(string const & arg, string const &)
971 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
974 cl_user_support = arg;
978 int parse_execute(string const & arg, string const &)
981 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
988 int parse_export(string const & type, string const &)
991 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
992 "--export switch")) << endl;
995 batch = "buffer-export " + type;
1000 int parse_import(string const & type, string const & file)
1003 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1004 "--import switch")) << endl;
1008 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1012 batch = "buffer-import " + type + ' ' + file;
1019 bool LyX::easyParse(int & argc, char * argv[])
1021 std::map<string, cmd_helper> cmdmap;
1023 cmdmap["-dbg"] = parse_dbg;
1024 cmdmap["-help"] = parse_help;
1025 cmdmap["--help"] = parse_help;
1026 cmdmap["-version"] = parse_version;
1027 cmdmap["--version"] = parse_version;
1028 cmdmap["-sysdir"] = parse_sysdir;
1029 cmdmap["-userdir"] = parse_userdir;
1030 cmdmap["-x"] = parse_execute;
1031 cmdmap["--execute"] = parse_execute;
1032 cmdmap["-e"] = parse_export;
1033 cmdmap["--export"] = parse_export;
1034 cmdmap["-i"] = parse_import;
1035 cmdmap["--import"] = parse_import;
1037 for (int i = 1; i < argc; ++i) {
1038 std::map<string, cmd_helper>::const_iterator it
1039 = cmdmap.find(argv[i]);
1041 // check for X11 -geometry option
1042 if (lyx::support::compare(argv[i], "-geometry") == 0)
1043 geometryOption_ = true;
1045 // don't complain if not found - may be parsed later
1046 if (it == cmdmap.end())
1049 string arg((i + 1 < argc) ? argv[i + 1] : "");
1050 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1052 int const remove = 1 + it->second(arg, arg2);
1054 // Now, remove used arguments by shifting
1055 // the following ones remove places down.
1057 for (int j = i; j < argc; ++j)
1058 argv[j] = argv[j + remove];
1062 batch_command = batch;