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>
This commit is contained in:
Guy Harris 2014-12-26 14:37:31 -08:00
parent 2c6d2bb1e5
commit c2c9a09880
5 changed files with 278 additions and 130 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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;