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 int arg_match(struct arg
*arg_
, const struct arg_def
*def
, char **argv
) {
40 if (!argv
[0] || argv
[0][0] != '-') return 0;
44 if (def
->short_name
&& strlen(arg
.argv
[0]) == strlen(def
->short_name
) + 1 &&
45 !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
);
52 if (strlen(arg
.argv
[0]) >= name_len
+ 2 && 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
;
62 if (arg
.name
&& !arg
.val
&& def
->has_val
)
63 die("Error: option %s requires argument.\n", arg
.name
);
65 if (arg
.name
&& arg
.val
&& !def
->has_val
)
66 die("Error: option %s requires no argument.\n", arg
.name
);
68 if (arg
.name
&& (arg
.val
|| !def
->has_val
)) {
77 const char *arg_next(struct arg
*arg
) {
78 if (arg
->argv
[0]) arg
->argv
+= arg
->argv_step
;
83 char **argv_dup(int argc
, const char **argv
) {
84 char **new_argv
= malloc((argc
+ 1) * sizeof(*argv
));
86 memcpy(new_argv
, argv
, argc
* sizeof(*argv
));
87 new_argv
[argc
] = NULL
;
91 void arg_show_usage(FILE *fp
, const struct arg_def
*const *defs
) {
92 char option_text
[40] = { 0 };
94 for (; *defs
; defs
++) {
95 const struct arg_def
*def
= *defs
;
96 char *short_val
= def
->has_val
? " <arg>" : "";
97 char *long_val
= def
->has_val
? "=<arg>" : "";
99 if (def
->short_name
&& def
->long_name
) {
100 char *comma
= def
->has_val
? "," : ", ";
102 snprintf(option_text
, 37, "-%s%s%s --%s%6s", def
->short_name
, short_val
,
103 comma
, def
->long_name
, long_val
);
104 } else if (def
->short_name
)
105 snprintf(option_text
, 37, "-%s%s", def
->short_name
, short_val
);
106 else if (def
->long_name
)
107 snprintf(option_text
, 37, " --%s%s", def
->long_name
, long_val
);
109 fprintf(fp
, " %-37s\t%s\n", option_text
, def
->desc
);
112 const struct arg_enum_list
*listptr
;
114 fprintf(fp
, " %-37s\t ", "");
116 for (listptr
= def
->enums
; listptr
->name
; listptr
++)
117 fprintf(fp
, "%s%s", listptr
->name
, listptr
[1].name
? ", " : "\n");
122 unsigned int arg_parse_uint(const struct arg
*arg
) {
124 const unsigned long rawval
= strtoul(arg
->val
, &endptr
, 10); // NOLINT
126 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
127 if (rawval
<= UINT_MAX
) return (unsigned int)rawval
;
129 die("Option %s: Value %lu out of range for unsigned int\n", arg
->name
,
133 die("Option %s: Invalid character '%c'\n", arg
->name
, *endptr
);
137 int arg_parse_int(const struct arg
*arg
) {
139 const long rawval
= strtol(arg
->val
, &endptr
, 10); // NOLINT
141 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
142 if (rawval
>= INT_MIN
&& rawval
<= INT_MAX
) return (int)rawval
;
144 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
148 die("Option %s: Invalid character '%c'\n", arg
->name
, *endptr
);
152 struct aom_rational
{
153 int num
; /**< fraction numerator */
154 int den
; /**< fraction denominator */
156 struct aom_rational
arg_parse_rational(const struct arg
*arg
) {
159 struct aom_rational rat
;
161 /* parse numerator */
162 rawval
= strtol(arg
->val
, &endptr
, 10);
164 if (arg
->val
[0] != '\0' && endptr
[0] == '/') {
165 if (rawval
>= INT_MIN
&& rawval
<= INT_MAX
)
166 rat
.num
= (int)rawval
;
168 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
171 die("Option %s: Expected / at '%c'\n", arg
->name
, *endptr
);
173 /* parse denominator */
174 rawval
= strtol(endptr
+ 1, &endptr
, 10);
176 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
177 if (rawval
>= INT_MIN
&& rawval
<= INT_MAX
)
178 rat
.den
= (int)rawval
;
180 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
183 die("Option %s: Invalid character '%c'\n", arg
->name
, *endptr
);
188 int arg_parse_enum(const struct arg
*arg
) {
189 const struct arg_enum_list
*listptr
;
193 /* First see if the value can be parsed as a raw value */
194 rawval
= strtol(arg
->val
, &endptr
, 10);
195 if (arg
->val
[0] != '\0' && endptr
[0] == '\0') {
196 /* Got a raw value, make sure it's valid */
197 for (listptr
= arg
->def
->enums
; listptr
->name
; listptr
++)
198 if (listptr
->val
== rawval
) return (int)rawval
;
201 /* Next see if it can be parsed as a string */
202 for (listptr
= arg
->def
->enums
; listptr
->name
; listptr
++)
203 if (!strcmp(arg
->val
, listptr
->name
)) return listptr
->val
;
205 die("Option %s: Invalid value '%s'\n", arg
->name
, arg
->val
);
209 int arg_parse_enum_or_int(const struct arg
*arg
) {
210 if (arg
->def
->enums
) return arg_parse_enum(arg
);
211 return arg_parse_int(arg
);
214 // parse a comma separated list of at most n integers
215 // return the number of elements in the list
216 int arg_parse_list(const struct arg
*arg
, int *list
, int n
) {
217 const char *ptr
= arg
->val
;
221 while (ptr
[0] != '\0') {
222 int32_t rawval
= (int32_t)strtol(ptr
, &endptr
, 10);
223 if (rawval
< INT_MIN
|| rawval
> INT_MAX
) {
224 die("Option %s: Value %ld out of range for signed int\n", arg
->name
,
227 die("Option %s: List has more than %d entries\n", arg
->name
, n
);
228 } else if (*endptr
== ',') {
230 } else if (*endptr
!= '\0') {
231 die("Option %s: Bad list separator '%c'\n", arg
->name
, *endptr
);
233 list
[i
++] = (int)rawval
;