argparse.c Source File

Reference Documentation

Platform
Intel® PAC
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.10
Napatech Software Suite: examples/common/argparse.c Source File
argparse.c
Go to the documentation of this file.
1 /**
2  * Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
3  * All rights reserved.
4  *
5  * Use of this source code is governed by a MIT-style license that can be found
6  * in the LICENSE file.
7  *
8  * Note: Some small changes has been made by Natatech.
9  */
10 
11 #include "argparse.h"
12 
13 #define OPT_UNSET 1
14 
15 static const char *
16 prefix_skip(const char *str, const char *prefix)
17 {
18  size_t len = strlen(prefix);
19  return strncmp(str, prefix, len) ? NULL : str + len;
20 }
21 
22 static int
23 prefix_cmp(const char *str, const char *prefix)
24 {
25  for (;; str++, prefix++)
26  if (!*prefix)
27  return 0;
28  else if (*str != *prefix)
29  return (unsigned char)*prefix - (unsigned char)*str;
30 }
31 
32 static void
33 argparse_error(struct argparse *This, const struct argparse_option *opt,
34  const char *reason)
35 {
36  if (!strncmp(This->argv[0], "--", 2)) {
37  fprintf(stderr, "error: option `%s` %s\n", opt->long_name, reason);
38  exit(-1);
39  } else {
40  fprintf(stderr, "error: option `%c` %s\n", opt->short_name, reason);
41  exit(-1);
42  }
43 }
44 
45 static int
46 argparse_getvalue(struct argparse *This, const struct argparse_option *opt,
47  int flags)
48 {
49  char *s;
50  if (!opt->value)
51  goto skipped;
52  switch (opt->type) {
54  if (flags & OPT_UNSET) {
55  *(int *)opt->value = *(int *)opt->value - 1;
56  } else {
57  *(int *)opt->value = *(int *)opt->value + 1;
58  }
59  if (*(int *)opt->value < 0) {
60  *(int *)opt->value = 0;
61  }
62  break;
63  case ARGPARSE_OPT_BIT:
64  if (flags & OPT_UNSET) {
65  *(int *)opt->value &= (int)~(1 << opt->data);
66  } else {
67  *(int *)opt->value |= (int)(1 << opt->data);
68  }
69  break;
70  case ARGPARSE_OPT_BIT64:
71  if (flags & OPT_UNSET) {
72  *(uint64_t *)opt->value &= (uint64_t)~(1 << opt->data);
73  } else {
74  *(uint64_t *)opt->value |= (uint64_t)(1 << opt->data);
75  }
76  break;
78  if (This->optvalue) {
79  *(const char **)opt->value = This->optvalue;
80  This->optvalue = NULL;
81  } else if (This->argc > 1) {
82  This->argc--;
83  *(const char **)opt->value = *++This->argv;
84  } else {
85  argparse_error(This, opt, "requires a value");
86  }
87  break;
89  if (This->optvalue) {
90  *(int *)opt->value = (int)strtol(This->optvalue, (char **)&s, 0);
91  This->optvalue = NULL;
92  } else if (This->argc > 1) {
93  This->argc--;
94  *(int *)opt->value = (int)strtol(*++This->argv, (char **)&s, 0);
95  } else {
96  argparse_error(This, opt, "requires a value");
97  break;
98  }
99  if (*s)
100  argparse_error(This, opt, "expects a numerical value");
101  break;
102  case ARGPARSE_OPT_UINT64:
103  if (This->optvalue) {
104 #ifdef WIN32
105  *(uint64_t *)opt->value = (uint64_t)_strtoui64(This->optvalue, (char **)&s, 0);
106 #else
107  *(uint64_t *)opt->value = (uint64_t)strtoull(This->optvalue, (char **)&s, 0);
108 #endif
109  This->optvalue = NULL;
110  } else if (This->argc > 1) {
111  This->argc--;
112 #ifdef WIN32
113  *(uint64_t *)opt->value = (uint64_t)_strtoui64(*++This->argv, (char **)&s, 0);
114 #else
115  *(uint64_t *)opt->value = (uint64_t)strtoull(*++This->argv, (char **)&s, 0);
116 #endif
117  } else {
118  argparse_error(This, opt, "requires a value");
119  break;
120  }
121  if (*s)
122  argparse_error(This, opt, "expects a numerical value");
123  break;
124  default:
125  assert(0);
126  }
127 
128 skipped:
129  if (opt->callback) {
130  return opt->callback(This, opt, 1);
131  }
132 
133  return 0;
134 }
135 
136 static void
138 {
139  for (; options->type != ARGPARSE_OPT_END; options++) {
140  switch (options->type) {
141  case ARGPARSE_OPT_END:
143  case ARGPARSE_OPT_BIT:
144  case ARGPARSE_OPT_BIT64:
146  case ARGPARSE_OPT_UINT64:
147  case ARGPARSE_OPT_STRING:
148  continue;
149  default:
150  fprintf(stderr, "wrong option type: %d", options->type);
151  break;
152  }
153  }
154 }
155 
156 static int
157 argparse_short_opt(struct argparse *This, const struct argparse_option *options)
158 {
159  for (; options->type != ARGPARSE_OPT_END; options++) {
160  if (options->short_name == *This->optvalue) {
161  This->optvalue = This->optvalue[1] ? This->optvalue + 1 : NULL;
162  return argparse_getvalue(This, options, 0);
163  }
164  }
165  return -2;
166 }
167 
168 static int
169 argparse_long_opt(struct argparse *This, const struct argparse_option *options)
170 {
171  for (; options->type != ARGPARSE_OPT_END; options++) {
172  const char *rest;
173  int opt_flags = 0;
174  if (!options->long_name)
175  continue;
176 
177  rest = prefix_skip(This->argv[0] + 2, options->long_name);
178  if (!rest) {
179  // Negation allowed?
180  if (options->flags & OPT_NONEG) {
181  continue;
182  }
183  // Only boolean/bit allow negation.
184  if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT && options->type != ARGPARSE_OPT_BIT64) {
185  continue;
186  }
187 
188  if (!prefix_cmp(This->argv[0] + 2, "no-")) {
189  rest = prefix_skip(This->argv[0] + 2 + 3, options->long_name);
190  if (!rest)
191  continue;
192  opt_flags |= OPT_UNSET;
193  } else {
194  continue;
195  }
196  }
197  if (*rest) {
198  if (*rest != '=')
199  continue;
200  This->optvalue = rest + 1;
201  }
202  return argparse_getvalue(This, options, opt_flags);
203  }
204  return -2;
205 }
206 
207 int
208 argparse_init(struct argparse *This, struct argparse_option *options,
209  const char *const *usage, int flags)
210 {
211  memset(This, 0, sizeof(*This));
212  This->options = options;
213  This->usage = usage;
214  This->flags = flags;
215  return 0;
216 }
217 
218 int
219 argparse_parse(struct argparse *This, int argc, const char **argv)
220 {
221  This->argc = argc - 1;
222  This->argv = argv + 1;
223  This->out = argv;
224 
226 
227  for (; This->argc; This->argc--, This->argv++) {
228  const char *arg = This->argv[0];
229  if (arg[0] != '-' || !arg[1]) {
230  if (This->flags & ARGPARSE_STOP_AT_NON_OPTION) {
231  goto end;
232  }
233  // if it's not option or is a single char '-', copy verbatimly
234  This->out[This->cpidx++] = This->argv[0];
235  continue;
236  }
237  // short option
238  if (arg[1] != '-') {
239  This->optvalue = arg + 1;
240  switch (argparse_short_opt(This, This->options)) {
241  case -1:
242  break;
243  case -2:
244  goto unknown;
245  }
246  while (This->optvalue) {
247  switch (argparse_short_opt(This, This->options)) {
248  case -1:
249  break;
250  case -2:
251  goto unknown;
252  }
253  }
254  continue;
255  }
256  // if '--' presents
257  if (!arg[2]) {
258  This->argc--;
259  This->argv++;
260  break;
261  }
262  // long option
263  switch (argparse_long_opt(This, This->options)) {
264  case -1:
265  break;
266  case -2:
267  goto unknown;
268  }
269  continue;
270 
271 unknown:
272  fprintf(stderr, "error: unknown option `%s`\n", This->argv[0]);
273  argparse_usage(This);
274  exit(1);
275  }
276 
277 end:
278  memmove((void *)(This->out + This->cpidx), This->argv,
279  This->argc * sizeof(*This->out));
280  This->out[This->cpidx + This->argc] = NULL;
281 
282  return This->cpidx + This->argc;
283 }
284 
285 void
287 {
288  const struct argparse_option *options;
289 
290  // figure out best width
291  size_t usage_opts_width = 0;
292  size_t len;
293 
294  fprintf(stdout, "%s\n", *This->usage++);
295 
296  options = This->options;
297  for (; options->type != ARGPARSE_OPT_END; options++) {
298  len = 0;
299  if ((options)->short_name) {
300  len += 2;
301  }
302  if ((options)->short_name && (options)->long_name) {
303  len += 2; // separator ", "
304  }
305  if ((options)->long_name) {
306  len += strlen((options)->long_name) + 2;
307  }
308  if (options->name_value != NULL) {
309  len += strlen(options->name_value) + 3;
310  }
311  else {
312  if (options->type == ARGPARSE_OPT_INTEGER) {
313  len += strlen(" <int>");
314  } else if (options->type == ARGPARSE_OPT_UINT64) {
315  len += strlen(" <int64>");
316  } else if (options->type == ARGPARSE_OPT_STRING) {
317  len += strlen(" <str>");
318  }
319  }
320  len = (size_t)ceil((float)len / 4) * 4;
321  if (usage_opts_width < len) {
322  usage_opts_width = len;
323  }
324  }
325  usage_opts_width += 4; // 4 spaces prefix
326 
327  options = This->options;
328  for (; options->type != ARGPARSE_OPT_END; options++) {
329  size_t pos;
330  int pad;
331 
332  if (options->flags & ARGPARSE_INTERNAL_OPTION)
333  continue;
334 
335  pos = fprintf(stdout, " ");
336  if (options->short_name) {
337  pos += fprintf(stdout, "-%c", options->short_name);
338  }
339  if (options->long_name && options->short_name) {
340  pos += fprintf(stdout, ", ");
341  }
342  if (options->long_name) {
343  pos += fprintf(stdout, "--%s", options->long_name);
344  }
345  if (options->name_value != NULL) {
346  pos += fprintf(stdout, " <%s>", options->name_value);
347  }
348  else {
349  if (options->type == ARGPARSE_OPT_INTEGER) {
350  pos += fprintf(stdout, " <int>");
351  } else if (options->type == ARGPARSE_OPT_UINT64) {
352  pos += fprintf(stdout, " <int64>");
353  } else if (options->type == ARGPARSE_OPT_STRING) {
354  pos += fprintf(stdout, " <str>");
355  }
356  }
357  if (pos <= usage_opts_width) {
358  pad = (int)(usage_opts_width - pos);
359  } else {
360  fputc('\n', stdout);
361  pad = (int)usage_opts_width;
362  }
363 #if 0
364  fprintf(stdout, "%*s%s\n", pad + 2, "", options->help);
365 #else
366  {
367  size_t l = strlen(options->help);
368  size_t i;
369  fprintf(stdout, "%*s: ", pad, "");
370  for (i = 0; i < l; i++)
371  {
372  fputc(options->help[i], stdout);
373  if (options->help[i] == '\n') {
374  /* A newline in the text. We must indent the next text */
375  fprintf(stdout, "%*s", (int)(usage_opts_width + 2), "");
376  }
377  }
378  fputc('\n', stdout);
379  }
380 #endif
381  }
382  while (*This->usage && **This->usage)
383  fprintf(stdout, "%s\n", *This->usage++);
384  fputc('\n', stdout);
385 }
386 
387 int
388 argparse_help_cb(struct argparse *This, const struct argparse_option *option, int terminate)
389 {
390  (void)option;
391  argparse_usage(This);
392  if (terminate == 1)
393  exit(0);
394  return 0;
395 }