args_helper.c (6470B)
1 /* 2 * Copyright (c) 2020, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 #include "common/args_helper.h" 12 13 #include <assert.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <limits.h> 18 19 #define SET_ERR_STRING(...) \ 20 if (err_msg) snprintf(err_msg, ARG_ERR_MSG_MAX_LEN, __VA_ARGS__) 21 22 static struct arg arg_init(char **argv) { 23 struct arg a; 24 25 a.argv = argv; 26 a.argv_step = 1; 27 a.name = NULL; 28 a.val = NULL; 29 a.def = NULL; 30 return a; 31 } 32 33 int arg_match_helper(struct arg *arg_, const struct arg_def *def, char **argv, 34 char *err_msg) { 35 struct arg arg; 36 37 if (err_msg) err_msg[0] = '\0'; 38 39 assert(def->has_val == 0 || def->has_val == 1 || def->has_val == -1); 40 41 if (!argv[0] || argv[0][0] != '-') return 0; 42 43 arg = arg_init(argv); 44 45 if (def->short_name && !strcmp(arg.argv[0] + 1, def->short_name)) { 46 arg.name = arg.argv[0] + 1; 47 arg.val = def->has_val ? arg.argv[1] : NULL; 48 arg.argv_step = def->has_val ? 2 : 1; 49 } else if (def->long_name) { 50 const size_t name_len = strlen(def->long_name); 51 52 if (arg.argv[0][1] == '-' && 53 !strncmp(arg.argv[0] + 2, def->long_name, name_len) && 54 (arg.argv[0][name_len + 2] == '=' || 55 arg.argv[0][name_len + 2] == '\0')) { 56 arg.name = arg.argv[0] + 2; 57 arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL; 58 arg.argv_step = 1; 59 } 60 } 61 62 if (arg.name) { 63 if (def->has_val == -1) { 64 arg.def = def; 65 *arg_ = arg; 66 return 1; 67 } 68 69 if (!arg.val && def->has_val) { 70 SET_ERR_STRING("Error: option %s requires argument.\n", arg.name); 71 return 0; 72 } 73 74 if (arg.val && !def->has_val) { 75 SET_ERR_STRING("Error: option %s requires no argument.\n", arg.name); 76 return 0; 77 } 78 79 arg.def = def; 80 *arg_ = arg; 81 return 1; 82 } 83 84 return 0; 85 } 86 87 unsigned int arg_parse_uint_helper(const struct arg *arg, char *err_msg) { 88 char *endptr; 89 const unsigned long rawval = strtoul(arg->val, &endptr, 10); // NOLINT 90 91 if (err_msg) err_msg[0] = '\0'; 92 93 if (arg->val[0] != '\0' && endptr[0] == '\0') { 94 if (rawval <= UINT_MAX) return (unsigned int)rawval; 95 SET_ERR_STRING("Option %s: Value %lu out of range for unsigned int\n", 96 arg->name, rawval); 97 return 0; 98 } 99 SET_ERR_STRING("Option %s: Invalid character '%c'\n", arg->name, *endptr); 100 return 0; 101 } 102 103 int arg_parse_int_helper(const struct arg *arg, char *err_msg) { 104 char *endptr; 105 const long rawval = strtol(arg->val, &endptr, 10); // NOLINT 106 107 if (err_msg) err_msg[0] = '\0'; 108 109 if (arg->val[0] != '\0' && endptr[0] == '\0') { 110 if (rawval >= INT_MIN && rawval <= INT_MAX) return (int)rawval; 111 SET_ERR_STRING("Option %s: Value %ld out of range for signed int\n", 112 arg->name, rawval); 113 return 0; 114 } 115 SET_ERR_STRING("Option %s: Invalid character '%c'\n", arg->name, *endptr); 116 return 0; 117 } 118 119 struct aom_rational arg_parse_rational_helper(const struct arg *arg, 120 char *err_msg) { 121 long rawval; // NOLINT 122 char *endptr; 123 struct aom_rational rat = { 0, 1 }; 124 125 if (err_msg) err_msg[0] = '\0'; 126 127 /* parse numerator */ 128 rawval = strtol(arg->val, &endptr, 10); 129 130 if (arg->val[0] != '\0' && endptr[0] == '/') { 131 if (rawval >= INT_MIN && rawval <= INT_MAX) { 132 rat.num = (int)rawval; 133 } else { 134 SET_ERR_STRING("Option %s: Value %ld out of range for signed int\n", 135 arg->name, rawval); 136 return rat; 137 } 138 } else { 139 SET_ERR_STRING("Option %s: Expected / at '%c'\n", arg->name, *endptr); 140 return rat; 141 } 142 143 /* parse denominator */ 144 rawval = strtol(endptr + 1, &endptr, 10); 145 146 if (arg->val[0] != '\0' && endptr[0] == '\0') { 147 if (rawval >= INT_MIN && rawval <= INT_MAX) { 148 rat.den = (int)rawval; 149 } else { 150 SET_ERR_STRING("Option %s: Value %ld out of range for signed int\n", 151 arg->name, rawval); 152 return rat; 153 } 154 } else { 155 SET_ERR_STRING("Option %s: Invalid character '%c'\n", arg->name, *endptr); 156 return rat; 157 } 158 159 return rat; 160 } 161 162 int arg_parse_enum_helper(const struct arg *arg, char *err_msg) { 163 const struct arg_enum_list *listptr; 164 long rawval; // NOLINT 165 char *endptr; 166 167 if (err_msg) err_msg[0] = '\0'; 168 169 /* First see if the value can be parsed as a raw value */ 170 rawval = strtol(arg->val, &endptr, 10); 171 if (arg->val[0] != '\0' && endptr[0] == '\0') { 172 /* Got a raw value, make sure it's valid */ 173 for (listptr = arg->def->enums; listptr->name; listptr++) 174 if (listptr->val == rawval) return (int)rawval; 175 } 176 177 /* Next see if it can be parsed as a string */ 178 for (listptr = arg->def->enums; listptr->name; listptr++) 179 if (!strcmp(arg->val, listptr->name)) return listptr->val; 180 181 SET_ERR_STRING("Option %s: Invalid value '%s'\n", arg->name, arg->val); 182 return 0; 183 } 184 185 int arg_parse_enum_or_int_helper(const struct arg *arg, char *err_msg) { 186 if (arg->def->enums) return arg_parse_enum_helper(arg, err_msg); 187 return arg_parse_int_helper(arg, err_msg); 188 } 189 190 // parse a comma separated list of at most n integers 191 // return the number of elements in the list 192 int arg_parse_list_helper(const struct arg *arg, int *list, int n, 193 char *err_msg) { 194 const char *ptr = arg->val; 195 char *endptr; 196 int i = 0; 197 198 if (err_msg) err_msg[0] = '\0'; 199 200 while (ptr[0] != '\0') { 201 long rawval = strtol(ptr, &endptr, 10); // NOLINT 202 if (rawval < INT_MIN || rawval > INT_MAX) { 203 SET_ERR_STRING("Option %s: Value %ld out of range for signed int\n", 204 arg->name, rawval); 205 return 0; 206 } else if (i >= n) { 207 SET_ERR_STRING("Option %s: List has more than %d entries\n", arg->name, 208 n); 209 return 0; 210 } else if (*endptr == ',') { 211 endptr++; 212 } else if (*endptr != '\0') { 213 SET_ERR_STRING("Option %s: Bad list separator '%c'\n", arg->name, 214 *endptr); 215 return 0; 216 } 217 list[i++] = (int)rawval; 218 ptr = endptr; 219 } 220 return i; 221 }