| /* |
| * Copyright (c) 2017 - 2020, Arm Limited and Contributors. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include <assert.h> |
| |
| #include "win_posix.h" |
| |
| /* |
| * This variable is set by getopt to the index of the next element of the |
| * argv array to be processed. Once getopt has found all of the option |
| * arguments, you can use this variable to determine where the remaining |
| * non-option arguments begin. The initial value of this variable is 1. |
| */ |
| int optind = 1; |
| |
| /* |
| * If the value of this variable is nonzero, then getopt prints an error |
| * message to the standard error stream if it encounters an unknown option |
| * default character or an option with a missing required argument. |
| * If you set this variable to zero, getopt does not print any messages, |
| * but it still returns the character ? to indicate an error. |
| */ |
| const int opterr; /* = 0; */ |
| /* const because we do not implement error printing.*/ |
| /* Not initialised to conform with the coding standard. */ |
| |
| /* |
| * When getopt encounters an unknown option character or an option with a |
| * missing required argument, it stores that option character in this |
| * variable. |
| */ |
| int optopt; /* = 0; */ |
| |
| /* |
| * This variable is set by getopt to point at the value of the option |
| * argument, for those options that accept arguments. |
| */ |
| char *optarg; /* = 0; */ |
| |
| enum return_flags { |
| RET_ERROR = -1, |
| RET_END_OPT_LIST = -1, |
| RET_NO_PARAM = '?', |
| RET_NO_PARAM2 = ':', |
| RET_UNKNOWN_OPT = '?' |
| }; |
| |
| /* |
| * Common initialisation on entry. |
| */ |
| static |
| void getopt_init(void) |
| { |
| optarg = (char *)0; |
| optopt = 0; |
| /* optind may be zero with some POSIX uses. |
| * For our purposes we just change it to 1. |
| */ |
| if (optind == 0) |
| optind = 1; |
| } |
| |
| /* |
| * Common handling for a single letter option. |
| */ |
| static |
| int getopt_1char(int argc, |
| char *const argv[], |
| const char *const opstring, |
| const int optchar) |
| { |
| size_t nlen = (opstring == 0) ? 0 : strlen(opstring); |
| size_t loptn; |
| |
| for (loptn = 0; loptn < nlen; loptn++) { |
| if (optchar == opstring[loptn]) { |
| if (opstring[loptn + 1] == ':') { |
| /* Option has argument */ |
| if (optind < argc) { |
| /* Found argument. */ |
| assert(argv != 0); |
| optind++; |
| optarg = argv[optind++]; |
| return optchar; |
| } |
| /* Missing argument. */ |
| if (opstring[loptn + 2] == ':') { |
| /* OK if optional "x::". */ |
| optind++; |
| return optchar; |
| } |
| /* Actual missing value. */ |
| optopt = optchar; |
| return ((opstring[0] == ':') |
| ? RET_NO_PARAM2 |
| : RET_NO_PARAM); |
| } |
| /* No argument, just return option char */ |
| optind++; |
| return optchar; |
| } |
| } |
| /* |
| * If getopt finds an option character in argv that was not included in |
| * options, ... it returns '?' and sets the external variable optopt to |
| * the actual option character. |
| */ |
| optopt = optchar; |
| return RET_UNKNOWN_OPT; |
| } |
| |
| int getopt(int argc, |
| char *argv[], |
| char *opstring) |
| { |
| int result = RET_END_OPT_LIST; |
| size_t argn = 0; |
| size_t nlen = strlen(opstring); |
| |
| getopt_init(); |
| /* If we have an argument left to play with */ |
| if ((argc > optind) && (argv != 0)) { |
| const char *arg = (const char *)argv[optind]; |
| |
| if ((arg != 0) && (arg[0] == '-')) |
| result = getopt_1char(argc, argv, opstring, arg[1]); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Match an argument value against an option name. |
| * Note that we only match over the shorter length of the pair, to allow |
| * for abbreviation or say --match=value |
| * Long option names may be abbreviated if the abbreviation is unique or an |
| * exact match for some defined option. This function does not check that the |
| * abbreviations are unique and should be handled by the caller. |
| * A long option may take a parameter, of the form --opt=param or --opt param. |
| */ |
| static |
| int optmatch(const char *argval, const char *optname) |
| { |
| int result = 0; |
| |
| while ((result == 0) && (*optname != 0) && (*argval != 0)) |
| result = (*argval++) - (*optname++); |
| return result; |
| } |
| |
| /* Handling for a single long option. */ |
| static |
| int getopt_1long(const int argc, |
| char *const argv[], |
| const struct option *const longopts, |
| const char *const optname, |
| int *const indexptr) |
| { |
| int result = RET_UNKNOWN_OPT; |
| size_t loptn = 0; |
| bool match_found = false; |
| |
| /* |
| * Long option names may be abbreviated if the abbreviation |
| * is unique or an exact match for some defined option. |
| * To handle this: |
| * - First search for an exact match. |
| * - If exact match was not found search for a abbreviated match. |
| * By doing this an incorrect option selection can be avoided. |
| */ |
| |
| /* 1. Search for an exact match. */ |
| while (longopts[loptn].name != NULL) { |
| if (strcmp(optname, longopts[loptn].name) == 0) { |
| match_found = true; |
| break; |
| } |
| ++loptn; |
| } |
| |
| /* 2. If exact match was not found search for a abbreviated match. */ |
| if (!match_found) { |
| loptn = 0; |
| while (longopts[loptn].name != NULL) { |
| if (optmatch(optname, longopts[loptn].name) == 0) { |
| match_found = true; |
| break; |
| } |
| ++loptn; |
| } |
| } |
| |
| if (match_found) { |
| /* We found a match. */ |
| result = longopts[loptn].val; |
| if (indexptr != 0) { |
| *indexptr = loptn; |
| } |
| switch (longopts[loptn].has_arg) { |
| case required_argument: |
| if ((optind + 1) >= argc) { |
| /* Missing argument. */ |
| optopt = result; |
| return RET_NO_PARAM; |
| } |
| /* Fallthrough to get option value. */ |
| |
| case optional_argument: |
| if ((argc - optind) > 0) { |
| /* Found argument. */ |
| optarg = argv[++optind]; |
| } |
| /* Fallthrough to handle flag. */ |
| |
| case no_argument: |
| optind++; |
| if (longopts[loptn].flag != 0) { |
| *longopts[loptn].flag = result; |
| result = 0; |
| } |
| break; |
| |
| } |
| return result; |
| } |
| |
| /* |
| * If getopt finds an option character in argv that was not included |
| * in options, ... it returns '?' and sets the external variable |
| * optopt to the actual option character. |
| */ |
| return RET_UNKNOWN_OPT; |
| } |
| |
| /* |
| * getopt_long gets the next option argument from the argument list |
| * specified by the argv and argc arguments. Options may be either short |
| * (single letter) as for getopt, or longer names (preceded by --). |
| */ |
| int getopt_long(int argc, |
| char *argv[], |
| const char *shortopts, |
| const struct option *longopts, |
| int *indexptr) |
| { |
| int result = RET_END_OPT_LIST; |
| |
| getopt_init(); |
| /* If we have an argument left to play with */ |
| if ((argc > optind) && (argv != 0)) { |
| const char *arg = argv[optind]; |
| |
| if ((arg != 0) && (arg[0] == '-')) { |
| if (arg[1] == '-') { |
| /* Looks like a long option. */ |
| result = getopt_1long(argc, |
| argv, |
| longopts, |
| &arg[2], |
| indexptr); |
| } else { |
| result = getopt_1char(argc, |
| argv, |
| shortopts, |
| arg[1]); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /* |
| * getopt_long_only gets the next option argument from the argument list |
| * specified by the argv and argc arguments. Options may be either short |
| * or long as for getopt_long, but the long names may have a single '-' |
| * prefix too. |
| */ |
| int getopt_long_only(int argc, |
| char *argv[], |
| const char *shortopts, |
| const struct option *longopts, |
| int *indexptr) |
| { |
| int result = RET_END_OPT_LIST; |
| |
| getopt_init(); |
| /* If we have an argument left to play with */ |
| if ((argc > optind) && (argv != 0)) { |
| const char *arg = argv[optind]; |
| |
| if ((arg != 0) && (arg[0] == '-')) { |
| if (arg[1] == '-') { |
| /* Looks like a long option. */ |
| result = getopt_1long(argc, |
| argv, |
| longopts, |
| &arg[2], |
| indexptr); |
| } else { |
| result = getopt_1long(argc, |
| argv, |
| longopts, |
| &arg[1], |
| indexptr); |
| if (result == RET_UNKNOWN_OPT) { |
| result = getopt_1char(argc, |
| argv, |
| shortopts, |
| arg[1]); |
| } |
| } |
| } |
| } |
| return result; |
| } |