nsprpub/lib/libc/src/plgetopt.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/lib/libc/src/plgetopt.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,248 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +** File:          plgetopt.c
    1.11 +** Description:   utilities to parse argc/argv
    1.12 +*/
    1.13 +
    1.14 +#include "prmem.h"
    1.15 +#include "prlog.h"
    1.16 +#include "prerror.h"
    1.17 +#include "plstr.h"
    1.18 +#include "plgetopt.h"
    1.19 +
    1.20 +#include <string.h>
    1.21 +
    1.22 +static char static_Nul = 0;
    1.23 +
    1.24 +struct PLOptionInternal
    1.25 +{
    1.26 +    const char *options;        /* client options list specification */
    1.27 +    PRIntn argc;                /* original number of arguments */
    1.28 +    char **argv;                /* vector of pointers to arguments */
    1.29 +    PRIntn xargc;               /* which one we're processing now */
    1.30 +    const char *xargv;          /* where within *argv[xargc] */
    1.31 +    PRIntn minus;               /* do we already have the '-'? */
    1.32 +    const PLLongOpt *longOpts;  /* Caller's array */
    1.33 +    PRBool endOfOpts;           /* have reached a "--" argument */
    1.34 +    PRIntn optionsLen;          /* is strlen(options) */
    1.35 +};
    1.36 +
    1.37 +/*
    1.38 +** Create the state in which to parse the tokens.
    1.39 +**
    1.40 +** argc        the sum of the number of options and their values
    1.41 +** argv        the options and their values
    1.42 +** options    vector of single character options w/ | w/o ':
    1.43 +*/
    1.44 +PR_IMPLEMENT(PLOptState*) PL_CreateOptState(
    1.45 +    PRIntn argc, char **argv, const char *options)
    1.46 +{
    1.47 +    return PL_CreateLongOptState( argc, argv, options, NULL);
    1.48 +}  /* PL_CreateOptState */
    1.49 +
    1.50 +PR_IMPLEMENT(PLOptState*) PL_CreateLongOptState(
    1.51 +    PRIntn argc, char **argv, const char *options, 
    1.52 +    const PLLongOpt *longOpts)
    1.53 +{
    1.54 +    PLOptState *opt = NULL;
    1.55 +    PLOptionInternal *internal;
    1.56 +
    1.57 +    if (NULL == options) 
    1.58 +    {
    1.59 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1.60 +        return opt;
    1.61 +    }
    1.62 +
    1.63 +    opt = PR_NEWZAP(PLOptState);
    1.64 +    if (NULL == opt) 
    1.65 +    {
    1.66 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    1.67 +        return opt;
    1.68 +    }
    1.69 +
    1.70 +    internal = PR_NEW(PLOptionInternal);
    1.71 +    if (NULL == internal)
    1.72 +    {
    1.73 +        PR_DELETE(opt);
    1.74 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    1.75 +        return NULL;
    1.76 +    }
    1.77 +
    1.78 +    opt->option = 0;
    1.79 +    opt->value = NULL;
    1.80 +    opt->internal = internal;
    1.81 +    opt->longOption   =  0;
    1.82 +    opt->longOptIndex = -1;
    1.83 +
    1.84 +    internal->argc = argc;
    1.85 +    internal->argv = argv;
    1.86 +    internal->xargc = 0;
    1.87 +    internal->xargv = &static_Nul;
    1.88 +    internal->minus = 0;
    1.89 +    internal->options = options;
    1.90 +    internal->longOpts = longOpts;
    1.91 +    internal->endOfOpts = PR_FALSE;
    1.92 +    internal->optionsLen = PL_strlen(options);
    1.93 +
    1.94 +    return opt;
    1.95 +}  /* PL_CreateLongOptState */
    1.96 +
    1.97 +/*
    1.98 +** Destroy object created by CreateOptState()
    1.99 +*/
   1.100 +PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt)
   1.101 +{
   1.102 +    PR_DELETE(opt->internal);
   1.103 +    PR_DELETE(opt);
   1.104 +}  /* PL_DestroyOptState */
   1.105 +
   1.106 +PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt)
   1.107 +{
   1.108 +    PLOptionInternal *internal = opt->internal;
   1.109 +
   1.110 +    opt->longOption   =  0;
   1.111 +    opt->longOptIndex = -1;
   1.112 +    /*
   1.113 +    ** If the current xarg points to nul, advance to the next
   1.114 +    ** element of the argv vector. If the vector index is equal
   1.115 +    ** to argc, we're out of arguments, so return an EOL.
   1.116 +    ** Note whether the first character of the new argument is
   1.117 +    ** a '-' and skip by it if it is.
   1.118 +    */
   1.119 +    while (0 == *internal->xargv)
   1.120 +    {
   1.121 +        internal->xargc += 1;
   1.122 +        if (internal->xargc >= internal->argc)
   1.123 +        {
   1.124 +            opt->option = 0;
   1.125 +            opt->value = NULL;
   1.126 +            return PL_OPT_EOL;
   1.127 +        }
   1.128 +        internal->xargv = internal->argv[internal->xargc];
   1.129 +        internal->minus = 0;
   1.130 +        if (!internal->endOfOpts && ('-' == *internal->xargv)) 
   1.131 +        {
   1.132 +            internal->minus++;
   1.133 +            internal->xargv++;  /* and consume */
   1.134 +            if ('-' == *internal->xargv && internal->longOpts) 
   1.135 +            {
   1.136 +                internal->minus++;
   1.137 +                internal->xargv++;
   1.138 +                if (0 == *internal->xargv) 
   1.139 +                {
   1.140 +                    internal->endOfOpts = PR_TRUE;
   1.141 +                }
   1.142 +            }
   1.143 +        }
   1.144 +    }
   1.145 +
   1.146 +    /*
   1.147 +    ** If we already have a '-' or '--' in hand, xargv points to the next
   1.148 +    ** option. See if we can find a match in the list of possible
   1.149 +    ** options supplied.
   1.150 +    */
   1.151 +    if (internal->minus == 2) 
   1.152 +    {
   1.153 +        char * foundEqual = strchr(internal->xargv,'=');
   1.154 +        PRIntn optNameLen = foundEqual ? (foundEqual - internal->xargv) :
   1.155 +                            strlen(internal->xargv);
   1.156 +        const PLLongOpt *longOpt = internal->longOpts;
   1.157 +        PLOptStatus result = PL_OPT_BAD;
   1.158 +
   1.159 +        opt->option = 0;
   1.160 +        opt->value  = NULL;
   1.161 +
   1.162 +        for (; longOpt->longOptName; ++longOpt) 
   1.163 +        {
   1.164 +            if (strncmp(longOpt->longOptName, internal->xargv, optNameLen))
   1.165 +                continue;  /* not a possible match */
   1.166 +            if (strlen(longOpt->longOptName) != optNameLen)
   1.167 +                continue;  /* not a match */
   1.168 +            /* option name match */
   1.169 +            opt->longOptIndex = longOpt - internal->longOpts;
   1.170 +            opt->longOption   = longOpt->longOption;
   1.171 +            /* value is part of the current argv[] element if = was found */
   1.172 +            /* note: this sets value even for long options that do not
   1.173 +             * require option if specified as --long=value */
   1.174 +            if (foundEqual) 
   1.175 +            {
   1.176 +                opt->value = foundEqual + 1;
   1.177 +            }
   1.178 +            else if (longOpt->valueRequired)
   1.179 +            {
   1.180 +                /* value is the next argv[] element, if any */
   1.181 +                if (internal->xargc + 1 < internal->argc)
   1.182 +                {
   1.183 +                    opt->value = internal->argv[++(internal->xargc)];
   1.184 +                }
   1.185 +                /* missing value */
   1.186 +                else
   1.187 +                {
   1.188 +                    break; /* return PL_OPT_BAD */
   1.189 +                }
   1.190 +            }
   1.191 +            result = PL_OPT_OK;
   1.192 +            break;
   1.193 +        }
   1.194 +        internal->xargv = &static_Nul; /* consume this */
   1.195 +        return result;
   1.196 +    }
   1.197 +    if (internal->minus)
   1.198 +    {
   1.199 +        PRIntn cop;
   1.200 +        PRIntn eoo = internal->optionsLen;
   1.201 +        for (cop = 0; cop < eoo; ++cop)
   1.202 +        {
   1.203 +            if (internal->options[cop] == *internal->xargv)
   1.204 +            {
   1.205 +                opt->option = *internal->xargv++;
   1.206 +                opt->longOption = opt->option & 0xff;
   1.207 +                /*
   1.208 +                ** if options indicates that there's an associated
   1.209 +                ** value, it must be provided, either as part of this
   1.210 +                ** argv[] element or as the next one
   1.211 +                */
   1.212 +                if (':' == internal->options[cop + 1])
   1.213 +                {
   1.214 +                    /* value is part of the current argv[] element */
   1.215 +                    if (0 != *internal->xargv)
   1.216 +                    {
   1.217 +                        opt->value = internal->xargv;
   1.218 +                    }
   1.219 +                    /* value is the next argv[] element, if any */
   1.220 +                    else if (internal->xargc + 1 < internal->argc)
   1.221 +                    {
   1.222 +                        opt->value = internal->argv[++(internal->xargc)];
   1.223 +                    }
   1.224 +                    /* missing value */
   1.225 +                    else
   1.226 +                    {
   1.227 +                        return PL_OPT_BAD;
   1.228 +                    }
   1.229 +
   1.230 +                    internal->xargv = &static_Nul;
   1.231 +                    internal->minus = 0;
   1.232 +                }
   1.233 +                else 
   1.234 +                    opt->value = NULL; 
   1.235 +                return PL_OPT_OK;
   1.236 +            }
   1.237 +        }
   1.238 +        internal->xargv += 1;  /* consume that option */
   1.239 +        return PL_OPT_BAD;
   1.240 +    }
   1.241 +
   1.242 +    /*
   1.243 +    ** No '-', so it must be a standalone value. The option is nul.
   1.244 +    */
   1.245 +    opt->value = internal->argv[internal->xargc];
   1.246 +    internal->xargv = &static_Nul;
   1.247 +    opt->option = 0;
   1.248 +    return PL_OPT_OK;
   1.249 +}  /* PL_GetNextOpt */
   1.250 +
   1.251 +/* plgetopt.c */

mercurial