[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] apr_getopt_long interface update and interleaving support

From: Karl Fogel <kfogel_at_galois.collab.net>
Date: 2000-11-24 22:40:34 CET

Greg Hudson <ghudson@mit.edu> writes:
> Okay, here is my finalized patch for apr_getopt_long, to change over
> to the new simplified interface and to support interleaved arguments.
> Thanks, Greg, for clearing up how to do an anonymous checkout.
>
> I have asked rbb for commit access, but this being Thanksgiving
> weekend, I'm not sure if he'll be up and about until Monday. So it
> might speed things up if someone who is around (such as Greg Stein)
> could check this in.

I'm around, and I'd be happy to check it in (or Greg S. can beat me to
it, is fine too).

Could you write a log message to accompany the commit? I could write
it myself, based on reading the patch, but you can probably do it
better, and with less effort.

I'll put your name and addr when I commit, of course, so people know
who really made the change.

There's also been talk about eliminating the redundant `opts' param to
apr_getopt_long(). Did you not do that because you didn't want to mix
two changes in one commit, or because you don't think it's a good
idea?

-K

> Index: include/apr_getopt.h
> ===================================================================
> RCS file: /home/cvspublic/apr/include/apr_getopt.h,v
> retrieving revision 1.22
> diff -u -r1.22 apr_getopt.h
> --- include/apr_getopt.h 2000/11/17 07:56:52 1.22
> +++ include/apr_getopt.h 2000/11/24 23:39:58
> @@ -77,23 +77,25 @@
> /** count of arguments */
> int argc;
> /** array of pointers to arguments */
> - char *const *argv;
> + char **argv;
> /** argument associated with option */
> char const* place;
> + /** set to nonzero to support interleaving */
> + int interleave;
> + /** range of non-option arguments skipped for interleaving */
> + int skip_start;
> + int skip_end;
> };
>
> -typedef struct apr_getopt_long_t apr_getopt_long_t;
> +typedef struct apr_option_t apr_option_t;
>
> -/* structure representing a single longopt */
> -struct apr_getopt_long_t {
> - /** the name of the long argument (sans "--") */
> +struct apr_option_t {
> + /** long option name, or NULL if option has no long name */
> const char *name;
> - /** 0 for no arg, 1 for arg */
> + /** option letter, or a value greater than 255 if option has no letter */
> + int optch;
> + /** nonzero if option takes an argument */
> int has_arg;
> - /** Either the short option char that this option corresponds to
> - * or a unique integer > 255
> - */
> - int val;
> };
>
> /**
> @@ -106,7 +108,7 @@
> * @deffunc apr_status_t apr_initopt(apr_getopt_t **os, apr_pool_t *cont,int argc, char *const *argv)
> */
> APR_DECLARE(apr_status_t) apr_initopt(apr_getopt_t **os, apr_pool_t *cont,
> - int argc, char *const *argv);
> + int argc, char **argv);
>
> /**
> * Parse the options initialized by apr_initopt().
> @@ -131,26 +133,15 @@
> /**
> * Parse the options initialized by apr_initopt(), accepting long
> * options beginning with "--" in addition to single-character
> - * options beginning with "-" (which are passed along to apr_getopt).
> - *
> - * Long options are accepted in both "--foo bar" and well as
> - * "--foo=bar" format
> - *
> - * End of argument processing if we encounter "--" or any option that
> - * doesn't start with "-" or "--".
> - *
> - * @param os The apr_opt_t structure returned by apr_initopt()
> - * @param opts A string of acceptable single-character options to the
> - * program. Characters followed by ":" are required to have
> - * an argument associated
> - * @param longopts A pointer to an array of apr_long_option_t structures, which
> - * can be initialized with { "name", has_args, val }. has_args
> - * is nonzero if the option requires an argument. A structure
> - * with a NULL name terminates the list
> - * @param optval The next option character parsed, or the value of "optval"
> - * from the appropriate apr_long_option_t structure if
> - * the next option is a long option.
> - * @param optarg The argument following the option, if any
> + * options beginning with "-".
> + * @param os The apr_getopt_t structure created by apr_initopt()
> + * @param opts A pointer to a list of apr_option_t structures, which can
> + * be initialized with { "name", optch, has_args }. has_args
> + * is nonzero if the option requires an argument. A structure
> + * with an optch value of 0 terminates the list.
> + * @param optch Receives the value of "optch" from the apr_option_t structure
> + * corresponding to the next option matched.
> + * @param optarg Receives the argument following the option, if any.
> * @tip There are four potential status values on exit. They are:
> * <PRE>
> * APR_EOF -- No more options to parse
> @@ -158,11 +149,14 @@
> * APR_BADARG -- No argument followed @parameter:
> * APR_SUCCESS -- The next option was found.
> * </PRE>
> - * @deffunc apr_status_t apr_getopt_long(apr_getopt_t *os, const char *opts, const apr_getopt_long_t *longopts, int *optval, const char **optarg) */
> -APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
> - const char *opts,
> - const apr_getopt_long_t *long_opts,
> - int *optval,
> - const char **optarg);
> -
> + * When APR_SUCCESS is returned, os->ind gives the index of the first
> + * non-option argument. On error, a message will be printed to stdout unless
> + * os->err is set to 0. If os->interleave is set to nonzero, options can come
> + * after arguments, and os->argv will be permuted to leave non-option arguments
> + * at the end.
> + * @deffunc apr_status_t apr_getopt_long(apr_getopt_t *os, const apr_option_t *opts, int *optch, const char **optarg)
> + */
> +APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
> + const apr_option_t *opts,
> + int *optch, const char **optarg);
> #endif /* ! APR_GETOPT_H */
> Index: misc/unix/getopt.c
> ===================================================================
> RCS file: /home/cvspublic/apr/misc/unix/getopt.c,v
> retrieving revision 1.24
> diff -u -r1.24 getopt.c
> --- misc/unix/getopt.c 2000/11/17 07:56:52 1.24
> +++ misc/unix/getopt.c 2000/11/24 23:39:58
> @@ -41,14 +41,15 @@
> static const char *pretty_path (const char *name)
> {
> const char *p;
> +
> if (!(p = strrchr(name, '/')))
> - return p;
> + return name;
> else
> - return ++p;
> + return p + 1;
> }
>
> APR_DECLARE(apr_status_t) apr_initopt(apr_getopt_t **os, apr_pool_t *cont,
> - int argc, char *const *argv)
> + int argc, char **argv)
> {
> *os = apr_palloc(cont, sizeof(apr_getopt_t));
> (*os)->cont = cont;
> @@ -57,6 +58,8 @@
> (*os)->place = EMSG;
> (*os)->argc = argc;
> (*os)->argv = argv;
> + (*os)->interleave = 0;
> + (*os)->skip_start = (*os)->skip_end = (*os)->ind;
> return APR_SUCCESS;
> }
>
> @@ -130,90 +133,158 @@
> return APR_SUCCESS;
> }
>
> -APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
> - const char *opts,
> - const apr_getopt_long_t *long_opts,
> - int *optval,
> - const char **optarg)
> -
> -{
> - const apr_getopt_long_t *ptr;
> - const char *opt = os->argv[os->ind];
> - const char *arg = os->argv[os->ind +1];
> - int arg_index_incr = 1;
> -
> - /* Finished processing opts */
> - if (os->ind >= os->argc)
> - return APR_EOF;
> -
> - /* End of options processing if we encounter "--" */
> - if (strcmp(opt, "--") == 0)
> - return APR_EOF;
> -
> - /*
> - * End of options processing if we encounter something that
> - * doesn't start with "-" or "--" (it's not an option if we hit it
> - * here, it's an argument)
> - */
> - if (*opt != '-')
> - return APR_EOF;
> +/* Reverse the sequence argv[start..start+len-1]. */
> +static void reverse(char **argv, int start, int len)
> +{
> + char *temp;
>
> - if ((os->ind + 1) >= os->argc)
> - arg = NULL;
> + for (; len >= 2; start++, len -= 2) {
> + temp = argv[start];
> + argv[start] = argv[start + len - 1];
> + argv[start + len - 1] = temp;
> + }
> +}
>
> - /* Handle --foo=bar style opts */
> - if (strchr(opt, '=')) {
> - const char *index = strchr(opt, '=') + 1;
> - opt = apr_pstrndup(os->cont, opt, ((index - opt) - 1));
> - if (*index != '\0') /* account for "--foo=" */
> - arg = apr_pstrdup(os->cont, index);
> - arg_index_incr = 0;
> - }
> -
> - /* If it's a longopt */
> - if (opt[1] == '-') {
> - /* see if it's in our array of long opts */
> - for (ptr = long_opts; ptr->name; ptr++) {
> - if (strcmp((opt + 2), ptr->name) == 0) { /* it's in the array */
> - if (ptr->has_arg) {
> - if (((os->ind + 1) >= os->argc)
> - && (arg == NULL)) {
> - fprintf(stderr,
> - "%s: option requires an argument: %s\n",
> - pretty_path(*os->argv), opt);
> - return APR_BADARG;
> - }
> -
> - /* If we make it here, then we should be ok. */
> - *optarg = arg;
> - os->ind += arg_index_incr;
> - }
> - else { /* has no arg */
> - *optarg = NULL;
> - }
> - *optval = ptr->val;
> - ++os->ind;
> - return APR_SUCCESS;
> - }
> - }
> +/*
> + * Permute os->argv with the goal that non-option arguments will all
> + * appear at the end. os->skip_start is where we started skipping
> + * non-option arguments, os->skip_end is where we stopped, and os->ind
> + * is where we are now.
> + */
> +static void permute(apr_getopt_t *os)
> +{
> + int len1 = os->skip_end - os->skip_start;
> + int len2 = os->ind - os->skip_end;
>
> - /* If we get here, then we don't have the longopt in our
> - * longopts array
> - */
> - fprintf(stderr, "%s: illegal option: %s\n",
> - pretty_path(*os->argv), opt);
> - return APR_BADCH;
> + if (os->interleave) {
> + /*
> + * Exchange the sequences argv[os->skip_start..os->skip_end-1] and
> + * argv[os->skip_end..os->ind-1]. The easiest way to do that is
> + * to reverse the entire range and then reverse the two
> + * sub-ranges.
> + */
> + reverse(os->argv, os->skip_start, len1 + len2);
> + reverse(os->argv, os->skip_start, len2);
> + reverse(os->argv, os->skip_start + len2, len1);
> }
>
> - { /* otherwise, apr_getopt gets it. */
> - char optch;
> - apr_status_t status;
> - status = apr_getopt (os, opts, &optch, optarg);
> - *optval = optch;
> - return status;
> - }
> + /* Reset skip range to the new location of the non-option sequence. */
> + os->skip_start += len2;
> + os->skip_end += len2;
> +}
> +
> +/* Helper function to print out an error involving a long option */
> +static apr_status_t serr(apr_getopt_t *os, const char *err, const char *str,
> + apr_status_t status)
> +{
> + if (os->err)
> + fprintf(stderr, "%s: %s: %s\n", pretty_path(*os->argv), err, str);
> + return status;
> }
>
> +/* Helper function to print out an error involving a short option */
> +static apr_status_t cerr(apr_getopt_t *os, const char *err, int ch,
> + apr_status_t status)
> +{
> + if (os->err)
> + fprintf(stderr, "%s: %s: %c\n", pretty_path(*os->argv), err, ch);
> + return status;
> +}
> +
> +APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
> + const apr_option_t *opts,
> + int *optch, const char **optarg)
> +{
> + const char *p;
> + int i, len;
> +
> + /* Let the calling program reset option processing. */
> + if (os->reset) {
> + os->place = EMSG;
> + os->ind = 1;
> + os->reset = 0;
> + }
>
> + /*
> + * We can be in one of two states: in the middle of processing a
> + * run of short options, or about to process a new argument.
> + * Since the second case can lead to the first one, handle that
> + * one first. */
> + p = os->place;
> + if (*p == '\0') {
> + /* If we are interleaving, skip non-option arguments. */
> + if (os->interleave) {
> + while (os->ind < os->argc && *os->argv[os->ind] != '-')
> + os->ind++;
> + os->skip_end = os->ind;
> + }
> + if (os->ind >= os->argc || *os->argv[os->ind] != '-') {
> + os->ind = os->skip_start;
> + return APR_EOF;
> + }
> +
> + p = os->argv[os->ind++] + 1;
> + if (*p == '-' && p[1] != '\0') { /* Long option */
> + /* Search for the long option name in the caller's table. */
> + p++;
> + for (i = 0; opts[i].optch != 0; i++) {
> + len = strlen(opts[i].name);
> + if (strncmp(p, opts[i].name, len) == 0
> + && (p[len] == '\0' || p[len] == '='))
> + break;
> + }
> + if (opts[i].optch == 0) /* No match */
> + return serr(os, "invalid option", p - 2, APR_BADCH);
> + *optch = opts[i].optch;
> +
> + if (opts[i].has_arg) {
> + if (p[len] == '=') /* Argument inline */
> + *optarg = p + len + 1;
> + else if (os->ind >= os->argc) /* Argument missing */
> + return serr(os, "missing argument", p - 2, APR_BADARG);
> + else /* Argument in next arg */
> + *optarg = os->argv[os->ind++];
> + } else {
> + *optarg = NULL;
> + if (p[len] == '=')
> + return serr(os, "erroneous argument", p - 2, APR_BADARG);
> + }
> + permute(os);
> + return APR_SUCCESS;
> + } else if (*p == '-') { /* Bare "--"; we're done */
> + permute(os);
> + os->ind = os->skip_start;
> + return APR_EOF;
> + }
> + else if (*p == '\0') /* Bare "-" is illegal */
> + return serr(os, "invalid option", p, APR_BADCH);
> + }
>
> + /*
> + * Now we're in a run of short options, and *p is the next one.
> + * Look for it in the caller's table.
> + */
> + for (i = 0; opts[i].optch != 0; i++) {
> + if (*p == opts[i].optch)
> + break;
> + }
> + if (opts[i].optch == 0) /* No match */
> + return cerr(os, "invalid option character", *p, APR_BADCH);
> + *optch = *p++;
> +
> + if (opts[i].has_arg) {
> + if (*p != '\0') /* Argument inline */
> + *optarg = p;
> + else if (os->ind >= os->argc) /* Argument missing */
> + return cerr(os, "option requires an argument", *optch, APR_BADARG);
> + else /* Argument in next arg */
> + *optarg = os->argv[os->ind++];
> + os->place = EMSG;
> + } else {
> + *optarg = NULL;
> + os->place = p;
> + }
>
> + permute(os);
> + return APR_SUCCESS;
> +}
Received on Sat Oct 21 14:36:15 2006

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.