X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyx_main.C;h=f323a19069e7b52177e7380761f5a3267e131388;hb=a9713c5563c924f4ab98bde3d9f24a5c1e4dd50e;hp=6597696bc84e6e49a424119f10cc5e5605a986b6;hpb=d1e95f33c4cf4d9b03b535f82561943b58cdcd64;p=lyx.git diff --git a/src/lyx_main.C b/src/lyx_main.C index 6597696bc8..f323a19069 100644 --- a/src/lyx_main.C +++ b/src/lyx_main.C @@ -1,187 +1,219 @@ -/* This file is part of - * ====================================================== - * - * LyX, The Document Processor - * - * Copyright 1995 Matthias Ettrich - * Copyright 1995-2000 The LyX Team. +/** + * \file lyx_main.C + * Copyright 1995-2002 the LyX Team + * Read the file COPYING * - * ====================================================== */ + * \author unknown + */ #include +#include -#include -#include - -#ifdef __GNUG__ -#pragma implementation -#endif - -#include "version.h" #include "lyx_main.h" -#include "lyx_gui.h" -#include "LyXView.h" -#include "lyxfunc.h" -#include "lyx_gui_misc.h" -#include "lyxrc.h" -#include "support/path.h" + #include "support/filetools.h" -#include "bufferlist.h" -#include "debug.h" +#include "support/lyxlib.h" +#include "support/os.h" #include "support/FileInfo.h" -#include "lastfiles.h" -#include "intl.h" -#include "lyxserver.h" -#include "layout.h" +#include "support/path.h" +#include "debug.h" #include "gettext.h" +#include "lyxlex.h" + +#include "graphics/GraphicsTypes.h" + +#include "bufferlist.h" +#include "buffer.h" +#include "lyxserver.h" #include "kbmap.h" +#include "lyxfunc.h" +#include "ToolbarBackend.h" #include "MenuBackend.h" -#include "ToolbarDefaults.h" -#include "lyxlex.h" +#include "language.h" +#include "lastfiles.h" #include "encoding.h" #include "converter.h" +#include "format.h" +#include "lyxtextclasslist.h" +#include "frontends/Alert.h" +#include "frontends/lyx_gui.h" + +#include + +#include +#include + +using std::vector; using std::endl; +#ifndef CXX_GLOBAL_CSTD +using std::exit; +using std::signal; +using std::system; +#endif + extern void LoadLyXFile(string const &); extern void QuitLyX(); +extern LyXServer * lyxserver; + string system_lyxdir; string build_lyxdir; string system_tempdir; -string user_lyxdir; // Default $HOME/.lyx +string user_lyxdir; -// Should this be kept global? Asger says Yes. DebugStream lyxerr; -LastFiles * lastfiles; +boost::scoped_ptr lastfiles; // This is the global bufferlist object BufferList bufferlist; -LyXServer * lyxserver = 0; -// this should be static, but I need it in buffer.C -bool finished = false; // flag, that we are quitting the program - // convenient to have it here. -kb_keymap * toplevel_keymap; +boost::scoped_ptr toplevel_keymap; +namespace { -LyX::LyX(int * argc, char * argv[]) +void showFileError(string const & error) { - // Prevent crash with --help - lyxGUI = 0; - lastfiles = 0; + Alert::warning(_("Could not read configuration file"), + bformat(_("Error while reading the configuration file\n%1$s.\n" + "Please check your installation."), error)); + exit(EXIT_FAILURE); +} + +} +LyX::LyX(int & argc, char * argv[]) +{ // Here we need to parse the command line. At least // we need to parse for "-dbg" and "-help" - bool gui = easyParse(argc, argv); + bool const want_gui = easyParse(argc, argv); // Global bindings (this must be done as early as possible.) (Lgb) - toplevel_keymap = new kb_keymap; - defaultKeyBindings(toplevel_keymap); - - // Make the GUI object, and let it take care of the - // command line arguments that concerns it. - lyxerr[Debug::INIT] << "Initializing LyXGUI..." << endl; - lyxGUI = new LyXGUI(this, argc, argv, gui); - lyxerr[Debug::INIT] << "Initializing LyXGUI...done" << endl; - - // Now the GUI and LyX have taken care of their arguments, so - // the only thing left on the command line should be - // filenames. Let's check anyway. - for (int argi = 1; argi < *argc ; ++argi) { + toplevel_keymap.reset(new kb_keymap); + defaultKeyBindings(toplevel_keymap.get()); + + // set the DisplayTranslator only once; should that be done here?? + // if this should not be in this file, please also remove + // #include "graphics/GraphicsTypes.h" at the top -- Rob Lahaye. + grfx::setDisplayTranslator(); + + if (want_gui) { + lyx_gui::parse_init(argc, argv); + } + + // check for any spurious extra arguments + // other than documents + for (int argi = 1; argi < argc ; ++argi) { if (argv[argi][0] == '-') { - lyxerr << _("Wrong command line option `") - << argv[argi] - << _("'. Exiting.") << endl; - exit(0); + lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."), + argv[argi]) << endl; + exit(1); } } - + // Initialization of LyX (reads lyxrc and more) lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl; - init(argc, argv, gui); + init(want_gui); lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl; - lyxGUI->init(); - - // Load the files specified in the command line. - if ((*argc) == 2) - lyxerr[Debug::INFO] << "Opening document..." << endl; - else if ((*argc) > 2) - lyxerr[Debug::INFO] << "Opening documents..." << endl; - - Buffer * last_loaded = 0; - - for (int argi = (*argc) - 1; argi >= 1; --argi) { - Buffer * loadb = bufferlist.loadLyXFile(argv[argi]); - if (loadb != 0) { - last_loaded = loadb; - } + if (want_gui) { + lyx_gui::parse_lyxrc(); } - if (first_start) { - string splash = i18nLibFileSearch("examples", "splash.lyx"); - lyxerr[Debug::INIT] << "Opening splash document " - << splash << "..." << endl; - Buffer * loadb = bufferlist.loadLyXFile(splash); - if (loadb != 0) { - last_loaded = loadb; - } - } + vector files; - if (last_loaded != 0) { - lyxerr[Debug::INIT] << "Yes we loaded some files." << endl; - if (lyxrc.use_gui) - lyxGUI->regBuf(last_loaded); + for (int argi = argc - 1; argi >= 1; --argi) { + files.push_back(argv[argi]); } + if (first_start) + files.push_back(i18nLibFileSearch("examples", "splash.lyx")); + // Execute batch commands if available if (!batch_command.empty()) { - lyxerr << "About to handle -x '" - << batch_command << "'" << endl; + lyxerr[Debug::INIT] << "About to handle -x '" + << batch_command << '\'' << endl; + + Buffer * last_loaded = 0; + + vector::iterator it = files.begin(); + vector::iterator end = files.end(); + for (; it != end; ++it) { + last_loaded = bufferlist.loadLyXFile(*it); + } + + files.clear(); // no buffer loaded, create one if (!last_loaded) last_loaded = bufferlist.newFile("tmpfile", string()); + bool success = false; + // try to dispatch to last loaded buffer first - bool dispatched = last_loaded->Dispatch(batch_command); + bool const dispatched = last_loaded->dispatch(batch_command, &success); - // if this was successful, return. - // Maybe we could do something more clever than aborting... if (dispatched) { - lyxerr << "We are done!" << endl; QuitLyX(); - return; + exit(!success); } - - // otherwise, let the GUI handle the batch command - lyxGUI->regBuf(last_loaded); - lyxGUI->getLyXView()->getLyXFunc()->Dispatch(batch_command); - - // fall through... } - - // Let the ball begin... - lyxGUI->runTime(); + + lyx_gui::start(batch_command, files); } -// A destructor is always necessary (asierra-970604) -LyX::~LyX() +extern "C" { + +static void error_handler(int err_sig) { - delete lastfiles; - delete lyxGUI; + switch (err_sig) { + case SIGHUP: + lyxerr << "\nlyx: SIGHUP signal caught" << endl; + break; + case SIGINT: + // no comments + break; + case SIGFPE: + lyxerr << "\nlyx: SIGFPE signal caught" << endl; + break; + case SIGSEGV: + lyxerr << "\nlyx: SIGSEGV signal caught" << endl; + lyxerr << + "Sorry, you have found a bug in LyX. " + "Please read the bug-reporting instructions " + "in Help->Introduction and send us a bug report, " + "if necessary. Thanks !" << endl; + break; + case SIGTERM: + // no comments + break; + } + + // Deinstall the signal handlers + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGSEGV, SIG_DFL); + signal(SIGTERM, SIG_DFL); + + LyX::emergencyCleanup(); + + lyxerr << "Bye." << endl; + if (err_sig!= SIGHUP && + (!GetEnv("LYXDEBUG").empty() || err_sig == SIGSEGV)) + lyx::abort(); + exit(0); } +} -extern "C" void error_handler(int err_sig); -void LyX::init(int */*argc*/, char **argv, bool gui) +void LyX::init(bool gui) { - // Install the signal handlers signal(SIGHUP, error_handler); signal(SIGFPE, error_handler); signal(SIGSEGV, error_handler); @@ -192,28 +224,9 @@ void LyX::init(int */*argc*/, char **argv, bool gui) // Determine path of binary // - string fullbinpath; - string binpath = subst(argv[0], '\\', '/'); - string binname = OnlyFilename(argv[0]); - // Sorry for system specific code. (SMiyata) - if (suffixIs(binname, ".exe")) - binname.erase(binname.length()-4, string::npos); - - binpath = ExpandPath(binpath); // This expands ./ and ~/ - - if (!AbsolutePath(binpath)) { - string binsearchpath = GetEnvPath("PATH"); - // This will make "src/lyx" work always :-) - binsearchpath += ";."; - binpath = FileOpenSearch(binsearchpath, argv[0]); - } - - fullbinpath = binpath; - binpath = MakeAbsPath(OnlyPath(binpath)); - - // In case we are running in place and compiled with shared libraries - if (suffixIs(binpath, "/.libs/")) - binpath.erase(binpath.length()-6, string::npos); + string binpath = os::binpath(); + string binname = os::binname(); + string fullbinname = MakeAbsPath(binname, binpath); if (binpath.empty()) { lyxerr << _("Warning: could not determine path of binary.") @@ -221,6 +234,7 @@ void LyX::init(int */*argc*/, char **argv, bool gui) << _("If you have problems, try starting LyX with an absolute path.") << endl; } + lyxerr[Debug::INIT] << "Name of binary: " << binname << endl; lyxerr[Debug::INIT] << "Path of binary: " << binpath << endl; // @@ -229,7 +243,7 @@ void LyX::init(int */*argc*/, char **argv, bool gui) // Directories are searched in this order: // 1) -sysdir command line parameter - // 2) LYX_DIR_11x environment variable + // 2) LYX_DIR_13x environment variable // 3) Maybe /TOP_SRCDIR/lib // 4) /../share// // 4a) repeat 4 after following the Symlink if /TOP_SRCDIR/lib build_lyxdir = MakeAbsPath("../lib", binpath); if (!FileSearch(build_lyxdir, "lyxrc.defaults").empty()) { @@ -268,36 +320,14 @@ void LyX::init(int */*argc*/, char **argv, bool gui) build_lyxdir.erase(); } - bool FollowLink; - do { - // Path of binary/../share/name of binary/ - searchpath += NormalizePath(AddPath(binpath, "../share/") + - OnlyFilename(binname)) + ';'; - - // Follow Symlinks - FileInfo file(fullbinpath, true); - FollowLink = file.isLink(); - if (FollowLink) { - string Link; - if (LyXReadLink(fullbinpath, Link)) { - fullbinpath = Link; - binpath = MakeAbsPath(OnlyPath(fullbinpath)); - } - else { - FollowLink = false; - } - } - } while (FollowLink); - // Hardcoded dir searchpath += LYX_DIR; - // If debugging, show complete search path lyxerr[Debug::INIT] << "System directory search path: " << searchpath << endl; string const filename = "chkconfig.ltx"; - string temp = FileOpenSearch(searchpath, filename, string()); + string const temp = FileOpenSearch(searchpath, filename, string()); system_lyxdir = OnlyPath(temp); // Reduce "path/../path" stuff out of system directory @@ -308,9 +338,9 @@ void LyX::init(int */*argc*/, char **argv, bool gui) // Warn if environment variable is set, but unusable if (!lyxdir.empty()) { if (system_lyxdir != NormalizePath(lyxdir)) { - lyxerr <<_("LYX_DIR_11x environment variable no good.") + lyxerr <<_("LYX_DIR_13x environment variable no good.") << '\n' - << _("System directory set to: ") + << _("System directory set to: ") << system_lyxdir << endl; path_shown = true; } @@ -318,105 +348,102 @@ void LyX::init(int */*argc*/, char **argv, bool gui) // Warn the user if we couldn't find "chkconfig.ltx" if (system_lyxdir == "./") { - lyxerr <<_("LyX Warning! Couldn't determine system directory.") - <<_("Try the '-sysdir' command line parameter or") - <<_("set the environment variable LYX_DIR_11x to the " - "LyX system directory") + lyxerr <<_("LyX Warning! Couldn't determine system directory. ") + <<_("Try the '-sysdir' command line parameter or ") + <<_("set the environment variable LYX_DIR_13x to the " + "LyX system directory ") << _("containing the file `chkconfig.ltx'.") << endl; - if (!path_shown) - lyxerr << _("Using built-in default ") - << LYX_DIR << _(" but expect problems.") - << endl; - else + if (!path_shown) { + FileInfo fi(LYX_DIR); + if (!fi.exist()) { + lyxerr << "Couldn't even find the default LYX_DIR." << endl + << "Giving up." << endl; + exit(1); + } + lyxerr << bformat(_("Using built-in default %1$s but expect problems."), + LYX_DIR) << endl; + } else { lyxerr << _("Expect problems.") << endl; + } system_lyxdir = LYX_DIR; path_shown = true; } - // Report the system directory if debugging is on if (!path_shown) lyxerr[Debug::INIT] << "System directory: '" - << system_lyxdir << '\'' << endl; + << system_lyxdir << '\'' << endl; // // Determine user lyx-dir // - + // Directories are searched in this order: // 1) -userdir command line parameter - // 2) LYX_USERDIR_11x environment variable + // 2) LYX_USERDIR_13x environment variable // 3) $HOME/. // If we had a command line switch, user_lyxdir is already set bool explicit_userdir = true; if (user_lyxdir.empty()) { - // LYX_USERDIR_11x environment variable - user_lyxdir = GetEnvPath("LYX_USERDIR_11x"); + // LYX_USERDIR_13x environment variable + user_lyxdir = GetEnvPath("LYX_USERDIR_13x"); - // default behaviour + // default behaviour if (user_lyxdir.empty()) user_lyxdir = AddPath(GetEnvPath("HOME"), string(".") + PACKAGE); explicit_userdir = false; } - lyxerr[Debug::INIT] << "User LyX directory: '" + lyxerr[Debug::INIT] << "User LyX directory: '" << user_lyxdir << '\'' << endl; - // Check that user LyX directory is ok. - queryUserLyXDir(explicit_userdir); + // Check that user LyX directory is ok. We don't do that if + // running in batch mode. + if (gui) { + queryUserLyXDir(explicit_userdir); + } else { + first_start = false; + } - // - // Shine up lyxrc defaults - // + // Disable gui when easyparse says so + lyx_gui::use_gui = gui; - // Default template path: system_dir/templates - if (lyxrc.template_path.empty()){ + if (lyxrc.template_path.empty()) { lyxrc.template_path = AddPath(system_lyxdir, "templates"); } - - // Default lastfiles file: $HOME/.lyx/lastfiles - if (lyxrc.lastfiles.empty()){ + + if (lyxrc.lastfiles.empty()) { lyxrc.lastfiles = AddName(user_lyxdir, "lastfiles"); } - // Disable gui when either lyxrc or easyparse says so - if (!gui) - lyxrc.use_gui = false; - - // Calculate screen dpi as average of x-DPI and y-DPI: - if (lyxrc.use_gui) { - lyxrc.dpi = getScreenDPI(); - lyxerr[Debug::INIT] << "DPI setting detected to be " - << lyxrc.dpi + 0.5 << endl; - } else { - lyxrc.dpi = 1; // I hope this is safe - } + if (lyxrc.roman_font_name.empty()) + lyxrc.roman_font_name = lyx_gui::roman_font_name(); + if (lyxrc.sans_font_name.empty()) + lyxrc.sans_font_name = lyx_gui::sans_font_name(); + if (lyxrc.typewriter_font_name.empty()) + lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name(); // // Read configuration files // - ReadRcFile("lyxrc.defaults"); + readRcFile("lyxrc.defaults"); system_lyxrc = lyxrc; system_formats = formats; system_converters = converters; system_lcolor = lcolor; - // If there is a preferences file we read that instead - // of the old lyxrc file. - if (!ReadRcFile("preferences")) - ReadRcFile("lyxrc"); + string prefsfile = "preferences"; + // back compatibility to lyxs < 1.1.6 + if (LibFileSearch(string(), prefsfile).empty()) + prefsfile = "lyxrc"; + if (!LibFileSearch(string(), prefsfile).empty()) + readRcFile(prefsfile); - /// Init Converter - converters.Update(formats); - converters.BuildGraph(); - - // Read encodings - ReadEncodingsFile("encodings"); - // Read languages - ReadLangugesFile("languages"); + readEncodingsFile("encodings"); + readLanguagesFile("languages"); // Load the layouts lyxerr[Debug::INIT] << "Reading layouts..." << endl; @@ -424,92 +451,99 @@ void LyX::init(int */*argc*/, char **argv, bool gui) // Ensure that we have really read a bind file, so that LyX is // usable. - if (!lyxrc.hasBindFile) - lyxrc.ReadBindFile(); + lyxrc.readBindFileIfNeeded(); // Read menus - ReadUIFile(lyxrc.ui_file); - - // Bind the X dead keys to the corresponding LyX functions if - // necessary. - if (lyxrc.override_x_deadkeys) - deadKeyBindings(toplevel_keymap); + readUIFile(lyxrc.ui_file); - if (lyxerr.debugging(Debug::LYXRC)) { + if (lyxerr.debugging(Debug::LYXRC)) lyxrc.print(); - } - // Create temp directory - system_tempdir = CreateLyXTmpDir(lyxrc.tempdir_path); + os::setTmpDir(CreateLyXTmpDir(lyxrc.tempdir_path)); + system_tempdir = os::getTmpDir(); if (lyxerr.debugging(Debug::INIT)) { lyxerr << "LyX tmp dir: `" << system_tempdir << '\'' << endl; } - // load the lastfiles mini-database lyxerr[Debug::INIT] << "Reading lastfiles `" - << lyxrc.lastfiles << "'..." << endl; - lastfiles = new LastFiles(lyxrc.lastfiles, - lyxrc.check_lastfiles, - lyxrc.num_lastfiles); - - // start up the lyxserver. (is this a bit early?) (Lgb) - // 0.12 this will be way to early, we need the GUI to be initialized - // first, so move it for now. - // lyxserver = new LyXServer; + << lyxrc.lastfiles << "'..." << endl; + lastfiles.reset(new LastFiles(lyxrc.lastfiles, + lyxrc.check_lastfiles, + lyxrc.num_lastfiles)); } -// These are the default bindings known to LyX void LyX::defaultKeyBindings(kb_keymap * kbmap) { kbmap->bind("Right", LFUN_RIGHT); kbmap->bind("Left", LFUN_LEFT); kbmap->bind("Up", LFUN_UP); kbmap->bind("Down", LFUN_DOWN); - - kbmap->bind("Tab", LFUN_TAB); - + + kbmap->bind("Tab", LFUN_CELL_FORWARD); + kbmap->bind("ISO_Left_Tab", LFUN_CELL_FORWARD); // jbl 2001-23-02 + kbmap->bind("Home", LFUN_HOME); kbmap->bind("End", LFUN_END); kbmap->bind("Prior", LFUN_PRIOR); kbmap->bind("Next", LFUN_NEXT); - + kbmap->bind("Return", LFUN_BREAKPARAGRAPH); - kbmap->bind("~C-~S-~M-nobreakspace", LFUN_PROTECTEDSPACE); - + //kbmap->bind("~C-~S-~M-nobreakspace", LFUN_PROTECTEDSPACE); + kbmap->bind("Delete", LFUN_DELETE); kbmap->bind("BackSpace", LFUN_BACKSPACE); - + + // sub- and superscript -MV + kbmap->bind("~S-underscore", LFUN_SUBSCRIPT); + kbmap->bind("~S-asciicircum", LFUN_SUPERSCRIPT); + // kbmap->bindings to enable the use of the numeric keypad // e.g. Num Lock set - kbmap->bind("KP_0", LFUN_SELFINSERT); - kbmap->bind("KP_Decimal", LFUN_SELFINSERT); - kbmap->bind("KP_Enter", LFUN_SELFINSERT); - kbmap->bind("KP_1", LFUN_SELFINSERT); - kbmap->bind("KP_2", LFUN_SELFINSERT); - kbmap->bind("KP_3", LFUN_SELFINSERT); - kbmap->bind("KP_4", LFUN_SELFINSERT); - kbmap->bind("KP_5", LFUN_SELFINSERT); - kbmap->bind("KP_6", LFUN_SELFINSERT); - kbmap->bind("KP_Add", LFUN_SELFINSERT); - kbmap->bind("KP_7", LFUN_SELFINSERT); - kbmap->bind("KP_8", LFUN_SELFINSERT); - kbmap->bind("KP_9", LFUN_SELFINSERT); - kbmap->bind("KP_Divide", LFUN_SELFINSERT); - kbmap->bind("KP_Multiply", LFUN_SELFINSERT); - kbmap->bind("KP_Subtract", LFUN_SELFINSERT); - - /* Most self-insert keys are handled in the 'default:' section of - * WorkAreaKeyPress - so we don't have to define them all. - * However keys explicit decleared as self-insert are - * handled seperatly (LFUN_SELFINSERT.) Lgb. */ - - kbmap->bind("C-Tab", LFUN_TABINSERT); // ale970515 - kbmap->bind("S-Tab", LFUN_SHIFT_TAB); // jug20000522 + //kbmap->bind("KP_0", LFUN_SELFINSERT); + //kbmap->bind("KP_Decimal", LFUN_SELFINSERT); + kbmap->bind("KP_Enter", LFUN_BREAKPARAGRAPH); + //kbmap->bind("KP_1", LFUN_SELFINSERT); + //kbmap->bind("KP_2", LFUN_SELFINSERT); + //kbmap->bind("KP_3", LFUN_SELFINSERT); + //kbmap->bind("KP_4", LFUN_SELFINSERT); + //kbmap->bind("KP_5", LFUN_SELFINSERT); + //kbmap->bind("KP_6", LFUN_SELFINSERT); + //kbmap->bind("KP_Add", LFUN_SELFINSERT); + //kbmap->bind("KP_7", LFUN_SELFINSERT); + //kbmap->bind("KP_8", LFUN_SELFINSERT); + //kbmap->bind("KP_9", LFUN_SELFINSERT); + //kbmap->bind("KP_Divide", LFUN_SELFINSERT); + //kbmap->bind("KP_Multiply", LFUN_SELFINSERT); + //kbmap->bind("KP_Subtract", LFUN_SELFINSERT); + kbmap->bind("KP_Right", LFUN_RIGHT); + kbmap->bind("KP_Left", LFUN_LEFT); + kbmap->bind("KP_Up", LFUN_UP); + kbmap->bind("KP_Down", LFUN_DOWN); + kbmap->bind("KP_Home", LFUN_HOME); + kbmap->bind("KP_End", LFUN_END); + kbmap->bind("KP_Prior", LFUN_PRIOR); + kbmap->bind("KP_Next", LFUN_NEXT); + + kbmap->bind("C-Tab", LFUN_CELL_SPLIT); // ale970515 + kbmap->bind("S-Tab", LFUN_CELL_BACKWARD); // jug20000522 + kbmap->bind("S-ISO_Left_Tab", LFUN_CELL_BACKWARD); // jbl 2001-23-02 +} + + +void LyX::emergencyCleanup() +{ + // what to do about tmpfiles is non-obvious. we would + // like to delete any we find, but our lyxdir might + // contain documents etc. which might be helpful on + // a crash + + bufferlist.emergencyWriteAll(); + if (lyxserver) + lyxserver->emergencyCleanup(); } -// LyX can optionally take over the handling of deadkeys void LyX::deadKeyBindings(kb_keymap * kbmap) { // bindKeyings for transparent handling of deadkeys @@ -536,124 +570,143 @@ void LyX::deadKeyBindings(kb_keymap * kbmap) } -// This one is not allowed to use anything on the main form, since that -// one does not exist yet. (Asger) void LyX::queryUserLyXDir(bool explicit_userdir) { + string const configure_script = AddName(system_lyxdir, "configure"); + // Does user directory exist? FileInfo fileInfo(user_lyxdir); if (fileInfo.isOK() && fileInfo.isDir()) { first_start = false; - return; - } else { - first_start = true; - } - - // Nope - // Different wording if the user specifically requested a directory - if (!AskQuestion( explicit_userdir - ? _("You have specified an invalid LyX directory.") - : _("You don't have a personal LyX directory.") , - - _("It is needed to keep your own configuration."), - _("Should I try to set it up for you (recommended)?"))) { - lyxerr << _("Running without personal LyX directory.") << endl; - // No, let's use $HOME instead. - user_lyxdir = GetEnvPath("HOME"); + FileInfo script(configure_script); + FileInfo defaults(AddName(user_lyxdir, "lyxrc.defaults")); + if (defaults.isOK() && script.isOK() + && defaults.getModificationTime() < script.getModificationTime()) { + lyxerr << _("LyX: reconfiguring user directory") + << endl; + Path p(user_lyxdir); + ::system(configure_script.c_str()); + lyxerr << "LyX: " << _("Done!") << endl; + } return; } - // Tell the user what is going on - lyxerr << _("LyX: Creating directory ") << user_lyxdir - << _(" and running configure...") << endl; + first_start = !explicit_userdir; + + lyxerr << bformat(_("LyX: Creating directory %1$s" + " and running configure..."), user_lyxdir) << endl; - // Create directory structure if (!createDirectory(user_lyxdir, 0755)) { // Failed, let's use $HOME instead. user_lyxdir = GetEnvPath("HOME"); - lyxerr << _("Failed. Will use ") << user_lyxdir - << _(" instead.") << endl; + lyxerr << bformat(_("Failed. Will use %1$s instead."), + user_lyxdir) << endl; return; } // Run configure in user lyx directory Path p(user_lyxdir); - ::system(AddName(system_lyxdir, "configure").c_str()); + ::system(configure_script.c_str()); lyxerr << "LyX: " << _("Done!") << endl; } -// Read the rc file `name' -bool LyX::ReadRcFile(string const & name) +void LyX::readRcFile(string const & name) { lyxerr[Debug::INIT] << "About to read " << name << "..." << endl; - - string lyxrc_path = LibFileSearch(string(), name); - if (!lyxrc_path.empty()){ - lyxerr[Debug::INIT] << "Found " << name + + string const lyxrc_path = LibFileSearch(string(), name); + if (!lyxrc_path.empty()) { + + lyxerr[Debug::INIT] << "Found " << name << " in " << lyxrc_path << endl; - if (lyxrc.read(lyxrc_path) < 0) { - WriteAlert(_("LyX Warning!"), - _("Error while reading ")+lyxrc_path+".", - _("Using built-in defaults.")); - return false; - } - return true; - } else - lyxerr[Debug::INIT] << "Could not find " << name << endl; - return false; + + if (lyxrc.read(lyxrc_path) >= 0) + return; + } + + showFileError(name); } // Read the ui file `name' -void LyX::ReadUIFile(string const & name) +void LyX::readUIFile(string const & name) { enum Uitags { ui_menuset = 1, ui_toolbar, + ui_toolbars, + ui_include, ui_last }; - struct keyword_item uitags[ui_last-1] = { + struct keyword_item uitags[ui_last - 1] = { + { "include", ui_include }, { "menuset", ui_menuset }, - { "toolbar", ui_toolbar } + { "toolbar", ui_toolbar }, + { "toolbars", ui_toolbars } }; + // Ensure that a file is read only once (prevents include loops) + static std::list uifiles; + std::list::const_iterator it = uifiles.begin(); + std::list::const_iterator end = uifiles.end(); + it = std::find(it, end, name); + if (it != end) { + lyxerr[Debug::INIT] << "UI file '" << name + << "' has been read already. " + << "Is this an include loop?" + << endl; + return; + } + lyxerr[Debug::INIT] << "About to read " << name << "..." << endl; - - string ui_path = LibFileSearch("ui", name, "ui"); + + string const ui_path = LibFileSearch("ui", name, "ui"); if (ui_path.empty()) { - lyxerr[Debug::INIT] << "Could not find " << name << endl; - menubackend.defaults(); + lyxerr[Debug::INIT] << "Could not find " << name << endl; + showFileError(name); return; } - + uifiles.push_back(name); + lyxerr[Debug::INIT] << "Found " << name << " in " << ui_path << endl; LyXLex lex(uitags, ui_last - 1); lex.setFile(ui_path); - if (!lex.IsOK()) { + if (!lex.isOK()) { lyxerr << "Unable to set LyXLeX for ui file: " << ui_path << endl; } - + if (lyxerr.debugging(Debug::PARSER)) lex.printTable(lyxerr); - while (lex.IsOK()) { + while (lex.isOK()) { switch (lex.lex()) { - case ui_menuset: + case ui_include: { + lex.next(true); + string const file = lex.getString(); + readUIFile(file); + break; + } + case ui_menuset: menubackend.read(lex); break; case ui_toolbar: - toolbardefaults.read(lex); + toolbarbackend.read(lex); + break; + + case ui_toolbars: + toolbarbackend.readToolbars(lex); break; default: - lex.printError("LyX::ReadUFile: " - "Unknown menu tag: `$$Token'"); + if (!rtrim(lex.getString()).empty()) + lex.printError("LyX::ReadUIFile: " + "Unknown menu tag: `$$Token'"); break; } } @@ -661,14 +714,13 @@ void LyX::ReadUIFile(string const & name) // Read the languages file `name' -void LyX::ReadLangugesFile(string const & name) +void LyX::readLanguagesFile(string const & name) { lyxerr[Debug::INIT] << "About to read " << name << "..." << endl; - string lang_path = LibFileSearch(string(), name); + string const lang_path = LibFileSearch(string(), name); if (lang_path.empty()) { - lyxerr[Debug::INIT] << "Could not find " << name << endl; - languages.setDefaults(); + showFileError(name); return; } languages.read(lang_path); @@ -676,34 +728,44 @@ void LyX::ReadLangugesFile(string const & name) // Read the encodings file `name' -void LyX::ReadEncodingsFile(string const & name) +void LyX::readEncodingsFile(string const & name) { lyxerr[Debug::INIT] << "About to read " << name << "..." << endl; - string enc_path = LibFileSearch(string(), name); + string const enc_path = LibFileSearch(string(), name); if (enc_path.empty()) { - lyxerr[Debug::INIT] << "Could not find " << name << endl; + showFileError(name); return; } encodings.read(enc_path); } -// Set debugging level and report result to user -static -void setDebuggingLevel(string const & dbgLevel) +namespace { + +bool is_gui = true; +string batch; + +/// return the the number of arguments consumed +typedef boost::function cmd_helper; + +int parse_dbg(string const & arg, string const &) { - lyxerr << _("Setting debug level to ") << dbgLevel << endl; - lyxerr.level(Debug::value(dbgLevel)); + if (arg.empty()) { + lyxerr << _("List of supported debug flags:") << endl; + Debug::showTags(lyxerr); + exit(0); + } + lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl; + + lyxerr.level(Debug::value(arg)); Debug::showLevel(lyxerr, lyxerr.level()); + return 1; } -// Give command line help -static -void commandLineHelp() +int parse_help(string const &, string const &) { - lyxerr << "LyX " LYX_VERSION << " of " LYX_RELEASE << endl; lyxerr << _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n" "Command line switches (case sensitive):\n" @@ -711,159 +773,137 @@ void commandLineHelp() "\t-userdir dir try to set user directory to dir\n" "\t-sysdir dir try to set system directory to dir\n" "\t-geometry WxH+X+Y set geometry of the main window\n" - "\t-dbg feature[,feature]...\n" - " select the features to debug.\n" - " Type `lyx -dbg' to see the list of features\n" - "Check the LyX man page for more options.") << endl; + "\t-dbg feature[,feature]...\n" + " select the features to debug.\n" + " Type `lyx -dbg' to see the list of features\n" + "\t-x [--execute] command\n" + " where command is a lyx command.\n" + "\t-e [--export] fmt\n" + " where fmt is the export format of choice.\n" + "\t-i [--import] fmt file.xxx\n" + " where fmt is the import format of choice\n" + " and file.xxx is the file to be imported.\n" + "\t-version summarize version and build info\n" + "Check the LyX man page for more details.") << endl; + exit(0); + return 0; } +int parse_version(string const &, string const &) +{ + lyxerr << "LyX " << lyx_version + << " of " << lyx_release_date << endl; + lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl; + + lyxerr << lyx_version_info << endl; + exit(0); + return 0; +} -bool LyX::easyParse(int * argc, char * argv[]) +int parse_sysdir(string const & arg, string const &) { - bool gui = true; - int removeargs = 0; // used when options are read - for (int i = 1; i < *argc; ++i) { - string arg = argv[i]; - - // Check for -dbg int - if (arg == "-dbg") { - if (i + 1 < *argc) { - setDebuggingLevel(argv[i + 1]); - removeargs = 2; - } else { - lyxerr << _("List of supported debug flags:") - << endl; - Debug::showTags(lyxerr); - exit(0); - } - } - // Check for "-sysdir" - else if (arg == "-sysdir") { - if (i + 1 < *argc) { - system_lyxdir = argv[i + 1]; - removeargs = 2; - } else { - lyxerr << _("Missing directory for -sysdir switch!") - << endl; - exit(0); - } - } - // Check for "-userdir" - else if (arg == "-userdir") { - if (i + 1 < *argc) { - user_lyxdir = argv[i + 1]; - removeargs = 2; - } else { - lyxerr << _("Missing directory for -userdir switch!") - << endl; - exit(0); - } - } - // Check for --help or -help - else if (arg == "--help" || arg == "-help") { - commandLineHelp(); - exit(0); - } - // Check for "-nw": No XWindows as for emacs this should - // give a LyX that could be used in a terminal window. - //else if (arg == "-nw") { - // gui = false; - //} - - // Check for "-x": Execute commands - else if (arg == "-x" || arg == "--execute") { - if (i + 1 < *argc) { - batch_command = string(argv[i + 1]); - removeargs = 2; - } - else - lyxerr << _("Missing command string after -x switch!") << endl; + if (arg.empty()) { + lyxerr << _("Missing directory for -sysdir switch") << endl; + exit(1); + } + system_lyxdir = arg; + return 1; +} - // Argh. Setting gui to false segfaults.. - //gui = false; - } +int parse_userdir(string const & arg, string const &) +{ + if (arg.empty()) { + lyxerr << _("Missing directory for -userdir switch") << endl; + exit(1); + } + user_lyxdir = arg; + return 1; +} - else if (arg == "-e" || arg == "--export") { - if (i + 1 < *argc) { - string type(argv[i+1]); - removeargs = 2; - batch_command = "buffer-export " + type; - gui = false; - } else - lyxerr << _("Missing file type [eg latex, " - "ps...] after ") - << arg << _(" switch!") << endl; - } - else if (arg == "--import") { - if (i + 1 < *argc) { - string type(argv[i+1]); - string file(argv[i+2]); - removeargs = 3; - - batch_command = "buffer-import " + type + " " + file; - lyxerr << "batch_command: " - << batch_command << endl; - - } else - lyxerr << _("Missing type [eg latex, " - "ps...] after ") - << arg << _(" switch!") << endl; - } +int parse_execute(string const & arg, string const &) +{ + if (arg.empty()) { + lyxerr << _("Missing command string after --execute switch") << endl; + exit(1); + } + batch = arg; + // Argh. Setting gui to false segfaults.. + // FIXME: when ? how ? + // is_gui = false; + return 1; +} - if (removeargs > 0) { - // Now, remove used arguments by shifting - // the following ones removeargs places down. - (*argc) -= removeargs; - for (int j = i; j < (*argc); ++j) - argv[j] = argv[j + removeargs]; - --i; // After shift, check this number again. - removeargs = 0; - } +int parse_export(string const & type, string const &) +{ + if (type.empty()) { + lyxerr << _("Missing file type [eg latex, ps...] after " + "--export switch") << endl; + exit(1); + } + batch = "buffer-export " + type; + is_gui = false; + return 1; +} +int parse_import(string const & type, string const & file) +{ + if (type.empty()) { + lyxerr << _("Missing file type [eg latex, ps...] after " + "--import switch") << endl; + exit(1); + } + if (file.empty()) { + lyxerr << _("Missing filename for --import") << endl; + exit(1); } - return gui; + batch = "buffer-import " + type + ' ' + file; + return 2; } +} // namespace anon + -extern "C" -void error_handler(int err_sig) +bool LyX::easyParse(int & argc, char * argv[]) { - switch (err_sig) { - case SIGHUP: - lyxerr << "\nlyx: SIGHUP signal caught" << endl; - break; - case SIGINT: - // no comments - break; - case SIGFPE: - lyxerr << "\nlyx: SIGFPE signal caught" << endl; - break; - case SIGSEGV: - lyxerr << "\nlyx: SIGSEGV signal caught" << endl; - lyxerr << - "Sorry, you have found a bug in LyX." - " If possible, please read 'Known bugs'\n" - "under the Help menu and then send us " - "a full bug report. Thanks!" << endl; - break; - case SIGTERM: - // no comments - break; + std::map cmdmap; + + cmdmap["-dbg"] = parse_dbg; + cmdmap["-help"] = parse_help; + cmdmap["--help"] = parse_help; + cmdmap["-version"] = parse_version; + cmdmap["--version"] = parse_version; + cmdmap["-sysdir"] = parse_sysdir; + cmdmap["-userdir"] = parse_userdir; + cmdmap["-x"] = parse_execute; + cmdmap["--execute"] = parse_execute; + cmdmap["-e"] = parse_export; + cmdmap["--export"] = parse_export; + cmdmap["-i"] = parse_import; + cmdmap["--import"] = parse_import; + + for (int i = 1; i < argc; ++i) { + std::map::const_iterator it + = cmdmap.find(argv[i]); + + // don't complain if not found - may be parsed later + if (it == cmdmap.end()) + continue; + + string arg((i + 1 < argc) ? argv[i + 1] : ""); + string arg2((i + 2 < argc) ? argv[i + 2] : ""); + + int const remove = 1 + it->second(arg, arg2); + + // Now, remove used arguments by shifting + // the following ones remove places down. + argc -= remove; + for (int j = i; j < argc; ++j) + argv[j] = argv[j + remove]; + --i; } - - // Deinstall the signal handlers - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGFPE, SIG_DFL); - signal(SIGSEGV, SIG_DFL); - signal(SIGTERM, SIG_DFL); - bufferlist.emergencyWriteAll(); + batch_command = batch; - lyxerr << "Bye." << endl; - if (err_sig!= SIGHUP && - (!GetEnv("LYXDEBUG").empty() || err_sig == SIGSEGV)) - lyx::abort(); - exit(0); + return is_gui; }