blob: e12f16bed9719209f5dc778fce73c6d2f7102aee [file] [log] [blame]
John Koleszar0ea50ce2010-05-18 11:58:33 -04001/*
Yaowu Xu9c01aa12016-09-01 14:32:49 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
John Koleszar0ea50ce2010-05-18 11:58:33 -04003 *
Yaowu Xu9c01aa12016-09-01 14:32:49 -07004 * 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.
John Koleszar0ea50ce2010-05-18 11:58:33 -040010 */
11
John Koleszar0ea50ce2010-05-18 11:58:33 -040012#include <stdlib.h>
13#include <string.h>
14#include <limits.h>
15#include "args.h"
16
Yaowu Xuc27fc142016-08-22 16:08:15 -070017#include "aom_ports/msvc.h"
John Koleszar0ea50ce2010-05-18 11:58:33 -040018
19#if defined(__GNUC__) && __GNUC__
20extern void die(const char *fmt, ...) __attribute__((noreturn));
21#else
22extern void die(const char *fmt, ...);
23#endif
24
John Koleszarc6b90392012-07-13 15:21:29 -070025struct arg arg_init(char **argv) {
26 struct arg a;
John Koleszar0ea50ce2010-05-18 11:58:33 -040027
clang-format6c4d83e2016-08-08 19:03:30 -070028 a.argv = argv;
John Koleszarc6b90392012-07-13 15:21:29 -070029 a.argv_step = 1;
clang-format6c4d83e2016-08-08 19:03:30 -070030 a.name = NULL;
31 a.val = NULL;
32 a.def = NULL;
John Koleszarc6b90392012-07-13 15:21:29 -070033 return a;
John Koleszar0ea50ce2010-05-18 11:58:33 -040034}
35
John Koleszarc6b90392012-07-13 15:21:29 -070036int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
37 struct arg arg;
John Koleszar0ea50ce2010-05-18 11:58:33 -040038
clang-format6c4d83e2016-08-08 19:03:30 -070039 if (!argv[0] || argv[0][0] != '-') return 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -040040
John Koleszarc6b90392012-07-13 15:21:29 -070041 arg = arg_init(argv);
John Koleszar0ea50ce2010-05-18 11:58:33 -040042
clang-format6c4d83e2016-08-08 19:03:30 -070043 if (def->short_name && strlen(arg.argv[0]) == strlen(def->short_name) + 1 &&
44 !strcmp(arg.argv[0] + 1, def->short_name)) {
John Koleszarc6b90392012-07-13 15:21:29 -070045 arg.name = arg.argv[0] + 1;
46 arg.val = def->has_val ? arg.argv[1] : NULL;
47 arg.argv_step = def->has_val ? 2 : 1;
48 } else if (def->long_name) {
John Koleszar82b1a342012-11-06 12:08:05 -080049 const size_t name_len = strlen(def->long_name);
John Koleszarc6b90392012-07-13 15:21:29 -070050
clang-format6c4d83e2016-08-08 19:03:30 -070051 if (strlen(arg.argv[0]) >= name_len + 2 && arg.argv[0][1] == '-' &&
52 !strncmp(arg.argv[0] + 2, def->long_name, name_len) &&
53 (arg.argv[0][name_len + 2] == '=' ||
54 arg.argv[0][name_len + 2] == '\0')) {
John Koleszarc6b90392012-07-13 15:21:29 -070055 arg.name = arg.argv[0] + 2;
56 arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL;
57 arg.argv_step = 1;
John Koleszar0ea50ce2010-05-18 11:58:33 -040058 }
John Koleszarc6b90392012-07-13 15:21:29 -070059 }
60
61 if (arg.name && !arg.val && def->has_val)
62 die("Error: option %s requires argument.\n", arg.name);
63
64 if (arg.name && arg.val && !def->has_val)
65 die("Error: option %s requires no argument.\n", arg.name);
66
clang-format6c4d83e2016-08-08 19:03:30 -070067 if (arg.name && (arg.val || !def->has_val)) {
John Koleszarc6b90392012-07-13 15:21:29 -070068 arg.def = def;
69 *arg_ = arg;
70 return 1;
71 }
72
73 return 0;
74}
75
John Koleszarc6b90392012-07-13 15:21:29 -070076const char *arg_next(struct arg *arg) {
clang-format6c4d83e2016-08-08 19:03:30 -070077 if (arg->argv[0]) arg->argv += arg->argv_step;
John Koleszarc6b90392012-07-13 15:21:29 -070078
79 return *arg->argv;
80}
81
John Koleszarc6b90392012-07-13 15:21:29 -070082char **argv_dup(int argc, const char **argv) {
83 char **new_argv = malloc((argc + 1) * sizeof(*argv));
84
85 memcpy(new_argv, argv, argc * sizeof(*argv));
86 new_argv[argc] = NULL;
87 return new_argv;
88}
89
John Koleszarc6b90392012-07-13 15:21:29 -070090void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
clang-format6c4d83e2016-08-08 19:03:30 -070091 char option_text[40] = { 0 };
John Koleszarc6b90392012-07-13 15:21:29 -070092
93 for (; *defs; defs++) {
94 const struct arg_def *def = *defs;
95 char *short_val = def->has_val ? " <arg>" : "";
96 char *long_val = def->has_val ? "=<arg>" : "";
97
98 if (def->short_name && def->long_name) {
99 char *comma = def->has_val ? "," : ", ";
100
clang-format6c4d83e2016-08-08 19:03:30 -0700101 snprintf(option_text, 37, "-%s%s%s --%s%6s", def->short_name, short_val,
102 comma, def->long_name, long_val);
John Koleszarc6b90392012-07-13 15:21:29 -0700103 } else if (def->short_name)
clang-format6c4d83e2016-08-08 19:03:30 -0700104 snprintf(option_text, 37, "-%s%s", def->short_name, short_val);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400105 else if (def->long_name)
clang-format6c4d83e2016-08-08 19:03:30 -0700106 snprintf(option_text, 37, " --%s%s", def->long_name, long_val);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400107
John Koleszarc6b90392012-07-13 15:21:29 -0700108 fprintf(fp, " %-37s\t%s\n", option_text, def->desc);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400109
John Koleszarc6b90392012-07-13 15:21:29 -0700110 if (def->enums) {
111 const struct arg_enum_list *listptr;
112
113 fprintf(fp, " %-37s\t ", "");
114
115 for (listptr = def->enums; listptr->name; listptr++)
clang-format6c4d83e2016-08-08 19:03:30 -0700116 fprintf(fp, "%s%s", listptr->name, listptr[1].name ? ", " : "\n");
John Koleszar0ea50ce2010-05-18 11:58:33 -0400117 }
John Koleszarc6b90392012-07-13 15:21:29 -0700118 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400119}
120
John Koleszarc6b90392012-07-13 15:21:29 -0700121unsigned int arg_parse_uint(const struct arg *arg) {
clang-format6c4d83e2016-08-08 19:03:30 -0700122 long int rawval;
123 char *endptr;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400124
John Koleszarc6b90392012-07-13 15:21:29 -0700125 rawval = strtol(arg->val, &endptr, 10);
126
127 if (arg->val[0] != '\0' && endptr[0] == '\0') {
clang-format6c4d83e2016-08-08 19:03:30 -0700128 if (rawval >= 0 && rawval <= UINT_MAX) return rawval;
John Koleszarc6b90392012-07-13 15:21:29 -0700129
clang-format6c4d83e2016-08-08 19:03:30 -0700130 die("Option %s: Value %ld out of range for unsigned int\n", arg->name,
131 rawval);
John Koleszarc6b90392012-07-13 15:21:29 -0700132 }
133
134 die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
135 return 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400136}
137
John Koleszarc6b90392012-07-13 15:21:29 -0700138int arg_parse_int(const struct arg *arg) {
clang-format6c4d83e2016-08-08 19:03:30 -0700139 long int rawval;
140 char *endptr;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400141
John Koleszarc6b90392012-07-13 15:21:29 -0700142 rawval = strtol(arg->val, &endptr, 10);
143
144 if (arg->val[0] != '\0' && endptr[0] == '\0') {
clang-format6c4d83e2016-08-08 19:03:30 -0700145 if (rawval >= INT_MIN && rawval <= INT_MAX) return rawval;
John Koleszarc6b90392012-07-13 15:21:29 -0700146
clang-format6c4d83e2016-08-08 19:03:30 -0700147 die("Option %s: Value %ld out of range for signed int\n", arg->name,
148 rawval);
John Koleszarc6b90392012-07-13 15:21:29 -0700149 }
150
151 die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
152 return 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400153}
154
Yaowu Xuf883b422016-08-30 14:01:10 -0700155struct aom_rational {
John Koleszarc6b90392012-07-13 15:21:29 -0700156 int num; /**< fraction numerator */
157 int den; /**< fraction denominator */
John Koleszar0ea50ce2010-05-18 11:58:33 -0400158};
Yaowu Xuf883b422016-08-30 14:01:10 -0700159struct aom_rational arg_parse_rational(const struct arg *arg) {
clang-format6c4d83e2016-08-08 19:03:30 -0700160 long int rawval;
161 char *endptr;
Yaowu Xuf883b422016-08-30 14:01:10 -0700162 struct aom_rational rat;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400163
John Koleszarc6b90392012-07-13 15:21:29 -0700164 /* parse numerator */
165 rawval = strtol(arg->val, &endptr, 10);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400166
John Koleszarc6b90392012-07-13 15:21:29 -0700167 if (arg->val[0] != '\0' && endptr[0] == '/') {
168 if (rawval >= INT_MIN && rawval <= INT_MAX)
169 rat.num = rawval;
clang-format6c4d83e2016-08-08 19:03:30 -0700170 else
171 die("Option %s: Value %ld out of range for signed int\n", arg->name,
172 rawval);
173 } else
174 die("Option %s: Expected / at '%c'\n", arg->name, *endptr);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400175
John Koleszarc6b90392012-07-13 15:21:29 -0700176 /* parse denominator */
177 rawval = strtol(endptr + 1, &endptr, 10);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400178
John Koleszarc6b90392012-07-13 15:21:29 -0700179 if (arg->val[0] != '\0' && endptr[0] == '\0') {
180 if (rawval >= INT_MIN && rawval <= INT_MAX)
181 rat.den = rawval;
clang-format6c4d83e2016-08-08 19:03:30 -0700182 else
183 die("Option %s: Value %ld out of range for signed int\n", arg->name,
184 rawval);
185 } else
186 die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400187
John Koleszarc6b90392012-07-13 15:21:29 -0700188 return rat;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400189}
John Koleszarb0da9b32010-12-17 09:43:39 -0500190
John Koleszarc6b90392012-07-13 15:21:29 -0700191int arg_parse_enum(const struct arg *arg) {
192 const struct arg_enum_list *listptr;
clang-format6c4d83e2016-08-08 19:03:30 -0700193 long int rawval;
194 char *endptr;
John Koleszarb0da9b32010-12-17 09:43:39 -0500195
John Koleszarc6b90392012-07-13 15:21:29 -0700196 /* First see if the value can be parsed as a raw value */
197 rawval = strtol(arg->val, &endptr, 10);
198 if (arg->val[0] != '\0' && endptr[0] == '\0') {
199 /* Got a raw value, make sure it's valid */
200 for (listptr = arg->def->enums; listptr->name; listptr++)
clang-format6c4d83e2016-08-08 19:03:30 -0700201 if (listptr->val == rawval) return rawval;
John Koleszarc6b90392012-07-13 15:21:29 -0700202 }
John Koleszarb0da9b32010-12-17 09:43:39 -0500203
John Koleszarc6b90392012-07-13 15:21:29 -0700204 /* Next see if it can be parsed as a string */
205 for (listptr = arg->def->enums; listptr->name; listptr++)
clang-format6c4d83e2016-08-08 19:03:30 -0700206 if (!strcmp(arg->val, listptr->name)) return listptr->val;
John Koleszarb0da9b32010-12-17 09:43:39 -0500207
John Koleszarc6b90392012-07-13 15:21:29 -0700208 die("Option %s: Invalid value '%s'\n", arg->name, arg->val);
209 return 0;
John Koleszarb0da9b32010-12-17 09:43:39 -0500210}
211
John Koleszarc6b90392012-07-13 15:21:29 -0700212int arg_parse_enum_or_int(const struct arg *arg) {
clang-format6c4d83e2016-08-08 19:03:30 -0700213 if (arg->def->enums) return arg_parse_enum(arg);
John Koleszarc6b90392012-07-13 15:21:29 -0700214 return arg_parse_int(arg);
John Koleszarb0da9b32010-12-17 09:43:39 -0500215}