diff options
Diffstat (limited to 'nsprpub/lib/libc/src/plgetopt.c')
-rw-r--r-- | nsprpub/lib/libc/src/plgetopt.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/nsprpub/lib/libc/src/plgetopt.c b/nsprpub/lib/libc/src/plgetopt.c new file mode 100644 index 000000000..960decfec --- /dev/null +++ b/nsprpub/lib/libc/src/plgetopt.c @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +** File: plgetopt.c +** Description: utilities to parse argc/argv +*/ + +#include "prmem.h" +#include "prlog.h" +#include "prerror.h" +#include "plstr.h" +#include "plgetopt.h" + +#include <string.h> + +static char static_Nul = 0; + +struct PLOptionInternal +{ + const char *options; /* client options list specification */ + PRIntn argc; /* original number of arguments */ + char **argv; /* vector of pointers to arguments */ + PRIntn xargc; /* which one we're processing now */ + const char *xargv; /* where within *argv[xargc] */ + PRIntn minus; /* do we already have the '-'? */ + const PLLongOpt *longOpts; /* Caller's array */ + PRBool endOfOpts; /* have reached a "--" argument */ + PRIntn optionsLen; /* is strlen(options) */ +}; + +/* +** Create the state in which to parse the tokens. +** +** argc the sum of the number of options and their values +** argv the options and their values +** options vector of single character options w/ | w/o ': +*/ +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; + PLOptionInternal *internal; + + if (NULL == options) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return opt; + } + + opt = PR_NEWZAP(PLOptState); + if (NULL == opt) + { + 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_CreateLongOptState */ + +/* +** Destroy object created by CreateOptState() +*/ +PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt) +{ + PR_DELETE(opt->internal); + PR_DELETE(opt); +} /* PL_DestroyOptState */ + +PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt) +{ + PLOptionInternal *internal = opt->internal; + + 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. + */ + while (0 == *internal->xargv) + { + internal->xargc += 1; + if (internal->xargc >= internal->argc) + { + opt->option = 0; + opt->value = NULL; + return PL_OPT_EOL; + } + internal->xargv = internal->argv[internal->xargc]; + 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 '-' 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; + PLOptStatus result = PL_OPT_BAD; + + 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; + /* value is part of the current argv[] element if = was found */ + /* note: this sets value even for long options that do not + * require option if specified as --long=value */ + if (foundEqual) + { + opt->value = foundEqual + 1; + } + else if (longOpt->valueRequired) + { + /* value is the next argv[] element, if any */ + if (internal->xargc + 1 < internal->argc) + { + opt->value = internal->argv[++(internal->xargc)]; + } + /* missing value */ + else + { + break; /* return PL_OPT_BAD */ + } + } + result = PL_OPT_OK; + break; + } + internal->xargv = &static_Nul; /* consume this */ + return result; + } + 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++; + opt->longOption = opt->option & 0xff; + /* + ** if options indicates that there's an associated + ** value, it must be provided, either as part of this + ** argv[] element or as the next one + */ + if (':' == internal->options[cop + 1]) + { + /* value is part of the current argv[] element */ + if (0 != *internal->xargv) + { + opt->value = internal->xargv; + } + /* value is the next argv[] element, if any */ + else if (internal->xargc + 1 < internal->argc) + { + opt->value = internal->argv[++(internal->xargc)]; + } + /* missing value */ + else + { + return PL_OPT_BAD; + } + + internal->xargv = &static_Nul; + internal->minus = 0; + } + else + opt->value = NULL; + return PL_OPT_OK; + } + } + internal->xargv += 1; /* consume that option */ + return PL_OPT_BAD; + } + + /* + ** No '-', so it must be a standalone value. The option is nul. + */ + opt->value = internal->argv[internal->xargc]; + internal->xargv = &static_Nul; + opt->option = 0; + return PL_OPT_OK; +} /* PL_GetNextOpt */ + +/* plgetopt.c */ |