From cb5e08b40d7444817c7eb6c1e4e8bf5208c2823c Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 16 Nov 2016 16:06:12 +0100 Subject: improved command line option handling * it turns out that option-like arguments could not be reliably passed to SciTECO scripts for two reasons: a) "--" arguments are not removed from argv by GOption if it detects and following option-like argument. "--" would thus be passed as a script argument which will disable option parsing in scripts that interpret "--". b) A script run via the Hash-Bang line "#!...sciteco -m" would require an explicit "--" to turn of GOption parsing. However it is __impossible__ to insert after the script file name on UNIX. * Therefore, SciTECO now removes leading "--" arguments left over by GOption. * If possible (Glib >= 2.44), option parsing is performed in strict POSIX mode which inhibits parsing after the first non-option argument. This reduces the number of cases where an explicit "--" is required. * --mung no longer takes an argument. Instead, the first non-option argument is expected to be the script file name. This looks weird at first but is more consistent with how other interpeters work. Once we revise argument passing to scripts, the script name can also be passed to the script which is more consistent with it being the first non-option argument. Also, with strict POSIX parsing, this fixed Hash-Bang lines since the script file name constructed by the kernel will automatically switch off option parsing, passing all option-like script arguments uninterpreted to the script. * Since we're supporting Glib < 2.44, the Hash-Bang lines are still broken for certain builds. Therefore, a wrapper script is installed to libexecdir (it never has to be executed by users and Hash-Bang lines need absolute paths anyway) which transparently inserts "--" into the SciTECO command line and should be used as the interpreter in portable SciTECO scripts. The wrapper script is generated and points to the exact SciTECO binary installed. This is important when doing parallel installs of Curses and Gtk binaries since each one will get its own working wrapper script. The wrapper-script workaround can be removed once we depend on Glib >= 2.44 (some day...). * The default /usr/bin/env Hash-Bang lines are no longer used in the scripts since they are broken anyway (UNIX incl. Linux cannot pass multiple arguments to the interpreter!). Scripts that get installed will get a fixed-up Hash-Bang line referring to the installed SciTECO binary anyway. * Interface::main() has been renamed to Interface::init() and is optional now. The Interface::main() method was introduced because of the misconception that interfaces will find their options in the argv array and have to do their own parsing. This is wrong, since their option group already cares about parsing. Therefore, gtk_init() does not have to called explicitly, too. --- src/main.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 22 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index d14e2e5..e9be929 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,7 +75,7 @@ namespace Flags { } static gchar *eval_macro = NULL; -static gchar *mung_file = NULL; +static gboolean mung_file = FALSE; static gboolean mung_profile = TRUE; sig_atomic_t sigint_occurred = FALSE; @@ -165,29 +165,31 @@ get_default_config_path(const gchar *program) #endif -static inline void +static inline gchar * process_options(int &argc, char **&argv) { static const GOptionEntry option_entries[] = { {"eval", 'e', 0, G_OPTION_ARG_STRING, &eval_macro, "Evaluate macro", "macro"}, - {"mung", 'm', 0, G_OPTION_ARG_FILENAME, &mung_file, - "Mung file instead of " - "$SCITECOCONFIG" G_DIR_SEPARATOR_S INI_FILE, "file"}, + {"mung", 'm', 0, G_OPTION_ARG_NONE, &mung_file, + "Mung script file (first non-option argument) instead of " + "$SCITECOCONFIG" G_DIR_SEPARATOR_S INI_FILE}, {"no-profile", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &mung_profile, "Do not mung " - "$SCITECOCONFIG" G_DIR_SEPARATOR_S INI_FILE - " even if it exists"}, + "$SCITECOCONFIG" G_DIR_SEPARATOR_S INI_FILE " " + "even if it exists"}, {NULL} }; + gchar *mung_filename = NULL; + GError *gerror = NULL; GOptionContext *options; GOptionGroup *interface_group = interface.get_options(); - options = g_option_context_new("[--] [ARGUMENT...]"); + options = g_option_context_new("[--] [SCRIPT] [ARGUMENT...]"); g_option_context_set_summary( options, @@ -203,6 +205,21 @@ process_options(int &argc, char **&argv) if (interface_group) g_option_context_add_group(options, interface_group); +#if GLIB_CHECK_VERSION(2,44,0) + /* + * If possible we parse in POSIX mode, which means that + * the first non-option argument terminates option parsing. + * SciTECO considers all non-option arguments to be script + * arguments and it makes little sense to mix script arguments + * with SciTECO options, so this lets the user avoid "--" + * in many situations. + * It is also strictly required to make hash-bang lines like + * #!/usr/bin/sciteco -m + * work (see sciteco(1)). + */ + g_option_context_set_strict_posix(options, TRUE); +#endif + if (!g_option_context_parse(options, &argc, &argv, &gerror)) { g_fprintf(stderr, "Option parsing failed: %s\n", gerror->message); @@ -212,15 +229,41 @@ process_options(int &argc, char **&argv) g_option_context_free(options); + /* + * GOption will NOT remove "--" if followed by an + * option-argument, which may interfer with scripts + * doing their own option handling and interpreting "--". + * + * NOTE: This is still true if we're parsing in GNU-mode + * and "--" is not the first non-option argument as in + * sciteco foo -- -C bar. + */ + if (argc >= 2 && !strcmp(argv[1], "--")) { + argv[1] = argv[0]; + argv++; + argc--; + } + if (mung_file) { - if (!g_file_test(mung_file, G_FILE_TEST_IS_REGULAR)) { + if (argc < 2) { + g_fprintf(stderr, "Script to mung expected!\n"); + exit(EXIT_FAILURE); + } + + if (!g_file_test(argv[1], G_FILE_TEST_IS_REGULAR)) { g_fprintf(stderr, "Cannot mung \"%s\". File does not exist!\n", - mung_file); + argv[1]); exit(EXIT_FAILURE); } + + mung_filename = g_strdup(argv[1]); + + argv[1] = argv[0]; + argv++; + argc--; } - /* remaining arguments, are arguments to the interface */ + return mung_filename; } static inline void @@ -369,6 +412,8 @@ main(int argc, char **argv) realloc /* try_realloc */ }; + gchar *mung_filename; + #ifdef DEBUG_PAUSE /* Windows debugging hack (see above) */ system("pause"); @@ -379,9 +424,12 @@ main(int argc, char **argv) g_mem_set_vtable(&vtable); - process_options(argc, argv); - interface.main(argc, argv); - /* remaining arguments are arguments to the munged file */ + mung_filename = process_options(argc, argv); + /* + * All remaining arguments in argv are arguments + * to the macro or munged file. + */ + interface.init(); /* * QRegister view must be initialized only now @@ -405,7 +453,7 @@ main(int argc, char **argv) ring.edit((const gchar *)NULL); /* add remaining arguments to unnamed buffer */ - for (int i = 1; i < argc; i++) { + for (gint i = 1; i < argc; i++) { /* * FIXME: arguments may contain line-feeds. * Once SciTECO is 8-byte clear, we can add the @@ -435,15 +483,15 @@ main(int argc, char **argv) exit(EXIT_SUCCESS); } - if (!mung_file && mung_profile) + if (!mung_filename && mung_profile) /* NOTE: Still safe to use g_getenv() */ - mung_file = g_build_filename(g_getenv("SCITECOCONFIG"), - INI_FILE, NIL); + mung_filename = g_build_filename(g_getenv("SCITECOCONFIG"), + INI_FILE, NIL); - if (mung_file && - g_file_test(mung_file, G_FILE_TEST_IS_REGULAR)) { + if (mung_filename && + g_file_test(mung_filename, G_FILE_TEST_IS_REGULAR)) { try { - Execute::file(mung_file, false); + Execute::file(mung_filename, false); } catch (Quit) { /* * ^C invoked, quit hook should still @@ -456,7 +504,6 @@ main(int argc, char **argv) exit(EXIT_SUCCESS); } } - g_free(mung_file); } catch (Error &error) { error.display_full(); exit(EXIT_FAILURE); @@ -495,5 +542,6 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } + g_free(mung_filename); return 0; } -- cgit v1.2.3