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 */