You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by kf...@locus.apache.org on 2000/11/25 03:19:43 UTC

cvs commit: apr/misc/unix getopt.c

kfogel      00/11/24 18:19:43

  Modified:    misc/unix getopt.c
  Log:
  Changes from Greg Hudson <gh...@mit.edu> (with minor meddling from
  Greg Stein <gs...@lyra.org> and Karl Fogel <kf...@collab.net>):
  
  Simplify apr_getopt_long interface and add support for interleaving
  options with arguments.
  
  (apr_getopt_t, apr_initopt): Add "interleave" settable flag and
  "skip_start" and "skip_end" fields to keep track of skipped non-option
  arguments.  Change argv to a char ** so that we can permute it.
  (apr_long_option_t): Renamed to apr_longopt_t.
  (apr_longopt_t): Rename "val" to "optch" and use for the short option
  name as well as the result.  "name" can now be NULL, and a structure
  with an "optch" of 0 now terminates the list.
  (reverse, permute, serr, cerr): New helper functions.
  (apr_getopt_long): Rewrite for simplified interface and for
  interleaved option support.
  
  Revision  Changes    Path
  1.25      +153 -81   apr/misc/unix/getopt.c
  
  Index: getopt.c
  ===================================================================
  RCS file: /home/cvs/apr/misc/unix/getopt.c,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- getopt.c	2000/11/17 07:56:52	1.24
  +++ getopt.c	2000/11/25 02:19:43	1.25
  @@ -41,22 +41,26 @@
   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;
       (*os)->err = 1;
  -    (*os)->ind = 1;
       (*os)->place = EMSG;
       (*os)->argc = argc;
       (*os)->argv = argv;
  +    (*os)->interleave = 0;
  +    (*os)->ind = 1;
  +    (*os)->skip_start = 1;
  +    (*os)->skip_end = 1;
       return APR_SUCCESS;
   }
   
  @@ -130,90 +134,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_longopt_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, "missing 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;
  +}