#include "frontends/alert.h"
#include "frontends/Application.h"
+#include "support/ConsoleApplication.h"
#include "support/lassert.h"
#include "support/debug.h"
#include "support/environment.h"
#include "support/Messages.h"
#include "support/os.h"
#include "support/Package.h"
-#include "support/PathChanger.h"
-#include "support/Systemcall.h"
#include "support/bind.h"
#include <boost/scoped_ptr.hpp>
using namespace std;
using namespace lyx::support;
+#if defined (USE_MACOSX_PACKAGING)
+#include <crt_externs.h>
+#endif
+
namespace lyx {
namespace Alert = frontend::Alert;
"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.
///
Movers system_movers_;
- /// has this user started lyx for the first time?
- bool first_start;
/// the parsed command line batch command if any
vector<string> batch_commands;
};
+/// 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()
{
setLocale();
if (!use_gui) {
- // FIXME: create a ConsoleApplication
- int exit_status = init(argc, argv);
- if (exit_status) {
- prepareExit();
- return exit_status;
- }
+ LyXConsoleApp app(this, argc, argv);
- // this is correct, since return values are inverted.
- exit_status = !loadFiles();
+ // Reestablish our defaults, as Qt overwrites them
+ // after creating app
+ setLocale();//???
- 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<string>::const_iterator bcit = pimpl_->batch_commands.begin();
- vector<string>::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
// 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.
}
+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<string>::const_iterator bcit = pimpl_->batch_commands.begin();
+ vector<string>::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()
{
LATTEST(!use_gui);
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
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<std::string> seen;
+ std::set<std::string> 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<std::string>::iterator dupe = dupes.begin();
+ std::set<std::string>::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
+
+
+static void initTemplatePath()
+{
+ FileName const package_template_path =
+ FileName(addName(package().system_support().absFileName(), "templates"));
+
+ if (lyxrc.template_path.empty()) {
+ lyxrc.template_path = package_template_path.absFileName();
+ }
+#if defined (USE_MACOSX_PACKAGING)
+ FileName const user_template_path =
+ FileName(addName(package().user_support().absFileName(), "templates"));
+
+ if (package_template_path != FileName(lyxrc.template_path) &&
+ user_template_path != FileName(lyxrc.template_path))
+ {
+ return;
+ }
+ FileName const user_template_link =
+ FileName(addName(user_template_path.absFileName(),"SystemTemplates"));
+ if (user_template_link.isSymLink() && !equivalent(user_template_link, package_template_path)) {
+ user_template_link.removeFile();
+ }
+ if (!user_template_link.exists()) {
+ if (!package_template_path.link(user_template_link)) {
+ FileName const user_support = package().user_support();
+ if (user_support.exists() && user_support.isDirectory()) {
+ LYXERR(Debug::INIT, "Cannot create symlink " + user_template_link.absFileName());
+ lyxrc.template_path = package_template_path.absFileName();
+ }
+ return;
+ }
+ LYXERR(Debug::INIT, "Symlink \"" << user_template_link.absFileName() << "\" created.");
+ }
+ lyxrc.template_path = user_template_path.absFileName();
+#endif
+}
+
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();
lyxrc.example_path = addPath(package().system_support().absFileName(),
"examples");
}
- if (lyxrc.template_path.empty()) {
- lyxrc.template_path = addPath(package().system_support().absFileName(),
- "templates");
- }
+ initTemplatePath();
// init LyXDir environment variable
string const lyx_dir = package().lyx_dir().absFileName();
return false;
// Set the PATH correctly.
-#if !defined (USE_POSIX_PACKAGING)
+#if !defined (USE_POSIX_PACKAGING) && !defined (USE_HAIKU_PACKAGING)
// Add the directory containing the LyX executable to the path
// so that LyX can find things like tex2lyx.
if (package().build_support().empty())
// Check that user LyX directory is ok.
{
- string const lock_file = package().user_support().absFileName() + ".lyx_configure_lock";
+ string const lock_file = package().getConfigureLockName();
int fd = fileLock(lock_file.c_str());
if (queryUserLyXDir(package().explicit_user_support())) {
- reconfigureUserLyXDir();
+ package().reconfigureUserLyXDir("");
+ // Now the user directory is present on first start.
+ initTemplatePath();
}
fileUnlock(fd, lock_file.c_str());
}
}
-// 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?
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;
{
cout << "LyX " << lyx_version
<< " (" << lyx_release_date << ")" << endl;
- cout << to_utf8(bformat(_("Built on %1$s[[date]], %2$s[[time]]"),
- from_ascii(__DATE__), from_ascii(__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;
cmdmap["-userdir"] = parse_userdir;
cmdmap["-x"] = parse_execute;
cmdmap["--execute"] = parse_execute;
- cmdmap["-e"] = parse_export;
+ cmdmap["-e"] = parse_export;
cmdmap["--export"] = parse_export;
cmdmap["-E"] = parse_export_to;
cmdmap["--export-to"] = parse_export_to;
}
-void dispatch(FuncRequest const & action)
+DispatchResult const & dispatch(FuncRequest const & action)
{
LAPPERR(theApp());
return theApp()->dispatch(action);
void dispatch(FuncRequest const & action, DispatchResult & dr)
{
LAPPERR(theApp());
- return theApp()->dispatch(action, dr);
+ theApp()->dispatch(action, dr);
}