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::destroyDir;
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;
100 lyx::frontend::Application * theApp = 0;
104 /// are we using the GUI at all?
106 * We default to true and this is changed to false when the export feature is used.
114 // Filled with the command line arguments "foo" of "-sysdir foo" or
116 string cl_system_support;
117 string cl_user_support;
120 void showFileError(string const & error)
122 Alert::warning(_("Could not read configuration file"),
123 bformat(_("Error while reading the configuration file\n%1$s.\n"
124 "Please check your installation."), lyx::from_utf8(error)));
128 void reconfigureUserLyXDir()
130 string const configure_command = package().configure_command();
132 lyxerr << lyx::to_utf8(_("LyX: reconfiguring user directory")) << endl;
133 lyx::support::Path p(package().user_support());
135 one.startscript(Systemcall::Wait, configure_command);
136 lyxerr << "LyX: " << lyx::to_utf8(_("Done!")) << endl;
142 boost::scoped_ptr<LyX> LyX::singleton_;
144 int LyX::exec(int & argc, char * argv[])
146 BOOST_ASSERT(!singleton_.get());
147 // We must return from this before launching the gui so that
148 // other parts of the code can access singleton_ through
149 // LyX::ref and LyX::cref.
150 singleton_.reset(new LyX);
151 // Start the real execution loop.
152 return singleton_->priv_exec(argc, argv);
158 BOOST_ASSERT(singleton_.get());
159 return *singleton_.get();
163 LyX const & LyX::cref()
165 BOOST_ASSERT(singleton_.get());
166 return *singleton_.get();
170 BufferList & theBufferList()
172 return LyX::ref().bufferList();
177 : first_start(false), geometryOption_(false)
179 buffer_list_.reset(new BufferList);
183 BufferList & LyX::bufferList()
185 return *buffer_list_.get();
189 BufferList const & LyX::bufferList() const
191 return *buffer_list_.get();
195 lyx::Session & LyX::session()
197 BOOST_ASSERT(session_.get());
198 return *session_.get();
202 lyx::Session const & LyX::session() const
204 BOOST_ASSERT(session_.get());
205 return *session_.get();
209 void LyX::addLyXView(LyXView * lyxview)
211 views_.push_back(lyxview);
215 Buffer const * const LyX::updateInset(InsetBase const * inset) const
220 Buffer const * buffer_ptr = 0;
221 ViewList::const_iterator it = views_.begin();
222 ViewList::const_iterator const end = views_.end();
223 for (; it != end; ++it) {
224 Buffer const * ptr = (*it)->updateInset(inset);
232 int LyX::priv_exec(int & argc, char * argv[])
234 // Here we need to parse the command line. At least
235 // we need to parse for "-dbg" and "-help"
236 easyParse(argc, argv);
238 lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
239 lyx::support::top_build_dir_is_one_level_up);
241 vector<string> files;
242 int exit_status = execBatchCommands(argc, argv, files);
248 // Force adding of font path _before_ Application is initialized
249 lyx::support::addFontResources();
250 application_.reset(lyx::createApplication(argc, argv));
252 // FIXME: this global pointer should probably go.
253 theApp = application_.get();
254 restoreGuiSession(files);
255 // Start the real execution loop.
256 exit_status = application_->start(batch_command);
257 // Kill the application object before exiting. This avoid crash
259 application_.reset();
260 // Restore original font resources after Application is destroyed.
261 lyx::support::restoreFontResources();
264 // FIXME: create a ConsoleApplication
272 void LyX::prepareExit()
274 // Set a flag that we do quitting from the program,
275 // so no refreshes are necessary.
278 // close buffers first
279 buffer_list_->closeAll();
281 // do any other cleanup procedures now
282 lyxerr[Debug::INFO] << "Deleting tmp dir " << package().temp_dir() << endl;
284 if (!destroyDir(package().temp_dir())) {
285 docstring const msg =
286 bformat(_("Unable to remove the temporary directory %1$s"),
287 lyx::from_utf8(package().temp_dir()));
288 Alert::warning(_("Unable to remove temporary directory"), msg);
293 void LyX::earlyExit(int status)
295 BOOST_ASSERT(application_.get());
296 // LyX::application_ is not initialised at this
297 // point so it's safe to just exit after some cleanup.
303 void LyX::quit(bool noask)
305 lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
308 if (!noask && !buffer_list_->quitWriteAll())
311 session_->writeFile();
317 application_->exit(0);
322 int LyX::execBatchCommands(int & argc, char * argv[],
323 vector<string> & files)
325 // check for any spurious extra arguments
326 // other than documents
327 for (int argi = 1; argi < argc ; ++argi) {
328 if (argv[argi][0] == '-') {
329 lyxerr << lyx::to_utf8(
330 bformat(_("Wrong command line option `%1$s'. Exiting."),
331 lyx::from_utf8(argv[argi]))) << endl;
336 // Initialization of LyX (reads lyxrc and more)
337 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
338 bool success = init();
339 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
343 for (int argi = argc - 1; argi >= 1; --argi)
344 files.push_back(os::internal_path(argv[argi]));
347 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
349 // Execute batch commands if available
350 if (!batch_command.empty()) {
352 lyxerr[Debug::INIT] << "About to handle -x '"
353 << batch_command << '\'' << endl;
355 Buffer * last_loaded = 0;
357 vector<string>::const_iterator it = files.begin();
358 vector<string>::const_iterator end = files.end();
360 for (; it != end; ++it) {
361 // get absolute path of file and add ".lyx" to
362 // the filename if necessary
363 string s = fileSearch(string(), *it, "lyx");
365 Buffer * const b = newFile(*it, string(), true);
369 Buffer * buf = buffer_list_->newBuffer(s, false);
370 if (loadLyXFile(buf, s)) {
372 ErrorList const & el = buf->errorList("Parse");
374 for_each(el.begin(), el.end(),
375 boost::bind(&LyX::printError, this, _1));
378 buffer_list_->release(buf);
382 // try to dispatch to last loaded buffer first
385 if (last_loaded->dispatch(batch_command, &success)) {
390 files.clear(); // the files are already loaded
397 void LyX::restoreGuiSession(vector<string> const & files)
399 // determine windows size and position, from lyxrc and/or session
401 unsigned int width = 690;
402 unsigned int height = 510;
403 bool maximize = false;
405 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
406 width = lyxrc.geometry_width;
407 height = lyxrc.geometry_height;
409 // if lyxrc returns (0,0), then use session info
411 string val = session().loadSessionInfo("WindowWidth");
413 width = convert<unsigned int>(val);
414 val = session().loadSessionInfo("WindowHeight");
416 height = convert<unsigned int>(val);
417 if (session().loadSessionInfo("WindowIsMaximized") == "yes")
420 // if user wants to restore window position
423 if (lyxrc.geometry_xysaved) {
424 string val = session().loadSessionInfo("WindowPosX");
426 posx = convert<int>(val);
427 val = session().loadSessionInfo("WindowPosY");
429 posy = convert<int>(val);
432 if (geometryOption_) {
436 // create the main window
437 LyXView * view = &application_->createView(width, height, posx, posy, maximize);
438 ref().addLyXView(view);
441 for_each(files.begin(), files.end(),
442 bind(&LyXView::loadLyXFile, view, _1, true));
444 // if a file is specified, I assume that user wants to edit *that* file
445 if (files.empty() && lyxrc.load_session) {
446 vector<string> const & lastopened = session_->lastOpenedFiles();
447 // do not add to the lastfile list since these files are restored from
448 // last seesion, and should be already there (regular files), or should
449 // not be added at all (help files).
450 for_each(lastopened.begin(), lastopened.end(),
451 bind(&LyXView::loadLyXFile, view, _1, false));
453 // clear this list to save a few bytes of RAM
454 session_->clearLastOpenedFiles();
461 The SIGHUP signal does not exist on Windows and does not need to be handled.
463 Windows handles SIGFPE and SIGSEGV signals as expected.
465 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
466 cause a new thread to be spawned. This may well result in unexpected
467 behaviour by the single-threaded LyX.
469 SIGTERM signals will come only from another process actually sending
470 that signal using 'raise' in Windows' POSIX compatability layer. It will
471 not come from the general "terminate process" methods that everyone
472 actually uses (and which can't be trapped). Killing an app 'politely' on
473 Windows involves first sending a WM_CLOSE message, something that is
474 caught already by the Qt frontend.
476 For more information see:
478 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
479 ...signals are mostly useless on Windows for a variety of reasons that are
482 'UNIX Application Migration Guide, Chapter 9'
483 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
485 'How To Terminate an Application "Cleanly" in Win32'
486 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
490 static void error_handler(int err_sig)
492 // Throw away any signals other than the first one received.
493 static sig_atomic_t handling_error = false;
496 handling_error = true;
498 // We have received a signal indicating a fatal error, so
499 // try and save the data ASAP.
500 LyX::cref().emergencyCleanup();
502 // These lyxerr calls may or may not work:
504 // Signals are asynchronous, so the main program may be in a very
505 // fragile state when a signal is processed and thus while a signal
506 // handler function executes.
507 // In general, therefore, we should avoid performing any
508 // I/O operations or calling most library and system functions from
511 // This shouldn't matter here, however, as we've already invoked
516 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
520 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
523 lyxerr << "\nlyx: SIGSEGV signal caught\n"
524 "Sorry, you have found a bug in LyX. "
525 "Please read the bug-reporting instructions "
526 "in Help->Introduction and send us a bug report, "
527 "if necessary. Thanks !\nBye." << endl;
535 // Deinstall the signal handlers
537 signal(SIGHUP, SIG_DFL);
539 signal(SIGINT, SIG_DFL);
540 signal(SIGFPE, SIG_DFL);
541 signal(SIGSEGV, SIG_DFL);
542 signal(SIGTERM, SIG_DFL);
545 if (err_sig == SIGSEGV ||
546 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
548 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
550 lyx::support::abort();
557 void LyX::printError(ErrorItem const & ei)
559 docstring tmp = _("LyX: ") + ei.error + lyx::char_type(':')
561 std::cerr << lyx::to_utf8(tmp) << std::endl;
565 void LyX::initGuiFont()
567 if (lyxrc.roman_font_name.empty())
568 lyxrc.roman_font_name = application_->romanFontName();
570 if (lyxrc.sans_font_name.empty())
571 lyxrc.sans_font_name = application_->sansFontName();
573 if (lyxrc.typewriter_font_name.empty())
574 lyxrc.typewriter_font_name
575 = application_->typewriterFontName();
582 signal(SIGHUP, error_handler);
584 signal(SIGFPE, error_handler);
585 signal(SIGSEGV, error_handler);
586 signal(SIGINT, error_handler);
587 signal(SIGTERM, error_handler);
588 // SIGPIPE can be safely ignored.
590 lyxrc.tempdir_path = package().temp_dir();
591 lyxrc.document_path = package().document_dir();
593 if (lyxrc.template_path.empty()) {
594 lyxrc.template_path = addPath(package().system_support(),
599 // Read configuration files
602 // This one may have been distributed along with LyX.
603 if (!readRcFile("lyxrc.dist"))
606 // Set the PATH correctly.
607 #if !defined (USE_POSIX_PACKAGING)
608 // Add the directory containing the LyX executable to the path
609 // so that LyX can find things like tex2lyx.
610 if (package().build_support().empty())
611 prependEnvPath("PATH", package().binary_dir());
613 if (!lyxrc.path_prefix.empty())
614 prependEnvPath("PATH", lyxrc.path_prefix);
616 // Check that user LyX directory is ok.
617 if (queryUserLyXDir(package().explicit_user_support()))
618 reconfigureUserLyXDir();
620 // no need for a splash when there is no GUI
625 // This one is generated in user_support directory by lib/configure.py.
626 if (!readRcFile("lyxrc.defaults"))
629 // Query the OS to know what formats are viewed natively
630 formats.setAutoOpen();
632 system_lyxrc = lyxrc;
633 system_formats = formats;
634 system_converters = converters;
635 system_movers = movers;
636 system_lcolor = lcolor;
638 // This one is edited through the preferences dialog.
639 if (!readRcFile("preferences"))
642 if (!readEncodingsFile("encodings"))
644 if (!readLanguagesFile("languages"))
648 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
654 toplevel_keymap.reset(new kb_keymap);
655 defaultKeyBindings(toplevel_keymap.get());
656 toplevel_keymap->read(lyxrc.bind_file);
659 if (!readUIFile(lyxrc.ui_file))
663 if (lyxerr.debugging(Debug::LYXRC))
666 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
667 if (!lyxrc.path_prefix.empty())
668 prependEnvPath("PATH", lyxrc.path_prefix);
670 if (fs::exists(lyxrc.document_path) &&
671 fs::is_directory(lyxrc.document_path))
672 package().document_dir() = lyxrc.document_path;
674 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
675 if (package().temp_dir().empty()) {
676 Alert::error(_("Could not create temporary directory"),
677 bformat(_("Could not create a temporary directory in\n"
678 "%1$s. Make sure that this\n"
679 "path exists and is writable and try again."),
680 lyx::from_utf8(lyxrc.tempdir_path)));
681 // createLyXTmpDir() tries sufficiently hard to create a
682 // usable temp dir, so the probability to come here is
683 // close to zero. We therefore don't try to overcome this
684 // problem with e.g. asking the user for a new path and
685 // trying again but simply exit.
689 if (lyxerr.debugging(Debug::INIT)) {
690 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
693 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
694 session_.reset(new lyx::Session(lyxrc.num_lastfiles));
699 void LyX::defaultKeyBindings(kb_keymap * kbmap)
701 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
702 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
703 kbmap->bind("Up", FuncRequest(LFUN_UP));
704 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
706 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
707 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
708 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
709 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
711 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
712 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
713 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
714 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
716 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
717 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
719 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
720 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
722 // kbmap->bindings to enable the use of the numeric keypad
724 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
725 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
726 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
727 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
728 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
729 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
730 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
731 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
732 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
733 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
734 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
735 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
736 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
737 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
738 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
739 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
740 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
741 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
742 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
743 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
744 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
745 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
746 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
747 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
751 void LyX::emergencyCleanup() const
753 // what to do about tmpfiles is non-obvious. we would
754 // like to delete any we find, but our lyxdir might
755 // contain documents etc. which might be helpful on
758 buffer_list_->emergencyWriteAll();
760 application_->server().emergencyCleanup();
764 void LyX::deadKeyBindings(kb_keymap * kbmap)
766 // bindKeyings for transparent handling of deadkeys
767 // The keysyms are gotten from XFree86 X11R6
768 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
769 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
770 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
771 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
772 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
773 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
774 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
775 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
776 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
777 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
778 // nothing with this name
779 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
780 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
781 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
782 // nothing with this name either...
783 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
784 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
785 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
786 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
792 // return true if file does not exist or is older than configure.py.
793 bool needsUpdate(string const & file)
795 static string const configure_script =
796 addName(package().system_support(), "configure.py");
797 string const absfile =
798 addName(package().user_support(), file);
800 return (! fs::exists(absfile))
801 || (fs::last_write_time(configure_script)
802 > fs::last_write_time(absfile));
808 bool LyX::queryUserLyXDir(bool explicit_userdir)
810 // Does user directory exist?
811 if (fs::exists(package().user_support()) &&
812 fs::is_directory(package().user_support())) {
815 return needsUpdate("lyxrc.defaults")
816 || needsUpdate("textclass.lst")
817 || needsUpdate("packages.lst");
820 first_start = !explicit_userdir;
822 // If the user specified explicitly a directory, ask whether
823 // to create it. If the user says "no", then exit.
824 if (explicit_userdir &&
826 _("Missing user LyX directory"),
827 bformat(_("You have specified a non-existent user "
828 "LyX directory, %1$s.\n"
829 "It is needed to keep your own configuration."),
830 lyx::from_utf8(package().user_support())),
832 _("&Create directory"),
834 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
835 earlyExit(EXIT_FAILURE);
838 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
839 lyx::from_utf8(package().user_support())))
842 if (!createDirectory(package().user_support(), 0755)) {
843 // Failed, so let's exit.
844 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
846 earlyExit(EXIT_FAILURE);
853 bool LyX::readRcFile(string const & name)
855 lyxerr[Debug::INIT] << "About to read " << name << "... ";
857 string const lyxrc_path = libFileSearch(string(), name);
858 if (!lyxrc_path.empty()) {
860 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
862 if (lyxrc.read(lyxrc_path) < 0) {
867 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
873 // Read the ui file `name'
874 bool LyX::readUIFile(string const & name)
884 struct keyword_item uitags[ui_last - 1] = {
885 { "include", ui_include },
886 { "menuset", ui_menuset },
887 { "toolbar", ui_toolbar },
888 { "toolbars", ui_toolbars }
891 // Ensure that a file is read only once (prevents include loops)
892 static std::list<string> uifiles;
893 std::list<string>::const_iterator it = uifiles.begin();
894 std::list<string>::const_iterator end = uifiles.end();
895 it = std::find(it, end, name);
897 lyxerr[Debug::INIT] << "UI file '" << name
898 << "' has been read already. "
899 << "Is this an include loop?"
904 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
906 string const ui_path = libFileSearch("ui", name, "ui");
908 if (ui_path.empty()) {
909 lyxerr[Debug::INIT] << "Could not find " << name << endl;
913 uifiles.push_back(name);
915 lyxerr[Debug::INIT] << "Found " << name
916 << " in " << ui_path << endl;
917 LyXLex lex(uitags, ui_last - 1);
918 lex.setFile(ui_path);
920 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
924 if (lyxerr.debugging(Debug::PARSER))
925 lex.printTable(lyxerr);
931 string const file = lex.getString();
932 if (!readUIFile(file))
937 menubackend.read(lex);
941 toolbarbackend.read(lex);
945 toolbarbackend.readToolbars(lex);
949 if (!rtrim(lex.getString()).empty())
950 lex.printError("LyX::ReadUIFile: "
951 "Unknown menu tag: `$$Token'");
959 // Read the languages file `name'
960 bool LyX::readLanguagesFile(string const & name)
962 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
964 string const lang_path = libFileSearch(string(), name);
965 if (lang_path.empty()) {
969 languages.read(lang_path);
974 // Read the encodings file `name'
975 bool LyX::readEncodingsFile(string const & name)
977 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
979 string const enc_path = libFileSearch(string(), name);
980 if (enc_path.empty()) {
984 encodings.read(enc_path);
993 /// return the the number of arguments consumed
994 typedef boost::function<int(string const &, string const &)> cmd_helper;
996 int parse_dbg(string const & arg, string const &)
999 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
1000 Debug::showTags(lyxerr);
1003 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
1005 lyxerr.level(Debug::value(arg));
1006 Debug::showLevel(lyxerr, lyxerr.level());
1011 int parse_help(string const &, string const &)
1014 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1015 "Command line switches (case sensitive):\n"
1016 "\t-help summarize LyX usage\n"
1017 "\t-userdir dir set user directory to dir\n"
1018 "\t-sysdir dir set system directory to dir\n"
1019 "\t-geometry WxH+X+Y set geometry of the main window\n"
1020 "\t-dbg feature[,feature]...\n"
1021 " select the features to debug.\n"
1022 " Type `lyx -dbg' to see the list of features\n"
1023 "\t-x [--execute] command\n"
1024 " where command is a lyx command.\n"
1025 "\t-e [--export] fmt\n"
1026 " where fmt is the export format of choice.\n"
1027 "\t-i [--import] fmt file.xxx\n"
1028 " where fmt is the import format of choice\n"
1029 " and file.xxx is the file to be imported.\n"
1030 "\t-version summarize version and build info\n"
1031 "Check the LyX man page for more details.")) << endl;
1036 int parse_version(string const &, string const &)
1038 lyxerr << "LyX " << lyx_version
1039 << " (" << lyx_release_date << ")" << endl;
1040 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1042 lyxerr << lyx_version_info << endl;
1047 int parse_sysdir(string const & arg, string const &)
1050 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
1053 cl_system_support = arg;
1057 int parse_userdir(string const & arg, string const &)
1060 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
1063 cl_user_support = arg;
1067 int parse_execute(string const & arg, string const &)
1070 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
1077 int parse_export(string const & type, string const &)
1080 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1081 "--export switch")) << endl;
1084 batch = "buffer-export " + type;
1085 lyx::use_gui = false;
1089 int parse_import(string const & type, string const & file)
1092 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1093 "--import switch")) << endl;
1097 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1101 batch = "buffer-import " + type + ' ' + file;
1108 void LyX::easyParse(int & argc, char * argv[])
1110 std::map<string, cmd_helper> cmdmap;
1112 cmdmap["-dbg"] = parse_dbg;
1113 cmdmap["-help"] = parse_help;
1114 cmdmap["--help"] = parse_help;
1115 cmdmap["-version"] = parse_version;
1116 cmdmap["--version"] = parse_version;
1117 cmdmap["-sysdir"] = parse_sysdir;
1118 cmdmap["-userdir"] = parse_userdir;
1119 cmdmap["-x"] = parse_execute;
1120 cmdmap["--execute"] = parse_execute;
1121 cmdmap["-e"] = parse_export;
1122 cmdmap["--export"] = parse_export;
1123 cmdmap["-i"] = parse_import;
1124 cmdmap["--import"] = parse_import;
1126 for (int i = 1; i < argc; ++i) {
1127 std::map<string, cmd_helper>::const_iterator it
1128 = cmdmap.find(argv[i]);
1130 // check for X11 -geometry option
1131 if (lyx::support::compare(argv[i], "-geometry") == 0)
1132 geometryOption_ = true;
1134 // don't complain if not found - may be parsed later
1135 if (it == cmdmap.end())
1138 string arg((i + 1 < argc) ? argv[i + 1] : "");
1139 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1141 int const remove = 1 + it->second(arg, arg2);
1143 // Now, remove used arguments by shifting
1144 // the following ones remove places down.
1146 for (int j = i; j < argc; ++j)
1147 argv[j] = argv[j + remove];
1151 batch_command = batch;