2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
17 #include "aom/aom_integer.h"
18 #include "aom_ports/msvc.h"
20 #if defined(__GNUC__) && __GNUC__
21 extern void die(const char *fmt
, ...) __attribute__((noreturn
));
23 extern void die(const char *fmt
, ...);
26 struct arg
arg_init(char **argv
) {
37 char *ignore_front_spaces(const char *str
) {
38 while (str
[0] == ' ' || str
[0] == '\t') ++str
;
42 void ignore_end_spaces(char *str
) {
43 char *end
= str
+ strlen(str
);
44 while (end
> str
&& (end
[0] == ' ' || end
[0] == '\t' || end
[0] == '\n' ||
45 end
[0] == '\r' || end
[0] == '\0'))
47 if (end
>= str
) end
[1] = '\0';
50 int arg_cfg(int *argc
, char ***argv
, const char *file
) {
51 char **argv_local
= (char **)*argv
;
52 char **argv_org
= (char **)*argv
;
54 FILE *f
= fopen(file
, "r");
57 while (fgets(line
, sizeof(line
) - 1, f
)) {
58 char *actual_line
= ignore_front_spaces(line
);
59 char *left
, *right
, *comment
;
60 size_t length
= strlen(actual_line
);
62 if (length
== 0 || actual_line
[0] == '#') continue;
63 right
= strchr(actual_line
, ':');
64 if (right
== NULL
) continue;
67 left
= ignore_front_spaces(actual_line
);
68 right
= ignore_front_spaces(right
+ 1);
70 comment
= strchr(right
, '#');
71 if (comment
!= NULL
) comment
[0] = '\0';
73 ignore_end_spaces(left
);
74 ignore_end_spaces(right
);
76 char **new_args
= argv_dup(*argc
, (const char **)argv_local
);
77 char *new_line
= (char *)malloc(sizeof(*new_line
) * 128);
79 if (argv_local
!= argv_org
) free(argv_local
);
81 if (!strcmp(right
, "ON"))
82 snprintf(new_line
, sizeof(*new_line
) * 128, "--%s", left
);
84 snprintf(new_line
, sizeof(*new_line
) * 128, "--%s=%s", left
, right
);
86 new_args
[(*argc
) - 1] = new_args
[(*argc
) - 2];
87 new_args
[(*argc
) - 2] = new_line
;
88 argv_local
= new_args
;
96 int arg_match(struct arg
*arg_
, const struct arg_def
*def
, char **argv
) {
99 if (!argv
[0] || argv
[0][0] != '-') return 0;
101 arg
= arg_init(argv
);
103 if (def
->short_name
&& strlen(arg
.argv
[0]) == strlen(def
->short_name
) + 1 &&
104 !strcmp(arg
.argv
[0] + 1, def
->short_name
)) {
105 arg
.name
= arg
.argv
[0] + 1;
106 arg
.val
= def
->has_val
? arg
.argv
[1] : NULL
;
107 arg
.argv_step
= def
->has_val
? 2 : 1;
108 } else if (def
->long_name
) {
109 const size_t name_len
= strlen(def
->long_name
);
111 if (strlen(arg
.argv
[0]) >= name_len
+ 2 && arg
.argv
[0][1] == '-' &&
112 !strncmp(arg
.argv
[0] + 2, def
->long_name
, name_len
) &&
113 (arg
.argv
[0][name_len
+ 2] == '=' ||
114 arg
.argv
[0][name_len
+ 2] == '\0')) {
115 arg
.name
= arg
.argv
[0] + 2;
116 arg
.val
= arg
.name
[name_len
] == '=' ? arg
.name
+ name_len
+ 1 : NULL
;
121 if (arg
.name
&& !arg
.val
&& def
->has_val
)
122 die("Error: option %s requires argument.\n", arg
.name
);
124 if (arg
.name
&& arg
.val
&& !def
->has_val
)
125 die("Error: option %s requires no argument.\n", arg
.name
);
127 if (arg
.name
&& (arg
.val
|| !def
->has_val
)) {
136 const char *arg_next(struct arg
*arg
) {
137 if (arg
->argv
[0]) arg
->argv
+= arg
->argv_step
;
142 char **argv_dup(int argc
, const char **argv
) {
143 char **new_argv
= malloc((argc
+ 1) * sizeof(*argv
));
145 memcpy(new_argv
, argv
, argc
* sizeof(*argv
));
146 new_argv
[argc
] = NULL
;
150 void arg_show_usage(FILE *fp
, const struct arg_def
*const *defs
) {
151 char option_text
[40] = { 0 };
153 for (; *defs
; defs
++) {
154 const struct arg_def
*def
= *defs
;
155 char *short_val
= def
->has_val
? " <arg>" : "";
156 char *long_val
= def
->has_val
? "=<arg>" : "";
158 if (def
->short_name
&& def
->long_name
) {
159 char *comma
= def
->has_val
? "," : ", ";
161 snprintf(option_text
, 37, "-%s%s%s --%s%6s", def
->short_name
, short_val
,
162 comma
, def
->long_name
, long_val
);
163 } else if (def
->short_name
)
164 snprintf(option_text
, 37, "-%s%s", def
->short_name
, short_val
);
165 else if (def
->long_name
)
166 snprintf(option_text
, 37, " --%s%s", def
->long_name
, long_val
);
168 fprintf(fp
, " %-37s\t%s\n", option_text
, def
->desc
);
171 const struct arg_enum_list
*listptr
;
173 fprintf(fp
, " %-37s\t ", "");
175 for (listptr
= def
->enums
; listptr
->name
; listptr
++)
176 fprintf(fp
, "%s%s", listptr
->name
, listptr
[1].name
? ", " : "\n");
181 unsigned int arg_parse_uint(const struct arg
*arg
) {
183 const unsigned long rawval
= strtoul(arg
->val
, &endptr
, 10); // NOLINT
185 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
186 if (rawval
<= UINT_MAX
) return (unsigned int)rawval
;
188 die("Option %s: Value %lu out of range for unsigned int\n", arg
->name
,
192 die("Option %s: Invalid character '%c'\n", arg
->name
, *endptr
);
196 int arg_parse_int(const struct arg
*arg
) {
198 const long rawval
= strtol(arg
->val
, &endptr
, 10); // NOLINT
200 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
201 if (rawval
>= INT_MIN
&& rawval
<= INT_MAX
) return (int)rawval
;
203 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
207 die("Option %s: Invalid character '%c'\n", arg
->name
, *endptr
);
211 struct aom_rational
{
212 int num
; /**< fraction numerator */
213 int den
; /**< fraction denominator */
215 struct aom_rational
arg_parse_rational(const struct arg
*arg
) {
218 struct aom_rational rat
;
220 /* parse numerator */
221 rawval
= strtol(arg
->val
, &endptr
, 10);
223 if (arg
->val
[0] != '\0' && endptr
[0] == '/') {
224 if (rawval
>= INT_MIN
&& rawval
<= INT_MAX
)
225 rat
.num
= (int)rawval
;
227 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
230 die("Option %s: Expected / at '%c'\n", arg
->name
, *endptr
);
232 /* parse denominator */
233 rawval
= strtol(endptr
+ 1, &endptr
, 10);
235 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
236 if (rawval
>= INT_MIN
&& rawval
<= INT_MAX
)
237 rat
.den
= (int)rawval
;
239 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
242 die("Option %s: Invalid character '%c'\n", arg
->name
, *endptr
);
247 int arg_parse_enum(const struct arg
*arg
) {
248 const struct arg_enum_list
*listptr
;
252 /* First see if the value can be parsed as a raw value */
253 rawval
= strtol(arg
->val
, &endptr
, 10);
254 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
255 /* Got a raw value, make sure it's valid */
256 for (listptr
= arg
->def
->enums
; listptr
->name
; listptr
++)
257 if (listptr
->val
== rawval
) return (int)rawval
;
260 /* Next see if it can be parsed as a string */
261 for (listptr
= arg
->def
->enums
; listptr
->name
; listptr
++)
262 if (!strcmp(arg
->val
, listptr
->name
)) return listptr
->val
;
264 die("Option %s: Invalid value '%s'\n", arg
->name
, arg
->val
);
268 int arg_parse_enum_or_int(const struct arg
*arg
) {
269 if (arg
->def
->enums
) return arg_parse_enum(arg
);
270 return arg_parse_int(arg
);
273 // parse a comma separated list of at most n integers
274 // return the number of elements in the list
275 int arg_parse_list(const struct arg
*arg
, int *list
, int n
) {
276 const char *ptr
= arg
->val
;
280 while (ptr
[0] != '\0') {
281 int32_t rawval
= (int32_t)strtol(ptr
, &endptr
, 10);
282 if (rawval
< INT_MIN
|| rawval
> INT_MAX
) {
283 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
286 die("Option %s: List has more than %d entries\n", arg
->name
, n
);
287 } else if (*endptr
== ',') {
289 } else if (*endptr
!= '\0') {
290 die("Option %s: Bad list separator '%c'\n", arg
->name
, *endptr
);
292 list
[i
++] = (int)rawval
;