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.
20 #include "LayoutFile.h"
22 #include "BufferList.h"
25 #include "ConverterCache.h"
26 #include "Converter.h"
27 #include "CutAndPaste.h"
29 #include "ErrorList.h"
31 #include "FuncStatus.h"
35 #include "LyXAction.h"
38 #include "ModuleList.h"
41 #include "ServerSocket.h"
44 #include "frontends/alert.h"
45 #include "frontends/Application.h"
47 #include "graphics/Previews.h"
49 #include "support/lassert.h"
50 #include "support/debug.h"
51 #include "support/environment.h"
52 #include "support/ExceptionMessage.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/lstrings.h"
56 #include "support/Messages.h"
57 #include "support/os.h"
58 #include "support/Package.h"
59 #include "support/Path.h"
60 #include "support/Systemcall.h"
62 #include <boost/bind.hpp>
63 #include <boost/scoped_ptr.hpp>
74 using namespace lyx::support;
78 namespace Alert = frontend::Alert;
79 namespace os = support::os;
83 // Are we using the GUI at all? We default to true and this is changed
84 // to false when the export feature is used.
90 // Filled with the command line arguments "foo" of "-sysdir foo" or
92 string cl_system_support;
93 string cl_user_support;
99 void showFileError(string const & error)
101 Alert::warning(_("Could not read configuration file"),
102 bformat(_("Error while reading the configuration file\n%1$s.\n"
103 "Please check your installation."), from_utf8(error)));
107 void reconfigureUserLyXDir()
109 string const configure_command = package().configure_command();
111 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
112 PathChanger p(package().user_support());
114 one.startscript(Systemcall::Wait, configure_command);
115 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
121 /// The main application class private implementation.
126 // Set the default User Interface language as soon as possible.
127 // The language used will be derived from the environment
129 messages_["GUI"] = Messages();
131 /// our function handler
134 BufferList buffer_list_;
136 KeyMap toplevel_keymap_;
138 CmdDef toplevel_cmddef_;
140 boost::scoped_ptr<Server> lyx_server_;
142 boost::scoped_ptr<ServerSocket> lyx_socket_;
144 boost::scoped_ptr<frontend::Application> application_;
145 /// lyx session, containing lastfiles, lastfilepos, and lastopened
146 boost::scoped_ptr<Session> session_;
148 /// Files to load at start.
149 vector<string> files_to_load_;
151 /// The messages translators.
152 map<string, Messages> messages_;
154 /// The file converters.
155 Converters converters_;
157 // The system converters copy after reading lyxrc.defaults.
158 Converters system_converters_;
163 Movers system_movers_;
165 /// has this user started lyx for the first time?
167 /// the parsed command line batch command if any
168 vector<string> batch_commands;
171 graphics::Previews preview_;
175 frontend::Application * theApp()
178 return singleton_->pimpl_->application_.get();
191 void LyX::exit(int exit_code) const
194 // Something wrong happened so better save everything, just in
199 // Properly crash in debug mode in order to get a useful backtrace.
203 // In release mode, try to exit gracefully.
205 theApp()->exit(exit_code);
213 LASSERT(singleton_, /**/);
218 LyX const & LyX::cref()
220 LASSERT(singleton_, /**/);
233 BufferList & LyX::bufferList()
235 return pimpl_->buffer_list_;
239 BufferList const & LyX::bufferList() const
241 return pimpl_->buffer_list_;
245 Session & LyX::session()
247 LASSERT(pimpl_->session_.get(), /**/);
248 return *pimpl_->session_.get();
252 Session const & LyX::session() const
254 LASSERT(pimpl_->session_.get(), /**/);
255 return *pimpl_->session_.get();
259 LyXFunc & LyX::lyxFunc()
261 return pimpl_->lyxfunc_;
265 LyXFunc const & LyX::lyxFunc() const
267 return pimpl_->lyxfunc_;
271 Server & LyX::server()
273 LASSERT(pimpl_->lyx_server_.get(), /**/);
274 return *pimpl_->lyx_server_.get();
278 Server const & LyX::server() const
280 LASSERT(pimpl_->lyx_server_.get(), /**/);
281 return *pimpl_->lyx_server_.get();
285 ServerSocket & LyX::socket()
287 LASSERT(pimpl_->lyx_socket_.get(), /**/);
288 return *pimpl_->lyx_socket_.get();
292 ServerSocket const & LyX::socket() const
294 LASSERT(pimpl_->lyx_socket_.get(), /**/);
295 return *pimpl_->lyx_socket_.get();
299 frontend::Application & LyX::application()
301 LASSERT(pimpl_->application_.get(), /**/);
302 return *pimpl_->application_.get();
306 frontend::Application const & LyX::application() const
308 LASSERT(pimpl_->application_.get(), /**/);
309 return *pimpl_->application_.get();
313 CmdDef & LyX::topLevelCmdDef()
315 return pimpl_->toplevel_cmddef_;
319 Converters & LyX::converters()
321 return pimpl_->converters_;
325 Converters & LyX::systemConverters()
327 return pimpl_->system_converters_;
331 Messages & LyX::getMessages(string const & language)
333 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
335 if (it != pimpl_->messages_.end())
338 pair<map<string, Messages>::iterator, bool> result =
339 pimpl_->messages_.insert(make_pair(language, Messages(language)));
341 LASSERT(result.second, /**/);
342 return result.first->second;
346 Messages & LyX::getGuiMessages()
348 return pimpl_->messages_["GUI"];
352 void LyX::setRcGuiLanguage()
354 if (lyxrc.gui_language == "auto")
356 Language const * language = languages.getLanguage(lyxrc.gui_language);
357 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
358 if (!setEnv("LANGUAGE", language->code()))
359 LYXERR(Debug::LOCALE, "\t... failed!");
360 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
361 if (!setEnv("LC_ALL", "en_US"))
362 LYXERR(Debug::LOCALE, "\t... failed!");
363 pimpl_->messages_["GUI"] = Messages();
367 int LyX::exec(int & argc, char * argv[])
369 // Here we need to parse the command line. At least
370 // we need to parse for "-dbg" and "-help"
371 easyParse(argc, argv);
374 init_package(to_utf8(from_local8bit(argv[0])),
375 cl_system_support, cl_user_support,
376 top_build_dir_is_one_level_up);
377 } catch (ExceptionMessage const & message) {
378 if (message.type_ == ErrorException) {
379 Alert::error(message.title_, message.details_);
381 } else if (message.type_ == WarningException) {
382 Alert::warning(message.title_, message.details_);
386 // Reinit the messages machinery in case package() knows
387 // something interesting about the locale directory.
391 // FIXME: create a ConsoleApplication
392 int exit_status = init(argc, argv);
398 // this is correct, since return values are inverted.
399 exit_status = !loadFiles();
401 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
406 BufferList::iterator begin = pimpl_->buffer_list_.begin();
408 bool final_success = false;
409 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
411 if (buf != buf->masterBuffer())
413 bool success = false;
414 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
415 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
416 for (; bcit != bcend; bcit++) {
417 buf->dispatch(*bcit, &success);
418 final_success |= success;
422 return !final_success;
425 // Let the frontend parse and remove all arguments that it knows
426 pimpl_->application_.reset(createApplication(argc, argv));
428 // Reestablish our defaults, as Qt overwrites them
429 // after createApplication()
432 // Parse and remove all known arguments in the LyX singleton
433 // Give an error for all remaining ones.
434 int exit_status = init(argc, argv);
436 // Kill the application object before exiting.
437 pimpl_->application_.reset();
444 /* Create a CoreApplication class that will provide the main event loop
445 * and the socket callback registering. With Qt4, only QtCore
446 * library would be needed.
447 * When this is done, a server_mode could be created and the following two
448 * line would be moved out from here.
450 // Note: socket callback must be registered after init(argc, argv)
451 // such that package().temp_dir() is properly initialized.
452 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
453 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
454 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
456 // Start the real execution loop.
457 exit_status = pimpl_->application_->exec();
465 void LyX::prepareExit()
467 // Clear the clipboard and selection stack:
468 cap::clearCutStack();
469 cap::clearSelection();
471 // close buffers first
472 pimpl_->buffer_list_.closeAll();
474 // register session changes and shutdown server and socket
476 if (pimpl_->session_)
477 pimpl_->session_->writeFile();
478 pimpl_->session_.reset();
479 pimpl_->lyx_server_.reset();
480 pimpl_->lyx_socket_.reset();
483 // do any other cleanup procedures now
484 if (package().temp_dir() != package().system_temp_dir()) {
485 string const abs_tmpdir = package().temp_dir().absFilename();
486 if (!contains(package().temp_dir().absFilename(), "lyx_tmpdir")) {
487 docstring const msg =
488 bformat(_("%1$s does not appear like a LyX created temporary directory."),
489 from_utf8(abs_tmpdir));
490 Alert::warning(_("Cannot remove temporary directory"), msg);
492 LYXERR(Debug::INFO, "Deleting tmp dir "
493 << package().temp_dir().absFilename());
494 if (!package().temp_dir().destroyDirectory()) {
495 docstring const msg =
496 bformat(_("Unable to remove the temporary directory %1$s"),
497 from_utf8(package().temp_dir().absFilename()));
498 Alert::warning(_("Unable to remove temporary directory"), msg);
503 // Kill the application object before exiting. This avoids crashes
504 // when exiting on Linux.
505 if (pimpl_->application_)
506 pimpl_->application_.reset();
510 void LyX::earlyExit(int status)
512 LASSERT(pimpl_->application_.get(), /**/);
513 // LyX::pimpl_::application_ is not initialised at this
514 // point so it's safe to just exit after some cleanup.
520 int LyX::init(int & argc, char * argv[])
522 // check for any spurious extra arguments
523 // other than documents
524 for (int argi = 1; argi < argc ; ++argi) {
525 if (argv[argi][0] == '-') {
527 bformat(_("Wrong command line option `%1$s'. Exiting."),
528 from_utf8(argv[argi]))) << endl;
533 // Initialization of LyX (reads lyxrc and more)
534 LYXERR(Debug::INIT, "Initializing LyX::init...");
535 bool success = init();
536 LYXERR(Debug::INIT, "Initializing LyX::init...done");
540 // Remaining arguments are assumed to be files to load.
541 for (int argi = argc - 1; argi >= 1; --argi)
542 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
545 pimpl_->files_to_load_.push_back(
546 i18nLibFileSearch("examples", "splash.lyx").absFilename());
553 bool LyX::loadFiles()
555 LASSERT(!use_gui, /**/);
557 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
558 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
560 for (; it != end; ++it) {
561 // get absolute path of file and add ".lyx" to
562 // the filename if necessary
563 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
569 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
570 if (buf->loadLyXFile(fname)) {
571 ErrorList const & el = buf->errorList("Parse");
573 for_each(el.begin(), el.end(),
574 boost::bind(&LyX::printError, this, _1));
577 pimpl_->buffer_list_.release(buf);
585 void LyX::execBatchCommands()
587 // The advantage of doing this here is that the event loop
588 // is already started. So any need for interaction will be
591 // if reconfiguration is needed.
592 while (LayoutFileList::get().empty()) {
593 switch (Alert::prompt(
594 _("No textclass is found"),
595 _("LyX cannot continue because no textclass is found. "
596 "You can either reconfigure normally, or reconfigure using "
597 "default textclasses, or quit LyX."),
604 // regular reconfigure
605 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
608 // reconfigure --without-latex-config
609 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
610 " --without-latex-config"));
613 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
618 // create the first main window
619 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
621 if (!pimpl_->files_to_load_.empty()) {
622 // if some files were specified at command-line we assume that the
623 // user wants to edit *these* files and not to restore the session.
624 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
625 pimpl_->lyxfunc_.dispatch(
626 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
628 // clear this list to save a few bytes of RAM
629 pimpl_->files_to_load_.clear();
632 pimpl_->application_->restoreGuiSession();
634 // Execute batch commands if available
635 if (pimpl_->batch_commands.empty())
638 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
639 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
640 for (; bcit != bcend; bcit++) {
641 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
642 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(*bcit));
650 The SIGHUP signal does not exist on Windows and does not need to be handled.
652 Windows handles SIGFPE and SIGSEGV signals as expected.
654 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
655 cause a new thread to be spawned. This may well result in unexpected
656 behaviour by the single-threaded LyX.
658 SIGTERM signals will come only from another process actually sending
659 that signal using 'raise' in Windows' POSIX compatability layer. It will
660 not come from the general "terminate process" methods that everyone
661 actually uses (and which can't be trapped). Killing an app 'politely' on
662 Windows involves first sending a WM_CLOSE message, something that is
663 caught already by the Qt frontend.
665 For more information see:
667 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
668 ...signals are mostly useless on Windows for a variety of reasons that are
671 'UNIX Application Migration Guide, Chapter 9'
672 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
674 'How To Terminate an Application "Cleanly" in Win32'
675 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
679 static void error_handler(int err_sig)
681 // Throw away any signals other than the first one received.
682 static sig_atomic_t handling_error = false;
685 handling_error = true;
687 // We have received a signal indicating a fatal error, so
688 // try and save the data ASAP.
689 LyX::cref().emergencyCleanup();
691 // These lyxerr calls may or may not work:
693 // Signals are asynchronous, so the main program may be in a very
694 // fragile state when a signal is processed and thus while a signal
695 // handler function executes.
696 // In general, therefore, we should avoid performing any
697 // I/O operations or calling most library and system functions from
700 // This shouldn't matter here, however, as we've already invoked
705 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
709 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
712 lyxerr << "\nlyx: SIGSEGV signal caught\n"
713 "Sorry, you have found a bug in LyX. "
714 "Please read the bug-reporting instructions "
715 "in Help->Introduction and send us a bug report, "
716 "if necessary. Thanks !\nBye." << endl;
724 // Deinstall the signal handlers
726 signal(SIGHUP, SIG_DFL);
728 signal(SIGINT, SIG_DFL);
729 signal(SIGFPE, SIG_DFL);
730 signal(SIGSEGV, SIG_DFL);
731 signal(SIGTERM, SIG_DFL);
734 if (err_sig == SIGSEGV ||
735 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
737 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
746 void LyX::printError(ErrorItem const & ei)
748 docstring tmp = _("LyX: ") + ei.error + char_type(':')
750 cerr << to_utf8(tmp) << endl;
757 signal(SIGHUP, error_handler);
759 signal(SIGFPE, error_handler);
760 signal(SIGSEGV, error_handler);
761 signal(SIGINT, error_handler);
762 signal(SIGTERM, error_handler);
763 // SIGPIPE can be safely ignored.
765 lyxrc.tempdir_path = package().temp_dir().absFilename();
766 lyxrc.document_path = package().document_dir().absFilename();
768 if (lyxrc.example_path.empty()) {
769 lyxrc.example_path = addPath(package().system_support().absFilename(),
772 if (lyxrc.template_path.empty()) {
773 lyxrc.template_path = addPath(package().system_support().absFilename(),
778 // Read configuration files
781 // This one may have been distributed along with LyX.
782 if (!readRcFile("lyxrc.dist"))
785 // Set the language defined by the distributor.
788 // Set the PATH correctly.
789 #if !defined (USE_POSIX_PACKAGING)
790 // Add the directory containing the LyX executable to the path
791 // so that LyX can find things like tex2lyx.
792 if (package().build_support().empty())
793 prependEnvPath("PATH", package().binary_dir().absFilename());
795 if (!lyxrc.path_prefix.empty())
796 prependEnvPath("PATH", lyxrc.path_prefix);
798 // Check that user LyX directory is ok.
799 if (queryUserLyXDir(package().explicit_user_support()))
800 reconfigureUserLyXDir();
802 // no need for a splash when there is no GUI
807 // This one is generated in user_support directory by lib/configure.py.
808 if (!readRcFile("lyxrc.defaults"))
811 // Query the OS to know what formats are viewed natively
812 formats.setAutoOpen();
814 // Read lyxrc.dist again to be able to override viewer auto-detection.
815 readRcFile("lyxrc.dist");
817 system_lyxrc = lyxrc;
818 system_formats = formats;
819 pimpl_->system_converters_ = pimpl_->converters_;
820 pimpl_->system_movers_ = pimpl_->movers_;
821 system_lcolor = lcolor;
823 // This one is edited through the preferences dialog.
824 if (!readRcFile("preferences"))
827 if (!readEncodingsFile("encodings", "unicodesymbols"))
829 if (!readLanguagesFile("languages"))
832 // Set the language defined by the user.
836 LYXERR(Debug::INIT, "Reading layouts...");
842 // read keymap and ui files in batch mode as well
843 // because InsetInfo needs to know these to produce
844 // the correct output
846 // Set up command definitions
847 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
850 pimpl_->toplevel_keymap_.read("site");
851 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
852 // load user bind file user.bind
853 pimpl_->toplevel_keymap_.read("user");
855 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
857 if (lyxerr.debugging(Debug::LYXRC))
860 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
861 if (!lyxrc.path_prefix.empty())
862 prependEnvPath("PATH", lyxrc.path_prefix);
864 FileName const document_path(lyxrc.document_path);
865 if (document_path.exists() && document_path.isDirectory())
866 package().document_dir() = document_path;
868 package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
869 if (package().temp_dir().empty()) {
870 Alert::error(_("Could not create temporary directory"),
871 bformat(_("Could not create a temporary directory in\n"
873 "Make sure that this path exists and is writable and try again."),
874 from_utf8(lyxrc.tempdir_path)));
875 // createLyXTmpDir() tries sufficiently hard to create a
876 // usable temp dir, so the probability to come here is
877 // close to zero. We therefore don't try to overcome this
878 // problem with e.g. asking the user for a new path and
879 // trying again but simply exit.
883 LYXERR(Debug::INIT, "LyX tmp dir: `"
884 << package().temp_dir().absFilename() << '\'');
886 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
887 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
889 // This must happen after package initialization and after lyxrc is
890 // read, therefore it can't be done by a static object.
891 ConverterCache::init();
897 void LyX::emergencyCleanup() const
899 // what to do about tmpfiles is non-obvious. we would
900 // like to delete any we find, but our lyxdir might
901 // contain documents etc. which might be helpful on
904 pimpl_->buffer_list_.emergencyWriteAll();
906 if (pimpl_->lyx_server_)
907 pimpl_->lyx_server_->emergencyCleanup();
908 pimpl_->lyx_server_.reset();
909 pimpl_->lyx_socket_.reset();
914 // return true if file does not exist or is older than configure.py.
915 static bool needsUpdate(string const & file)
917 // We cannot initialize configure_script directly because the package
918 // is not initialized yet when static objects are constructed.
919 static FileName configure_script;
920 static bool firstrun = true;
923 FileName(addName(package().system_support().absFilename(),
929 FileName(addName(package().user_support().absFilename(), file));
930 return !absfile.exists()
931 || configure_script.lastModified() > absfile.lastModified();
935 bool LyX::queryUserLyXDir(bool explicit_userdir)
937 // Does user directory exist?
938 FileName const sup = package().user_support();
939 if (sup.exists() && sup.isDirectory()) {
942 return needsUpdate("lyxrc.defaults")
943 || needsUpdate("lyxmodules.lst")
944 || needsUpdate("textclass.lst")
945 || needsUpdate("packages.lst");
948 first_start = !explicit_userdir;
950 // If the user specified explicitly a directory, ask whether
951 // to create it. If the user says "no", then exit.
952 if (explicit_userdir &&
954 _("Missing user LyX directory"),
955 bformat(_("You have specified a non-existent user "
956 "LyX directory, %1$s.\n"
957 "It is needed to keep your own configuration."),
958 from_utf8(package().user_support().absFilename())),
960 _("&Create directory"),
962 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
963 earlyExit(EXIT_FAILURE);
966 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
967 from_utf8(sup.absFilename()))) << endl;
969 if (!sup.createDirectory(0755)) {
970 // Failed, so let's exit.
971 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
973 earlyExit(EXIT_FAILURE);
980 bool LyX::readRcFile(string const & name)
982 LYXERR(Debug::INIT, "About to read " << name << "... ");
984 FileName const lyxrc_path = libFileSearch(string(), name);
985 if (!lyxrc_path.empty()) {
986 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
987 if (lyxrc.read(lyxrc_path) < 0) {
992 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
997 // Read the languages file `name'
998 bool LyX::readLanguagesFile(string const & name)
1000 LYXERR(Debug::INIT, "About to read " << name << "...");
1002 FileName const lang_path = libFileSearch(string(), name);
1003 if (lang_path.empty()) {
1004 showFileError(name);
1007 languages.read(lang_path);
1012 // Read the encodings file `name'
1013 bool LyX::readEncodingsFile(string const & enc_name,
1014 string const & symbols_name)
1016 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1017 << symbols_name << "...");
1019 FileName const symbols_path = libFileSearch(string(), symbols_name);
1020 if (symbols_path.empty()) {
1021 showFileError(symbols_name);
1025 FileName const enc_path = libFileSearch(string(), enc_name);
1026 if (enc_path.empty()) {
1027 showFileError(enc_name);
1030 encodings.read(enc_path, symbols_path);
1037 /// return the the number of arguments consumed
1038 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
1040 int parse_dbg(string const & arg, string const &, string &)
1043 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1044 Debug::showTags(lyxerr);
1047 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1049 lyxerr.level(Debug::value(arg));
1050 Debug::showLevel(lyxerr, lyxerr.level());
1055 int parse_help(string const &, string const &, string &)
1058 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1059 "Command line switches (case sensitive):\n"
1060 "\t-help summarize LyX usage\n"
1061 "\t-userdir dir set user directory to dir\n"
1062 "\t-sysdir dir set system directory to dir\n"
1063 "\t-geometry WxH+X+Y set geometry of the main window\n"
1064 "\t-dbg feature[,feature]...\n"
1065 " select the features to debug.\n"
1066 " Type `lyx -dbg' to see the list of features\n"
1067 "\t-x [--execute] command\n"
1068 " where command is a lyx command.\n"
1069 "\t-e [--export] fmt\n"
1070 " where fmt is the export format of choice.\n"
1071 " Look on Tools->Preferences->File formats->Format\n"
1072 " to get an idea which parameters should be passed.\n"
1073 "\t-i [--import] fmt file.xxx\n"
1074 " where fmt is the import format of choice\n"
1075 " and file.xxx is the file to be imported.\n"
1076 "\t-version summarize version and build info\n"
1077 "Check the LyX man page for more details.")) << endl;
1083 int parse_version(string const &, string const &, string &)
1085 lyxerr << "LyX " << lyx_version
1086 << " (" << lyx_release_date << ")" << endl;
1087 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1089 lyxerr << lyx_version_info << endl;
1095 int parse_sysdir(string const & arg, string const &, string &)
1098 Alert::error(_("No system directory"),
1099 _("Missing directory for -sysdir switch"));
1102 cl_system_support = arg;
1107 int parse_userdir(string const & arg, string const &, string &)
1110 Alert::error(_("No user directory"),
1111 _("Missing directory for -userdir switch"));
1114 cl_user_support = arg;
1119 int parse_execute(string const & arg, string const &, string & batch)
1122 Alert::error(_("Incomplete command"),
1123 _("Missing command string after --execute switch"));
1131 int parse_export(string const & type, string const &, string & batch)
1134 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1135 "--export switch")) << endl;
1138 batch = "buffer-export " + type;
1144 int parse_import(string const & type, string const & file, string & batch)
1147 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1148 "--import switch")) << endl;
1152 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1156 batch = "buffer-import " + type + ' ' + file;
1161 int parse_geometry(string const & arg1, string const &, string &)
1164 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1165 // remove also the arg
1168 // don't remove "-geometry"
1177 void LyX::easyParse(int & argc, char * argv[])
1179 map<string, cmd_helper> cmdmap;
1181 cmdmap["-dbg"] = parse_dbg;
1182 cmdmap["-help"] = parse_help;
1183 cmdmap["--help"] = parse_help;
1184 cmdmap["-version"] = parse_version;
1185 cmdmap["--version"] = parse_version;
1186 cmdmap["-sysdir"] = parse_sysdir;
1187 cmdmap["-userdir"] = parse_userdir;
1188 cmdmap["-x"] = parse_execute;
1189 cmdmap["--execute"] = parse_execute;
1190 cmdmap["-e"] = parse_export;
1191 cmdmap["--export"] = parse_export;
1192 cmdmap["-i"] = parse_import;
1193 cmdmap["--import"] = parse_import;
1194 cmdmap["-geometry"] = parse_geometry;
1196 for (int i = 1; i < argc; ++i) {
1197 map<string, cmd_helper>::const_iterator it
1198 = cmdmap.find(argv[i]);
1200 // don't complain if not found - may be parsed later
1201 if (it == cmdmap.end())
1205 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1207 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1210 int const remove = 1 + it->second(arg, arg2, batch);
1212 pimpl_->batch_commands.push_back(batch);
1214 // Now, remove used arguments by shifting
1215 // the following ones remove places down.
1218 for (int j = i; j < argc; ++j)
1219 argv[j] = argv[j + remove];
1226 FuncStatus getStatus(FuncRequest const & action)
1228 return LyX::ref().lyxFunc().getStatus(action);
1232 void dispatch(FuncRequest const & action)
1234 LyX::ref().lyxFunc().dispatch(action);
1238 BufferList & theBufferList()
1240 return LyX::ref().bufferList();
1244 LyXFunc & theLyXFunc()
1246 return LyX::ref().lyxFunc();
1250 Server & theServer()
1252 // FIXME: this should not be use_gui dependent
1253 LASSERT(use_gui, /**/);
1254 return LyX::ref().server();
1258 ServerSocket & theServerSocket()
1260 // FIXME: this should not be use_gui dependent
1261 LASSERT(use_gui, /**/);
1262 return LyX::ref().socket();
1266 KeyMap & theTopLevelKeymap()
1268 return LyX::ref().pimpl_->toplevel_keymap_;
1272 Converters & theConverters()
1274 return LyX::ref().converters();
1278 Converters & theSystemConverters()
1280 return LyX::ref().systemConverters();
1284 Movers & theMovers()
1286 return LyX::ref().pimpl_->movers_;
1290 Mover const & getMover(string const & fmt)
1292 return LyX::ref().pimpl_->movers_(fmt);
1296 void setMover(string const & fmt, string const & command)
1298 LyX::ref().pimpl_->movers_.set(fmt, command);
1302 Movers & theSystemMovers()
1304 return LyX::ref().pimpl_->system_movers_;
1308 Messages & getMessages(string const & language)
1310 return LyX::ref().getMessages(language);
1314 Messages & getGuiMessages()
1316 return LyX::ref().getGuiMessages();
1320 graphics::Previews * thePreviews()
1322 return singleton_ ? 0 : &singleton_->pimpl_->preview_;