You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stdcxx.apache.org by se...@apache.org on 2005/12/22 03:45:33 UTC
svn commit: r358445 - /incubator/stdcxx/trunk/tests/src/cmdopt.cpp
Author: sebor
Date: Wed Dec 21 18:45:30 2005
New Revision: 358445
URL: http://svn.apache.org/viewcvs?rev=358445&view=rev
Log:
2005-12-21 Martin Sebor <se...@roguewave.com>
* cmdopt.cpp (rw_vsetopts): Factored out the processing of the numeric
argument(s) of restricted command line arguments from here...
(_rw_getbounds): ...to here. Added the ability to specify arguments
in the option specification (denoted by a '*') instead of hardcoding
their numeric value in the option string.
(_rw_getarg): New function to parse and validate the argument of
a restricted numeric command line option.
(rw_runopts): Factored out single command line option processing code
from here...
(_rw_runopt): ...to this function. Implemented restricted numeric
arguments for all types of options (i.e., with or without callbacks
and optional or required).
(_rw_set_ignenv): Renamed to follow the naming convention for symbols
with internal linkage.
(_rw_print_help): Same. Added informational output for restricted
numeric arguments to command line options.
(_RWSTD_NO_VA_LIST_ARRAY): Used the new config macro.
Modified:
incubator/stdcxx/trunk/tests/src/cmdopt.cpp
Modified: incubator/stdcxx/trunk/tests/src/cmdopt.cpp
URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/src/cmdopt.cpp?rev=358445&r1=358444&r2=358445&view=diff
==============================================================================
--- incubator/stdcxx/trunk/tests/src/cmdopt.cpp (original)
+++ incubator/stdcxx/trunk/tests/src/cmdopt.cpp Wed Dec 21 18:45:30 2005
@@ -73,7 +73,7 @@
/**************************************************************************/
static int
-rw_print_help (int argc, char *argv[])
+_rw_print_help (int argc, char *argv[])
{
if (1 == argc && argv && 0 == argv [0]) {
static const char helpstr[] = {
@@ -128,6 +128,12 @@
}
}
+ // separate options with help functionality (which typically
+ // produce multiline output) from previous options without
+ // it (and thus very brief output)
+ if (i && 0 == cmdopts [i - 1].callback_ && cmdopts [i].callback_)
+ puts ("");
+
printf (" ");
if (cmdopts [i].sopt_) {
@@ -149,7 +155,31 @@
}
}
- printf ("%s%s%s", pfx, cmdopts [i].arg_ ? "<arg>" : "", sfx);
+ const char* arg =
+ _RWSTD_INT_MIN < cmdopts [i].minval_
+ || cmdopts [i].maxval_ < _RWSTD_INT_MAX ? "int" : "arg";
+
+ if (cmdopts [i].arg_) {
+ // print argument (in brackets when it's optional)
+ printf ("%s<%s>%s", pfx, arg, sfx);
+ }
+
+ if (cmdopts [i].pcntr_)
+ printf (" | -%s=<%s>", lopt, arg);
+
+ if ('i' == *arg) {
+ printf (", with ");
+
+ if (_RWSTD_INT_MIN < cmdopts [i].minval_)
+ printf ("%d <= ", cmdopts [i].minval_);
+
+ printf ("<%s>", arg);
+
+ if (cmdopts [i].maxval_ < _RWSTD_INT_MAX)
+ printf (" <= %d", cmdopts [i].maxval_);
+
+ printf ("\n ");
+ }
if (_RWSTD_SIZE_MAX == cmdopts [i].maxcount_)
printf (" (each occurrence evaluated)\n");
@@ -193,7 +223,7 @@
/**************************************************************************/
static int
-rw_set_ignenv (int argc, char *argv[])
+_rw_set_ignenv (int argc, char *argv[])
{
if (1 == argc && argv && 0 == argv [0]) {
static const char helpstr[] = {
@@ -263,10 +293,11 @@
++recursive;
- rw_setopts ("|-help: " // argument optional
+ rw_setopts (""
+ "|-help: " // argument optional
"|-ignenv ",
- rw_print_help,
- rw_set_ignenv);
+ _rw_print_help,
+ _rw_set_ignenv);
ndefopts = ncmdopts;
@@ -275,6 +306,121 @@
/**************************************************************************/
+#ifndef _RWSTD_NO_VA_LIST_ARRAY
+ // va_list is an array type
+# define RW_VA_LIST_ARG_PTR va_list
+# define RW_VA_LIST_ARG_TO_PTR(va) va
+# define RW_VA_LIST_PTR_ARG_TO_VA_LIST(va) va
+#else // if defined (_RWSTD_NO_VA_LIST_ARRAY)
+ // va_list is an object type
+# define RW_VA_LIST_ARG_PTR va_list*
+# define RW_VA_LIST_ARG_TO_PTR(va) &va
+# define RW_VA_LIST_PTR_ARG_TO_VA_LIST(pva) *pva
+#endif // _RWSTD_NO_VA_LIST_ARRAY
+
+
+static const char*
+_rw_getbounds (const char *next, RW_VA_LIST_ARG_PTR pva)
+{
+ ++next;
+
+ if ('*' == *next || '+' == *next || '-' == *next || isdigit (*next)) {
+
+ char *end = 0;
+
+ // '*' designates an int va_arg argument
+ const long minval = '*' == *next ?
+ long (va_arg (RW_VA_LIST_PTR_ARG_TO_VA_LIST (pva), int))
+ : strtol (next, &end, 10);
+
+#if _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
+ // validate
+ if (minval < _RWSTD_INT_MIN || _RWSTD_INT_MAX < minval) {
+ fprintf (stderr,
+ "lower bound %ld out of range [%d, %d]: "
+ "%s\n", minval, _RWSTD_INT_MIN, _RWSTD_INT_MAX,
+ next);
+ return 0;
+ }
+#endif // INT_SIZE < LONG_SIZE
+
+ next = end ? end : next + 1;
+
+ cmdopts [ncmdopts].minval_ = minval;
+
+ if ('-' == *next) {
+ ++next;
+
+ if ( '*' == *next
+ || '+' == *next
+ || minval < 0 && '-' == *next
+ || isdigit (*next)) {
+
+ end = 0;
+
+ // '*' designates an int va_arg argument
+ const long maxval = '*' == *next ?
+ long (va_arg (RW_VA_LIST_PTR_ARG_TO_VA_LIST (pva), int))
+ : strtol (next, &end, 10);
+
+#if _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
+ // validate
+ if (maxval < _RWSTD_INT_MIN || _RWSTD_INT_MAX < maxval) {
+
+ fprintf (stderr,
+ "upper bound %ld out of range [%ld, %d]: "
+ "%s\n", maxval, minval, _RWSTD_INT_MAX,
+ next);
+ return 0;
+ }
+#endif // INT_SIZE < LONG_SIZE
+
+ if (maxval < minval) {
+ // invalid range (upper bound < lower bound
+ fprintf (stderr,
+ "invalid range [%ld, %ld]: %s\n",
+ minval, maxval, next);
+ return 0;
+ }
+
+ next = end ? end : next + 1;
+ cmdopts [ncmdopts].maxval_ = int (maxval);
+ }
+ else {
+ // syntax error in range
+ fprintf (stderr,
+ "syntax error in range specification: %s\n",
+ next);
+ return 0;
+ }
+ }
+ else if (*next && !isspace (*next)) {
+ // syntax error in numeric argument
+ fprintf (stderr,
+ "syntax error numeric argument: %s\n",
+ next);
+ return 0;
+ }
+ else {
+ // no upper bound on the value of the option argument
+ cmdopts [ncmdopts].maxval_ = _RWSTD_INT_MAX;
+ }
+
+ }
+ else {
+ // no minimum/maximum value for this option is set
+ cmdopts [ncmdopts].minval_ = _RWSTD_INT_MIN;
+ cmdopts [ncmdopts].maxval_ = _RWSTD_INT_MAX;
+ }
+
+ // an unlimited number of occurrences of the option
+ // are allowed and will be counted
+ cmdopts [ncmdopts].maxcount_ = _RWSTD_SIZE_MAX;
+
+ return next;
+}
+
+
_TEST_EXPORT int
rw_vsetopts (const char *opts, va_list va)
{
@@ -322,6 +468,9 @@
// clear the next option info
memset (cmdopts + ncmdopts, 0, sizeof *cmdopts);
+ cmdopts [ncmdopts].minval_ = _RWSTD_INT_MIN;
+ cmdopts [ncmdopts].maxval_ = _RWSTD_INT_MAX;
+
if ('|' != *next)
cmdopts [ncmdopts].sopt_ = *next++;
@@ -358,103 +507,29 @@
int arg_is_callback = true;
if ('#' == *next) {
- // insead of a pointer to a callback, the argument is a pointer
+ // instead of a pointer to a callback, the argument is a pointer
// to an int counter that is to be incremented for each occurrence
// of the option during processing
// when the option is immediately followed by the equals sign ('=')
- // and a numeric argument, the value of the argument will be stored
- // instead
- arg_is_callback = false;
- ++next;
+ // and a numeric argument N, the value of N will be stored instead
+ next = _rw_getbounds (next, RW_VA_LIST_ARG_TO_PTR (va));
- if ('+' == *next || '-' == *next || isdigit (*next)) {
+ if (0 == next)
+ return -1; // error
- char *end = 0;
- const long minval = strtol (next, &end, 10);
-
-#if _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
- // validate
- if (minval < _RWSTD_INT_MIN || _RWSTD_INT_MAX < minval) {
- fprintf (stderr,
- "lower bound %ld out of range [%d, %d]: "
- "%s\n", minval, _RWSTD_INT_MIN, _RWSTD_INT_MAX,
- next);
- return -1;
- }
-#endif // INT_SIZE < LONG_SIZE
-
- next = end;
-
- cmdopts [ncmdopts].minval_ = minval;
-
- if ('-' == *next) {
- ++next;
-
- if ( '+' == *next
- || minval < 0 && '-' == *next
- || isdigit (*next)) {
- const long maxval = strtol (next, &end, 10);
-
-#if _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
- // validate
- if ( maxval < _RWSTD_INT_MIN
- || _RWSTD_INT_MAX < maxval) {
-
- fprintf (stderr,
- "upper bound %ld out of range [%ld, %d]: "
- "%s\n", maxval, minval, _RWSTD_INT_MAX,
- next);
- return -1;
- }
-#endif // INT_SIZE < LONG_SIZE
-
- if (maxval < minval) {
- // invalid range (upper bound < lower bound
- fprintf (stderr,
- "invalid range [%ld, %ld]: %s\n",
- minval, maxval, next);
- return -1;
- }
-
- next = end;
- cmdopts [ncmdopts].maxval_ = int (maxval);
- }
- else {
- // syntax error in range
- fprintf (stderr,
- "syntax error in range specification: %s\n",
- next);
- return -1;
- }
- }
- else if (*next && !isspace (*next)) {
- // syntax error in numeric argument
- fprintf (stderr,
- "syntax error numeric argument: %s\n",
- next);
- return -1;
- }
- else {
- // no upper bound on the value of the option argument
- cmdopts [ncmdopts].maxval_ = _RWSTD_INT_MAX;
- }
-
- }
- else {
- // no minimum/maximum value for this option is set
- cmdopts [ncmdopts].minval_ = _RWSTD_INT_MIN;
- cmdopts [ncmdopts].maxval_ = _RWSTD_INT_MAX;
- }
+ arg_is_callback = false;
- // an unlimited number of occurrences of the option
- // are allowed and will be counted
- cmdopts [ncmdopts].maxcount_ = _RWSTD_SIZE_MAX;
}
else if (':' == *next || '=' == *next) {
// ':' : argument optional
// '=' : argument required
cmdopts [ncmdopts].arg_ = true;
- ++next;
+
+ // check if the value of the argument is restricted
+ next = _rw_getbounds (next, RW_VA_LIST_ARG_TO_PTR (va));
+
+ if (0 == next)
+ return -1; // error
}
if ('@' == *next) {
@@ -529,15 +604,158 @@
/**************************************************************************/
+// validates (and optionally stores) a restricted numeric option argument
+static int
+_rw_getarg (cmdopts_t *optspec, const char *opt, const char *arg)
+{
+ assert (0 != optspec);
+ assert (0 != arg);
+
+ // obtain the numeric argument
+ char *end = 0;
+ const long optval = strtol (arg, &end, 0);
+
+ int status = 0;
+
+ if (end && '\0' != *end) {
+ fprintf (stderr, "expected numeric argument: %s\n", opt);
+ errno = EINVAL;
+ status = 1;
+ }
+
+#if _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
+
+ else if (optval < _RWSTD_INT_MIN || _RWSTD_INT_MAX < optval) {
+ fprintf (stderr, "numeric argument %ld out of range"
+ " [%d, %d]: %s\n", optval,
+ _RWSTD_INT_MIN, _RWSTD_INT_MAX, opt);
+ errno = EINVAL;
+ status = 1;
+ }
+
+#endif // _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
+
+ else if ( optval < long (optspec->minval_)
+ || long (optspec->maxval_) < optval) {
+
+ // numeric argument out of range
+ fprintf (stderr, "numeric argument %ld out of range"
+ " [%d, %d]: %s\n", optval,
+ optspec->minval_, optspec->maxval_, opt);
+ errno = EINVAL;
+ status = 1;
+ }
+ else if (optspec->pcntr_) {
+
+ // set the counter
+ *optspec->pcntr_ = optval;
+ }
+
+ return status;
+}
+
+/**************************************************************************/
+
+static bool
+_rw_runopt_recursive = false;
+
+
+// processes a single command line option and its arguments
+static int
+_rw_runopt (cmdopts_t *optspec, int argc, char *argv[])
+{
+ assert (0 != optspec);
+ assert (0 != argv);
+
+ // ignore the option if invoked recursively (by processing options
+ // set in the environment) and the option has already been seen
+ // (this prevents duplicate processing of options that are set both
+ // on the command line and in the environment and allows option with
+ // an argument set on the command line to override those set in the
+ // environment)
+
+ if (optspec->count_ && _rw_runopt_recursive)
+ return 0;
+
+ // if the option has been evaluated the maximum number
+ // of times, avoid evaluating it and continue processing
+ if (optspec->maxcount_ <= optspec->count_)
+ return 0;
+
+ int status = 0;
+
+ char* equals = strchr (argv [0], '=');
+
+ if (optspec->callback_) {
+ // option matched the specification
+
+ if (!optspec->inv_) {
+ // option is not inverted (i.e., is processed when seen
+ // on the command line as opposed processed when missing)
+
+ const char* const lopt = optspec->lopt_ ?
+ optspec->lopt_ : optspec->loptbuf_;
+
+ if ( optspec->arg_
+ && ( _RWSTD_INT_MIN < optspec->minval_
+ || optspec->maxval_ < _RWSTD_INT_MAX)) {
+
+ if (equals) {
+ if (strchr (lopt, '=')) {
+ // option requires a restricted numeric argument
+ // retrieve and validate it before invoking the
+ // callback
+
+ status = _rw_getarg (optspec, argv [0], equals + 1);
+ }
+ }
+ else if (1 < argc && '-' != argv [1][0]) {
+
+ const char *arg = argv [1];
+
+ // handle escaped minus (necessary to disambiguate
+ // it from a leading dash that introduces an option)
+ if ('\\' == arg [0] && '-' == arg [1])
+ ++arg;
+
+ status = _rw_getarg (optspec, argv [0], arg);
+ }
+ }
+
+ if (0 == status)
+ status = optspec->callback_ (argc, argv);
+ }
+ }
+ else if (equals) {
+
+ // option takes an optional numeric argument
+
+ assert (0 != optspec->pcntr_);
+
+ status = _rw_getarg (optspec, argv [0], equals + 1);
+ }
+ else {
+ assert (0 != optspec->pcntr_);
+ ++*optspec->pcntr_;
+ }
+
+ ++optspec->count_;
+
+ if (_rw_runopt_recursive)
+ optspec->envseen_ = true;
+
+ return status;
+}
+
+/**************************************************************************/
+
_TEST_EXPORT int
rw_runopts (int argc, char *argv[])
{
rw_set_myopts ();
- static int recursive = false;
-
// ignore options set in the environment?
- int ignenv = recursive;
+ int ignenv = _rw_runopt_recursive;
// return status
int status = 0;
@@ -605,84 +823,11 @@
// matching option has been found
found = true;
- // ignore the option if invoked recursively (by processing
- // options set in the environment) and the option has
- // already been seen (this prevents duplicate processing
- // of options that are set both on the command line and
- // in the environment and allows option with an argument
- // set on the command line to override those set in the
- // environment)
-
- if (cmdopts [j].count_ && recursive)
- continue;
-
- // if the option has been evaluated the maximum number
- // of times, avoid evaluating it and continue processing
- if (cmdopts [j].maxcount_ <= cmdopts [j].count_)
- continue;
-
- if (cmdopts [j].callback_) {
- if (!cmdopts [j].inv_) {
- // when the command line argument matched
- // the option, invoke the callback function
- status = cmdopts [j].callback_ (argc - i, argv + i);
- }
- }
- else if (eq) {
- assert (0 != cmdopts [j].pcntr_);
-
- // obtain the numeric argument
- char *end = 0;
- const long optval = strtol (eq + 1, &end, 0);
-
- if (end && '\0' != *end) {
- fprintf (stderr, "expected numeric argument: %s\n",
- optname);
- ignenv = true;
- errno = EINVAL;
- status = 1;
- }
-
-#if _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
-
- else if ( optval < _RWSTD_INT_MIN
- || _RWSTD_INT_MAX < optval) {
- fprintf (stderr, "numeric argument %ld out of range"
- " [%d, %d]: %s\n", optval,
- _RWSTD_INT_MIN, _RWSTD_INT_MAX, optname);
- ignenv = true;
- errno = EINVAL;
- status = 1;
- }
-
-#endif // _RWSTD_INT_SIZE < _RWSTD_LONG_SIZE
-
- else if ( optval < long (cmdopts [j].minval_)
- || cmdopts [j].maxval_ < optval) {
-
- // numeric argument out of range
- fprintf (stderr, "numeric argument %ld out of range"
- " [%d, %d]: %s\n", optval,
- cmdopts [j].minval_,
- cmdopts [j].maxval_, optname);
- ignenv = true;
- errno = EINVAL;
- status = 1;
- }
- else {
- *cmdopts [j].pcntr_ = optval;
- }
- }
- else {
- assert (0 != cmdopts [j].pcntr_);
- ++*cmdopts [j].pcntr_;
- }
-
- ++cmdopts [j].count_;
-
- if (recursive)
- cmdopts [j].envseen_ = true;
+ // process it and its arguments, if any
+ status = _rw_runopt (cmdopts + j, int (argc - i), argv + i);
+ // increment the number of options processed
+ // (whether successfully or otherwise)
++nopts;
if (status) {
@@ -729,9 +874,9 @@
// process options from the environment
const char* const envar = getenv ("RWSTD_TESTOPTS");
if (envar) {
- recursive = true;
+ _rw_runopt_recursive = true;
rw_runopts (envar);
- recursive = false;
+ _rw_runopt_recursive = false;
}
}