]> git.lyx.org Git - lyx.git/blob - src/lyx_main.C
More 'standard conformant blurb' nonsense.
[lyx.git] / src / lyx_main.C
1 /**
2  * \file lyx_main.C
3  * Copyright 1995-2002 the LyX Team
4  * Read the file COPYING
5  *
6  * \author Lars Gullik Bjønnes
7  */
8
9 #include <config.h>
10 #include <version.h>
11
12 #include "lyx_main.h"
13
14 #include "support/filetools.h"
15 #include "support/lyxlib.h"
16 #include "support/FileInfo.h"
17 #include "support/path.h"
18 #include "support/path_defines.h"
19 #include "debug.h"
20 #include "gettext.h"
21 #include "lyxlex.h"
22
23 #include "graphics/GraphicsTypes.h"
24
25 #include "bufferlist.h"
26 #include "buffer.h"
27 #include "buffer_funcs.h"
28 #include "lyxserver.h"
29 #include "kbmap.h"
30 #include "lyxfunc.h"
31 #include "ToolbarBackend.h"
32 #include "MenuBackend.h"
33 #include "language.h"
34 #include "lastfiles.h"
35 #include "encoding.h"
36 #include "converter.h"
37 #include "format.h"
38 #include "lyxtextclasslist.h"
39
40 #include "frontends/Alert.h"
41 #include "frontends/lyx_gui.h"
42
43 #include <boost/function.hpp>
44 #include <boost/bind.hpp>
45 #include <boost/signals/signal1.hpp>
46
47 #include <cstdlib>
48 #include <csignal>
49 #include <iostream>
50
51 using namespace lyx::support;
52
53 using std::vector;
54 using std::endl;
55
56 #ifndef CXX_GLOBAL_CSTD
57 using std::exit;
58 using std::signal;
59 using std::system;
60 #endif
61
62 extern void QuitLyX();
63
64 extern LyXServer * lyxserver;
65
66 DebugStream lyxerr;
67
68 boost::scoped_ptr<LastFiles> lastfiles;
69
70 // This is the global bufferlist object
71 BufferList bufferlist;
72
73 // convenient to have it here.
74 boost::scoped_ptr<kb_keymap> toplevel_keymap;
75
76 namespace {
77
78 void showFileError(string const & error)
79 {
80         Alert::warning(_("Could not read configuration file"),
81                    bformat(_("Error while reading the configuration file\n%1$s.\n"
82                      "Please check your installation."), error));
83         exit(EXIT_FAILURE);
84 }
85
86 }
87
88 LyX::LyX(int & argc, char * argv[])
89 {
90         // Here we need to parse the command line. At least
91         // we need to parse for "-dbg" and "-help"
92         bool const want_gui = easyParse(argc, argv);
93
94         // set the DisplayTranslator only once; should that be done here??
95         // if this should not be in this file, please also remove
96         // #include "graphics/GraphicsTypes.h" at the top -- Rob Lahaye.
97         lyx::graphics::setDisplayTranslator();
98
99         if (want_gui)
100                 lyx_gui::parse_init(argc, argv);
101
102         // check for any spurious extra arguments
103         // other than documents
104         for (int argi = 1; argi < argc ; ++argi) {
105                 if (argv[argi][0] == '-') {
106                         lyxerr << bformat(_("Wrong command line option `%1$s'. Exiting."),
107                                 argv[argi]) << endl;
108                         exit(1);
109                 }
110         }
111
112         // Initialization of LyX (reads lyxrc and more)
113         lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
114         init(want_gui);
115         lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
116
117         if (want_gui) 
118                 lyx_gui::parse_lyxrc();
119
120         vector<string> files;
121
122         for (int argi = argc - 1; argi >= 1; --argi) 
123                 files.push_back(argv[argi]);
124
125         if (first_start)
126                 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
127
128         // Execute batch commands if available
129         if (!batch_command.empty()) {
130
131                 lyxerr[Debug::INIT] << "About to handle -x '"
132                        << batch_command << '\'' << endl;
133
134                 Buffer * last_loaded = 0;
135
136                 vector<string>::const_iterator it = files.begin();
137                 vector<string>::const_iterator end = files.end();
138
139                 for (; it != end; ++it) {
140                         // get absolute path of file and add ".lyx" to
141                         // the filename if necessary
142                         string s = FileSearch(string(), *it, "lyx");
143                         if (s.empty()) {
144                                 last_loaded = newFile(*it, string(), true);
145                         } else {
146                                 Buffer * buf = bufferlist.newBuffer(s, false);
147                                 buf->error.connect(boost::bind(&LyX::printError, this, _1));
148                                 if (loadLyXFile(buf, s)) 
149                                         last_loaded = buf;
150                                 else
151                                         bufferlist.release(buf);
152                         }
153                 }
154
155                 // try to dispatch to last loaded buffer first
156                 if (last_loaded) {
157                         bool success = false;
158                         if (last_loaded->dispatch(batch_command, &success)) {
159                                 QuitLyX();
160                                 exit(!success);
161                         }
162                 } 
163                 files.clear(); // the files are already loaded
164         }
165
166         lyx_gui::start(batch_command, files);
167 }
168
169
170 extern "C" {
171
172 static void error_handler(int err_sig)
173 {
174         switch (err_sig) {
175         case SIGHUP:
176                 lyxerr << "\nlyx: SIGHUP signal caught" << endl;
177                 break;
178         case SIGINT:
179                 // no comments
180                 break;
181         case SIGFPE:
182                 lyxerr << "\nlyx: SIGFPE signal caught" << endl;
183                 break;
184         case SIGSEGV:
185                 lyxerr << "\nlyx: SIGSEGV signal caught" << endl;
186                 lyxerr <<
187                         "Sorry, you have found a bug in LyX. "
188                         "Please read the bug-reporting instructions "
189                         "in Help->Introduction and send us a bug report, "
190                         "if necessary. Thanks !" << endl;
191                 break;
192         case SIGTERM:
193                 // no comments
194                 break;
195         }
196
197         // Deinstall the signal handlers
198         signal(SIGHUP, SIG_DFL);
199         signal(SIGINT, SIG_DFL);
200         signal(SIGFPE, SIG_DFL);
201         signal(SIGSEGV, SIG_DFL);
202         signal(SIGTERM, SIG_DFL);
203
204         LyX::emergencyCleanup();
205
206         lyxerr << "Bye." << endl;
207         if (err_sig!= SIGHUP &&
208            (!GetEnv("LYXDEBUG").empty() || err_sig == SIGSEGV))
209                 lyx::support::abort();
210         exit(0);
211 }
212
213 }
214
215
216 void LyX::printError(ErrorItem const & ei)
217 {
218         std::cerr << _("LyX: ") << ei.error
219                   << ':' << ei.description << std::endl;
220
221 }
222
223
224 void LyX::init(bool gui)
225 {
226         signal(SIGHUP, error_handler);
227         signal(SIGFPE, error_handler);
228         signal(SIGSEGV, error_handler);
229         signal(SIGINT, error_handler);
230         signal(SIGTERM, error_handler);
231
232         bool const explicit_userdir = setLyxPaths();
233
234         // Check that user LyX directory is ok. We don't do that if
235         // running in batch mode.
236         if (gui) {
237                 queryUserLyXDir(explicit_userdir);
238         } else {
239                 first_start = false;
240         }
241
242         // Disable gui when easyparse says so
243         lyx_gui::use_gui = gui;
244
245         if (lyxrc.template_path.empty()) {
246                 lyxrc.template_path = AddPath(system_lyxdir(), "templates");
247         }
248
249         if (lyxrc.lastfiles.empty()) {
250                 lyxrc.lastfiles = AddName(user_lyxdir(), "lastfiles");
251         }
252
253         if (lyxrc.roman_font_name.empty())
254                 lyxrc.roman_font_name = lyx_gui::roman_font_name();
255         if (lyxrc.sans_font_name.empty())
256                 lyxrc.sans_font_name = lyx_gui::sans_font_name();
257         if (lyxrc.typewriter_font_name.empty())
258                 lyxrc.typewriter_font_name = lyx_gui::typewriter_font_name();
259
260         //
261         // Read configuration files
262         //
263
264         readRcFile("lyxrc.defaults");
265         system_lyxrc = lyxrc;
266         system_formats = formats;
267         system_converters = converters;
268         system_lcolor = lcolor;
269
270         string prefsfile = "preferences";
271         // back compatibility to lyxs < 1.1.6
272         if (LibFileSearch(string(), prefsfile).empty())
273                 prefsfile = "lyxrc";
274         if (!LibFileSearch(string(), prefsfile).empty())
275                 readRcFile(prefsfile);
276
277         readEncodingsFile("encodings");
278         readLanguagesFile("languages");
279
280         // Load the layouts
281         lyxerr[Debug::INIT] << "Reading layouts..." << endl;
282         LyXSetStyle();
283
284         if (gui) {
285                 // Set up bindings
286                 toplevel_keymap.reset(new kb_keymap);
287                 defaultKeyBindings(toplevel_keymap.get());
288                 toplevel_keymap->read(lyxrc.bind_file);
289
290                 // Read menus
291                 readUIFile(lyxrc.ui_file);
292         }
293
294         if (lyxerr.debugging(Debug::LYXRC))
295                 lyxrc.print();
296
297         os::setTmpDir(CreateLyXTmpDir(lyxrc.tempdir_path));
298         if (lyxerr.debugging(Debug::INIT)) {
299                 lyxerr << "LyX tmp dir: `" << os::getTmpDir() << '\'' << endl;
300         }
301
302         lyxerr[Debug::INIT] << "Reading lastfiles `"
303                             << lyxrc.lastfiles << "'..." << endl;
304         lastfiles.reset(new LastFiles(lyxrc.lastfiles,
305                                       lyxrc.check_lastfiles,
306                                       lyxrc.num_lastfiles));
307 }
308
309
310 void LyX::defaultKeyBindings(kb_keymap  * kbmap)
311 {
312         kbmap->bind("Right", LFUN_RIGHT);
313         kbmap->bind("Left", LFUN_LEFT);
314         kbmap->bind("Up", LFUN_UP);
315         kbmap->bind("Down", LFUN_DOWN);
316
317         kbmap->bind("Tab", LFUN_CELL_FORWARD);
318         kbmap->bind("ISO_Left_Tab", LFUN_CELL_FORWARD); // jbl 2001-23-02
319
320         kbmap->bind("Home", LFUN_HOME);
321         kbmap->bind("End", LFUN_END);
322         kbmap->bind("Prior", LFUN_PRIOR);
323         kbmap->bind("Next", LFUN_NEXT);
324
325         kbmap->bind("Return", LFUN_BREAKPARAGRAPH);
326         //kbmap->bind("~C-~S-~M-nobreakspace", LFUN_PROTECTEDSPACE);
327
328         kbmap->bind("Delete", LFUN_DELETE);
329         kbmap->bind("BackSpace", LFUN_BACKSPACE);
330
331         // sub- and superscript -MV
332         kbmap->bind("~S-underscore", LFUN_SUBSCRIPT);
333         kbmap->bind("~S-asciicircum", LFUN_SUPERSCRIPT);
334
335         // kbmap->bindings to enable the use of the numeric keypad
336         // e.g. Num Lock set
337         //kbmap->bind("KP_0", LFUN_SELFINSERT);
338         //kbmap->bind("KP_Decimal", LFUN_SELFINSERT);
339         kbmap->bind("KP_Enter", LFUN_BREAKPARAGRAPH);
340         //kbmap->bind("KP_1", LFUN_SELFINSERT);
341         //kbmap->bind("KP_2", LFUN_SELFINSERT);
342         //kbmap->bind("KP_3", LFUN_SELFINSERT);
343         //kbmap->bind("KP_4", LFUN_SELFINSERT);
344         //kbmap->bind("KP_5", LFUN_SELFINSERT);
345         //kbmap->bind("KP_6", LFUN_SELFINSERT);
346         //kbmap->bind("KP_Add", LFUN_SELFINSERT);
347         //kbmap->bind("KP_7", LFUN_SELFINSERT);
348         //kbmap->bind("KP_8", LFUN_SELFINSERT);
349         //kbmap->bind("KP_9", LFUN_SELFINSERT);
350         //kbmap->bind("KP_Divide", LFUN_SELFINSERT);
351         //kbmap->bind("KP_Multiply", LFUN_SELFINSERT);
352         //kbmap->bind("KP_Subtract", LFUN_SELFINSERT);
353         kbmap->bind("KP_Right", LFUN_RIGHT);
354         kbmap->bind("KP_Left", LFUN_LEFT);
355         kbmap->bind("KP_Up", LFUN_UP);
356         kbmap->bind("KP_Down", LFUN_DOWN);
357         kbmap->bind("KP_Home", LFUN_HOME);
358         kbmap->bind("KP_End", LFUN_END);
359         kbmap->bind("KP_Prior", LFUN_PRIOR);
360         kbmap->bind("KP_Next", LFUN_NEXT);
361
362         kbmap->bind("C-Tab", LFUN_CELL_SPLIT);  // ale970515
363         kbmap->bind("S-Tab", LFUN_CELL_BACKWARD);  // jug20000522
364         kbmap->bind("S-ISO_Left_Tab", LFUN_CELL_BACKWARD); // jbl 2001-23-02
365 }
366
367
368 void LyX::emergencyCleanup()
369 {
370         // what to do about tmpfiles is non-obvious. we would
371         // like to delete any we find, but our lyxdir might
372         // contain documents etc. which might be helpful on
373         // a crash
374
375         bufferlist.emergencyWriteAll();
376         if (lyxserver)
377                 lyxserver->emergencyCleanup();
378 }
379
380
381 void LyX::deadKeyBindings(kb_keymap * kbmap)
382 {
383         // bindKeyings for transparent handling of deadkeys
384         // The keysyms are gotten from XFree86 X11R6
385         kbmap->bind("~C-~S-~M-dead_acute", LFUN_ACUTE);
386         kbmap->bind("~C-~S-~M-dead_breve", LFUN_BREVE);
387         kbmap->bind("~C-~S-~M-dead_caron", LFUN_CARON);
388         kbmap->bind("~C-~S-~M-dead_cedilla", LFUN_CEDILLA);
389         kbmap->bind("~C-~S-~M-dead_abovering", LFUN_CIRCLE);
390         kbmap->bind("~C-~S-~M-dead_circumflex", LFUN_CIRCUMFLEX);
391         kbmap->bind("~C-~S-~M-dead_abovedot", LFUN_DOT);
392         kbmap->bind("~C-~S-~M-dead_grave", LFUN_GRAVE);
393         kbmap->bind("~C-~S-~M-dead_doubleacute", LFUN_HUNG_UMLAUT);
394         kbmap->bind("~C-~S-~M-dead_macron", LFUN_MACRON);
395         // nothing with this name
396         // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_SPECIAL_CARON);
397         kbmap->bind("~C-~S-~M-dead_tilde", LFUN_TILDE);
398         kbmap->bind("~C-~S-~M-dead_diaeresis", LFUN_UMLAUT);
399         // nothing with this name either...
400         //kbmap->bind("~C-~S-~M-dead_underbar", LFUN_UNDERBAR);
401         kbmap->bind("~C-~S-~M-dead_belowdot", LFUN_UNDERDOT);
402         kbmap->bind("~C-~S-~M-dead_tie", LFUN_TIE);
403         kbmap->bind("~C-~S-~M-dead_ogonek", LFUN_OGONEK);
404 }
405
406
407 void LyX::queryUserLyXDir(bool explicit_userdir)
408 {
409         string const configure_script = AddName(system_lyxdir(), "configure");
410
411         // Does user directory exist?
412         FileInfo fileInfo(user_lyxdir());
413         if (fileInfo.isOK() && fileInfo.isDir()) {
414                 first_start = false;
415                 FileInfo script(configure_script);
416                 FileInfo defaults(AddName(user_lyxdir(), "lyxrc.defaults"));
417                 if (defaults.isOK() && script.isOK()
418                     && defaults.getModificationTime() < script.getModificationTime()) {
419                         lyxerr << _("LyX: reconfiguring user directory")
420                                << endl;
421                         Path p(user_lyxdir());
422                         ::system(configure_script.c_str());
423                         lyxerr << "LyX: " << _("Done!") << endl;
424                 }
425                 return;
426         }
427
428         first_start = !explicit_userdir;
429
430         lyxerr << bformat(_("LyX: Creating directory %1$s"
431                                   " and running configure..."), user_lyxdir()) << endl;
432
433         if (!createDirectory(user_lyxdir(), 0755)) {
434                 // Failed, let's use $HOME instead.
435                 user_lyxdir(GetEnvPath("HOME"));
436                 lyxerr << bformat(_("Failed. Will use %1$s instead."),
437                         user_lyxdir()) << endl;
438                 return;
439         }
440
441         // Run configure in user lyx directory
442         Path p(user_lyxdir());
443         ::system(configure_script.c_str());
444         lyxerr << "LyX: " << _("Done!") << endl;
445 }
446
447
448 void LyX::readRcFile(string const & name)
449 {
450         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
451
452         string const lyxrc_path = LibFileSearch(string(), name);
453         if (!lyxrc_path.empty()) {
454
455                 lyxerr[Debug::INIT] << "Found " << name
456                                     << " in " << lyxrc_path << endl;
457
458                 if (lyxrc.read(lyxrc_path) >= 0)
459                         return;
460         }
461
462         showFileError(name);
463 }
464
465
466 // Read the ui file `name'
467 void LyX::readUIFile(string const & name)
468 {
469         enum Uitags {
470                 ui_menuset = 1,
471                 ui_toolbar,
472                 ui_toolbars,
473                 ui_include,
474                 ui_last
475         };
476
477         struct keyword_item uitags[ui_last - 1] = {
478                 { "include", ui_include },
479                 { "menuset", ui_menuset },
480                 { "toolbar", ui_toolbar },
481                 { "toolbars", ui_toolbars }
482         };
483
484         // Ensure that a file is read only once (prevents include loops)
485         static std::list<string> uifiles;
486         std::list<string>::const_iterator it  = uifiles.begin();
487         std::list<string>::const_iterator end = uifiles.end();
488         it = std::find(it, end, name);
489         if (it != end) {
490                 lyxerr[Debug::INIT] << "UI file '" << name
491                                     << "' has been read already. "
492                                     << "Is this an include loop?"
493                                     << endl;
494                 return;
495         }
496
497         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
498
499         string const ui_path = LibFileSearch("ui", name, "ui");
500
501         if (ui_path.empty()) {
502                 lyxerr[Debug::INIT] << "Could not find " << name << endl;
503                 showFileError(name);
504                 return;
505         }
506         uifiles.push_back(name);
507
508         lyxerr[Debug::INIT] << "Found " << name
509                             << " in " << ui_path << endl;
510         LyXLex lex(uitags, ui_last - 1);
511         lex.setFile(ui_path);
512         if (!lex.isOK()) {
513                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
514                        << endl;
515         }
516
517         if (lyxerr.debugging(Debug::PARSER))
518                 lex.printTable(lyxerr);
519
520         while (lex.isOK()) {
521                 switch (lex.lex()) {
522                 case ui_include: {
523                         lex.next(true);
524                         string const file = lex.getString();
525                         readUIFile(file);
526                         break;
527                 }
528                 case ui_menuset:
529                         menubackend.read(lex);
530                         break;
531
532                 case ui_toolbar:
533                         toolbarbackend.read(lex);
534                         break;
535
536                 case ui_toolbars:
537                         toolbarbackend.readToolbars(lex);
538                         break;
539
540                 default:
541                         if (!rtrim(lex.getString()).empty())
542                                 lex.printError("LyX::ReadUIFile: "
543                                                "Unknown menu tag: `$$Token'");
544                         break;
545                 }
546         }
547 }
548
549
550 // Read the languages file `name'
551 void LyX::readLanguagesFile(string const & name)
552 {
553         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
554
555         string const lang_path = LibFileSearch(string(), name);
556         if (lang_path.empty()) {
557                 showFileError(name);
558                 return;
559         }
560         languages.read(lang_path);
561 }
562
563
564 // Read the encodings file `name'
565 void LyX::readEncodingsFile(string const & name)
566 {
567         lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
568
569         string const enc_path = LibFileSearch(string(), name);
570         if (enc_path.empty()) {
571                 showFileError(name);
572                 return;
573         }
574         encodings.read(enc_path);
575 }
576
577
578 namespace {
579
580 bool is_gui = true;
581 string batch;
582
583 /// return the the number of arguments consumed
584 typedef boost::function<int(string const &, string const &)> cmd_helper;
585
586 int parse_dbg(string const & arg, string const &)
587 {
588         if (arg.empty()) {
589                 lyxerr << _("List of supported debug flags:") << endl;
590                 Debug::showTags(lyxerr);
591                 exit(0);
592         }
593         lyxerr << bformat(_("Setting debug level to %1$s"), arg) << endl;
594
595         lyxerr.level(Debug::value(arg));
596         Debug::showLevel(lyxerr, lyxerr.level());
597         return 1;
598 }
599
600
601 int parse_help(string const &, string const &)
602 {
603         lyxerr <<
604                 _("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
605                   "Command line switches (case sensitive):\n"
606                   "\t-help              summarize LyX usage\n"
607                   "\t-userdir dir       try to set user directory to dir\n"
608                   "\t-sysdir dir        try to set system directory to dir\n"
609                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
610                   "\t-dbg feature[,feature]...\n"
611                   "                  select the features to debug.\n"
612                   "                  Type `lyx -dbg' to see the list of features\n"
613                   "\t-x [--execute] command\n"
614                   "                  where command is a lyx command.\n"
615                   "\t-e [--export] fmt\n"
616                   "                  where fmt is the export format of choice.\n"
617                   "\t-i [--import] fmt file.xxx\n"
618                   "                  where fmt is the import format of choice\n"
619                   "                  and file.xxx is the file to be imported.\n"
620                   "\t-version        summarize version and build info\n"
621                   "Check the LyX man page for more details.") << endl;
622         exit(0);
623         return 0;
624 }
625
626 int parse_version(string const &, string const &)
627 {
628         lyxerr << "LyX " << lyx_version
629                << " of " << lyx_release_date << endl;
630         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
631
632         lyxerr << lyx_version_info << endl;
633         exit(0);
634         return 0;
635 }
636
637 int parse_sysdir(string const & arg, string const &)
638 {
639         if (arg.empty()) {
640                 lyxerr << _("Missing directory for -sysdir switch") << endl;
641                 exit(1);
642         }
643         system_lyxdir(arg);
644         return 1;
645 }
646
647 int parse_userdir(string const & arg, string const &)
648 {
649         if (arg.empty()) {
650                 lyxerr << _("Missing directory for -userdir switch") << endl;
651                 exit(1);
652         }
653         user_lyxdir(arg);
654         return 1;
655 }
656
657 int parse_execute(string const & arg, string const &)
658 {
659         if (arg.empty()) {
660                 lyxerr << _("Missing command string after --execute switch") << endl;
661                 exit(1);
662         }
663         batch = arg;
664         // Argh. Setting gui to false segfaults..
665         // FIXME: when ? how ?
666         // is_gui = false;
667         return 1;
668 }
669
670 int parse_export(string const & type, string const &)
671 {
672         if (type.empty()) {
673                 lyxerr << _("Missing file type [eg latex, ps...] after "
674                         "--export switch") << endl;
675                 exit(1);
676         }
677         batch = "buffer-export " + type;
678         is_gui = false;
679         return 1;
680 }
681
682 int parse_import(string const & type, string const & file)
683 {
684         if (type.empty()) {
685                 lyxerr << _("Missing file type [eg latex, ps...] after "
686                         "--import switch") << endl;
687                 exit(1);
688         }
689         if (file.empty()) {
690                 lyxerr << _("Missing filename for --import") << endl;
691                 exit(1);
692         }
693
694         batch = "buffer-import " + type + ' ' + file;
695         return 2;
696 }
697
698 } // namespace anon
699
700
701 bool LyX::easyParse(int & argc, char * argv[])
702 {
703         std::map<string, cmd_helper> cmdmap;
704
705         cmdmap["-dbg"] = parse_dbg;
706         cmdmap["-help"] = parse_help;
707         cmdmap["--help"] = parse_help;
708         cmdmap["-version"] = parse_version;
709         cmdmap["--version"] = parse_version;
710         cmdmap["-sysdir"] = parse_sysdir;
711         cmdmap["-userdir"] = parse_userdir;
712         cmdmap["-x"] = parse_execute;
713         cmdmap["--execute"] = parse_execute;
714         cmdmap["-e"] = parse_export;
715         cmdmap["--export"] = parse_export;
716         cmdmap["-i"] = parse_import;
717         cmdmap["--import"] = parse_import;
718
719         for (int i = 1; i < argc; ++i) {
720                 std::map<string, cmd_helper>::const_iterator it
721                         = cmdmap.find(argv[i]);
722
723                 // don't complain if not found - may be parsed later
724                 if (it == cmdmap.end())
725                         continue;
726
727                 string arg((i + 1 < argc) ? argv[i + 1] : "");
728                 string arg2((i + 2 < argc) ? argv[i + 2] : "");
729
730                 int const remove = 1 + it->second(arg, arg2);
731
732                 // Now, remove used arguments by shifting
733                 // the following ones remove places down.
734                 argc -= remove;
735                 for (int j = i; j < argc; ++j)
736                         argv[j] = argv[j + remove];
737                 --i;
738         }
739
740         batch_command = batch;
741
742         return is_gui;
743 }