You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Greg Hudson <gh...@mit.edu> on 2000/11/24 02:33:41 UTC

New apr_getopt_long implementation

So, I'm having no luck getting at the new apr repository to construct
a proper patch.  (If anyone answered my earlier question to the apr
list, then I missed it; are there archives for that list anywhere?)

In the meantime, here is my implementation of the new apr_getopt_long
interface for people's review.  (I didn't use fitz's code as a base
mostly because I couldn't easily get at it given my apr repository
problems.  No intended slight.)

static apr_status_t serr(apr_getopt_t *os, const char *err, const char *str,
			 apr_status_t status)
{
    const char *progname;

    if (os->err) {
	progname = strrchr(os->argv[0], '/');
	progname = (progname != NULL) ? progname + 1 : os->argv[0];
	fprintf(stderr, "%s: %s: %s\n", progname, err, str);
    }
    return status;
}

static apr_status_t cerr(apr_getopt_t *os, const char *err, int ch,
			 apr_status_t status)
{
    char s[2];

    s[0] = ch;
    s[1] = '\0';
    return serr(os, err, s, 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;

    /*
     * 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') {
	/* We're about to process a new argument.  Make sure it's an option. */
	if (os->ind >= os->argc || *os->argv[os->ind] != '-')
	    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);
	    }
	    return APR_SUCCESS;
	} else if (*p == '-')                   /* Bare "--"; we're done */
	    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 = "";
    } else {
	*optarg = NULL;
	os->place = p;
    }

    return APR_SUCCESS;
}