1/* 2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7#include <assert.h> 8 9#include "win_posix.h" 10 11/* 12 * This variable is set by getopt to the index of the next element of the 13 * argv array to be processed. Once getopt has found all of the option 14 * arguments, you can use this variable to determine where the remaining 15 * non-option arguments begin. The initial value of this variable is 1. 16 */ 17int optind = 1; 18 19/* 20 * If the value of this variable is nonzero, then getopt prints an error 21 * message to the standard error stream if it encounters an unknown option 22 * default character or an option with a missing required argument. 23 * If you set this variable to zero, getopt does not print any messages, 24 * but it still returns the character ? to indicate an error. 25 */ 26const int opterr; /* = 0; */ 27/* const because we do not implement error printing.*/ 28/* Not initialised to conform with the coding standard. */ 29 30/* 31 * When getopt encounters an unknown option character or an option with a 32 * missing required argument, it stores that option character in this 33 * variable. 34 */ 35int optopt; /* = 0; */ 36 37/* 38 * This variable is set by getopt to point at the value of the option 39 * argument, for those options that accept arguments. 40 */ 41char *optarg; /* = 0; */ 42 43enum return_flags { 44 RET_ERROR = -1, 45 RET_END_OPT_LIST = -1, 46 RET_NO_PARAM = '?', 47 RET_NO_PARAM2 = ':', 48 RET_UNKNOWN_OPT = '?' 49}; 50 51/* 52 * Common initialisation on entry. 53 */ 54static 55void getopt_init(void) 56{ 57 optarg = (char *)0; 58 optopt = 0; 59 /* optind may be zero with some POSIX uses. 60 * For our purposes we just change it to 1. 61 */ 62 if (optind == 0) 63 optind = 1; 64} 65 66/* 67 * Common handling for a single letter option. 68 */ 69static 70int getopt_1char(int argc, 71 char *const argv[], 72 const char *const opstring, 73 const int optchar) 74{ 75 size_t nlen = (opstring == 0) ? 0 : strlen(opstring); 76 size_t loptn; 77 78 for (loptn = 0; loptn < nlen; loptn++) { 79 if (optchar == opstring[loptn]) { 80 if (opstring[loptn + 1] == ':') { 81 /* Option has argument */ 82 if (optind < argc) { 83 /* Found argument. */ 84 assert(argv != 0); 85 optind++; 86 optarg = argv[optind++]; 87 return optchar; 88 } 89 /* Missing argument. */ 90 if (opstring[loptn + 2] == ':') { 91 /* OK if optional "x::". */ 92 optind++; 93 return optchar; 94 } 95 /* Actual missing value. */ 96 optopt = optchar; 97 return ((opstring[0] == ':') 98 ? RET_NO_PARAM2 99 : RET_NO_PARAM); 100 } 101 /* No argument, just return option char */ 102 optind++; 103 return optchar; 104 } 105 } 106 /* 107 * If getopt finds an option character in argv that was not included in 108 * options, ... it returns '?' and sets the external variable optopt to 109 * the actual option character. 110 */ 111 optopt = optchar; 112 return RET_UNKNOWN_OPT; 113} 114 115int getopt(int argc, 116 char *argv[], 117 char *opstring) 118{ 119 int result = RET_END_OPT_LIST; 120 size_t argn = 0; 121 size_t nlen = strlen(opstring); 122 123 getopt_init(); 124 /* If we have an argument left to play with */ 125 if ((argc > optind) && (argv != 0)) { 126 const char *arg = (const char *)argv[optind]; 127 128 if ((arg != 0) && (arg[0] == '-')) 129 result = getopt_1char(argc, argv, opstring, arg[1]); 130 } 131 132 return result; 133} 134 135/* 136 * Match an argument value against an option name. 137 * Note that we only match over the shorter length of the pair, to allow 138 * for abbreviation or say --match=value 139 * Long option names may be abbreviated if the abbreviation is unique or an 140 * exact match for some defined option. 141 * A long option may take a parameter, of the form --opt=param or --opt param. 142*/ 143static 144int optmatch(const char *argval, const char *optname) 145{ 146 int result = 0; 147 148 while ((result == 0) && (*optname != 0) && (*argval != 0)) 149 result = (*argval++) - (*optname++); 150 return result; 151} 152 153/* Handling for a single long option. */ 154static 155int getopt_1long(const int argc, 156 char *const argv[], 157 const struct option *const longopts, 158 const char *const optname, 159 int *const indexptr) 160{ 161 int result = RET_UNKNOWN_OPT; 162 size_t loptn = 0; 163 164 while (longopts[loptn].name != 0) { 165 if (optmatch(optname, longopts[loptn].name) == 0) { 166 /* We found a match. */ 167 result = longopts[loptn].val; 168 if (indexptr != 0) 169 *indexptr = loptn; 170 switch (longopts[loptn].has_arg) { 171 case required_argument: 172 if ((optind + 1) >= argc) { 173 /* Missing argument. */ 174 optopt = result; 175 return RET_NO_PARAM; 176 } 177 /* Fallthrough to get option value. */ 178 179 case optional_argument: 180 if ((argc - optind) > 0) { 181 /* Found argument. */ 182 optarg = argv[++optind]; 183 } 184 /* Fallthrough to handle flag. */ 185 186 case no_argument: 187 optind++; 188 if (longopts[loptn].flag != 0) { 189 *longopts[loptn].flag = result; 190 result = 0; 191 } 192 break; 193 194 } 195 return result; 196 } 197 ++loptn; 198 } 199 /* 200 * If getopt finds an option character in argv that was not included 201 * in options, ... it returns '?' and sets the external variable 202 * optopt to the actual option character. 203 */ 204 return RET_UNKNOWN_OPT; 205} 206 207/* 208 * getopt_long gets the next option argument from the argument list 209 * specified by the argv and argc arguments. Options may be either short 210 * (single letter) as for getopt, or longer names (preceded by --). 211 */ 212int getopt_long(int argc, 213 char *argv[], 214 const char *shortopts, 215 const struct option *longopts, 216 int *indexptr) 217{ 218 int result = RET_END_OPT_LIST; 219 220 getopt_init(); 221 /* If we have an argument left to play with */ 222 if ((argc > optind) && (argv != 0)) { 223 const char *arg = argv[optind]; 224 225 if ((arg != 0) && (arg[0] == '-')) { 226 if (arg[1] == '-') { 227 /* Looks like a long option. */ 228 result = getopt_1long(argc, 229 argv, 230 longopts, 231 &arg[2], 232 indexptr); 233 } else { 234 result = getopt_1char(argc, 235 argv, 236 shortopts, 237 arg[1]); 238 } 239 } 240 } 241 return result; 242} 243 244/* 245 * getopt_long_only gets the next option argument from the argument list 246 * specified by the argv and argc arguments. Options may be either short 247 * or long as for getopt_long, but the long names may have a single '-' 248 * prefix too. 249 */ 250int getopt_long_only(int argc, 251 char *argv[], 252 const char *shortopts, 253 const struct option *longopts, 254 int *indexptr) 255{ 256 int result = RET_END_OPT_LIST; 257 258 getopt_init(); 259 /* If we have an argument left to play with */ 260 if ((argc > optind) && (argv != 0)) { 261 const char *arg = argv[optind]; 262 263 if ((arg != 0) && (arg[0] == '-')) { 264 if (arg[1] == '-') { 265 /* Looks like a long option. */ 266 result = getopt_1long(argc, 267 argv, 268 longopts, 269 &arg[2], 270 indexptr); 271 } else { 272 result = getopt_1long(argc, 273 argv, 274 longopts, 275 &arg[1], 276 indexptr); 277 if (result == RET_UNKNOWN_OPT) { 278 result = getopt_1char(argc, 279 argv, 280 shortopts, 281 arg[1]); 282 } 283 } 284 } 285 } 286 return result; 287} 288