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