• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
arg_init(char ** argv)22 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 
arg_match_helper(struct arg * arg_,const struct arg_def * def,char ** argv,char * err_msg)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 
arg_parse_uint_helper(const struct arg * arg,char * err_msg)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 
arg_parse_int_helper(const struct arg * arg,char * err_msg)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 
arg_parse_rational_helper(const struct arg * arg,char * err_msg)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 
arg_parse_enum_helper(const struct arg * arg,char * err_msg)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 
arg_parse_enum_or_int_helper(const struct arg * arg,char * err_msg)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
arg_parse_list_helper(const struct arg * arg,int * list,int n,char * err_msg)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 }
222