Home | History | Annotate | Download | only in fiptool
      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  */
     17 int 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  */
     26 const 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  */
     35 int 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  */
     41 char *optarg;	/* = 0; */
     42 
     43 enum 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  */
     54 static
     55 void 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  */
     69 static
     70 int 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 
    115 int 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 */
    143 static
    144 int 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. */
    154 static
    155 int 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  */
    212 int 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  */
    250 int 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