X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLyX.cpp;h=44e6e34088a2d3a1a7003953f5433daa4b8a84b5;hb=bc47054be88467f01fd2f6e437d555743bd8a7c9;hp=2247f33212fe2a00b6a577490960ab7296438f8b;hpb=0247f726aaf4411d7221254fb81a18771ef448f8;p=lyx.git diff --git a/src/LyX.cpp b/src/LyX.cpp index 2247f33212..44e6e34088 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -50,6 +50,7 @@ #include "frontends/alert.h" #include "frontends/Application.h" +#include "support/ConsoleApplication.h" #include "support/lassert.h" #include "support/debug.h" #include "support/environment.h" @@ -60,8 +61,6 @@ #include "support/Messages.h" #include "support/os.h" #include "support/Package.h" -#include "support/Path.h" -#include "support/Systemcall.h" #include "support/bind.h" #include @@ -77,6 +76,10 @@ using namespace std; using namespace lyx::support; +#if defined (USE_MACOSX_PACKAGING) +#include +#endif + namespace lyx { namespace Alert = frontend::Alert; @@ -123,18 +126,6 @@ void showFileError(string const & error) "Please check your installation."), from_utf8(error))); } - -void reconfigureUserLyXDir() -{ - string const configure_command = package().configure_command(); - - lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl; - PathChanger p(package().user_support()); - Systemcall one; - one.startscript(Systemcall::Wait, configure_command); - lyxerr << "LyX: " << to_utf8(_("Done!")) << endl; -} - } // namespace anon /// The main application class private implementation. @@ -184,11 +175,9 @@ struct LyX::Impl { /// Movers system_movers_; - /// has this user started lyx for the first time? - bool first_start; /// the parsed command line batch command if any vector batch_commands; - + /// LaTeXFonts * latexfonts_; @@ -205,6 +194,27 @@ struct LyX::Impl { }; +/// The main application class for console mode +class LyXConsoleApp : public ConsoleApplication +{ +public: + LyXConsoleApp(LyX * lyx, int & argc, char * argv[]) + : ConsoleApplication(lyx_package, argc, argv), lyx_(lyx), + argc_(argc), argv_(argv) + { + } + void doExec() + { + int const exit_status = lyx_->execWithoutGui(argc_, argv_); + exit(exit_status); + } +private: + LyX * lyx_; + int & argc_; + char ** argv_; +}; + + /// frontend::Application * theApp() { @@ -261,7 +271,7 @@ Messages & LyX::messages(string const & language) pair::iterator, bool> result = pimpl_->messages_.insert(make_pair(language, Messages(language))); - LASSERT(result.second, /**/); + LATTEST(result.second); return result.first->second; } @@ -272,7 +282,7 @@ int LyX::exec(int & argc, char * argv[]) try { init_package(os::utf8_argv(0), string(), string()); // we do not get to this point when init_package throws an exception - locale_init(); + setLocale(); } catch (ExceptionMessage const & message) { LYXERR(Debug::LOCALE, message.title_ + ", " + message.details_); } @@ -294,42 +304,16 @@ int LyX::exec(int & argc, char * argv[]) // Reinit the messages machinery in case package() knows // something interesting about the locale directory. - Messages::init(); + setLocale(); if (!use_gui) { - // FIXME: create a ConsoleApplication - int exit_status = init(argc, argv); - if (exit_status) { - prepareExit(); - return exit_status; - } - - // this is correct, since return values are inverted. - exit_status = !loadFiles(); + LyXConsoleApp app(this, argc, argv); - if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) { - prepareExit(); - return exit_status; - } + // Reestablish our defaults, as Qt overwrites them + // after creating app + setLocale();//??? - BufferList::iterator begin = pimpl_->buffer_list_.begin(); - - bool final_success = false; - for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) { - Buffer * buf = *I; - if (buf != buf->masterBuffer()) - continue; - vector::const_iterator bcit = pimpl_->batch_commands.begin(); - vector::const_iterator bcend = pimpl_->batch_commands.end(); - DispatchResult dr; - for (; bcit != bcend; ++bcit) { - LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit); - buf->dispatch(*bcit, dr); - final_success |= !dr.error(); - } - } - prepareExit(); - return !final_success; + return app.exec(); } // Let the frontend parse and remove all arguments that it knows @@ -337,7 +321,7 @@ int LyX::exec(int & argc, char * argv[]) // Reestablish our defaults, as Qt overwrites them // after createApplication() - locale_init(); + setLocale();//??? // Parse and remove all known arguments in the LyX singleton // Give an error for all remaining ones. @@ -357,7 +341,7 @@ int LyX::exec(int & argc, char * argv[]) // FIXME /* Create a CoreApplication class that will provide the main event loop - * and the socket callback registering. With Qt4, only QtCore + * and the socket callback registering. With Qt, only QtCore * library would be needed. * When this is done, a server_mode could be created and the following two * line would be moved out from here. @@ -436,7 +420,7 @@ void LyX::prepareExit() void LyX::earlyExit(int status) { - LASSERT(pimpl_->application_.get(), /**/); + LATTEST(pimpl_->application_.get()); // LyX::pimpl_::application_ is not initialised at this // point so it's safe to just exit after some cleanup. prepareExit(); @@ -468,6 +452,11 @@ int LyX::init(int & argc, char * argv[]) for (int argi = 1; argi < argc; ++argi) pimpl_->files_to_load_.push_back(os::utf8_argv(argi)); + if (!use_gui && pimpl_->files_to_load_.empty()) { + lyxerr << to_utf8(_("Missing filename for this operation.")) << endl; + return EXIT_FAILURE; + } + if (first_start) { pimpl_->files_to_load_.push_back( i18nLibFileSearch("examples", "splash.lyx").absFileName()); @@ -477,9 +466,46 @@ int LyX::init(int & argc, char * argv[]) } +int LyX::execWithoutGui(int & argc, char * argv[]) +{ + int exit_status = init(argc, argv); + if (exit_status) { + prepareExit(); + return exit_status; + } + + // this is correct, since return values are inverted. + exit_status = !loadFiles(); + + if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) { + prepareExit(); + return exit_status; + } + + BufferList::iterator begin = pimpl_->buffer_list_.begin(); + + bool final_success = false; + for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) { + Buffer * buf = *I; + if (buf != buf->masterBuffer()) + continue; + vector::const_iterator bcit = pimpl_->batch_commands.begin(); + vector::const_iterator bcend = pimpl_->batch_commands.end(); + DispatchResult dr; + for (; bcit != bcend; ++bcit) { + LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit); + buf->dispatch(*bcit, dr); + final_success |= !dr.error(); + } + } + prepareExit(); + return !final_success; +} + + bool LyX::loadFiles() { - LASSERT(!use_gui, /**/); + LATTEST(!use_gui); bool success = true; vector::const_iterator it = pimpl_->files_to_load_.begin(); vector::const_iterator end = pimpl_->files_to_load_.end(); @@ -502,6 +528,10 @@ bool LyX::loadFiles() } else { pimpl_->buffer_list_.release(buf); + docstring const error_message = + bformat(_("LyX failed to load the following file: %1$s"), + from_utf8(fname.absFileName())); + lyxerr << to_utf8(error_message) << endl; success = false; } } @@ -511,7 +541,7 @@ bool LyX::loadFiles() void execBatchCommands() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); singleton_->execCommands(); } @@ -658,7 +688,7 @@ static void error_handler(int err_sig) if (!msg.empty()) { lyxerr << "\nlyx: " << msg << endl; // try to make a GUI message - Alert::error(_("LyX crashed!"), msg); + Alert::error(_("LyX crashed!"), msg, true); } // Deinstall the signal handlers @@ -697,6 +727,57 @@ void LyX::printError(ErrorItem const & ei) cerr << to_utf8(tmp) << endl; } +#if defined (USE_MACOSX_PACKAGING) +namespace { + // Unexposed--extract an environment variable name from its NAME=VALUE + // representation + std::string varname(const char* line) + { + size_t nameLen = strcspn(line, "="); + if (nameLen == strlen(line)) { + return std::string(); + } else { + return std::string(line, nameLen); + } + } +} + +void cleanDuplicateEnvVars() +{ + std::set seen; + std::set dupes; + + // Create a list of the environment variables that appear more than once + for (char **read = *_NSGetEnviron(); *read; read++) { + std::string name = varname(*read); + if (name.size() == 0) { + continue; + } + if (seen.find(name) != seen.end()) { + dupes.insert(name); + } else { + seen.insert(name); + } + } + + // Loop over the list of duplicated variables + std::set::iterator dupe = dupes.begin(); + std::set::iterator const dend = dupes.end(); + for (; dupe != dend; ++dupe) { + const char *name = (*dupe).c_str(); + char *val = getenv(name); + if (val != NULL) { + LYXERR(Debug::INIT, "Duplicate environment variable: " << name); + // unsetenv removes *all* instances of the variable from the environment + unsetenv(name); + + // replace with the value from getenv (in practice appears to be the + // first value in the list) + setenv(name, val, 0); + } + } +} +#endif bool LyX::init() { @@ -709,6 +790,10 @@ bool LyX::init() signal(SIGTERM, error_handler); // SIGPIPE can be safely ignored. +#if defined (USE_MACOSX_PACKAGING) + cleanDuplicateEnvVars(); +#endif + lyxrc.tempdir_path = package().temp_dir().absFileName(); lyxrc.document_path = package().document_dir().absFileName(); @@ -727,6 +812,18 @@ bool LyX::init() if (!setEnv("LyXDir", lyx_dir)) LYXERR(Debug::INIT, "\t... failed!"); + if (package().explicit_user_support() && getEnv(LYX_USERDIR_VER).empty()) { + // -userdir was given on the command line. + // Make it available to child processes, otherwise tex2lyx + // would not find all layout files, and other converters might + // use it as well. + string const user_dir = package().user_support().absFileName(); + LYXERR(Debug::INIT, "Setting " LYX_USERDIR_VER "... to \"" + << user_dir << '"'); + if (!setEnv(LYX_USERDIR_VER, user_dir)) + LYXERR(Debug::INIT, "\t... failed!"); + } + // // Read configuration files // @@ -746,8 +843,15 @@ bool LyX::init() prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix)); // Check that user LyX directory is ok. - if (queryUserLyXDir(package().explicit_user_support())) - reconfigureUserLyXDir(); + { + string const lock_file = package().getConfigureLockName(); + int fd = fileLock(lock_file.c_str()); + + if (queryUserLyXDir(package().explicit_user_support())) { + package().reconfigureUserLyXDir(""); + } + fileUnlock(fd, lock_file.c_str()); + } if (!use_gui) { // No need for a splash when there is no GUI @@ -785,6 +889,9 @@ bool LyX::init() if (!readRcFile("preferences", true)) return false; + // The language may have been set to someting useful through prefs + setLocale(); + if (!readEncodingsFile("encodings", "unicodesymbols")) return false; if (!readLanguagesFile("languages")) @@ -814,6 +921,7 @@ bool LyX::init() lyxrc.print(); os::windows_style_tex_paths(lyxrc.windows_style_tex_paths); + // Prepend path prefix a second time to take the user preferences into a account if (!lyxrc.path_prefix.empty()) prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix)); @@ -867,27 +975,6 @@ void emergencyCleanup() } -// return true if file does not exist or is older than configure.py. -static bool needsUpdate(string const & file) -{ - // We cannot initialize configure_script directly because the package - // is not initialized yet when static objects are constructed. - static FileName configure_script; - static bool firstrun = true; - if (firstrun) { - configure_script = - FileName(addName(package().system_support().absFileName(), - "configure.py")); - firstrun = false; - } - - FileName absfile = - FileName(addName(package().user_support().absFileName(), file)); - return !absfile.exists() - || configure_script.lastModified() > absfile.lastModified(); -} - - bool LyX::queryUserLyXDir(bool explicit_userdir) { // Does user directory exist? @@ -895,10 +982,10 @@ bool LyX::queryUserLyXDir(bool explicit_userdir) if (sup.exists() && sup.isDirectory()) { first_start = false; - return needsUpdate("lyxrc.defaults") - || needsUpdate("lyxmodules.lst") - || needsUpdate("textclass.lst") - || needsUpdate("packages.lst"); + return configFileNeedsUpdate("lyxrc.defaults") + || configFileNeedsUpdate("lyxmodules.lst") + || configFileNeedsUpdate("textclass.lst") + || configFileNeedsUpdate("packages.lst"); } first_start = !explicit_userdir; @@ -1057,8 +1144,9 @@ int parse_version(string const &, string const &, string &) { cout << "LyX " << lyx_version << " (" << lyx_release_date << ")" << endl; - cout << "Built on " << __DATE__ << ", " << __TIME__ << endl; - + if (string(lyx_git_commit_hash) != "none") + cout << to_utf8(_(" Git commit hash ")) + << string(lyx_git_commit_hash).substr(0,8) << endl; cout << lyx_version_info << endl; exit(0); return 0; @@ -1143,7 +1231,6 @@ int parse_import(string const & type, string const & file, string & batch) lyxerr << to_utf8(_("Missing filename for --import")) << endl; exit(1); } - batch = "buffer-import " + type + ' ' + file; return 2; } @@ -1260,35 +1347,35 @@ void LyX::easyParse(int & argc, char * argv[]) FuncStatus getStatus(FuncRequest const & action) { - LASSERT(theApp(), /**/); + LAPPERR(theApp()); return theApp()->getStatus(action); } void dispatch(FuncRequest const & action) { - LASSERT(theApp(), /**/); + LAPPERR(theApp()); return theApp()->dispatch(action); } void dispatch(FuncRequest const & action, DispatchResult & dr) { - LASSERT(theApp(), /**/); + LAPPERR(theApp()); return theApp()->dispatch(action, dr); } vector & theFilesToLoad() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->files_to_load_; } BufferList & theBufferList() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->buffer_list_; } @@ -1296,8 +1383,8 @@ BufferList & theBufferList() Server & theServer() { // FIXME: this should not be use_gui dependent - LASSERT(use_gui, /**/); - LASSERT(singleton_, /**/); + LWARNIF(use_gui); + LAPPERR(singleton_); return *singleton_->pimpl_->lyx_server_.get(); } @@ -1305,97 +1392,85 @@ Server & theServer() ServerSocket & theServerSocket() { // FIXME: this should not be use_gui dependent - LASSERT(use_gui, /**/); - LASSERT(singleton_, /**/); + LWARNIF(use_gui); + LAPPERR(singleton_); return *singleton_->pimpl_->lyx_socket_.get(); } KeyMap & theTopLevelKeymap() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->toplevel_keymap_; } Converters & theConverters() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->converters_; } Converters & theSystemConverters() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->system_converters_; } Movers & theMovers() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->movers_; } Mover const & getMover(string const & fmt) { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->movers_(fmt); } void setMover(string const & fmt, string const & command) { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); singleton_->pimpl_->movers_.set(fmt, command); } Movers & theSystemMovers() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->system_movers_; } Messages const & getMessages(string const & language) { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->messages(language); } Messages const & getGuiMessages() { - LASSERT(singleton_, /**/); - // A cache to translate full language name to language code - static string last_language = "auto"; - static string code; - if (lyxrc.gui_language != last_language) { - if (lyxrc.gui_language == "auto") - code.clear(); - else { - Language const * l = languages.getLanguage(lyxrc.gui_language); - code = l ? l->code() : string(); - } - last_language = lyxrc.gui_language; - } - return singleton_->messages(code); + LAPPERR(singleton_); + return singleton_->messages(Messages::guiLanguage()); } Session & theSession() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return *singleton_->pimpl_->session_.get(); } LaTeXFonts & theLaTeXFonts() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); if (!singleton_->pimpl_->latexfonts_) singleton_->pimpl_->latexfonts_ = new LaTeXFonts; return *singleton_->pimpl_->latexfonts_; @@ -1404,7 +1479,7 @@ LaTeXFonts & theLaTeXFonts() CmdDef & theTopLevelCmdDef() { - LASSERT(singleton_, /**/); + LAPPERR(singleton_); return singleton_->pimpl_->toplevel_cmddef_; }