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 theApp = lyx::createApplication(argc, argv);
262 // FIXME: create a ConsoleApplication
266 return exec2(argc, argv);
270 int LyX::exec2(int & argc, char * argv[])
272 // check for any spurious extra arguments
273 // other than documents
274 for (int argi = 1; argi < argc ; ++argi) {
275 if (argv[argi][0] == '-') {
276 lyxerr << lyx::to_utf8(
277 bformat(_("Wrong command line option `%1$s'. Exiting."),
278 lyx::from_utf8(argv[argi]))) << endl;
283 // Initialization of LyX (reads lyxrc and more)
284 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
285 bool const success = init();
286 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
290 vector<string> files;
292 for (int argi = argc - 1; argi >= 1; --argi)
293 files.push_back(os::internal_path(argv[argi]));
296 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
298 // Execute batch commands if available
299 if (!batch_command.empty()) {
301 lyxerr[Debug::INIT] << "About to handle -x '"
302 << batch_command << '\'' << endl;
304 Buffer * last_loaded = 0;
306 vector<string>::const_iterator it = files.begin();
307 vector<string>::const_iterator end = files.end();
309 for (; it != end; ++it) {
310 // get absolute path of file and add ".lyx" to
311 // the filename if necessary
312 string s = fileSearch(string(), *it, "lyx");
314 Buffer * const b = newFile(*it, string(), true);
318 Buffer * buf = theBufferList().newBuffer(s, false);
319 if (loadLyXFile(buf, s)) {
321 ErrorList const & el = buf->errorList("Parse");
323 for_each(el.begin(), el.end(),
324 boost::bind(&LyX::printError, this, _1));
327 theBufferList().release(buf);
331 // try to dispatch to last loaded buffer first
333 bool success = false;
334 if (last_loaded->dispatch(batch_command, &success)) {
339 files.clear(); // the files are already loaded
343 // determine windows size and position, from lyxrc and/or session
345 unsigned int width = 690;
346 unsigned int height = 510;
347 bool maximize = false;
349 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
350 width = lyxrc.geometry_width;
351 height = lyxrc.geometry_height;
353 // if lyxrc returns (0,0), then use session info
355 string val = session().loadSessionInfo("WindowWidth");
357 width = convert<unsigned int>(val);
358 val = session().loadSessionInfo("WindowHeight");
360 height = convert<unsigned int>(val);
361 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
364 // if user wants to restore window position
367 if (lyxrc.geometry_xysaved) {
368 string val = session().loadSessionInfo("WindowPosX");
370 posx = convert<int>(val);
371 val = session().loadSessionInfo("WindowPosY");
373 posy = convert<int>(val);
376 if (geometryOption_) {
380 // create the main window
381 LyXView * view = &theApp->createView(width, height, posx, posy, maximize);
382 ref().addLyXView(view);
385 for_each(files.begin(), files.end(),
386 bind(&LyXView::loadLyXFile, view, _1, true));
388 // if a file is specified, I assume that user wants to edit *that* file
389 if (files.empty() && lyxrc.load_session) {
390 vector<string> const & lastopened = session_->lastOpenedFiles();
391 // do not add to the lastfile list since these files are restored from
392 // last seesion, and should be already there (regular files), or should
393 // not be added at all (help files).
394 for_each(lastopened.begin(), lastopened.end(),
395 bind(&LyXView::loadLyXFile, view, _1, false));
397 // clear this list to save a few bytes of RAM
398 session_->clearLastOpenedFiles();
400 return theApp->start(batch_command);
402 // Something went wrong above
412 The SIGHUP signal does not exist on Windows and does not need to be handled.
414 Windows handles SIGFPE and SIGSEGV signals as expected.
416 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
417 cause a new thread to be spawned. This may well result in unexpected
418 behaviour by the single-threaded LyX.
420 SIGTERM signals will come only from another process actually sending
421 that signal using 'raise' in Windows' POSIX compatability layer. It will
422 not come from the general "terminate process" methods that everyone
423 actually uses (and which can't be trapped). Killing an app 'politely' on
424 Windows involves first sending a WM_CLOSE message, something that is
425 caught already by the Qt frontend.
427 For more information see:
429 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
430 ...signals are mostly useless on Windows for a variety of reasons that are
433 'UNIX Application Migration Guide, Chapter 9'
434 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
436 'How To Terminate an Application "Cleanly" in Win32'
437 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
441 static void error_handler(int err_sig)
443 // Throw away any signals other than the first one received.
444 static sig_atomic_t handling_error = false;
447 handling_error = true;
449 // We have received a signal indicating a fatal error, so
450 // try and save the data ASAP.
451 LyX::cref().emergencyCleanup();
453 // These lyxerr calls may or may not work:
455 // Signals are asynchronous, so the main program may be in a very
456 // fragile state when a signal is processed and thus while a signal
457 // handler function executes.
458 // In general, therefore, we should avoid performing any
459 // I/O operations or calling most library and system functions from
462 // This shouldn't matter here, however, as we've already invoked
467 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
471 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
474 lyxerr << "\nlyx: SIGSEGV signal caught\n"
475 "Sorry, you have found a bug in LyX. "
476 "Please read the bug-reporting instructions "
477 "in Help->Introduction and send us a bug report, "
478 "if necessary. Thanks !\nBye." << endl;
486 // Deinstall the signal handlers
488 signal(SIGHUP, SIG_DFL);
490 signal(SIGINT, SIG_DFL);
491 signal(SIGFPE, SIG_DFL);
492 signal(SIGSEGV, SIG_DFL);
493 signal(SIGTERM, SIG_DFL);
496 if (err_sig == SIGSEGV ||
497 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
499 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
501 lyx::support::abort();
508 void LyX::printError(ErrorItem const & ei)
510 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
512 std::cerr << lyx::to_utf8(tmp) << std::endl;
519 signal(SIGHUP, error_handler);
521 signal(SIGFPE, error_handler);
522 signal(SIGSEGV, error_handler);
523 signal(SIGINT, error_handler);
524 signal(SIGTERM, error_handler);
525 // SIGPIPE can be safely ignored.
527 lyxrc.tempdir_path = package().temp_dir();
528 lyxrc.document_path = package().document_dir();
530 if (lyxrc.template_path.empty()) {
531 lyxrc.template_path = addPath(package().system_support(),
535 if (lyxrc.roman_font_name.empty())
536 lyxrc.roman_font_name =
537 lyx::use_gui? theApp->romanFontName(): "serif";
539 if (lyxrc.sans_font_name.empty())
540 lyxrc.sans_font_name =
541 lyx::use_gui? theApp->sansFontName(): "sans";
543 if (lyxrc.typewriter_font_name.empty())
544 lyxrc.typewriter_font_name =
545 lyx::use_gui? theApp->typewriterFontName(): "monospace";
548 // Read configuration files
551 // This one may have been distributed along with LyX.
552 if (!readRcFile("lyxrc.dist"))
555 // Set the PATH correctly.
556 #if !defined (USE_POSIX_PACKAGING)
557 // Add the directory containing the LyX executable to the path
558 // so that LyX can find things like tex2lyx.
559 if (package().build_support().empty())
560 prependEnvPath("PATH", package().binary_dir());
562 if (!lyxrc.path_prefix.empty())
563 prependEnvPath("PATH", lyxrc.path_prefix);
565 // Check that user LyX directory is ok.
566 if (queryUserLyXDir(package().explicit_user_support()))
567 reconfigureUserLyXDir();
569 // no need for a splash when there is no GUI
574 // This one is generated in user_support directory by lib/configure.py.
575 if (!readRcFile("lyxrc.defaults"))
578 // Query the OS to know what formats are viewed natively
579 formats.setAutoOpen();
581 system_lyxrc = lyxrc;
582 system_formats = formats;
583 system_converters = converters;
584 system_movers = movers;
585 system_lcolor = lcolor;
587 // This one is edited through the preferences dialog.
588 if (!readRcFile("preferences"))
591 if (!readEncodingsFile("encodings"))
593 if (!readLanguagesFile("languages"))
597 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
603 toplevel_keymap.reset(new kb_keymap);
604 defaultKeyBindings(toplevel_keymap.get());
605 toplevel_keymap->read(lyxrc.bind_file);
608 if (!readUIFile(lyxrc.ui_file))
612 if (lyxerr.debugging(Debug::LYXRC))
615 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
616 if (!lyxrc.path_prefix.empty())
617 prependEnvPath("PATH", lyxrc.path_prefix);
619 if (fs::exists(lyxrc.document_path) &&
620 fs::is_directory(lyxrc.document_path))
621 package().document_dir() = lyxrc.document_path;
623 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
624 if (package().temp_dir().empty()) {
625 Alert::error(_("Could not create temporary directory"),
626 bformat(_("Could not create a temporary directory in\n"
627 "%1$s. Make sure that this\n"
628 "path exists and is writable and try again."),
629 lyx::from_utf8(lyxrc.tempdir_path)));
630 // createLyXTmpDir() tries sufficiently hard to create a
631 // usable temp dir, so the probability to come here is
632 // close to zero. We therefore don't try to overcome this
633 // problem with e.g. asking the user for a new path and
634 // trying again but simply exit.
638 if (lyxerr.debugging(Debug::INIT)) {
639 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
642 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
643 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
648 void LyX::defaultKeyBindings(kb_keymap * kbmap)
650 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
651 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
652 kbmap->bind("Up", FuncRequest(LFUN_UP));
653 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
655 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
656 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
657 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
658 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
660 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
661 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
662 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
663 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
665 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
666 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
668 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
669 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
671 // kbmap->bindings to enable the use of the numeric keypad
673 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
674 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
675 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
676 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
677 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
678 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
679 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
680 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
681 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
682 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
683 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
684 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
685 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
686 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
687 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
688 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
689 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
690 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
691 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
692 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
693 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
694 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
695 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
696 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
700 void LyX::emergencyCleanup() const
702 // what to do about tmpfiles is non-obvious. we would
703 // like to delete any we find, but our lyxdir might
704 // contain documents etc. which might be helpful on
707 theBufferList().emergencyWriteAll();
708 theApp->server().emergencyCleanup();
712 void LyX::deadKeyBindings(kb_keymap * kbmap)
714 // bindKeyings for transparent handling of deadkeys
715 // The keysyms are gotten from XFree86 X11R6
716 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
717 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
718 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
719 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
720 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
721 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
722 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
723 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
724 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
725 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
726 // nothing with this name
727 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
728 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
729 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
730 // nothing with this name either...
731 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
732 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
733 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
734 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
740 // return true if file does not exist or is older than configure.py.
741 bool needsUpdate(string const & file)
743 static string const configure_script =
744 addName(package().system_support(), "configure.py");
745 string const absfile =
746 addName(package().user_support(), file);
748 return (! fs::exists(absfile))
749 || (fs::last_write_time(configure_script)
750 > fs::last_write_time(absfile));
756 bool LyX::queryUserLyXDir(bool explicit_userdir)
758 // Does user directory exist?
759 if (fs::exists(package().user_support()) &&
760 fs::is_directory(package().user_support())) {
763 return needsUpdate("lyxrc.defaults")
764 || needsUpdate("textclass.lst")
765 || needsUpdate("packages.lst");
768 first_start = !explicit_userdir;
770 // If the user specified explicitly a directory, ask whether
771 // to create it. If the user says "no", then exit.
772 if (explicit_userdir &&
774 _("Missing user LyX directory"),
775 bformat(_("You have specified a non-existent user "
776 "LyX directory, %1$s.\n"
777 "It is needed to keep your own configuration."),
778 lyx::from_utf8(package().user_support())),
780 _("&Create directory"),
782 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
783 lyx_exit(EXIT_FAILURE);
786 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
787 lyx::from_utf8(package().user_support())))
790 if (!createDirectory(package().user_support(), 0755)) {
791 // Failed, so let's exit.
792 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
794 lyx_exit(EXIT_FAILURE);
801 bool LyX::readRcFile(string const & name)
803 lyxerr[Debug::INIT] << "About to read " << name << "... ";
805 string const lyxrc_path = libFileSearch(string(), name);
806 if (!lyxrc_path.empty()) {
808 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
810 if (lyxrc.read(lyxrc_path) < 0) {
815 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
821 // Read the ui file `name'
822 bool LyX::readUIFile(string const & name)
832 struct keyword_item uitags[ui_last - 1] = {
833 { "include", ui_include },
834 { "menuset", ui_menuset },
835 { "toolbar", ui_toolbar },
836 { "toolbars", ui_toolbars }
839 // Ensure that a file is read only once (prevents include loops)
840 static std::list<string> uifiles;
841 std::list<string>::const_iterator it = uifiles.begin();
842 std::list<string>::const_iterator end = uifiles.end();
843 it = std::find(it, end, name);
845 lyxerr[Debug::INIT] << "UI file '" << name
846 << "' has been read already. "
847 << "Is this an include loop?"
852 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
854 string const ui_path = libFileSearch("ui", name, "ui");
856 if (ui_path.empty()) {
857 lyxerr[Debug::INIT] << "Could not find " << name << endl;
861 uifiles.push_back(name);
863 lyxerr[Debug::INIT] << "Found " << name
864 << " in " << ui_path << endl;
865 LyXLex lex(uitags, ui_last - 1);
866 lex.setFile(ui_path);
868 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
872 if (lyxerr.debugging(Debug::PARSER))
873 lex.printTable(lyxerr);
879 string const file = lex.getString();
880 if (!readUIFile(file))
885 menubackend.read(lex);
889 toolbarbackend.read(lex);
893 toolbarbackend.readToolbars(lex);
897 if (!rtrim(lex.getString()).empty())
898 lex.printError("LyX::ReadUIFile: "
899 "Unknown menu tag: `$$Token'");
907 // Read the languages file `name'
908 bool LyX::readLanguagesFile(string const & name)
910 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
912 string const lang_path = libFileSearch(string(), name);
913 if (lang_path.empty()) {
917 languages.read(lang_path);
922 // Read the encodings file `name'
923 bool LyX::readEncodingsFile(string const & name)
925 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
927 string const enc_path = libFileSearch(string(), name);
928 if (enc_path.empty()) {
932 encodings.read(enc_path);
941 /// return the the number of arguments consumed
942 typedef boost::function<int(string const &, string const &)> cmd_helper;
944 int parse_dbg(string const & arg, string const &)
947 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
948 Debug::showTags(lyxerr);
951 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
953 lyxerr.level(Debug::value(arg));
954 Debug::showLevel(lyxerr, lyxerr.level());
959 int parse_help(string const &, string const &)
962 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
963 "Command line switches (case sensitive):\n"
964 "\t-help summarize LyX usage\n"
965 "\t-userdir dir set user directory to dir\n"
966 "\t-sysdir dir set system directory to dir\n"
967 "\t-geometry WxH+X+Y set geometry of the main window\n"
968 "\t-dbg feature[,feature]...\n"
969 " select the features to debug.\n"
970 " Type `lyx -dbg' to see the list of features\n"
971 "\t-x [--execute] command\n"
972 " where command is a lyx command.\n"
973 "\t-e [--export] fmt\n"
974 " where fmt is the export format of choice.\n"
975 "\t-i [--import] fmt file.xxx\n"
976 " where fmt is the import format of choice\n"
977 " and file.xxx is the file to be imported.\n"
978 "\t-version summarize version and build info\n"
979 "Check the LyX man page for more details.")) << endl;
984 int parse_version(string const &, string const &)
986 lyxerr << "LyX " << lyx_version
987 << " (" << lyx_release_date << ")" << endl;
988 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
990 lyxerr << lyx_version_info << endl;
995 int parse_sysdir(string const & arg, string const &)
998 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
1001 cl_system_support = arg;
1005 int parse_userdir(string const & arg, string const &)
1008 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
1011 cl_user_support = arg;
1015 int parse_execute(string const & arg, string const &)
1018 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
1025 int parse_export(string const & type, string const &)
1028 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1029 "--export switch")) << endl;
1032 batch = "buffer-export " + type;
1033 lyx::use_gui = true;
1037 int parse_import(string const & type, string const & file)
1040 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1041 "--import switch")) << endl;
1045 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1049 batch = "buffer-import " + type + ' ' + file;
1056 void LyX::easyParse(int & argc, char * argv[])
1058 std::map<string, cmd_helper> cmdmap;
1060 cmdmap["-dbg"] = parse_dbg;
1061 cmdmap["-help"] = parse_help;
1062 cmdmap["--help"] = parse_help;
1063 cmdmap["-version"] = parse_version;
1064 cmdmap["--version"] = parse_version;
1065 cmdmap["-sysdir"] = parse_sysdir;
1066 cmdmap["-userdir"] = parse_userdir;
1067 cmdmap["-x"] = parse_execute;
1068 cmdmap["--execute"] = parse_execute;
1069 cmdmap["-e"] = parse_export;
1070 cmdmap["--export"] = parse_export;
1071 cmdmap["-i"] = parse_import;
1072 cmdmap["--import"] = parse_import;
1074 for (int i = 1; i < argc; ++i) {
1075 std::map<string, cmd_helper>::const_iterator it
1076 = cmdmap.find(argv[i]);
1078 // check for X11 -geometry option
1079 if (lyx::support::compare(argv[i], "-geometry") == 0)
1080 geometryOption_ = true;
1082 // don't complain if not found - may be parsed later
1083 if (it == cmdmap.end())
1086 string arg((i + 1 < argc) ? argv[i + 1] : "");
1087 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1089 int const remove = 1 + it->second(arg, arg2);
1091 // Now, remove used arguments by shifting
1092 // the following ones remove places down.
1094 for (int j = i; j < argc; ++j)
1095 argv[j] = argv[j + remove];
1099 batch_command = batch;