tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

plgetopt.c (6757B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /*
      7 ** File:          plgetopt.c
      8 ** Description:   utilities to parse argc/argv
      9 */
     10 
     11 #include "prmem.h"
     12 #include "prlog.h"
     13 #include "prerror.h"
     14 #include "plstr.h"
     15 #include "plgetopt.h"
     16 
     17 #include <string.h>
     18 
     19 static char static_Nul = 0;
     20 
     21 struct PLOptionInternal {
     22  const char* options;       /* client options list specification */
     23  PRIntn argc;               /* original number of arguments */
     24  char** argv;               /* vector of pointers to arguments */
     25  PRIntn xargc;              /* which one we're processing now */
     26  const char* xargv;         /* where within *argv[xargc] */
     27  PRIntn minus;              /* do we already have the '-'? */
     28  const PLLongOpt* longOpts; /* Caller's array */
     29  PRBool endOfOpts;          /* have reached a "--" argument */
     30  PRIntn optionsLen;         /* is strlen(options) */
     31 };
     32 
     33 /*
     34 ** Create the state in which to parse the tokens.
     35 **
     36 ** argc        the sum of the number of options and their values
     37 ** argv        the options and their values
     38 ** options    vector of single character options w/ | w/o ':
     39 */
     40 PR_IMPLEMENT(PLOptState*)
     41 PL_CreateOptState(PRIntn argc, char** argv, const char* options) {
     42  return PL_CreateLongOptState(argc, argv, options, NULL);
     43 } /* PL_CreateOptState */
     44 
     45 PR_IMPLEMENT(PLOptState*)
     46 PL_CreateLongOptState(PRIntn argc, char** argv, const char* options,
     47                      const PLLongOpt* longOpts) {
     48  PLOptState* opt = NULL;
     49  PLOptionInternal* internal;
     50 
     51  if (NULL == options) {
     52    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     53    return opt;
     54  }
     55 
     56  opt = PR_NEWZAP(PLOptState);
     57  if (NULL == opt) {
     58    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     59    return opt;
     60  }
     61 
     62  internal = PR_NEW(PLOptionInternal);
     63  if (NULL == internal) {
     64    PR_DELETE(opt);
     65    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     66    return NULL;
     67  }
     68 
     69  opt->option = 0;
     70  opt->value = NULL;
     71  opt->internal = internal;
     72  opt->longOption = 0;
     73  opt->longOptIndex = -1;
     74 
     75  internal->argc = argc;
     76  internal->argv = argv;
     77  internal->xargc = 0;
     78  internal->xargv = &static_Nul;
     79  internal->minus = 0;
     80  internal->options = options;
     81  internal->longOpts = longOpts;
     82  internal->endOfOpts = PR_FALSE;
     83  internal->optionsLen = PL_strlen(options);
     84 
     85  return opt;
     86 } /* PL_CreateLongOptState */
     87 
     88 /*
     89 ** Destroy object created by CreateOptState()
     90 */
     91 PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState* opt) {
     92  PR_DELETE(opt->internal);
     93  PR_DELETE(opt);
     94 } /* PL_DestroyOptState */
     95 
     96 PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState* opt) {
     97  PLOptionInternal* internal = opt->internal;
     98 
     99  opt->longOption = 0;
    100  opt->longOptIndex = -1;
    101  /*
    102  ** If the current xarg points to nul, advance to the next
    103  ** element of the argv vector. If the vector index is equal
    104  ** to argc, we're out of arguments, so return an EOL.
    105  ** Note whether the first character of the new argument is
    106  ** a '-' and skip by it if it is.
    107  */
    108  while (0 == *internal->xargv) {
    109    internal->xargc += 1;
    110    if (internal->xargc >= internal->argc) {
    111      opt->option = 0;
    112      opt->value = NULL;
    113      return PL_OPT_EOL;
    114    }
    115    internal->xargv = internal->argv[internal->xargc];
    116    internal->minus = 0;
    117    if (!internal->endOfOpts && ('-' == *internal->xargv)) {
    118      internal->minus++;
    119      internal->xargv++; /* and consume */
    120      if ('-' == *internal->xargv && internal->longOpts) {
    121        internal->minus++;
    122        internal->xargv++;
    123        if (0 == *internal->xargv) {
    124          internal->endOfOpts = PR_TRUE;
    125        }
    126      }
    127    }
    128  }
    129 
    130  /*
    131  ** If we already have a '-' or '--' in hand, xargv points to the next
    132  ** option. See if we can find a match in the list of possible
    133  ** options supplied.
    134  */
    135  if (internal->minus == 2) {
    136    char* foundEqual = strchr(internal->xargv, '=');
    137    PRIntn optNameLen =
    138        foundEqual ? (foundEqual - internal->xargv) : strlen(internal->xargv);
    139    const PLLongOpt* longOpt = internal->longOpts;
    140    PLOptStatus result = PL_OPT_BAD;
    141 
    142    opt->option = 0;
    143    opt->value = NULL;
    144 
    145    for (; longOpt->longOptName; ++longOpt) {
    146      if (strncmp(longOpt->longOptName, internal->xargv, optNameLen)) {
    147        continue; /* not a possible match */
    148      }
    149      if (strlen(longOpt->longOptName) != optNameLen) {
    150        continue; /* not a match */
    151      }
    152      /* option name match */
    153      opt->longOptIndex = longOpt - internal->longOpts;
    154      opt->longOption = longOpt->longOption;
    155      /* value is part of the current argv[] element if = was found */
    156      /* note: this sets value even for long options that do not
    157       * require option if specified as --long=value */
    158      if (foundEqual) {
    159        opt->value = foundEqual + 1;
    160      } else if (longOpt->valueRequired) {
    161        /* value is the next argv[] element, if any */
    162        if (internal->xargc + 1 < internal->argc) {
    163          opt->value = internal->argv[++(internal->xargc)];
    164        }
    165        /* missing value */
    166        else {
    167          break; /* return PL_OPT_BAD */
    168        }
    169      }
    170      result = PL_OPT_OK;
    171      break;
    172    }
    173    internal->xargv = &static_Nul; /* consume this */
    174    return result;
    175  }
    176  if (internal->minus) {
    177    PRIntn cop;
    178    PRIntn eoo = internal->optionsLen;
    179    for (cop = 0; cop < eoo; ++cop) {
    180      if (internal->options[cop] == *internal->xargv) {
    181        opt->option = *internal->xargv++;
    182        opt->longOption = opt->option & 0xff;
    183        /*
    184        ** if options indicates that there's an associated
    185        ** value, it must be provided, either as part of this
    186        ** argv[] element or as the next one
    187        */
    188        if (':' == internal->options[cop + 1]) {
    189          /* value is part of the current argv[] element */
    190          if (0 != *internal->xargv) {
    191            opt->value = internal->xargv;
    192          }
    193          /* value is the next argv[] element, if any */
    194          else if (internal->xargc + 1 < internal->argc) {
    195            opt->value = internal->argv[++(internal->xargc)];
    196          }
    197          /* missing value */
    198          else {
    199            return PL_OPT_BAD;
    200          }
    201 
    202          internal->xargv = &static_Nul;
    203          internal->minus = 0;
    204        } else {
    205          opt->value = NULL;
    206        }
    207        return PL_OPT_OK;
    208      }
    209    }
    210    internal->xargv += 1; /* consume that option */
    211    return PL_OPT_BAD;
    212  }
    213 
    214  /*
    215  ** No '-', so it must be a standalone value. The option is nul.
    216  */
    217  opt->value = internal->argv[internal->xargc];
    218  internal->xargv = &static_Nul;
    219  opt->option = 0;
    220  return PL_OPT_OK;
    221 } /* PL_GetNextOpt */
    222 
    223 /* plgetopt.c */