diff options
author | Guy Harris <guy@alum.mit.edu> | 2014-12-26 14:37:31 -0800 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2014-12-26 22:39:46 +0000 |
commit | c2c9a09880a6c2aad7529f9e133f53cfe7aba7ec (patch) | |
tree | 8f7b37c08f0f635ae25a8de45d65de3af20ccd1c | |
parent | 2c6d2bb1e56055f53531468be83075c4f12cdcb2 (diff) | |
download | wireshark-c2c9a09880a6c2aad7529f9e133f53cfe7aba7ec.tar.gz |
Use getopt_long() for the first pass through the argument list.
That way:
1) we don't have to worry about the system getopt() and our
getopt_long(), on platforms that have getopt() but not
getopt_long() (Solaris prior to Solaris 10, HP-UX, AIX), not
working well together;
2) if necessary, we can handle long options in the first pass.
Switch to using getopt_long() for the *second* pass for the GTK+ version
of Wireshark.
Use the documented mechanism for resetting the argument parser for the
glibc version of getopt_long(); use the mostly-undocumented-but-at-least-
they-documented-optreset mechanism for the *BSD version.
(We should look into doing only one pass, saving away arguments that
can't fully be processed in the first pass for further processing after
initializing libwireshark.)
Change-Id: Ide5069f1c7c66a5d04acc712551eb201080ce02f
Reviewed-on: https://code.wireshark.org/review/6063
Reviewed-by: Guy Harris <guy@alum.mit.edu>
-rw-r--r-- | configure.ac | 19 | ||||
-rw-r--r-- | tfshark.c | 59 | ||||
-rw-r--r-- | tshark.c | 61 | ||||
-rw-r--r-- | ui/gtk/main.c | 134 | ||||
-rw-r--r-- | ui/qt/main.cpp | 135 |
5 files changed, 278 insertions, 130 deletions
diff --git a/configure.ac b/configure.ac index 5ebfa04c7f..4a71282f91 100644 --- a/configure.ac +++ b/configure.ac @@ -2669,6 +2669,25 @@ AC_CHECK_FUNC(getopt_long, [ GETOPT_LO="" AC_DEFINE(HAVE_GETOPT_LONG, 1, [Define to 1 if you have the getopt_long function.]) + + # + # Do we have optreset? + # + AC_MSG_CHECKING(whether optreset is defined) + AC_TRY_LINK([], + [ + extern int optreset; + + return optreset; + ], + ac_cv_pcap_debug_defined=yes, + ac_cv_pcap_debug_defined=no) + if test "$ac_cv_pcap_debug_defined" = yes ; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_OPTRESET, 1, [Define to 1 if you have the optreset variable]) + else + AC_MSG_RESULT(no) + fi ], GETOPT_LO="wsgetopt.lo") AC_SUBST(GETOPT_LO) @@ -793,12 +793,22 @@ main(int argc, char *argv[]) dfilter_t *dfcode = NULL; e_prefs *prefs_p; int log_flags; - int optind_initial; gchar *output_only = NULL; -/* the leading - ensures that getopt() does not permute the argv[] entries - we have to make sure that the first getopt() preserves the content of argv[] - for the subsequent getopt_long() call */ +/* + * The leading - ensures that getopt_long() does not permute the argv[] entries. + * + * We have to make sure that the first getopt_long() preserves the content + * of argv[] for the subsequent getopt_long() call. + * + * We use getopt_long() in both cases to ensure that we're using a routine + * whose permutation behavior we can control in the same fashion on all + * platforms, and so that, if we ever need to process a long argument before + * doing further initialization, we can do so. + * + * XXX - the behavior of a leading - is platform-dependent, so we shouldn't + * use it. + */ #define OPTSTRING "-2C:d:e:E:hK:lo:O:qQr:R:S:t:T:u:vVxX:Y:z:" static const char optstring[] = OPTSTRING; @@ -853,11 +863,18 @@ main(int argc, char *argv[]) /* * In order to have the -X opts assigned before the wslua machine starts * we need to call getopts before epan_init() gets called. + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -898,11 +915,6 @@ main(int argc, char *argv[]) if (print_summary == -1) print_summary = (print_details || print_hex) ? FALSE : TRUE; - optind = optind_initial; - opterr = 1; - - - /** Send All g_log messages to our own handler **/ log_flags = @@ -1081,6 +1093,28 @@ main(int argc, char *argv[]) output_fields = output_fields_new(); + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { @@ -1088,7 +1122,7 @@ main(int argc, char *argv[]) perform_two_pass_analysis = TRUE; break; case 'C': - /* Configuration profile settings were already processed just ignore them this time*/ + /* already processed; just ignore it now */ break; case 'd': /* Decode as rule */ if (!add_decode_as(optarg)) @@ -1280,6 +1314,7 @@ main(int argc, char *argv[]) /* already processed; just ignore it now */ break; case 'X': + /* already processed; just ignore it now */ break; case 'Y': dfilter = optarg; @@ -992,12 +992,22 @@ main(int argc, char *argv[]) e_prefs *prefs_p; char badopt; int log_flags; - int optind_initial; gchar *output_only = NULL; -/* the leading - ensures that getopt() does not permute the argv[] entries - we have to make sure that the first getopt() preserves the content of argv[] - for the subsequent getopt_long() call */ +/* + * The leading - ensures that getopt_long() does not permute the argv[] entries. + * + * We have to make sure that the first getopt_long() preserves the content + * of argv[] for the subsequent getopt_long() call. + * + * We use getopt_long() in both cases to ensure that we're using a routine + * whose permutation behavior we can control in the same fashion on all + * platforms, and so that, if we ever need to process a long argument before + * doing further initialization, we can do so. + * + * XXX - the behavior of a leading - is platform-dependent, so we shouldn't + * use it. + */ #define OPTSTRING "-2" OPTSTRING_CAPTURE_COMMON "C:d:e:E:F:gG:hH:" "K:lnN:o:O:PqQr:R:S:t:T:u:vVw:W:xX:Y:z:" static const char optstring[] = OPTSTRING; @@ -1062,12 +1072,19 @@ main(int argc, char *argv[]) /* * In order to have the -X opts assigned before the wslua machine starts - * we need to call getopts before epan_init() gets called. + * we need to call getopt_long before epan_init() gets called. + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -1112,11 +1129,6 @@ main(int argc, char *argv[]) if (print_summary == -1) print_summary = (print_details || print_hex) ? FALSE : TRUE; - optind = optind_initial; - opterr = 1; - - - /** Send All g_log messages to our own handler **/ log_flags = @@ -1310,6 +1322,28 @@ main(int argc, char *argv[]) output_fields = output_fields_new(); + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { @@ -1355,7 +1389,7 @@ main(int argc, char *argv[]) #endif break; case 'C': - /* Configuration profile settings were already processed just ignore them this time*/ + /* already processed; just ignore it now */ break; case 'd': /* Decode as rule */ if (!add_decode_as(optarg)) @@ -1625,6 +1659,7 @@ main(int argc, char *argv[]) /* already processed; just ignore it now */ break; case 'X': + /* already processed; just ignore it now */ break; case 'Y': dfilter = optarg; diff --git a/ui/gtk/main.c b/ui/gtk/main.c index 17785d6fc8..a7c53c3e2a 100644 --- a/ui/gtk/main.c +++ b/ui/gtk/main.c @@ -40,6 +40,10 @@ #include <unistd.h> #endif +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif + #ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif @@ -2160,14 +2164,21 @@ main(int argc, char *argv[]) guint go_to_packet = 0; search_direction jump_backwards = SD_FORWARD; dfilter_t *jump_to_filter = NULL; - int optind_initial; unsigned int in_file_type = WTAP_TYPE_AUTO; #ifdef HAVE_GTKOSXAPPLICATION GtkosxApplication *theApp; #endif #define OPTSTRING OPTSTRING_CAPTURE_COMMON "C:g:Hh" "jJ:kK:lm:nN:o:P:r:R:St:u:vw:X:Y:z:" - + static const struct option long_options[] = { + {(char *)"help", no_argument, NULL, 'h'}, + {(char *)"read-file", required_argument, NULL, 'r' }, + {(char *)"read-filter", required_argument, NULL, 'R' }, + {(char *)"display-filter", required_argument, NULL, 'Y' }, + {(char *)"version", no_argument, NULL, 'v'}, + LONGOPT_CAPTURE_COMMON + {0, 0, 0, 0 } + }; static const char optstring[] = OPTSTRING; cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont); @@ -2281,20 +2292,41 @@ main(int argc, char *argv[]) rf_path, g_strerror(rf_open_errno)); } - /* "pre-scan" the command line parameters, if we have "console only" - parameters. We do this so we don't start GTK+ if we're only showing - command-line help or version information. - - XXX - this pre-scan is done before we start GTK+, so we haven't - run gtk_init() on the arguments. That means that GTK+ arguments - have not been removed from the argument list; those arguments - begin with "--", and will be treated as an error by getopt(). - - We thus ignore errors - *and* set "opterr" to 0 to suppress the - error messages. */ + /* + * In order to have the -X opts assigned before the wslua machine starts + * we need to call getopt_long before epan_init() gets called. + * + * In addition, we process "console only" parameters (ones where we + * send output to the console and exit) here, so we don't start GTK+ + * if we're only showing command-line help or version information. + * + * XXX - this pre-scan is done before we start GTK+, so we haven't + * run gtk_init() on the arguments. That means that GTK+ arguments + * have not been removed from the argument list; those arguments + * begin with "--", and will be treated as an error by getopt_long(). + * + * We thus ignore errors - *and* set "opterr" to 0 to suppress the + * error messages. + * + * XXX - should we, instead, first call gtk_parse_args(), without + * calling gtk_init(), and then call this? + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences, so we have another getopt_long() + * call later. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? + * + * Note that we don't want to initialize libwireshark until after the + * GUI is up, as that can take a while, and we want a window of some + * sort up to show progress while that's happening. + */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -2390,42 +2422,6 @@ main(int argc, char *argv[]) set_last_open_dir(get_persdatafile_dir()); } - /* Set getopt index back to initial value, so it will start with the - first command line parameter again. Also reset opterr to 1, so that - error messages are printed by getopt(). - - XXX - this seems to work on most platforms, but time will tell. - The Single UNIX Specification says "The getopt() function need - not be reentrant", so this isn't guaranteed to work. The Mac - OS X 10.4[.x] getopt() man page says - - In order to use getopt() to evaluate multiple sets of arguments, or to - evaluate a single set of arguments multiple times, the variable optreset - must be set to 1 before the second and each additional set of calls to - getopt(), and the variable optind must be reinitialized. - - ... - - The optreset variable was added to make it possible to call the getopt() - function multiple times. This is an extension to the IEEE Std 1003.2 - (``POSIX.2'') specification. - - which I think comes from one of the other BSDs. - - XXX - if we want to control all the command-line option errors, so - that we can display them where we choose (e.g., in a window), we'd - want to leave opterr as 0, and produce our own messages using optopt. - We'd have to check the value of optopt to see if it's a valid option - letter, in which case *presumably* the error is "this option requires - an argument but none was specified", or not a valid option letter, - in which case *presumably* the error is "this option isn't valid". - Some versions of getopt() let you supply a option string beginning - with ':', which means that getopt() will return ':' rather than '?' - for "this option requires an argument but none was specified", but - not all do. */ - optind = optind_initial; - opterr = 1; - #if !GLIB_CHECK_VERSION(2,31,0) g_thread_init(NULL); #endif @@ -2546,8 +2542,42 @@ main(int argc, char *argv[]) /*#ifdef HAVE_LIBPCAP fill_in_local_interfaces(); #endif*/ + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + * + * XXX - if we want to control all the command-line option errors, so + * that we can display them where we choose (e.g., in a window), we'd + * want to leave opterr as 0, and produce our own messages using optopt. + * We'd have to check the value of optopt to see if it's a valid option + * letter, in which case *presumably* the error is "this option requires + * an argument but none was specified", or not a valid option letter, + * in which case *presumably* the error is "this option isn't valid". + * Some versions of getopt() let you supply a option string beginning + * with ':', which means that getopt() will return ':' rather than '?' + * for "this option requires an argument but none was specified", but + * not all do. But we're now using getopt_long() - what does it do? + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { /*** capture option specific ***/ case 'a': /* autostop criteria */ diff --git a/ui/qt/main.cpp b/ui/qt/main.cpp index 2acdb80688..017296a33f 100644 --- a/ui/qt/main.cpp +++ b/ui/qt/main.cpp @@ -547,7 +547,6 @@ int main(int argc, char *argv[]) QString locale; QString cf_name; - int optind_initial; unsigned int in_file_type = WTAP_TYPE_AUTO; // In Qt 5, C strings are treated always as UTF-8 when converted to @@ -610,21 +609,47 @@ int main(int argc, char *argv[]) } wsApp->emitAppSignal(WiresharkApplication::StaticRecentFilesRead); - - /* "pre-scan" the command line parameters, if we have "console only" - parameters. We do this so we don't start Qt if we're only showing - command-line help or version information. - - XXX - this pre-scan is done before we start Qt. That means that Qt - arguments have not been removed from the argument list; those arguments - begin with "--", and will be treated as an error by getopt(). - - We thus ignore errors - *and* set "opterr" to 0 to suppress the - error messages.*/ - + /* + * In order to have the -X opts assigned before the wslua machine starts + * we need to call getopt_long before epan_init() gets called. + * + * In addition, we process "console only" parameters (ones where we + * send output to the console and exit) here, so we don't start GTK+ + * if we're only showing command-line help or version information. + * + * XXX - with the GTK+ version, this pre-scan was done before we started + * GTK+, so we hadn't run gtk_init() on the arguments. That meant that + * GTK+ arguments had not been removed from the argument list; those + * arguments begin with "--", and would be treated as an error by + * getopt_long(). + * + * We thus ignored errors - *and* set "opterr" to 0 to suppress the + * error messages. + * + * That's not the case here - the call to WiresharkApplication's + * constructor above does that (WiresharkApplication is a subclass + * of QApplication, and QApplication's constructor handles the Qt + * arguments). + * + * This means that there's some UI popped up before here. Can we + * move the call to the constructor after here? + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences, so we have another getopt_long() + * call later. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? + * + * Note that we don't want to initialize libwireshark until after the + * GUI is up, as that can take a while, and we want a window of some + * sort up to show progress while that's happening. + */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -713,43 +738,6 @@ int main(int argc, char *argv[]) rf_path, g_strerror(rf_open_errno)); } - - /* Set getopt index back to initial value, so it will start with the - first command line parameter again. Also reset opterr to 1, so that - error messages are printed by getopt(). - - XXX - this seems to work on most platforms, but time will tell. - The Single UNIX Specification says "The getopt() function need - not be reentrant", so this isn't guaranteed to work. The Mac - OS X 10.4[.x] getopt() man page says - - In order to use getopt() to evaluate multiple sets of arguments, or to - evaluate a single set of arguments multiple times, the variable optreset - must be set to 1 before the second and each additional set of calls to - getopt(), and the variable optind must be reinitialized. - - ... - - The optreset variable was added to make it possible to call the getopt() - function multiple times. This is an extension to the IEEE Std 1003.2 - (``POSIX.2'') specification. - - which I think comes from one of the other BSDs. - - XXX - if we want to control all the command-line option errors, so - that we can display them where we choose (e.g., in a window), we'd - want to leave opterr as 0, and produce our own messages using optopt. - We'd have to check the value of optopt to see if it's a valid option - letter, in which case *presumably* the error is "this option requires - an argument but none was specified", or not a valid option letter, - in which case *presumably* the error is "this option isn't valid". - Some versions of getopt() let you supply a option string beginning - with ':', which means that getopt() will return ':' rather than '?' - for "this option requires an argument but none was specified", but - not all do. */ - optind = optind_initial; - opterr = 1; - // Initialize our language read_language_prefs(); locale = QString(language); @@ -855,6 +843,40 @@ int main(int argc, char *argv[]) prefs_p = ws_app.readConfigurationFiles (&gdp_path, &dp_path); + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + * + * XXX - if we want to control all the command-line option errors, so + * that we can display them where we choose (e.g., in a window), we'd + * want to leave opterr as 0, and produce our own messages using optopt. + * We'd have to check the value of optopt to see if it's a valid option + * letter, in which case *presumably* the error is "this option requires + * an argument but none was specified", or not a valid option letter, + * in which case *presumably* the error is "this option isn't valid". + * Some versions of getopt() let you supply a option string beginning + * with ':', which means that getopt() will return ':' rather than '?' + * for "this option requires an argument but none was specified", but + * not all do. But we're now using getopt_long() - what does it do? + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { @@ -896,6 +918,8 @@ int main(int argc, char *argv[]) read_keytab_file(optarg); break; #endif + + /*** all non capture option specific ***/ case 'C': /* Configuration profile settings were already processed just ignore them this time*/ break; @@ -909,7 +933,12 @@ int main(int argc, char *argv[]) /* Not supported yet */ break; case 'l': /* Automatic scrolling in live capture mode */ +#ifdef HAVE_LIBPCAP /* Not supported yet */ +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif break; case 'L': /* Print list of link-layer types and exit */ #ifdef HAVE_LIBPCAP @@ -1055,7 +1084,7 @@ int main(int argc, char *argv[]) } break; default: - case '?': + case '?': /* Bad flag - print usage message */ print_usage(FALSE); exit(0); break; |