summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornelson%bolyard.com <devnull@localhost>2007-08-04 23:26:07 +0000
committernelson%bolyard.com <devnull@localhost>2007-08-04 23:26:07 +0000
commit5da19b22af091e68f9b02202d7170a233e35f72c (patch)
treea7e4d2ebb176250924915348581f1948d35d220e
parentee5eaf92d6d3b7af98431919ec6e7ef3cbdf9d47 (diff)
downloadnspr-hg-5da19b22af091e68f9b02202d7170a233e35f72c.tar.gz
Bug 346354 - add capability to parse string command line options, r=wtc
-rw-r--r--lib/libc/include/plgetopt.h75
-rw-r--r--lib/libc/src/plc.def5
-rw-r--r--lib/libc/src/plgetopt.c164
3 files changed, 197 insertions, 47 deletions
diff --git a/lib/libc/include/plgetopt.h b/lib/libc/include/plgetopt.h
index 423feab3..fcdf23b6 100644
--- a/lib/libc/include/plgetopt.h
+++ b/lib/libc/include/plgetopt.h
@@ -57,6 +57,14 @@ typedef enum
PL_OPT_BAD /* invalid option (and value) */
} PLOptStatus;
+typedef struct PLLongOpt
+{
+ const char * longOptName; /* long option name string */
+ PRIntn longOption; /* value put in PLOptState for this option. */
+ PRBool valueRequired; /* If option name not followed by '=', */
+ /* value is the next argument from argv. */
+} PLLongOpt;
+
typedef struct PLOptState
{
char option; /* the name of the option */
@@ -64,13 +72,80 @@ typedef struct PLOptState
PLOptionInternal *internal; /* private processing state */
+ PRIntn longOption; /* value from PLLongOpt put here */
+ PRIntn longOptIndex; /* index into caller's array of PLLongOpts */
} PLOptState;
+/*
+ * PL_CreateOptState
+ *
+ * The argument "options" points to a string of single-character option
+ * names. Option names that may have an option argument value must be
+ * followed immediately by a ':' character.
+ */
PR_EXTERN(PLOptState*) PL_CreateOptState(
PRIntn argc, char **argv, const char *options);
+/*
+ * PL_CreateLongOptState
+ *
+ * Alternative to PL_CreateOptState.
+ * Allows caller to specify BOTH a string of single-character option names,
+ * AND an array of structures describing "long" (keyword) option names.
+ * The array is terminated by a structure in which longOptName is NULL.
+ * Long option values (arguments) may always be given as "--name=value".
+ * If PLLongOpt.valueRequired is not PR_FALSE, and the option name was not
+ * followed by '=' then the next argument from argv is taken as the value.
+ */
+PR_EXTERN(PLOptState*) PL_CreateLongOptState(
+ PRIntn argc, char **argv, const char *options,
+ const PLLongOpt *longOpts);
+/*
+ * PL_DestroyOptState
+ *
+ * Call this to destroy the PLOptState returned from PL_CreateOptState or
+ * PL_CreateLongOptState.
+ */
PR_EXTERN(void) PL_DestroyOptState(PLOptState *opt);
+/*
+ * PL_GetNextOpt
+ *
+ * When this function returns PL_OPT_OK,
+ * - opt->option will hold the single-character option name that was parsed,
+ * or zero.
+ * When opt->option is zero, the token parsed was either a "long" (keyword)
+ * option or a positional parameter.
+ * For a positional parameter,
+ * - opt->longOptIndex will contain -1, and
+ * - opt->value will point to the positional parameter string.
+ * For a long option name,
+ * - opt->longOptIndex will contain the non-negative index of the
+ * PLLongOpt structure in the caller's array of PLLongOpt structures
+ 8 corresponding to the long option name, and
+ * For a single-character or long option,
+ * - opt->longOption will contain the value of the single-character option
+ * name, or the value of the longOption from the PLLongOpt structure
+ * for that long option. See notes below.
+ * - opt->value will point to the argument option string, or will
+ * be NULL if no argument option string was given.
+ * When opt->option is non-zero,
+ * - opt->longOptIndex will be -1
+ * When this function returns PL_OPT_EOL, or PL_OPT_BAD, the contents of
+ * opt are undefined.
+ *
+ * Notes: It is possible to ignore opt->option, and always look at
+ * opt->longOption instead. opt->longOption will contain the same value
+ * as opt->option for single-character option names, and will contain the
+ * value of longOption from the PLLongOpt structure for long option names.
+ * This means that it is possible to equivalence long option names to
+ * single character names by giving the longOption in the PLLongOpt struct
+ * the same value as the single-character option name.
+ * For long options that are NOT intended to be equivalent to any single-
+ * character option, the longOption value should be chosen to not match
+ * any possible single character name. It might be advisable to choose
+ * longOption values greater than 0xff for such long options.
+ */
PR_EXTERN(PLOptStatus) PL_GetNextOpt(PLOptState *opt);
PR_END_EXTERN_C
diff --git a/lib/libc/src/plc.def b/lib/libc/src/plc.def
index 18bb88d6..bb996a13 100644
--- a/lib/libc/src/plc.def
+++ b/lib/libc/src/plc.def
@@ -97,3 +97,8 @@ libVersionPoint;
;+ global:
PL_strtok_r;
;+} NSPR_4.0;
+;+
+;+NSPR_4.7 {
+;+ global:
+PL_CreateLongOptState;
+;+} NSPR_4.2;
diff --git a/lib/libc/src/plgetopt.c b/lib/libc/src/plgetopt.c
index e2ccfa1b..0fe4fafe 100644
--- a/lib/libc/src/plgetopt.c
+++ b/lib/libc/src/plgetopt.c
@@ -57,7 +57,10 @@ struct PLOptionInternal
char **argv; /* vector of pointers to arguments */
PRIntn xargc; /* which one we're processing now */
const char *xargv; /* where within *argv[xargc] */
- PRBool minus; /* do we already have the '-'? */
+ PRIntn minus; /* do we already have the '-'? */
+ const PLLongOpt *longOpts; /* Caller's array */
+ PRBool endOfOpts; /* have reached a "--" argument */
+ PRIntn optionsLen; /* is strlen(options) */
};
/*
@@ -70,39 +73,55 @@ struct PLOptionInternal
PR_IMPLEMENT(PLOptState*) PL_CreateOptState(
PRIntn argc, char **argv, const char *options)
{
+ return PL_CreateLongOptState( argc, argv, options, NULL);
+} /* PL_CreateOptState */
+
+PR_IMPLEMENT(PLOptState*) PL_CreateLongOptState(
+ PRIntn argc, char **argv, const char *options,
+ const PLLongOpt *longOpts)
+{
PLOptState *opt = NULL;
- if (NULL == options)
+ PLOptionInternal *internal;
+
+ if (NULL == options)
+ {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- else
+ return opt;
+ }
+
+ opt = PR_NEWZAP(PLOptState);
+ if (NULL == opt)
{
- opt = PR_NEWZAP(PLOptState);
- if (NULL == opt)
- PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
- else
- {
- PLOptionInternal *internal = PR_NEW(PLOptionInternal);
- if (NULL == internal)
- {
- PR_DELETE(opt);
- PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
- }
- else
- {
- opt->option = 0;
- opt->value = NULL;
- opt->internal = internal;
-
- internal->argc = argc;
- internal->argv = argv;
- internal->xargc = 0;
- internal->xargv = &static_Nul;
- internal->minus = PR_FALSE;
- internal->options = options;
- }
- }
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return opt;
+ }
+
+ internal = PR_NEW(PLOptionInternal);
+ if (NULL == internal)
+ {
+ PR_DELETE(opt);
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
}
+
+ opt->option = 0;
+ opt->value = NULL;
+ opt->internal = internal;
+ opt->longOption = 0;
+ opt->longOptIndex = -1;
+
+ internal->argc = argc;
+ internal->argv = argv;
+ internal->xargc = 0;
+ internal->xargv = &static_Nul;
+ internal->minus = 0;
+ internal->options = options;
+ internal->longOpts = longOpts;
+ internal->endOfOpts = PR_FALSE;
+ internal->optionsLen = PL_strlen(options);
+
return opt;
-} /* PL_CreateOptState */
+} /* PL_CreateLongOptState */
/*
** Destroy object created by CreateOptState()
@@ -116,56 +135,107 @@ PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt)
PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt)
{
PLOptionInternal *internal = opt->internal;
- PRIntn cop, eoo = PL_strlen(internal->options);
+ opt->longOption = 0;
+ opt->longOptIndex = -1;
/*
** If the current xarg points to nul, advance to the next
** element of the argv vector. If the vector index is equal
** to argc, we're out of arguments, so return an EOL.
- ** Note whether the first character of the new argument is
- ** a '-' and skip by it if it is.
+ ** Note whether the first character of the new argument is
+ ** a '-' and skip by it if it is.
*/
while (0 == *internal->xargv)
{
internal->xargc += 1;
if (internal->xargc >= internal->argc)
- {
- opt->option = 0;
- opt->value = NULL;
- return PL_OPT_EOL;
- }
+ {
+ opt->option = 0;
+ opt->value = NULL;
+ return PL_OPT_EOL;
+ }
internal->xargv = internal->argv[internal->xargc];
- internal->minus = ('-' == *internal->xargv ? PR_TRUE : PR_FALSE); /* not it */
- if (internal->minus) internal->xargv += 1; /* and consume */
+ internal->minus = 0;
+ if (!internal->endOfOpts && ('-' == *internal->xargv))
+ {
+ internal->minus++;
+ internal->xargv++; /* and consume */
+ if ('-' == *internal->xargv && internal->longOpts)
+ {
+ internal->minus++;
+ internal->xargv++;
+ if (0 == *internal->xargv)
+ {
+ internal->endOfOpts = PR_TRUE;
+ }
+ }
+ }
}
/*
- ** If we already have a '-' in hand, xargv points to the next
+ ** If we already have a '-' or '--' in hand, xargv points to the next
** option. See if we can find a match in the list of possible
** options supplied.
*/
+ if (internal->minus == 2)
+ {
+ char * foundEqual = strchr(internal->xargv,'=');
+ PRIntn optNameLen = foundEqual ? (foundEqual - internal->xargv) :
+ strlen(internal->xargv);
+ const PLLongOpt *longOpt = internal->longOpts;
+
+ opt->option = 0;
+ opt->value = NULL;
+
+ for (; longOpt->longOptName; ++longOpt)
+ {
+ if (strncmp(longOpt->longOptName, internal->xargv, optNameLen))
+ continue; /* not a possible match */
+ if (strlen(longOpt->longOptName) != optNameLen)
+ continue; /* not a match */
+ /* option name match */
+ opt->longOptIndex = longOpt - internal->longOpts;
+ opt->longOption = longOpt->longOption;
+ if (foundEqual)
+ {
+ opt->value = foundEqual[1] ? foundEqual + 1 : NULL;
+ }
+ else if (longOpt->valueRequired)
+ {
+ opt->value = internal->argv[++(internal->xargc)];
+ }
+ internal->xargv = &static_Nul; /* consume this */
+ return PL_OPT_OK;
+ }
+ internal->xargv = &static_Nul; /* consume this */
+ return PL_OPT_BAD;
+ }
if (internal->minus)
{
+ PRIntn cop;
+ PRIntn eoo = internal->optionsLen;
for (cop = 0; cop < eoo; ++cop)
{
if (internal->options[cop] == *internal->xargv)
{
- opt->option = *internal->xargv;
- internal->xargv += 1;
+ opt->option = *internal->xargv++;
+ opt->longOption = opt->option & 0xff;
/*
** if options indicates that there's an associated
- ** value, this argv is finished and the next is the
- ** option's value.
+ ** value, this argv is finished and the next is the
+ ** option's value.
*/
if (':' == internal->options[cop + 1])
{
- if (0 != *internal->xargv) return PL_OPT_BAD;
+ if (0 != *internal->xargv)
+ return PL_OPT_BAD;
opt->value = internal->argv[++(internal->xargc)];
internal->xargv = &static_Nul;
- internal->minus = PR_FALSE;
+ internal->minus = 0;
}
- else opt->value = NULL;
+ else
+ opt->value = NULL;
return PL_OPT_OK;
}
}