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 "lyxtextclasslist.h"
38 #include "lyxserver.h"
39 #include "MenuBackend.h"
41 #include "ToolbarBackend.h"
43 #include "mathed/math_inset.h"
45 #include "frontends/Alert.h"
46 #include "frontends/lyx_gui.h"
47 #include "frontends/LyXView.h"
49 #include "support/environment.h"
50 #include "support/filetools.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;
87 #ifndef CXX_GLOBAL_CSTD
94 extern LyXServer * lyxserver;
96 // This is the global bufferlist object
97 BufferList bufferlist;
99 // convenient to have it here.
100 boost::scoped_ptr<kb_keymap> toplevel_keymap;
104 // Filled with the command line arguments "foo" of "-sysdir foo" or
106 string cl_system_support;
107 string cl_user_support;
110 void lyx_exit(int status)
112 // FIXME: We should not directly call exit(), since it only
113 // guarantees a return to the system, no application cleanup.
114 // This may cause troubles with not executed destructors.
115 if (lyx_gui::use_gui)
116 // lyx_gui::exit may return and only schedule the exit
117 lyx_gui::exit(status);
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 return lyx_gui::exec(argc, argv);
227 return exec2(argc, argv);
231 int LyX::exec2(int & argc, char * argv[])
233 // check for any spurious extra arguments
234 // other than documents
235 for (int argi = 1; argi < argc ; ++argi) {
236 if (argv[argi][0] == '-') {
237 lyxerr << lyx::to_utf8(
238 bformat(_("Wrong command line option `%1$s'. Exiting."),
239 lyx::from_utf8(argv[argi]))) << endl;
244 // Initialization of LyX (reads lyxrc and more)
245 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
246 bool const success = init();
247 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
251 if (lyx_gui::use_gui)
252 lyx_gui::parse_lyxrc();
254 vector<string> files;
256 for (int argi = argc - 1; argi >= 1; --argi)
257 files.push_back(os::internal_path(argv[argi]));
260 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
262 // Execute batch commands if available
263 if (!batch_command.empty()) {
265 lyxerr[Debug::INIT] << "About to handle -x '"
266 << batch_command << '\'' << endl;
268 Buffer * last_loaded = 0;
270 vector<string>::const_iterator it = files.begin();
271 vector<string>::const_iterator end = files.end();
273 for (; it != end; ++it) {
274 // get absolute path of file and add ".lyx" to
275 // the filename if necessary
276 string s = fileSearch(string(), *it, "lyx");
278 Buffer * const b = newFile(*it, string(), true);
282 Buffer * buf = bufferlist.newBuffer(s, false);
283 if (loadLyXFile(buf, s)) {
285 ErrorList const & el = buf->errorList("Parse");
287 for_each(el.begin(), el.end(),
288 boost::bind(&LyX::printError, this, _1));
291 bufferlist.release(buf);
295 // try to dispatch to last loaded buffer first
297 bool success = false;
298 if (last_loaded->dispatch(batch_command, &success)) {
303 files.clear(); // the files are already loaded
306 if (lyx_gui::use_gui) {
307 // determine windows size and position, from lyxrc and/or session
309 unsigned int width = 690;
310 unsigned int height = 510;
311 bool maximize = false;
313 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
314 width = lyxrc.geometry_width;
315 height = lyxrc.geometry_height;
317 // if lyxrc returns (0,0), then use session info
319 string val = session().loadSessionInfo("WindowWidth");
321 width = convert<unsigned int>(val);
322 val = session().loadSessionInfo("WindowHeight");
324 height = convert<unsigned int>(val);
325 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
328 // if user wants to restore window position
331 if (lyxrc.geometry_xysaved) {
332 string val = session().loadSessionInfo("WindowPosX");
334 posx = convert<int>(val);
335 val = session().loadSessionInfo("WindowPosY");
337 posy = convert<int>(val);
340 if (geometryOption_) {
344 // create the main window
345 LyXView * view = lyx_gui::create_view(width, height, posx, posy, maximize);
348 for_each(files.begin(), files.end(),
349 bind(&LyXView::loadLyXFile, view, _1, true));
351 // if a file is specified, I assume that user wants to edit *that* file
352 if (files.empty() && lyxrc.load_session) {
353 vector<string> const & lastopened = session_->lastOpenedFiles();
354 // do not add to the lastfile list since these files are restored from
355 // last seesion, and should be already there (regular files), or should
356 // not be added at all (help files).
357 for_each(lastopened.begin(), lastopened.end(),
358 bind(&LyXView::loadLyXFile, view, _1, false));
360 // clear this list to save a few bytes of RAM
361 session_->clearLastOpenedFiles();
363 return lyx_gui::start(view, batch_command);
365 // Something went wrong above
375 The SIGHUP signal does not exist on Windows and does not need to be handled.
377 Windows handles SIGFPE and SIGSEGV signals as expected.
379 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
380 cause a new thread to be spawned. This may well result in unexpected
381 behaviour by the single-threaded LyX.
383 SIGTERM signals will come only from another process actually sending
384 that signal using 'raise' in Windows' POSIX compatability layer. It will
385 not come from the general "terminate process" methods that everyone
386 actually uses (and which can't be trapped). Killing an app 'politely' on
387 Windows involves first sending a WM_CLOSE message, something that is
388 caught already by the Qt frontend.
390 For more information see:
392 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
393 ...signals are mostly useless on Windows for a variety of reasons that are
396 'UNIX Application Migration Guide, Chapter 9'
397 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
399 'How To Terminate an Application "Cleanly" in Win32'
400 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
404 static void error_handler(int err_sig)
406 // Throw away any signals other than the first one received.
407 static sig_atomic_t handling_error = false;
410 handling_error = true;
412 // We have received a signal indicating a fatal error, so
413 // try and save the data ASAP.
414 LyX::cref().emergencyCleanup();
416 // These lyxerr calls may or may not work:
418 // Signals are asynchronous, so the main program may be in a very
419 // fragile state when a signal is processed and thus while a signal
420 // handler function executes.
421 // In general, therefore, we should avoid performing any
422 // I/O operations or calling most library and system functions from
425 // This shouldn't matter here, however, as we've already invoked
430 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
434 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
437 lyxerr << "\nlyx: SIGSEGV signal caught\n"
438 "Sorry, you have found a bug in LyX. "
439 "Please read the bug-reporting instructions "
440 "in Help->Introduction and send us a bug report, "
441 "if necessary. Thanks !\nBye." << endl;
449 // Deinstall the signal handlers
451 signal(SIGHUP, SIG_DFL);
453 signal(SIGINT, SIG_DFL);
454 signal(SIGFPE, SIG_DFL);
455 signal(SIGSEGV, SIG_DFL);
456 signal(SIGTERM, SIG_DFL);
459 if (err_sig == SIGSEGV ||
460 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
462 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
464 lyx::support::abort();
471 void LyX::printError(ErrorItem const & ei)
473 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
475 std::cerr << lyx::to_utf8(tmp) << std::endl;
482 signal(SIGHUP, error_handler);
484 signal(SIGFPE, error_handler);
485 signal(SIGSEGV, error_handler);
486 signal(SIGINT, error_handler);
487 signal(SIGTERM, error_handler);
488 // SIGPIPE can be safely ignored.
490 lyxrc.tempdir_path = package().temp_dir();
491 lyxrc.document_path = package().document_dir();
493 if (lyxrc.template_path.empty()) {
494 lyxrc.template_path = addPath(package().system_support(),
498 if (lyxrc.roman_font_name.empty())
499 lyxrc.roman_font_name = lyx_gui::roman_font_name();
500 if (lyxrc.sans_font_name.empty())
501 lyxrc.sans_font_name = lyx_gui::sans_font_name();
502 if (lyxrc.typewriter_font_name.empty())
503 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
506 // Read configuration files
509 // This one may have been distributed along with LyX.
510 if (!readRcFile("lyxrc.dist"))
513 // Set the PATH correctly.
514 #if !defined (USE_POSIX_PACKAGING)
515 // Add the directory containing the LyX executable to the path
516 // so that LyX can find things like tex2lyx.
517 if (package().build_support().empty())
518 prependEnvPath("PATH", package().binary_dir());
520 if (!lyxrc.path_prefix.empty())
521 prependEnvPath("PATH", lyxrc.path_prefix);
523 // Check that user LyX directory is ok.
524 if (queryUserLyXDir(package().explicit_user_support()))
525 reconfigureUserLyXDir();
527 // no need for a splash when there is no GUI
528 if (!lyx_gui::use_gui) {
532 // This one is generated in user_support directory by lib/configure.py.
533 if (!readRcFile("lyxrc.defaults"))
536 // Query the OS to know what formats are viewed natively
537 formats.setAutoOpen();
539 system_lyxrc = lyxrc;
540 system_formats = formats;
541 system_converters = converters;
542 system_movers = movers;
543 system_lcolor = lcolor;
545 // This one is edited through the preferences dialog.
546 if (!readRcFile("preferences"))
549 if (!readEncodingsFile("encodings"))
551 if (!readLanguagesFile("languages"))
555 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
559 if (lyx_gui::use_gui) {
561 toplevel_keymap.reset(new kb_keymap);
562 defaultKeyBindings(toplevel_keymap.get());
563 toplevel_keymap->read(lyxrc.bind_file);
566 if (!readUIFile(lyxrc.ui_file))
570 if (lyxerr.debugging(Debug::LYXRC))
573 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
574 if (!lyxrc.path_prefix.empty())
575 prependEnvPath("PATH", lyxrc.path_prefix);
577 if (fs::exists(lyxrc.document_path) &&
578 fs::is_directory(lyxrc.document_path))
579 package().document_dir() = lyxrc.document_path;
581 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
582 if (package().temp_dir().empty()) {
583 Alert::error(_("Could not create temporary directory"),
584 bformat(_("Could not create a temporary directory in\n"
585 "%1$s. Make sure that this\n"
586 "path exists and is writable and try again."),
587 lyx::from_utf8(lyxrc.tempdir_path)));
588 // createLyXTmpDir() tries sufficiently hard to create a
589 // usable temp dir, so the probability to come here is
590 // close to zero. We therefore don't try to overcome this
591 // problem with e.g. asking the user for a new path and
592 // trying again but simply exit.
596 if (lyxerr.debugging(Debug::INIT)) {
597 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
600 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
601 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
606 void LyX::defaultKeyBindings(kb_keymap * kbmap)
608 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
609 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
610 kbmap->bind("Up", FuncRequest(LFUN_UP));
611 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
613 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
614 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
615 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
616 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
618 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
619 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
620 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
621 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
623 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
624 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
626 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
627 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
629 // kbmap->bindings to enable the use of the numeric keypad
631 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
632 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
633 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
634 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
635 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
636 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
637 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
638 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
639 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
640 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
641 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
642 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
643 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
644 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
645 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
646 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
647 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
648 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
649 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
650 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
651 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
652 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
653 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
654 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
658 void LyX::emergencyCleanup() const
660 // what to do about tmpfiles is non-obvious. we would
661 // like to delete any we find, but our lyxdir might
662 // contain documents etc. which might be helpful on
665 bufferlist.emergencyWriteAll();
667 lyxserver->emergencyCleanup();
671 void LyX::deadKeyBindings(kb_keymap * kbmap)
673 // bindKeyings for transparent handling of deadkeys
674 // The keysyms are gotten from XFree86 X11R6
675 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
676 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
677 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
678 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
679 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
680 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
681 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
682 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
683 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
684 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
685 // nothing with this name
686 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
687 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
688 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
689 // nothing with this name either...
690 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
691 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
692 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
693 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
699 // return true if file does not exist or is older than configure.py.
700 bool needsUpdate(string const & file)
702 static string const configure_script =
703 addName(package().system_support(), "configure.py");
704 string const absfile =
705 addName(package().user_support(), file);
707 return (! fs::exists(absfile))
708 || (fs::last_write_time(configure_script)
709 > fs::last_write_time(absfile));
715 bool LyX::queryUserLyXDir(bool explicit_userdir)
717 // Does user directory exist?
718 if (fs::exists(package().user_support()) &&
719 fs::is_directory(package().user_support())) {
722 return needsUpdate("lyxrc.defaults")
723 || needsUpdate("textclass.lst")
724 || needsUpdate("packages.lst");
727 first_start = !explicit_userdir;
729 // If the user specified explicitly a directory, ask whether
730 // to create it. If the user says "no", then exit.
731 if (explicit_userdir &&
733 _("Missing user LyX directory"),
734 bformat(_("You have specified a non-existent user "
735 "LyX directory, %1$s.\n"
736 "It is needed to keep your own configuration."),
737 lyx::from_utf8(package().user_support())),
739 _("&Create directory"),
741 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
742 lyx_exit(EXIT_FAILURE);
745 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
746 lyx::from_utf8(package().user_support())))
749 if (!createDirectory(package().user_support(), 0755)) {
750 // Failed, so let's exit.
751 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
753 lyx_exit(EXIT_FAILURE);
760 bool LyX::readRcFile(string const & name)
762 lyxerr[Debug::INIT] << "About to read " << name << "... ";
764 string const lyxrc_path = libFileSearch(string(), name);
765 if (!lyxrc_path.empty()) {
767 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
769 if (lyxrc.read(lyxrc_path) < 0) {
774 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
780 // Read the ui file `name'
781 bool LyX::readUIFile(string const & name)
791 struct keyword_item uitags[ui_last - 1] = {
792 { "include", ui_include },
793 { "menuset", ui_menuset },
794 { "toolbar", ui_toolbar },
795 { "toolbars", ui_toolbars }
798 // Ensure that a file is read only once (prevents include loops)
799 static std::list<string> uifiles;
800 std::list<string>::const_iterator it = uifiles.begin();
801 std::list<string>::const_iterator end = uifiles.end();
802 it = std::find(it, end, name);
804 lyxerr[Debug::INIT] << "UI file '" << name
805 << "' has been read already. "
806 << "Is this an include loop?"
811 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
813 string const ui_path = libFileSearch("ui", name, "ui");
815 if (ui_path.empty()) {
816 lyxerr[Debug::INIT] << "Could not find " << name << endl;
820 uifiles.push_back(name);
822 lyxerr[Debug::INIT] << "Found " << name
823 << " in " << ui_path << endl;
824 LyXLex lex(uitags, ui_last - 1);
825 lex.setFile(ui_path);
827 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
831 if (lyxerr.debugging(Debug::PARSER))
832 lex.printTable(lyxerr);
838 string const file = lex.getString();
839 if (!readUIFile(file))
844 menubackend.read(lex);
848 toolbarbackend.read(lex);
852 toolbarbackend.readToolbars(lex);
856 if (!rtrim(lex.getString()).empty())
857 lex.printError("LyX::ReadUIFile: "
858 "Unknown menu tag: `$$Token'");
866 // Read the languages file `name'
867 bool LyX::readLanguagesFile(string const & name)
869 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
871 string const lang_path = libFileSearch(string(), name);
872 if (lang_path.empty()) {
876 languages.read(lang_path);
881 // Read the encodings file `name'
882 bool LyX::readEncodingsFile(string const & name)
884 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
886 string const enc_path = libFileSearch(string(), name);
887 if (enc_path.empty()) {
891 encodings.read(enc_path);
901 /// return the the number of arguments consumed
902 typedef boost::function<int(string const &, string const &)> cmd_helper;
904 int parse_dbg(string const & arg, string const &)
907 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
908 Debug::showTags(lyxerr);
911 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
913 lyxerr.level(Debug::value(arg));
914 Debug::showLevel(lyxerr, lyxerr.level());
919 int parse_help(string const &, string const &)
922 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
923 "Command line switches (case sensitive):\n"
924 "\t-help summarize LyX usage\n"
925 "\t-userdir dir set user directory to dir\n"
926 "\t-sysdir dir set system directory to dir\n"
927 "\t-geometry WxH+X+Y set geometry of the main window\n"
928 "\t-dbg feature[,feature]...\n"
929 " select the features to debug.\n"
930 " Type `lyx -dbg' to see the list of features\n"
931 "\t-x [--execute] command\n"
932 " where command is a lyx command.\n"
933 "\t-e [--export] fmt\n"
934 " where fmt is the export format of choice.\n"
935 "\t-i [--import] fmt file.xxx\n"
936 " where fmt is the import format of choice\n"
937 " and file.xxx is the file to be imported.\n"
938 "\t-version summarize version and build info\n"
939 "Check the LyX man page for more details.")) << endl;
944 int parse_version(string const &, string const &)
946 lyxerr << "LyX " << lyx_version
947 << " (" << lyx_release_date << ")" << endl;
948 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
950 lyxerr << lyx_version_info << endl;
955 int parse_sysdir(string const & arg, string const &)
958 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
961 cl_system_support = arg;
965 int parse_userdir(string const & arg, string const &)
968 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
971 cl_user_support = arg;
975 int parse_execute(string const & arg, string const &)
978 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
985 int parse_export(string const & type, string const &)
988 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
989 "--export switch")) << endl;
992 batch = "buffer-export " + type;
997 int parse_import(string const & type, string const & file)
1000 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1001 "--import switch")) << endl;
1005 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1009 batch = "buffer-import " + type + ' ' + file;
1016 bool LyX::easyParse(int & argc, char * argv[])
1018 std::map<string, cmd_helper> cmdmap;
1020 cmdmap["-dbg"] = parse_dbg;
1021 cmdmap["-help"] = parse_help;
1022 cmdmap["--help"] = parse_help;
1023 cmdmap["-version"] = parse_version;
1024 cmdmap["--version"] = parse_version;
1025 cmdmap["-sysdir"] = parse_sysdir;
1026 cmdmap["-userdir"] = parse_userdir;
1027 cmdmap["-x"] = parse_execute;
1028 cmdmap["--execute"] = parse_execute;
1029 cmdmap["-e"] = parse_export;
1030 cmdmap["--export"] = parse_export;
1031 cmdmap["-i"] = parse_import;
1032 cmdmap["--import"] = parse_import;
1034 for (int i = 1; i < argc; ++i) {
1035 std::map<string, cmd_helper>::const_iterator it
1036 = cmdmap.find(argv[i]);
1038 // check for X11 -geometry option
1039 if (lyx::support::compare(argv[i], "-geometry") == 0)
1040 geometryOption_ = true;
1042 // don't complain if not found - may be parsed later
1043 if (it == cmdmap.end())
1046 string arg((i + 1 < argc) ? argv[i + 1] : "");
1047 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1049 int const remove = 1 + it->second(arg, arg2);
1051 // Now, remove used arguments by shifting
1052 // the following ones remove places down.
1054 for (int j = i; j < argc; ++j)
1055 argv[j] = argv[j + remove];
1059 batch_command = batch;