args.c 6.1 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  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.
John Koleszar's avatar
John Koleszar committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 */


#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "args.h"

#ifdef _MSC_VER
#define snprintf _snprintf
#endif

#if defined(__GNUC__) && __GNUC__
extern void die(const char *fmt, ...) __attribute__((noreturn));
#else
extern void die(const char *fmt, ...);
#endif


John Koleszar's avatar
John Koleszar committed
28 29 30 31 32 33 34 35 36
struct arg arg_init(char **argv) {
  struct arg a;

  a.argv      = argv;
  a.argv_step = 1;
  a.name      = NULL;
  a.val       = NULL;
  a.def       = NULL;
  return a;
John Koleszar's avatar
John Koleszar committed
37 38
}

John Koleszar's avatar
John Koleszar committed
39 40
int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
  struct arg arg;
John Koleszar's avatar
John Koleszar committed
41

John Koleszar's avatar
John Koleszar committed
42 43
  if (!argv[0] || argv[0][0] != '-')
    return 0;
John Koleszar's avatar
John Koleszar committed
44

John Koleszar's avatar
John Koleszar committed
45
  arg = arg_init(argv);
John Koleszar's avatar
John Koleszar committed
46

John Koleszar's avatar
John Koleszar committed
47 48 49
  if (def->short_name
      && strlen(arg.argv[0]) == strlen(def->short_name) + 1
      && !strcmp(arg.argv[0] + 1, def->short_name)) {
John Koleszar's avatar
John Koleszar committed
50

John Koleszar's avatar
John Koleszar committed
51 52 53 54
    arg.name = arg.argv[0] + 1;
    arg.val = def->has_val ? arg.argv[1] : NULL;
    arg.argv_step = def->has_val ? 2 : 1;
  } else if (def->long_name) {
55
    const size_t name_len = strlen(def->long_name);
John Koleszar's avatar
John Koleszar committed
56 57 58 59 60 61 62 63 64 65

    if (strlen(arg.argv[0]) >= name_len + 2
        && arg.argv[0][1] == '-'
        && !strncmp(arg.argv[0] + 2, def->long_name, name_len)
        && (arg.argv[0][name_len + 2] == '='
            || arg.argv[0][name_len + 2] == '\0')) {

      arg.name = arg.argv[0] + 2;
      arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL;
      arg.argv_step = 1;
John Koleszar's avatar
John Koleszar committed
66
    }
John Koleszar's avatar
John Koleszar committed
67
  }
John Koleszar's avatar
John Koleszar committed
68

John Koleszar's avatar
John Koleszar committed
69 70
  if (arg.name && !arg.val && def->has_val)
    die("Error: option %s requires argument.\n", arg.name);
John Koleszar's avatar
John Koleszar committed
71

John Koleszar's avatar
John Koleszar committed
72 73
  if (arg.name && arg.val && !def->has_val)
    die("Error: option %s requires no argument.\n", arg.name);
John Koleszar's avatar
John Koleszar committed
74

John Koleszar's avatar
John Koleszar committed
75 76 77 78 79 80
  if (arg.name
      && (arg.val || !def->has_val)) {
    arg.def = def;
    *arg_ = arg;
    return 1;
  }
John Koleszar's avatar
John Koleszar committed
81

John Koleszar's avatar
John Koleszar committed
82
  return 0;
John Koleszar's avatar
John Koleszar committed
83 84 85
}


John Koleszar's avatar
John Koleszar committed
86 87 88
const char *arg_next(struct arg *arg) {
  if (arg->argv[0])
    arg->argv += arg->argv_step;
John Koleszar's avatar
John Koleszar committed
89

John Koleszar's avatar
John Koleszar committed
90
  return *arg->argv;
John Koleszar's avatar
John Koleszar committed
91 92 93
}


John Koleszar's avatar
John Koleszar committed
94 95
char **argv_dup(int argc, const char **argv) {
  char **new_argv = malloc((argc + 1) * sizeof(*argv));
John Koleszar's avatar
John Koleszar committed
96

John Koleszar's avatar
John Koleszar committed
97 98 99
  memcpy(new_argv, argv, argc * sizeof(*argv));
  new_argv[argc] = NULL;
  return new_argv;
John Koleszar's avatar
John Koleszar committed
100 101 102
}


John Koleszar's avatar
John Koleszar committed
103 104
void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
  char option_text[40] = {0};
John Koleszar's avatar
John Koleszar committed
105

John Koleszar's avatar
John Koleszar committed
106 107 108 109
  for (; *defs; defs++) {
    const struct arg_def *def = *defs;
    char *short_val = def->has_val ? " <arg>" : "";
    char *long_val = def->has_val ? "=<arg>" : "";
John Koleszar's avatar
John Koleszar committed
110

John Koleszar's avatar
John Koleszar committed
111 112
    if (def->short_name && def->long_name) {
      char *comma = def->has_val ? "," : ",      ";
113

John Koleszar's avatar
John Koleszar committed
114 115 116 117 118 119 120 121 122
      snprintf(option_text, 37, "-%s%s%s --%s%6s",
               def->short_name, short_val, comma,
               def->long_name, long_val);
    } else if (def->short_name)
      snprintf(option_text, 37, "-%s%s",
               def->short_name, short_val);
    else if (def->long_name)
      snprintf(option_text, 37, "          --%s%s",
               def->long_name, long_val);
John Koleszar's avatar
John Koleszar committed
123

John Koleszar's avatar
John Koleszar committed
124
    fprintf(fp, "  %-37s\t%s\n", option_text, def->desc);
125

John Koleszar's avatar
John Koleszar committed
126 127
    if (def->enums) {
      const struct arg_enum_list *listptr;
128

John Koleszar's avatar
John Koleszar committed
129
      fprintf(fp, "  %-37s\t  ", "");
130

John Koleszar's avatar
John Koleszar committed
131 132 133
      for (listptr = def->enums; listptr->name; listptr++)
        fprintf(fp, "%s%s", listptr->name,
                listptr[1].name ? ", " : "\n");
John Koleszar's avatar
John Koleszar committed
134
    }
John Koleszar's avatar
John Koleszar committed
135
  }
John Koleszar's avatar
John Koleszar committed
136 137 138
}


John Koleszar's avatar
John Koleszar committed
139 140 141
unsigned int arg_parse_uint(const struct arg *arg) {
  long int   rawval;
  char      *endptr;
John Koleszar's avatar
John Koleszar committed
142

John Koleszar's avatar
John Koleszar committed
143
  rawval = strtol(arg->val, &endptr, 10);
John Koleszar's avatar
John Koleszar committed
144

John Koleszar's avatar
John Koleszar committed
145 146 147
  if (arg->val[0] != '\0' && endptr[0] == '\0') {
    if (rawval >= 0 && rawval <= UINT_MAX)
      return rawval;
John Koleszar's avatar
John Koleszar committed
148

John Koleszar's avatar
John Koleszar committed
149 150 151
    die("Option %s: Value %ld out of range for unsigned int\n",
        arg->name, rawval);
  }
John Koleszar's avatar
John Koleszar committed
152

John Koleszar's avatar
John Koleszar committed
153 154
  die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
  return 0;
John Koleszar's avatar
John Koleszar committed
155 156 157
}


John Koleszar's avatar
John Koleszar committed
158 159 160
int arg_parse_int(const struct arg *arg) {
  long int   rawval;
  char      *endptr;
John Koleszar's avatar
John Koleszar committed
161

John Koleszar's avatar
John Koleszar committed
162
  rawval = strtol(arg->val, &endptr, 10);
John Koleszar's avatar
John Koleszar committed
163

John Koleszar's avatar
John Koleszar committed
164 165 166
  if (arg->val[0] != '\0' && endptr[0] == '\0') {
    if (rawval >= INT_MIN && rawval <= INT_MAX)
      return rawval;
John Koleszar's avatar
John Koleszar committed
167

John Koleszar's avatar
John Koleszar committed
168 169 170
    die("Option %s: Value %ld out of range for signed int\n",
        arg->name, rawval);
  }
John Koleszar's avatar
John Koleszar committed
171

John Koleszar's avatar
John Koleszar committed
172 173
  die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
  return 0;
John Koleszar's avatar
John Koleszar committed
174 175 176
}


John Koleszar's avatar
John Koleszar committed
177 178 179
struct vpx_rational {
  int num; /**< fraction numerator */
  int den; /**< fraction denominator */
John Koleszar's avatar
John Koleszar committed
180
};
John Koleszar's avatar
John Koleszar committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
struct vpx_rational arg_parse_rational(const struct arg *arg) {
  long int             rawval;
  char                *endptr;
  struct vpx_rational  rat;

  /* parse numerator */
  rawval = strtol(arg->val, &endptr, 10);

  if (arg->val[0] != '\0' && endptr[0] == '/') {
    if (rawval >= INT_MIN && rawval <= INT_MAX)
      rat.num = rawval;
    else die("Option %s: Value %ld out of range for signed int\n",
               arg->name, rawval);
  } else die("Option %s: Expected / at '%c'\n", arg->name, *endptr);

  /* parse denominator */
  rawval = strtol(endptr + 1, &endptr, 10);

  if (arg->val[0] != '\0' && endptr[0] == '\0') {
    if (rawval >= INT_MIN && rawval <= INT_MAX)
      rat.den = rawval;
    else die("Option %s: Value %ld out of range for signed int\n",
               arg->name, rawval);
  } else die("Option %s: Invalid character '%c'\n", arg->name, *endptr);

  return rat;
John Koleszar's avatar
John Koleszar committed
207
}
208 209


John Koleszar's avatar
John Koleszar committed
210 211 212 213
int arg_parse_enum(const struct arg *arg) {
  const struct arg_enum_list *listptr;
  long int                    rawval;
  char                       *endptr;
214

John Koleszar's avatar
John Koleszar committed
215 216 217 218 219 220 221 222
  /* First see if the value can be parsed as a raw value */
  rawval = strtol(arg->val, &endptr, 10);
  if (arg->val[0] != '\0' && endptr[0] == '\0') {
    /* Got a raw value, make sure it's valid */
    for (listptr = arg->def->enums; listptr->name; listptr++)
      if (listptr->val == rawval)
        return rawval;
  }
223

John Koleszar's avatar
John Koleszar committed
224 225 226 227 228 229 230
  /* Next see if it can be parsed as a string */
  for (listptr = arg->def->enums; listptr->name; listptr++)
    if (!strcmp(arg->val, listptr->name))
      return listptr->val;

  die("Option %s: Invalid value '%s'\n", arg->name, arg->val);
  return 0;
231 232 233
}


John Koleszar's avatar
John Koleszar committed
234 235 236 237
int arg_parse_enum_or_int(const struct arg *arg) {
  if (arg->def->enums)
    return arg_parse_enum(arg);
  return arg_parse_int(arg);
238
}