1/*
2 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11
12#include <stdlib.h>
13#include <string.h>
14#include <limits.h>
15#include "args.h"
16
17#include "vpx_ports/msvc.h"
18
19#if defined(__GNUC__) && __GNUC__
20extern void die(const char *fmt, ...) __attribute__((noreturn));
21#else
22extern void die(const char *fmt, ...);
23#endif
24
25
26struct arg arg_init(char **argv) {
27  struct arg a;
28
29  a.argv      = argv;
30  a.argv_step = 1;
31  a.name      = NULL;
32  a.val       = NULL;
33  a.def       = NULL;
34  return a;
35}
36
37int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
38  struct arg arg;
39
40  if (!argv[0] || argv[0][0] != '-')
41    return 0;
42
43  arg = arg_init(argv);
44
45  if (def->short_name
46      && strlen(arg.argv[0]) == strlen(def->short_name) + 1
47      && !strcmp(arg.argv[0] + 1, def->short_name)) {
48
49    arg.name = arg.argv[0] + 1;
50    arg.val = def->has_val ? arg.argv[1] : NULL;
51    arg.argv_step = def->has_val ? 2 : 1;
52  } else if (def->long_name) {
53    const size_t name_len = strlen(def->long_name);
54
55    if (strlen(arg.argv[0]) >= name_len + 2
56        && arg.argv[0][1] == '-'
57        && !strncmp(arg.argv[0] + 2, def->long_name, name_len)
58        && (arg.argv[0][name_len + 2] == '='
59            || arg.argv[0][name_len + 2] == '\0')) {
60
61      arg.name = arg.argv[0] + 2;
62      arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL;
63      arg.argv_step = 1;
64    }
65  }
66
67  if (arg.name && !arg.val && def->has_val)
68    die("Error: option %s requires argument.\n", arg.name);
69
70  if (arg.name && arg.val && !def->has_val)
71    die("Error: option %s requires no argument.\n", arg.name);
72
73  if (arg.name
74      && (arg.val || !def->has_val)) {
75    arg.def = def;
76    *arg_ = arg;
77    return 1;
78  }
79
80  return 0;
81}
82
83
84const char *arg_next(struct arg *arg) {
85  if (arg->argv[0])
86    arg->argv += arg->argv_step;
87
88  return *arg->argv;
89}
90
91
92char **argv_dup(int argc, const char **argv) {
93  char **new_argv = malloc((argc + 1) * sizeof(*argv));
94
95  memcpy(new_argv, argv, argc * sizeof(*argv));
96  new_argv[argc] = NULL;
97  return new_argv;
98}
99
100
101void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
102  char option_text[40] = {0};
103
104  for (; *defs; defs++) {
105    const struct arg_def *def = *defs;
106    char *short_val = def->has_val ? " <arg>" : "";
107    char *long_val = def->has_val ? "=<arg>" : "";
108
109    if (def->short_name && def->long_name) {
110      char *comma = def->has_val ? "," : ",      ";
111
112      snprintf(option_text, 37, "-%s%s%s --%s%6s",
113               def->short_name, short_val, comma,
114               def->long_name, long_val);
115    } else if (def->short_name)
116      snprintf(option_text, 37, "-%s%s",
117               def->short_name, short_val);
118    else if (def->long_name)
119      snprintf(option_text, 37, "          --%s%s",
120               def->long_name, long_val);
121
122    fprintf(fp, "  %-37s\t%s\n", option_text, def->desc);
123
124    if (def->enums) {
125      const struct arg_enum_list *listptr;
126
127      fprintf(fp, "  %-37s\t  ", "");
128
129      for (listptr = def->enums; listptr->name; listptr++)
130        fprintf(fp, "%s%s", listptr->name,
131                listptr[1].name ? ", " : "\n");
132    }
133  }
134}
135
136
137unsigned int arg_parse_uint(const struct arg *arg) {
138  long int   rawval;
139  char      *endptr;
140
141  rawval = strtol(arg->val, &endptr, 10);
142
143  if (arg->val[0] != '\0' && endptr[0] == '\0') {
144    if (rawval >= 0 && rawval <= UINT_MAX)
145      return rawval;
146
147    die("Option %s: Value %ld out of range for unsigned int\n",
148        arg->name, rawval);
149  }
150
151  die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
152  return 0;
153}
154
155
156int arg_parse_int(const struct arg *arg) {
157  long int   rawval;
158  char      *endptr;
159
160  rawval = strtol(arg->val, &endptr, 10);
161
162  if (arg->val[0] != '\0' && endptr[0] == '\0') {
163    if (rawval >= INT_MIN && rawval <= INT_MAX)
164      return rawval;
165
166    die("Option %s: Value %ld out of range for signed int\n",
167        arg->name, rawval);
168  }
169
170  die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
171  return 0;
172}
173
174
175struct vpx_rational {
176  int num; /**< fraction numerator */
177  int den; /**< fraction denominator */
178};
179struct vpx_rational arg_parse_rational(const struct arg *arg) {
180  long int             rawval;
181  char                *endptr;
182  struct vpx_rational  rat;
183
184  /* parse numerator */
185  rawval = strtol(arg->val, &endptr, 10);
186
187  if (arg->val[0] != '\0' && endptr[0] == '/') {
188    if (rawval >= INT_MIN && rawval <= INT_MAX)
189      rat.num = rawval;
190    else die("Option %s: Value %ld out of range for signed int\n",
191               arg->name, rawval);
192  } else die("Option %s: Expected / at '%c'\n", arg->name, *endptr);
193
194  /* parse denominator */
195  rawval = strtol(endptr + 1, &endptr, 10);
196
197  if (arg->val[0] != '\0' && endptr[0] == '\0') {
198    if (rawval >= INT_MIN && rawval <= INT_MAX)
199      rat.den = rawval;
200    else die("Option %s: Value %ld out of range for signed int\n",
201               arg->name, rawval);
202  } else die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
203
204  return rat;
205}
206
207
208int arg_parse_enum(const struct arg *arg) {
209  const struct arg_enum_list *listptr;
210  long int                    rawval;
211  char                       *endptr;
212
213  /* First see if the value can be parsed as a raw value */
214  rawval = strtol(arg->val, &endptr, 10);
215  if (arg->val[0] != '\0' && endptr[0] == '\0') {
216    /* Got a raw value, make sure it's valid */
217    for (listptr = arg->def->enums; listptr->name; listptr++)
218      if (listptr->val == rawval)
219        return rawval;
220  }
221
222  /* Next see if it can be parsed as a string */
223  for (listptr = arg->def->enums; listptr->name; listptr++)
224    if (!strcmp(arg->val, listptr->name))
225      return listptr->val;
226
227  die("Option %s: Invalid value '%s'\n", arg->name, arg->val);
228  return 0;
229}
230
231
232int arg_parse_enum_or_int(const struct arg *arg) {
233  if (arg->def->enums)
234    return arg_parse_enum(arg);
235  return arg_parse_int(arg);
236}
237