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();
759 application_->server().emergencyCleanup();
763 void LyX::deadKeyBindings(kb_keymap * kbmap)
765 // bindKeyings for transparent handling of deadkeys
766 // The keysyms are gotten from XFree86 X11R6
767 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
768 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
769 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
770 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
771 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
772 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
773 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
774 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
775 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
776 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
777 // nothing with this name
778 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
779 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
780 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
781 // nothing with this name either...
782 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
783 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
784 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
785 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
791 // return true if file does not exist or is older than configure.py.
792 bool needsUpdate(string const & file)
794 static string const configure_script =
795 addName(package().system_support(), "configure.py");
796 string const absfile =
797 addName(package().user_support(), file);
799 return (! fs::exists(absfile))
800 || (fs::last_write_time(configure_script)
801 > fs::last_write_time(absfile));
807 bool LyX::queryUserLyXDir(bool explicit_userdir)
809 // Does user directory exist?
810 if (fs::exists(package().user_support()) &&
811 fs::is_directory(package().user_support())) {
814 return needsUpdate("lyxrc.defaults")
815 || needsUpdate("textclass.lst")
816 || needsUpdate("packages.lst");
819 first_start = !explicit_userdir;
821 // If the user specified explicitly a directory, ask whether
822 // to create it. If the user says "no", then exit.
823 if (explicit_userdir &&
825 _("Missing user LyX directory"),
826 bformat(_("You have specified a non-existent user "
827 "LyX directory, %1$s.\n"
828 "It is needed to keep your own configuration."),
829 lyx::from_utf8(package().user_support())),
831 _("&Create directory"),
833 lyxerr << lyx::to_utf8(_("No user LyX directory. Exiting.")) << endl;
834 earlyExit(EXIT_FAILURE);
837 lyxerr << lyx::to_utf8(bformat(_("LyX: Creating directory %1$s"),
838 lyx::from_utf8(package().user_support())))
841 if (!createDirectory(package().user_support(), 0755)) {
842 // Failed, so let's exit.
843 lyxerr << lyx::to_utf8(_("Failed to create directory. Exiting."))
845 earlyExit(EXIT_FAILURE);
852 bool LyX::readRcFile(string const & name)
854 lyxerr[Debug::INIT] << "About to read " << name << "... ";
856 string const lyxrc_path = libFileSearch(string(), name);
857 if (!lyxrc_path.empty()) {
859 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
861 if (lyxrc.read(lyxrc_path) < 0) {
866 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
872 // Read the ui file `name'
873 bool LyX::readUIFile(string const & name)
883 struct keyword_item uitags[ui_last - 1] = {
884 { "include", ui_include },
885 { "menuset", ui_menuset },
886 { "toolbar", ui_toolbar },
887 { "toolbars", ui_toolbars }
890 // Ensure that a file is read only once (prevents include loops)
891 static std::list<string> uifiles;
892 std::list<string>::const_iterator it = uifiles.begin();
893 std::list<string>::const_iterator end = uifiles.end();
894 it = std::find(it, end, name);
896 lyxerr[Debug::INIT] << "UI file '" << name
897 << "' has been read already. "
898 << "Is this an include loop?"
903 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
905 string const ui_path = libFileSearch("ui", name, "ui");
907 if (ui_path.empty()) {
908 lyxerr[Debug::INIT] << "Could not find " << name << endl;
912 uifiles.push_back(name);
914 lyxerr[Debug::INIT] << "Found " << name
915 << " in " << ui_path << endl;
916 LyXLex lex(uitags, ui_last - 1);
917 lex.setFile(ui_path);
919 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
923 if (lyxerr.debugging(Debug::PARSER))
924 lex.printTable(lyxerr);
930 string const file = lex.getString();
931 if (!readUIFile(file))
936 menubackend.read(lex);
940 toolbarbackend.read(lex);
944 toolbarbackend.readToolbars(lex);
948 if (!rtrim(lex.getString()).empty())
949 lex.printError("LyX::ReadUIFile: "
950 "Unknown menu tag: `$$Token'");
958 // Read the languages file `name'
959 bool LyX::readLanguagesFile(string const & name)
961 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
963 string const lang_path = libFileSearch(string(), name);
964 if (lang_path.empty()) {
968 languages.read(lang_path);
973 // Read the encodings file `name'
974 bool LyX::readEncodingsFile(string const & name)
976 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
978 string const enc_path = libFileSearch(string(), name);
979 if (enc_path.empty()) {
983 encodings.read(enc_path);
992 /// return the the number of arguments consumed
993 typedef boost::function<int(string const &, string const &)> cmd_helper;
995 int parse_dbg(string const & arg, string const &)
998 lyxerr << lyx::to_utf8(_("List of supported debug flags:")) << endl;
999 Debug::showTags(lyxerr);
1002 lyxerr << lyx::to_utf8(bformat(_("Setting debug level to %1$s"), lyx::from_utf8(arg))) << endl;
1004 lyxerr.level(Debug::value(arg));
1005 Debug::showLevel(lyxerr, lyxerr.level());
1010 int parse_help(string const &, string const &)
1013 lyx::to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1014 "Command line switches (case sensitive):\n"
1015 "\t-help summarize LyX usage\n"
1016 "\t-userdir dir set user directory to dir\n"
1017 "\t-sysdir dir set system directory to dir\n"
1018 "\t-geometry WxH+X+Y set geometry of the main window\n"
1019 "\t-dbg feature[,feature]...\n"
1020 " select the features to debug.\n"
1021 " Type `lyx -dbg' to see the list of features\n"
1022 "\t-x [--execute] command\n"
1023 " where command is a lyx command.\n"
1024 "\t-e [--export] fmt\n"
1025 " where fmt is the export format of choice.\n"
1026 "\t-i [--import] fmt file.xxx\n"
1027 " where fmt is the import format of choice\n"
1028 " and file.xxx is the file to be imported.\n"
1029 "\t-version summarize version and build info\n"
1030 "Check the LyX man page for more details.")) << endl;
1035 int parse_version(string const &, string const &)
1037 lyxerr << "LyX " << lyx_version
1038 << " (" << lyx_release_date << ")" << endl;
1039 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1041 lyxerr << lyx_version_info << endl;
1046 int parse_sysdir(string const & arg, string const &)
1049 lyxerr << lyx::to_utf8(_("Missing directory for -sysdir switch")) << endl;
1052 cl_system_support = arg;
1056 int parse_userdir(string const & arg, string const &)
1059 lyxerr << lyx::to_utf8(_("Missing directory for -userdir switch")) << endl;
1062 cl_user_support = arg;
1066 int parse_execute(string const & arg, string const &)
1069 lyxerr << lyx::to_utf8(_("Missing command string after --execute switch")) << endl;
1076 int parse_export(string const & type, string const &)
1079 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1080 "--export switch")) << endl;
1083 batch = "buffer-export " + type;
1084 lyx::use_gui = false;
1088 int parse_import(string const & type, string const & file)
1091 lyxerr << lyx::to_utf8(_("Missing file type [eg latex, ps...] after "
1092 "--import switch")) << endl;
1096 lyxerr << lyx::to_utf8(_("Missing filename for --import")) << endl;
1100 batch = "buffer-import " + type + ' ' + file;
1107 void LyX::easyParse(int & argc, char * argv[])
1109 std::map<string, cmd_helper> cmdmap;
1111 cmdmap["-dbg"] = parse_dbg;
1112 cmdmap["-help"] = parse_help;
1113 cmdmap["--help"] = parse_help;
1114 cmdmap["-version"] = parse_version;
1115 cmdmap["--version"] = parse_version;
1116 cmdmap["-sysdir"] = parse_sysdir;
1117 cmdmap["-userdir"] = parse_userdir;
1118 cmdmap["-x"] = parse_execute;
1119 cmdmap["--execute"] = parse_execute;
1120 cmdmap["-e"] = parse_export;
1121 cmdmap["--export"] = parse_export;
1122 cmdmap["-i"] = parse_import;
1123 cmdmap["--import"] = parse_import;
1125 for (int i = 1; i < argc; ++i) {
1126 std::map<string, cmd_helper>::const_iterator it
1127 = cmdmap.find(argv[i]);
1129 // check for X11 -geometry option
1130 if (lyx::support::compare(argv[i], "-geometry") == 0)
1131 geometryOption_ = true;
1133 // don't complain if not found - may be parsed later
1134 if (it == cmdmap.end())
1137 string arg((i + 1 < argc) ? argv[i + 1] : "");
1138 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1140 int const remove = 1 + it->second(arg, arg2);
1142 // Now, remove used arguments by shifting
1143 // the following ones remove places down.
1145 for (int j = i; j < argc; ++j)
1146 argv[j] = argv[j + remove];
1150 batch_command = batch;