1233d2500723e5594f3e7c70896ffeeef32b9c950ywan/*
2233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3233d2500723e5594f3e7c70896ffeeef32b9c950ywan *
4233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Use of this source code is governed by a BSD-style license
5233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  that can be found in the LICENSE file in the root of the source
6233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  tree. An additional intellectual property rights grant can be found
7233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  in the file PATENTS.  All contributing project authors may
8233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  be found in the AUTHORS file in the root of the source tree.
9233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
10233d2500723e5594f3e7c70896ffeeef32b9c950ywan
11233d2500723e5594f3e7c70896ffeeef32b9c950ywan
12233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdlib.h>
13233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <string.h>
14233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <limits.h>
15233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "args.h"
16233d2500723e5594f3e7c70896ffeeef32b9c950ywan
17233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef _MSC_VER
18233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define snprintf _snprintf
19233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
20233d2500723e5594f3e7c70896ffeeef32b9c950ywan
21233d2500723e5594f3e7c70896ffeeef32b9c950ywan#if defined(__GNUC__) && __GNUC__
22233d2500723e5594f3e7c70896ffeeef32b9c950ywanextern void die(const char *fmt, ...) __attribute__((noreturn));
23233d2500723e5594f3e7c70896ffeeef32b9c950ywan#else
24233d2500723e5594f3e7c70896ffeeef32b9c950ywanextern void die(const char *fmt, ...);
25233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
26233d2500723e5594f3e7c70896ffeeef32b9c950ywan
27233d2500723e5594f3e7c70896ffeeef32b9c950ywan
28233d2500723e5594f3e7c70896ffeeef32b9c950ywanstruct arg arg_init(char **argv) {
29233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct arg a;
30233d2500723e5594f3e7c70896ffeeef32b9c950ywan
31233d2500723e5594f3e7c70896ffeeef32b9c950ywan  a.argv      = argv;
32233d2500723e5594f3e7c70896ffeeef32b9c950ywan  a.argv_step = 1;
33233d2500723e5594f3e7c70896ffeeef32b9c950ywan  a.name      = NULL;
34233d2500723e5594f3e7c70896ffeeef32b9c950ywan  a.val       = NULL;
35233d2500723e5594f3e7c70896ffeeef32b9c950ywan  a.def       = NULL;
36233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return a;
37233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
38233d2500723e5594f3e7c70896ffeeef32b9c950ywan
39233d2500723e5594f3e7c70896ffeeef32b9c950ywanint arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
40233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct arg arg;
41233d2500723e5594f3e7c70896ffeeef32b9c950ywan
42233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!argv[0] || argv[0][0] != '-')
43233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
44233d2500723e5594f3e7c70896ffeeef32b9c950ywan
45233d2500723e5594f3e7c70896ffeeef32b9c950ywan  arg = arg_init(argv);
46233d2500723e5594f3e7c70896ffeeef32b9c950ywan
47233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (def->short_name
48233d2500723e5594f3e7c70896ffeeef32b9c950ywan      && strlen(arg.argv[0]) == strlen(def->short_name) + 1
49233d2500723e5594f3e7c70896ffeeef32b9c950ywan      && !strcmp(arg.argv[0] + 1, def->short_name)) {
50233d2500723e5594f3e7c70896ffeeef32b9c950ywan
51233d2500723e5594f3e7c70896ffeeef32b9c950ywan    arg.name = arg.argv[0] + 1;
52233d2500723e5594f3e7c70896ffeeef32b9c950ywan    arg.val = def->has_val ? arg.argv[1] : NULL;
53233d2500723e5594f3e7c70896ffeeef32b9c950ywan    arg.argv_step = def->has_val ? 2 : 1;
54233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else if (def->long_name) {
55233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const size_t name_len = strlen(def->long_name);
56233d2500723e5594f3e7c70896ffeeef32b9c950ywan
57233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (strlen(arg.argv[0]) >= name_len + 2
58233d2500723e5594f3e7c70896ffeeef32b9c950ywan        && arg.argv[0][1] == '-'
59233d2500723e5594f3e7c70896ffeeef32b9c950ywan        && !strncmp(arg.argv[0] + 2, def->long_name, name_len)
60233d2500723e5594f3e7c70896ffeeef32b9c950ywan        && (arg.argv[0][name_len + 2] == '='
61233d2500723e5594f3e7c70896ffeeef32b9c950ywan            || arg.argv[0][name_len + 2] == '\0')) {
62233d2500723e5594f3e7c70896ffeeef32b9c950ywan
63233d2500723e5594f3e7c70896ffeeef32b9c950ywan      arg.name = arg.argv[0] + 2;
64233d2500723e5594f3e7c70896ffeeef32b9c950ywan      arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL;
65233d2500723e5594f3e7c70896ffeeef32b9c950ywan      arg.argv_step = 1;
66233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
67233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
68233d2500723e5594f3e7c70896ffeeef32b9c950ywan
69233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg.name && !arg.val && def->has_val)
70233d2500723e5594f3e7c70896ffeeef32b9c950ywan    die("Error: option %s requires argument.\n", arg.name);
71233d2500723e5594f3e7c70896ffeeef32b9c950ywan
72233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg.name && arg.val && !def->has_val)
73233d2500723e5594f3e7c70896ffeeef32b9c950ywan    die("Error: option %s requires no argument.\n", arg.name);
74233d2500723e5594f3e7c70896ffeeef32b9c950ywan
75233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg.name
76233d2500723e5594f3e7c70896ffeeef32b9c950ywan      && (arg.val || !def->has_val)) {
77233d2500723e5594f3e7c70896ffeeef32b9c950ywan    arg.def = def;
78233d2500723e5594f3e7c70896ffeeef32b9c950ywan    *arg_ = arg;
79233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 1;
80233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
81233d2500723e5594f3e7c70896ffeeef32b9c950ywan
82233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 0;
83233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
84233d2500723e5594f3e7c70896ffeeef32b9c950ywan
85233d2500723e5594f3e7c70896ffeeef32b9c950ywan
86233d2500723e5594f3e7c70896ffeeef32b9c950ywanconst char *arg_next(struct arg *arg) {
87233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->argv[0])
88233d2500723e5594f3e7c70896ffeeef32b9c950ywan    arg->argv += arg->argv_step;
89233d2500723e5594f3e7c70896ffeeef32b9c950ywan
90233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return *arg->argv;
91233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
92233d2500723e5594f3e7c70896ffeeef32b9c950ywan
93233d2500723e5594f3e7c70896ffeeef32b9c950ywan
94233d2500723e5594f3e7c70896ffeeef32b9c950ywanchar **argv_dup(int argc, const char **argv) {
95233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char **new_argv = malloc((argc + 1) * sizeof(*argv));
96233d2500723e5594f3e7c70896ffeeef32b9c950ywan
97233d2500723e5594f3e7c70896ffeeef32b9c950ywan  memcpy(new_argv, argv, argc * sizeof(*argv));
98233d2500723e5594f3e7c70896ffeeef32b9c950ywan  new_argv[argc] = NULL;
99233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return new_argv;
100233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
101233d2500723e5594f3e7c70896ffeeef32b9c950ywan
102233d2500723e5594f3e7c70896ffeeef32b9c950ywan
103233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
104233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char option_text[40] = {0};
105233d2500723e5594f3e7c70896ffeeef32b9c950ywan
106233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (; *defs; defs++) {
107233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const struct arg_def *def = *defs;
108233d2500723e5594f3e7c70896ffeeef32b9c950ywan    char *short_val = def->has_val ? " <arg>" : "";
109233d2500723e5594f3e7c70896ffeeef32b9c950ywan    char *long_val = def->has_val ? "=<arg>" : "";
110233d2500723e5594f3e7c70896ffeeef32b9c950ywan
111233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (def->short_name && def->long_name) {
112233d2500723e5594f3e7c70896ffeeef32b9c950ywan      char *comma = def->has_val ? "," : ",      ";
113233d2500723e5594f3e7c70896ffeeef32b9c950ywan
114233d2500723e5594f3e7c70896ffeeef32b9c950ywan      snprintf(option_text, 37, "-%s%s%s --%s%6s",
115233d2500723e5594f3e7c70896ffeeef32b9c950ywan               def->short_name, short_val, comma,
116233d2500723e5594f3e7c70896ffeeef32b9c950ywan               def->long_name, long_val);
117233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else if (def->short_name)
118233d2500723e5594f3e7c70896ffeeef32b9c950ywan      snprintf(option_text, 37, "-%s%s",
119233d2500723e5594f3e7c70896ffeeef32b9c950ywan               def->short_name, short_val);
120233d2500723e5594f3e7c70896ffeeef32b9c950ywan    else if (def->long_name)
121233d2500723e5594f3e7c70896ffeeef32b9c950ywan      snprintf(option_text, 37, "          --%s%s",
122233d2500723e5594f3e7c70896ffeeef32b9c950ywan               def->long_name, long_val);
123233d2500723e5594f3e7c70896ffeeef32b9c950ywan
124233d2500723e5594f3e7c70896ffeeef32b9c950ywan    fprintf(fp, "  %-37s\t%s\n", option_text, def->desc);
125233d2500723e5594f3e7c70896ffeeef32b9c950ywan
126233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (def->enums) {
127233d2500723e5594f3e7c70896ffeeef32b9c950ywan      const struct arg_enum_list *listptr;
128233d2500723e5594f3e7c70896ffeeef32b9c950ywan
129233d2500723e5594f3e7c70896ffeeef32b9c950ywan      fprintf(fp, "  %-37s\t  ", "");
130233d2500723e5594f3e7c70896ffeeef32b9c950ywan
131233d2500723e5594f3e7c70896ffeeef32b9c950ywan      for (listptr = def->enums; listptr->name; listptr++)
132233d2500723e5594f3e7c70896ffeeef32b9c950ywan        fprintf(fp, "%s%s", listptr->name,
133233d2500723e5594f3e7c70896ffeeef32b9c950ywan                listptr[1].name ? ", " : "\n");
134233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
135233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
136233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
137233d2500723e5594f3e7c70896ffeeef32b9c950ywan
138233d2500723e5594f3e7c70896ffeeef32b9c950ywan
139233d2500723e5594f3e7c70896ffeeef32b9c950ywanunsigned int arg_parse_uint(const struct arg *arg) {
140233d2500723e5594f3e7c70896ffeeef32b9c950ywan  long int   rawval;
141233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char      *endptr;
142233d2500723e5594f3e7c70896ffeeef32b9c950ywan
143233d2500723e5594f3e7c70896ffeeef32b9c950ywan  rawval = strtol(arg->val, &endptr, 10);
144233d2500723e5594f3e7c70896ffeeef32b9c950ywan
145233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->val[0] != '\0' && endptr[0] == '\0') {
146233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (rawval >= 0 && rawval <= UINT_MAX)
147233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return rawval;
148233d2500723e5594f3e7c70896ffeeef32b9c950ywan
149233d2500723e5594f3e7c70896ffeeef32b9c950ywan    die("Option %s: Value %ld out of range for unsigned int\n",
150233d2500723e5594f3e7c70896ffeeef32b9c950ywan        arg->name, rawval);
151233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
152233d2500723e5594f3e7c70896ffeeef32b9c950ywan
153233d2500723e5594f3e7c70896ffeeef32b9c950ywan  die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
154233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 0;
155233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
156233d2500723e5594f3e7c70896ffeeef32b9c950ywan
157233d2500723e5594f3e7c70896ffeeef32b9c950ywan
158233d2500723e5594f3e7c70896ffeeef32b9c950ywanint arg_parse_int(const struct arg *arg) {
159233d2500723e5594f3e7c70896ffeeef32b9c950ywan  long int   rawval;
160233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char      *endptr;
161233d2500723e5594f3e7c70896ffeeef32b9c950ywan
162233d2500723e5594f3e7c70896ffeeef32b9c950ywan  rawval = strtol(arg->val, &endptr, 10);
163233d2500723e5594f3e7c70896ffeeef32b9c950ywan
164233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->val[0] != '\0' && endptr[0] == '\0') {
165233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (rawval >= INT_MIN && rawval <= INT_MAX)
166233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return rawval;
167233d2500723e5594f3e7c70896ffeeef32b9c950ywan
168233d2500723e5594f3e7c70896ffeeef32b9c950ywan    die("Option %s: Value %ld out of range for signed int\n",
169233d2500723e5594f3e7c70896ffeeef32b9c950ywan        arg->name, rawval);
170233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
171233d2500723e5594f3e7c70896ffeeef32b9c950ywan
172233d2500723e5594f3e7c70896ffeeef32b9c950ywan  die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
173233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 0;
174233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
175233d2500723e5594f3e7c70896ffeeef32b9c950ywan
176233d2500723e5594f3e7c70896ffeeef32b9c950ywan
177233d2500723e5594f3e7c70896ffeeef32b9c950ywanstruct vpx_rational {
178233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int num; /**< fraction numerator */
179233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int den; /**< fraction denominator */
180233d2500723e5594f3e7c70896ffeeef32b9c950ywan};
181233d2500723e5594f3e7c70896ffeeef32b9c950ywanstruct vpx_rational arg_parse_rational(const struct arg *arg) {
182233d2500723e5594f3e7c70896ffeeef32b9c950ywan  long int             rawval;
183233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char                *endptr;
184233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct vpx_rational  rat;
185233d2500723e5594f3e7c70896ffeeef32b9c950ywan
186233d2500723e5594f3e7c70896ffeeef32b9c950ywan  /* parse numerator */
187233d2500723e5594f3e7c70896ffeeef32b9c950ywan  rawval = strtol(arg->val, &endptr, 10);
188233d2500723e5594f3e7c70896ffeeef32b9c950ywan
189233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->val[0] != '\0' && endptr[0] == '/') {
190233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (rawval >= INT_MIN && rawval <= INT_MAX)
191233d2500723e5594f3e7c70896ffeeef32b9c950ywan      rat.num = rawval;
192233d2500723e5594f3e7c70896ffeeef32b9c950ywan    else die("Option %s: Value %ld out of range for signed int\n",
193233d2500723e5594f3e7c70896ffeeef32b9c950ywan               arg->name, rawval);
194233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else die("Option %s: Expected / at '%c'\n", arg->name, *endptr);
195233d2500723e5594f3e7c70896ffeeef32b9c950ywan
196233d2500723e5594f3e7c70896ffeeef32b9c950ywan  /* parse denominator */
197233d2500723e5594f3e7c70896ffeeef32b9c950ywan  rawval = strtol(endptr + 1, &endptr, 10);
198233d2500723e5594f3e7c70896ffeeef32b9c950ywan
199233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->val[0] != '\0' && endptr[0] == '\0') {
200233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (rawval >= INT_MIN && rawval <= INT_MAX)
201233d2500723e5594f3e7c70896ffeeef32b9c950ywan      rat.den = rawval;
202233d2500723e5594f3e7c70896ffeeef32b9c950ywan    else die("Option %s: Value %ld out of range for signed int\n",
203233d2500723e5594f3e7c70896ffeeef32b9c950ywan               arg->name, rawval);
204233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
205233d2500723e5594f3e7c70896ffeeef32b9c950ywan
206233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return rat;
207233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
208233d2500723e5594f3e7c70896ffeeef32b9c950ywan
209233d2500723e5594f3e7c70896ffeeef32b9c950ywan
210233d2500723e5594f3e7c70896ffeeef32b9c950ywanint arg_parse_enum(const struct arg *arg) {
211233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const struct arg_enum_list *listptr;
212233d2500723e5594f3e7c70896ffeeef32b9c950ywan  long int                    rawval;
213233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char                       *endptr;
214233d2500723e5594f3e7c70896ffeeef32b9c950ywan
215233d2500723e5594f3e7c70896ffeeef32b9c950ywan  /* First see if the value can be parsed as a raw value */
216233d2500723e5594f3e7c70896ffeeef32b9c950ywan  rawval = strtol(arg->val, &endptr, 10);
217233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->val[0] != '\0' && endptr[0] == '\0') {
218233d2500723e5594f3e7c70896ffeeef32b9c950ywan    /* Got a raw value, make sure it's valid */
219233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (listptr = arg->def->enums; listptr->name; listptr++)
220233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (listptr->val == rawval)
221233d2500723e5594f3e7c70896ffeeef32b9c950ywan        return rawval;
222233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
223233d2500723e5594f3e7c70896ffeeef32b9c950ywan
224233d2500723e5594f3e7c70896ffeeef32b9c950ywan  /* Next see if it can be parsed as a string */
225233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (listptr = arg->def->enums; listptr->name; listptr++)
226233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (!strcmp(arg->val, listptr->name))
227233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return listptr->val;
228233d2500723e5594f3e7c70896ffeeef32b9c950ywan
229233d2500723e5594f3e7c70896ffeeef32b9c950ywan  die("Option %s: Invalid value '%s'\n", arg->name, arg->val);
230233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 0;
231233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
232233d2500723e5594f3e7c70896ffeeef32b9c950ywan
233233d2500723e5594f3e7c70896ffeeef32b9c950ywan
234233d2500723e5594f3e7c70896ffeeef32b9c950ywanint arg_parse_enum_or_int(const struct arg *arg) {
235233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (arg->def->enums)
236233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return arg_parse_enum(arg);
237233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return arg_parse_int(arg);
238233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
239