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