Release v4.9237 - Ice Coffee :coffee:
[RRG-proxmark3.git] / client / deps / cliparser / argtable3.c
blobf64688b2a580523459911b25026de49e7d93937c
1 /*******************************************************************************
2 * This file is part of the argtable3 library.
4 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
5 * <sheitmann@users.sourceforge.net>
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of STEWART HEITMANN nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 ******************************************************************************/
31 #include "argtable3.h"
33 // On Windows isspace crashes app in case of using Unicode character set and string to be above ASCII
34 // so you have to use _istspace instead of space
35 #ifdef UNICODE
36 #include <tchar.h>
37 #define ISSPACE _istspace
38 #else
39 #define ISSPACE isspace
40 #endif
42 /*******************************************************************************
43 * This file is part of the argtable3 library.
45 * Copyright (C) 2013 Tom G. Huang
46 * <tomghuang@gmail.com>
47 * All rights reserved.
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions are met:
51 * * Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * * Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * * Neither the name of STEWART HEITMANN nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
60 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
61 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
64 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
66 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
67 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
69 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 ******************************************************************************/
72 #ifndef ARG_UTILS_H
73 #define ARG_UTILS_H
75 #define ARG_ENABLE_TRACE 0
76 #define ARG_ENABLE_LOG 1
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
82 enum {
83 EMINCOUNT = 1,
84 EMAXCOUNT,
85 EBADINT,
87 // The same name define EOVERFLOW in errno.h on windows platform or android
88 #if defined(__STDC_WANT_SECURE_LIB__) || defined(__ANDROID__) || defined(ANDROID)
89 EOVERFLOW_,
90 #else
91 EOVERFLOW,
92 #endif
93 EBADDOUBLE,
94 EBADDATE,
95 EREGNOMATCH
99 #if defined(_MSC_VER)
100 #define ARG_TRACE(x) \
101 __pragma(warning(push)) \
102 __pragma(warning(disable:4127)) \
103 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \
104 __pragma(warning(pop))
106 #define ARG_LOG(x) \
107 __pragma(warning(push)) \
108 __pragma(warning(disable:4127)) \
109 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
110 __pragma(warning(pop))
111 #else
112 #define ARG_TRACE(x) \
113 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
115 #define ARG_LOG(x) \
116 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
117 #endif
119 extern void dbg_printf(const char *fmt, ...);
121 #ifdef __cplusplus
123 #endif
125 #endif
127 /*******************************************************************************
128 * This file is part of the argtable3 library.
130 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
131 * <sheitmann@users.sourceforge.net>
132 * All rights reserved.
134 * Redistribution and use in source and binary forms, with or without
135 * modification, are permitted provided that the following conditions are met:
136 * * Redistributions of source code must retain the above copyright
137 * notice, this list of conditions and the following disclaimer.
138 * * Redistributions in binary form must reproduce the above copyright
139 * notice, this list of conditions and the following disclaimer in the
140 * documentation and/or other materials provided with the distribution.
141 * * Neither the name of STEWART HEITMANN nor the names of its contributors
142 * may be used to endorse or promote products derived from this software
143 * without specific prior written permission.
145 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
146 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
147 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
148 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
149 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
150 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
151 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
152 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
153 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
154 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
155 ******************************************************************************/
157 #include <stdarg.h>
158 #include <stdio.h>
161 void dbg_printf(const char *fmt, ...) {
162 va_list args;
163 va_start(args, fmt);
164 vfprintf(stderr, fmt, args);
165 va_end(args);
168 #include "getopt.h"
170 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
171 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
172 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
175 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
177 * Permission to use, copy, modify, and distribute this software for any
178 * purpose with or without fee is hereby granted, provided that the above
179 * copyright notice and this permission notice appear in all copies.
181 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
182 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
183 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
184 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
185 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
186 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
187 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
189 * Sponsored in part by the Defense Advanced Research Projects
190 * Agency (DARPA) and Air Force Research Laboratory, Air Force
191 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
194 // $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $"
197 * Copyright (c) 2000 The NetBSD Foundation, Inc.
198 * All rights reserved.
200 * This code is derived from software contributed to The NetBSD Foundation
201 * by Dieter Baron and Thomas Klausner.
203 * Redistribution and use in source and binary forms, with or without
204 * modification, are permitted provided that the following conditions
205 * are met:
206 * 1. Redistributions of source code must retain the above copyright
207 * notice, this list of conditions and the following disclaimer.
208 * 2. Redistributions in binary form must reproduce the above copyright
209 * notice, this list of conditions and the following disclaimer in the
210 * documentation and/or other materials provided with the distribution.
212 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
213 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
215 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
216 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
217 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
218 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
219 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
220 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
221 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
222 * POSSIBILITY OF SUCH DAMAGE.
225 #if 0
226 #include <err.h>
227 #endif
228 #include <errno.h>
229 #include <stdlib.h>
230 #include <string.h>
233 #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
235 #ifdef REPLACE_GETOPT
236 int opterr = 1; /* if error message should be printed */
237 int optind = 1; /* index into parent argv vector */
238 int optopt = '?'; /* character checked for validity */
239 int optreset; /* reset getopt */
240 const char *optarg; /* argument associated with option */
241 #endif
243 #define PRINT_ERROR ((opterr) && (*options != ':'))
245 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
246 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
247 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
249 /* return values */
250 #define BADCH (int)'?'
251 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
252 #define INORDER (int)1
254 #define EMSG ""
256 static int getopt_internal(int, char *const *, const char *,
257 const struct option *, int *, int);
258 static int parse_long_options(char *const *, const char *,
259 const struct option *, int *, int);
260 static int gcd(int, int);
261 static void permute_args(int, int, int, char *const *);
263 static const char *place = EMSG; /* option letter processing */
265 /* XXX: set optreset to 1 rather than these two */
266 static int nonopt_start = -1; /* first non option argument (for permute) */
267 static int nonopt_end = -1; /* first option after non options (for permute) */
269 /* Error messages */
270 static const char recargchar[] = "option requires an argument -- %c";
271 static const char recargstring[] = "option requires an argument -- %s";
272 static const char ambig[] = "ambiguous option -- %.*s";
273 static const char noarg[] = "option doesn't take an argument -- %.*s";
274 static const char illoptchar[] = "unknown option -- %c";
275 static const char illoptstring[] = "unknown option -- %s";
279 #ifdef _WIN32
281 /* Windows needs warnx(). We change the definition though:
282 * 1. (another) global is defined, opterrmsg, which holds the error message
283 * 2. errors are always printed out on stderr w/o the program name
284 * Note that opterrmsg always gets set no matter what opterr is set to. The
285 * error message will not be printed if opterr is 0 as usual.
288 #include <stdio.h>
289 #include <stdarg.h>
291 #define MAX_OPTER_MSG_SIZE 128
293 extern char opterrmsg[MAX_OPTER_MSG_SIZE];
294 char opterrmsg[MAX_OPTER_MSG_SIZE]; /* buffer for the last error message */
296 static void warnx(const char *fmt, ...) {
297 va_list ap;
298 va_start(ap, fmt);
300 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
301 implementation specifics and manually suppress the warning.
303 memset(opterrmsg, 0, sizeof opterrmsg);
304 if (fmt != NULL)
305 #ifdef __STDC_WANT_SECURE_LIB__
306 _vsnprintf_s(opterrmsg, MAX_OPTER_MSG_SIZE, sizeof(opterrmsg) - 1, fmt, ap);
307 #else
308 _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
309 #endif
310 va_end(ap);
312 fprintf(stderr, "%s\n", opterrmsg);
315 #else
316 #include <err.h>
317 #endif /*_WIN32*/
321 * Compute the greatest common divisor of a and b.
323 static int
324 gcd(int a, int b) {
325 int c;
327 c = a % b;
328 while (c != 0) {
329 a = b;
330 b = c;
331 c = a % b;
334 return (b);
338 * Exchange the block from nonopt_start to nonopt_end with the block
339 * from nonopt_end to opt_end (keeping the same order of arguments
340 * in each block).
342 static void
343 permute_args(int panonopt_start, int panonopt_end, int opt_end,
344 char *const *nargv) {
347 * compute lengths of blocks and number and size of cycles
349 int nnonopts = panonopt_end - panonopt_start;
350 int nopts = opt_end - panonopt_end;
351 int ncycle = gcd(nnonopts, nopts);
352 int cyclelen = (opt_end - panonopt_start) / ncycle;
354 for (int i = 0; i < ncycle; i++) {
355 int cstart = panonopt_end + i;
356 int pos = cstart;
357 for (int j = 0; j < cyclelen; j++) {
358 if (pos >= panonopt_end)
359 pos -= nnonopts;
360 else
361 pos += nopts;
362 char *swap = nargv[pos];
363 /* LINTED const cast */
364 ((char **) nargv)[pos] = nargv[cstart];
365 /* LINTED const cast */
366 ((char **)nargv)[cstart] = swap;
372 * parse_long_options --
373 * Parse long options in argc/argv argument vector.
374 * Returns -1 if short_too is set and the option does not match long_options.
376 static int
377 parse_long_options(char *const *nargv, const char *options,
378 const struct option *long_options, int *idx, int short_too) {
379 const char *current_argv, *has_equal;
380 size_t current_argv_len;
381 int i, match;
383 current_argv = place;
384 match = -1;
386 optind++;
388 if ((has_equal = strchr(current_argv, '=')) != NULL) {
389 /* argument found (--option=arg) */
390 current_argv_len = has_equal - current_argv;
391 has_equal++;
392 } else
393 current_argv_len = strlen(current_argv);
395 for (i = 0; long_options[i].name; i++) {
396 /* find matching long option */
397 if (strncmp(current_argv, long_options[i].name,
398 current_argv_len))
399 continue;
401 if (strlen(long_options[i].name) == current_argv_len) {
402 /* exact match */
403 match = i;
404 break;
407 * If this is a known short option, don't allow
408 * a partial match of a single character.
410 if (short_too && current_argv_len == 1)
411 continue;
413 if (match == -1) /* partial match */
414 match = i;
415 else {
416 /* ambiguous abbreviation */
417 if (PRINT_ERROR)
418 warnx(ambig, (int)current_argv_len,
419 current_argv);
420 optopt = 0;
421 return (BADCH);
424 if (match != -1) { /* option found */
425 if (long_options[match].has_arg == no_argument
426 && has_equal) {
427 if (PRINT_ERROR)
428 warnx(noarg, (int)current_argv_len,
429 current_argv);
431 * XXX: GNU sets optopt to val regardless of flag
433 if (long_options[match].flag == NULL)
434 optopt = long_options[match].val;
435 else
436 optopt = 0;
437 return (BADARG);
439 if (long_options[match].has_arg == required_argument ||
440 long_options[match].has_arg == optional_argument) {
441 if (has_equal)
442 optarg = has_equal;
443 else if (long_options[match].has_arg ==
444 required_argument) {
446 * optional argument doesn't use next nargv
448 optarg = nargv[optind++];
451 if ((long_options[match].has_arg == required_argument)
452 && (optarg == NULL)) {
454 * Missing argument; leading ':' indicates no error
455 * should be generated.
457 if (PRINT_ERROR)
458 warnx(recargstring,
459 current_argv);
461 * XXX: GNU sets optopt to val regardless of flag
463 if (long_options[match].flag == NULL)
464 optopt = long_options[match].val;
465 else
466 optopt = 0;
467 --optind;
468 return (BADARG);
470 } else { /* unknown option */
471 if (short_too) {
472 --optind;
473 return (-1);
475 if (PRINT_ERROR)
476 warnx(illoptstring, current_argv);
477 optopt = 0;
478 return (BADCH);
480 if (idx)
481 *idx = match;
482 if (long_options[match].flag) {
483 *long_options[match].flag = long_options[match].val;
484 return (0);
485 } else
486 return (long_options[match].val);
490 * getopt_internal --
491 * Parse argc/argv argument vector. Called by user level routines.
493 static int
494 getopt_internal(int nargc, char *const *nargv, const char *options,
495 const struct option *long_options, int *idx, int flags) {
496 char *oli; /* option letter list index */
497 int optchar, short_too;
498 static int posixly_correct = -1;
499 #ifdef __STDC_WANT_SECURE_LIB__
500 char *buffer = NULL;
501 size_t buffer_size = 0;
502 errno_t err = 0;
503 #endif
505 if (options == NULL)
506 return (-1);
509 * Disable GNU extensions if POSIXLY_CORRECT is set or options
510 * string begins with a '+'.
513 #ifdef __STDC_WANT_SECURE_LIB__
514 if (posixly_correct == -1) {
515 err = _dupenv_s(&buffer, &buffer_size, "POSIXLY_CORRECT") == 0;
516 posixly_correct = buffer != NULL;
517 if (buffer != NULL && err == 0) {
518 free(buffer);
521 #else
522 if (posixly_correct == -1)
523 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
524 #endif
525 if (posixly_correct || *options == '+')
526 flags &= ~FLAG_PERMUTE;
527 else if (*options == '-')
528 flags |= FLAG_ALLARGS;
529 if (*options == '+' || *options == '-')
530 options++;
533 * XXX Some GNU programs (like cvs) set optind to 0 instead of
534 * XXX using optreset. Work around this braindamage.
536 if (optind == 0)
537 optind = optreset = 1;
539 optarg = NULL;
540 if (optreset)
541 nonopt_start = nonopt_end = -1;
542 start:
543 if (optreset || !*place) { /* update scanning pointer */
544 optreset = 0;
545 if (optind >= nargc) { /* end of argument vector */
546 place = EMSG;
547 if (nonopt_end != -1) {
548 /* do permutation, if we have to */
549 permute_args(nonopt_start, nonopt_end,
550 optind, nargv);
551 optind -= nonopt_end - nonopt_start;
552 } else if (nonopt_start != -1) {
554 * If we skipped non-options, set optind
555 * to the first of them.
557 optind = nonopt_start;
559 nonopt_start = nonopt_end = -1;
560 return (-1);
562 if (*(place = nargv[optind]) != '-' ||
563 (place[1] == '\0' && strchr(options, '-') == NULL)) {
564 place = EMSG; /* found non-option */
565 if (flags & FLAG_ALLARGS) {
567 * GNU extension:
568 * return non-option as argument to option 1
570 optarg = nargv[optind++];
571 return (INORDER);
573 if (!(flags & FLAG_PERMUTE)) {
575 * If no permutation wanted, stop parsing
576 * at first non-option.
578 return (-1);
580 /* do permutation */
581 if (nonopt_start == -1)
582 nonopt_start = optind;
583 else if (nonopt_end != -1) {
584 permute_args(nonopt_start, nonopt_end,
585 optind, nargv);
586 nonopt_start = optind -
587 (nonopt_end - nonopt_start);
588 nonopt_end = -1;
590 optind++;
591 /* process next argument */
592 goto start;
594 if (nonopt_start != -1 && nonopt_end == -1)
595 nonopt_end = optind;
598 * If we have "-" do nothing, if "--" we are done.
600 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
601 optind++;
602 place = EMSG;
604 * We found an option (--), so if we skipped
605 * non-options, we have to permute.
607 if (nonopt_end != -1) {
608 permute_args(nonopt_start, nonopt_end,
609 optind, nargv);
610 optind -= nonopt_end - nonopt_start;
612 nonopt_start = nonopt_end = -1;
613 return (-1);
618 * Check long options if:
619 * 1) we were passed some
620 * 2) the arg is not just "-"
621 * 3) either the arg starts with -- we are getopt_long_only()
623 if (long_options != NULL && place != nargv[optind] &&
624 (*place == '-' || (flags & FLAG_LONGONLY))) {
625 short_too = 0;
626 if (*place == '-')
627 place++; /* --foo long option */
628 else if (*place != ':' && strchr(options, *place) != NULL)
629 short_too = 1; /* could be short option too */
631 optchar = parse_long_options(nargv, options, long_options,
632 idx, short_too);
633 if (optchar != -1) {
634 place = EMSG;
635 return (optchar);
639 if ((optchar = (int) * place++) == (int)':' ||
640 (optchar == (int)'-' && *place != '\0') ||
641 (oli = strchr(options, optchar)) == NULL) {
643 * If the user specified "-" and '-' isn't listed in
644 * options, return -1 (non-option) as per POSIX.
645 * Otherwise, it is an unknown option character (or ':').
647 if (optchar == (int)'-' && *place == '\0')
648 return (-1);
649 if (!*place)
650 ++optind;
651 if (PRINT_ERROR)
652 warnx(illoptchar, optchar);
653 optopt = optchar;
654 return (BADCH);
656 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
657 /* -W long-option */
658 if (*place) /* no space */
659 /* NOTHING */;
660 else if (++optind >= nargc) { /* no arg */
661 place = EMSG;
662 if (PRINT_ERROR)
663 warnx(recargchar, optchar);
664 optopt = optchar;
665 return (BADARG);
666 } else /* white space */
667 place = nargv[optind];
668 optchar = parse_long_options(nargv, options, long_options,
669 idx, 0);
670 place = EMSG;
671 return (optchar);
673 if (*++oli != ':') { /* doesn't take argument */
674 if (!*place)
675 ++optind;
676 } else { /* takes (optional) argument */
677 optarg = NULL;
678 if (*place) /* no white space */
679 optarg = place;
680 else if (oli[1] != ':') { /* arg not optional */
681 if (++optind >= nargc) { /* no arg */
682 place = EMSG;
683 if (PRINT_ERROR)
684 warnx(recargchar, optchar);
685 optopt = optchar;
686 return (BADARG);
687 } else
688 optarg = nargv[optind];
690 place = EMSG;
691 ++optind;
693 /* dump back option letter */
694 return (optchar);
697 #ifdef REPLACE_GETOPT
699 * getopt --
700 * Parse argc/argv argument vector.
702 * [eventually this will replace the BSD getopt]
705 getopt(int nargc, char *const *nargv, const char *options) {
708 * We don't pass FLAG_PERMUTE to getopt_internal() since
709 * the BSD getopt(3) (unlike GNU) has never done this.
711 * Furthermore, since many privileged programs call getopt()
712 * before dropping privileges it makes sense to keep things
713 * as simple (and bug-free) as possible.
715 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
717 #endif /* REPLACE_GETOPT */
720 * getopt_long --
721 * Parse argc/argv argument vector.
724 getopt_long(int nargc, char *const *nargv, const char *options,
725 const struct option *long_options, int *idx) {
727 return (getopt_internal(nargc, nargv, options, long_options, idx,
728 FLAG_PERMUTE));
732 * getopt_long_only --
733 * Parse argc/argv argument vector.
736 getopt_long_only(int nargc, char *const *nargv, const char *options,
737 const struct option *long_options, int *idx) {
739 return (getopt_internal(nargc, nargv, options, long_options, idx,
740 FLAG_PERMUTE | FLAG_LONGONLY));
742 /*******************************************************************************
743 * This file is part of the argtable3 library.
745 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
746 * <sheitmann@users.sourceforge.net>
747 * All rights reserved.
749 * Redistribution and use in source and binary forms, with or without
750 * modification, are permitted provided that the following conditions are met:
751 * * Redistributions of source code must retain the above copyright
752 * notice, this list of conditions and the following disclaimer.
753 * * Redistributions in binary form must reproduce the above copyright
754 * notice, this list of conditions and the following disclaimer in the
755 * documentation and/or other materials provided with the distribution.
756 * * Neither the name of STEWART HEITMANN nor the names of its contributors
757 * may be used to endorse or promote products derived from this software
758 * without specific prior written permission.
760 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
761 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
762 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
763 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
764 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
765 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
766 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
767 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
768 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
769 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
770 ******************************************************************************/
772 #include <stdlib.h>
773 #include <string.h>
775 #include "argtable3.h"
778 char *arg_strptime(const char *buf, const char *fmt, struct tm *tm);
781 static void arg_date_resetfn(struct arg_date *parent) {
782 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
783 parent->count = 0;
787 static int arg_date_scanfn(struct arg_date *parent, const char *argval) {
788 int errorcode = 0;
790 if (parent->count == parent->hdr.maxcount) {
791 errorcode = EMAXCOUNT;
792 } else if (!argval) {
793 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
794 parent->count++;
795 } else {
796 const char *pend;
797 struct tm tm = parent->tmval[parent->count];
799 /* parse the given argument value, store result in parent->tmval[] */
800 pend = arg_strptime(argval, parent->format, &tm);
801 if (pend && pend[0] == '\0')
802 parent->tmval[parent->count++] = tm;
803 else
804 errorcode = EBADDATE;
807 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
808 return errorcode;
812 static int arg_date_checkfn(struct arg_date *parent) {
813 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
815 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
816 return errorcode;
820 static void arg_date_errorfn(
821 struct arg_date *parent,
822 FILE *fp,
823 int errorcode,
824 const char *argval,
825 const char *progname) {
826 const char *shortopts = parent->hdr.shortopts;
827 const char *longopts = parent->hdr.longopts;
828 const char *datatype = parent->hdr.datatype;
830 /* make argval NULL safe */
831 argval = argval ? argval : "";
833 fprintf(fp, "%s: ", progname);
834 switch (errorcode) {
835 case EMINCOUNT:
836 fputs("missing option ", fp);
837 arg_print_option(fp, shortopts, longopts, datatype, "\n");
838 break;
840 case EMAXCOUNT:
841 fputs("excess option ", fp);
842 arg_print_option(fp, shortopts, longopts, argval, "\n");
843 break;
845 case EBADDATE: {
846 struct tm tm;
847 char buff[200];
849 fprintf(fp, "illegal timestamp format \"%s\"\n", argval);
850 memset(&tm, 0, sizeof(tm));
851 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
852 strftime(buff, sizeof(buff), parent->format, &tm);
853 printf("correct format is \"%s\"\n", buff);
854 break;
860 struct arg_date *arg_date0(
861 const char *shortopts,
862 const char *longopts,
863 const char *format,
864 const char *datatype,
865 const char *glossary) {
866 return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
870 struct arg_date *arg_date1(
871 const char *shortopts,
872 const char *longopts,
873 const char *format,
874 const char *datatype,
875 const char *glossary) {
876 return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
880 struct arg_date *arg_daten(
881 const char *shortopts,
882 const char *longopts,
883 const char *format,
884 const char *datatype,
885 int mincount,
886 int maxcount,
887 const char *glossary) {
888 size_t nbytes;
889 struct arg_date *result;
891 /* foolproof things by ensuring maxcount is not less than mincount */
892 maxcount = (maxcount < mincount) ? mincount : maxcount;
894 /* default time format is the national date format for the locale */
895 if (!format)
896 format = "%x";
898 nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
899 + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
901 /* allocate storage for the arg_date struct + tmval[] array. */
902 /* we use calloc because we want the tmval[] array zero filled. */
903 result = (struct arg_date *)calloc(1, nbytes);
904 if (result) {
905 /* init the arg_hdr struct */
906 result->hdr.flag = ARG_HASVALUE;
907 result->hdr.shortopts = shortopts;
908 result->hdr.longopts = longopts;
909 result->hdr.datatype = datatype ? datatype : format;
910 result->hdr.glossary = glossary;
911 result->hdr.mincount = mincount;
912 result->hdr.maxcount = maxcount;
913 result->hdr.parent = result;
914 result->hdr.resetfn = (arg_resetfn *)arg_date_resetfn;
915 result->hdr.scanfn = (arg_scanfn *)arg_date_scanfn;
916 result->hdr.checkfn = (arg_checkfn *)arg_date_checkfn;
917 result->hdr.errorfn = (arg_errorfn *)arg_date_errorfn;
919 /* store the tmval[maxcount] array immediately after the arg_date struct */
920 result->tmval = (struct tm *)(result + 1);
922 /* init the remaining arg_date member variables */
923 result->count = 0;
924 result->format = format;
927 ARG_TRACE(("arg_daten() returns %p\n", result));
928 return result;
933 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
934 * All rights reserved.
936 * This code was contributed to The NetBSD Foundation by Klaus Klein.
937 * Heavily optimised by David Laight
939 * Redistribution and use in source and binary forms, with or without
940 * modification, are permitted provided that the following conditions
941 * are met:
942 * 1. Redistributions of source code must retain the above copyright
943 * notice, this list of conditions and the following disclaimer.
944 * 2. Redistributions in binary form must reproduce the above copyright
945 * notice, this list of conditions and the following disclaimer in the
946 * documentation and/or other materials provided with the distribution.
948 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
949 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
950 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
951 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
952 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
953 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
954 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
955 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
956 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
957 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
958 * POSSIBILITY OF SUCH DAMAGE.
961 #include <ctype.h>
962 #include <string.h>
963 #include <time.h>
966 * We do not implement alternate representations. However, we always
967 * check whether a given modifier is allowed for a certain conversion.
969 #define ALT_E 0x01
970 #define ALT_O 0x02
971 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
972 #define TM_YEAR_BASE (1900)
974 static int conv_num(const char * *, int *, int, int);
976 static const char *day[7] = {
977 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
978 "Friday", "Saturday"
981 static const char *abday[7] = {
982 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
985 static const char *mon[12] = {
986 "January", "February", "March", "April", "May", "June", "July",
987 "August", "September", "October", "November", "December"
990 static const char *abmon[12] = {
991 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
992 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
995 static const char *am_pm[2] = {
996 "AM", "PM"
1000 static int arg_strcasecmp(const char *s1, const char *s2) {
1001 const unsigned char *us1 = (const unsigned char *)s1;
1002 const unsigned char *us2 = (const unsigned char *)s2;
1003 while (tolower(*us1) == tolower(*us2++))
1004 if (*us1++ == '\0')
1005 return 0;
1007 return tolower(*us1) - tolower(*--us2);
1011 static int arg_strncasecmp(const char *s1, const char *s2, size_t n) {
1012 if (n != 0) {
1013 const unsigned char *us1 = (const unsigned char *)s1;
1014 const unsigned char *us2 = (const unsigned char *)s2;
1015 do {
1016 if (tolower(*us1) != tolower(*us2++))
1017 return tolower(*us1) - tolower(*--us2);
1019 if (*us1++ == '\0')
1020 break;
1021 } while (--n != 0);
1024 return 0;
1028 char *arg_strptime(const char *buf, const char *fmt, struct tm *tm) {
1029 char c;
1030 const char *bp;
1031 size_t len = 0;
1032 int alt_format, i, split_year = 0;
1034 bp = buf;
1036 while ((c = *fmt) != '\0') {
1037 /* Clear `alternate' modifier prior to new conversion. */
1038 alt_format = 0;
1040 /* Eat up white-space. */
1041 if (ISSPACE(c)) {
1042 while (ISSPACE(*bp))
1043 bp++;
1045 fmt++;
1046 continue;
1049 if ((c = *fmt++) != '%')
1050 goto literal;
1053 again:
1054 switch (c = *fmt++) {
1055 case '%': /* "%%" is converted to "%". */
1056 literal:
1057 if (c != *bp++)
1058 return (0);
1059 break;
1062 * "Alternative" modifiers. Just set the appropriate flag
1063 * and start over again.
1065 case 'E': /* "%E?" alternative conversion modifier. */
1066 LEGAL_ALT(0);
1067 alt_format |= ALT_E;
1068 goto again;
1070 case 'O': /* "%O?" alternative conversion modifier. */
1071 LEGAL_ALT(0);
1072 alt_format |= ALT_O;
1073 goto again;
1076 * "Complex" conversion rules, implemented through recursion.
1078 case 'c': /* Date and time, using the locale's format. */
1079 LEGAL_ALT(ALT_E);
1080 bp = arg_strptime(bp, "%x %X", tm);
1081 if (!bp)
1082 return (0);
1083 break;
1085 case 'D': /* The date as "%m/%d/%y". */
1086 LEGAL_ALT(0);
1087 bp = arg_strptime(bp, "%m/%d/%y", tm);
1088 if (!bp)
1089 return (0);
1090 break;
1092 case 'R': /* The time as "%H:%M". */
1093 LEGAL_ALT(0);
1094 bp = arg_strptime(bp, "%H:%M", tm);
1095 if (!bp)
1096 return (0);
1097 break;
1099 case 'r': /* The time in 12-hour clock representation. */
1100 LEGAL_ALT(0);
1101 bp = arg_strptime(bp, "%I:%M:%S %p", tm);
1102 if (!bp)
1103 return (0);
1104 break;
1106 case 'T': /* The time as "%H:%M:%S". */
1107 LEGAL_ALT(0);
1108 bp = arg_strptime(bp, "%H:%M:%S", tm);
1109 if (!bp)
1110 return (0);
1111 break;
1113 case 'X': /* The time, using the locale's format. */
1114 LEGAL_ALT(ALT_E);
1115 bp = arg_strptime(bp, "%H:%M:%S", tm);
1116 if (!bp)
1117 return (0);
1118 break;
1120 case 'x': /* The date, using the locale's format. */
1121 LEGAL_ALT(ALT_E);
1122 bp = arg_strptime(bp, "%m/%d/%y", tm);
1123 if (!bp)
1124 return (0);
1125 break;
1128 * "Elementary" conversion rules.
1130 case 'A': /* The day of week, using the locale's form. */
1131 case 'a':
1132 LEGAL_ALT(0);
1133 for (i = 0; i < 7; i++) {
1134 /* Full name. */
1135 len = strlen(day[i]);
1136 if (arg_strncasecmp(day[i], bp, len) == 0)
1137 break;
1139 /* Abbreviated name. */
1140 len = strlen(abday[i]);
1141 if (arg_strncasecmp(abday[i], bp, len) == 0)
1142 break;
1145 /* Nothing matched. */
1146 if (i == 7)
1147 return (0);
1149 tm->tm_wday = i;
1150 bp += len;
1151 break;
1153 case 'B': /* The month, using the locale's form. */
1154 case 'b':
1155 case 'h':
1156 LEGAL_ALT(0);
1157 for (i = 0; i < 12; i++) {
1158 /* Full name. */
1159 len = strlen(mon[i]);
1160 if (arg_strncasecmp(mon[i], bp, len) == 0)
1161 break;
1163 /* Abbreviated name. */
1164 len = strlen(abmon[i]);
1165 if (arg_strncasecmp(abmon[i], bp, len) == 0)
1166 break;
1169 /* Nothing matched. */
1170 if (i == 12)
1171 return (0);
1173 tm->tm_mon = i;
1174 bp += len;
1175 break;
1177 case 'C': /* The century number. */
1178 LEGAL_ALT(ALT_E);
1179 if (!(conv_num(&bp, &i, 0, 99)))
1180 return (0);
1182 if (split_year) {
1183 tm->tm_year = (tm->tm_year % 100) + (i * 100);
1184 } else {
1185 tm->tm_year = i * 100;
1186 split_year = 1;
1188 break;
1190 case 'd': /* The day of month. */
1191 case 'e':
1192 LEGAL_ALT(ALT_O);
1193 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
1194 return (0);
1195 break;
1197 case 'k': /* The hour (24-hour clock representation). */
1198 LEGAL_ALT(0);
1199 /* FALLTHROUGH */
1200 case 'H':
1201 LEGAL_ALT(ALT_O);
1202 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
1203 return (0);
1204 break;
1206 case 'l': /* The hour (12-hour clock representation). */
1207 LEGAL_ALT(0);
1208 /* FALLTHROUGH */
1209 case 'I':
1210 LEGAL_ALT(ALT_O);
1211 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
1212 return (0);
1213 if (tm->tm_hour == 12)
1214 tm->tm_hour = 0;
1215 break;
1217 case 'j': /* The day of year. */
1218 LEGAL_ALT(0);
1219 if (!(conv_num(&bp, &i, 1, 366)))
1220 return (0);
1221 tm->tm_yday = i - 1;
1222 break;
1224 case 'M': /* The minute. */
1225 LEGAL_ALT(ALT_O);
1226 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
1227 return (0);
1228 break;
1230 case 'm': /* The month. */
1231 LEGAL_ALT(ALT_O);
1232 if (!(conv_num(&bp, &i, 1, 12)))
1233 return (0);
1234 tm->tm_mon = i - 1;
1235 break;
1237 case 'p': /* The locale's equivalent of AM/PM. */
1238 LEGAL_ALT(0);
1239 /* AM? */
1240 if (arg_strcasecmp(am_pm[0], bp) == 0) {
1241 if (tm->tm_hour > 11)
1242 return (0);
1244 bp += strlen(am_pm[0]);
1245 break;
1247 /* PM? */
1248 else if (arg_strcasecmp(am_pm[1], bp) == 0) {
1249 if (tm->tm_hour > 11)
1250 return (0);
1252 tm->tm_hour += 12;
1253 bp += strlen(am_pm[1]);
1254 break;
1257 /* Nothing matched. */
1258 return (0);
1260 case 'S': /* The seconds. */
1261 LEGAL_ALT(ALT_O);
1262 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
1263 return (0);
1264 break;
1266 case 'U': /* The week of year, beginning on sunday. */
1267 case 'W': /* The week of year, beginning on monday. */
1268 LEGAL_ALT(ALT_O);
1270 * XXX This is bogus, as we can not assume any valid
1271 * information present in the tm structure at this
1272 * point to calculate a real value, so just check the
1273 * range for now.
1275 if (!(conv_num(&bp, &i, 0, 53)))
1276 return (0);
1277 break;
1279 case 'w': /* The day of week, beginning on sunday. */
1280 LEGAL_ALT(ALT_O);
1281 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
1282 return (0);
1283 break;
1285 case 'Y': /* The year. */
1286 LEGAL_ALT(ALT_E);
1287 if (!(conv_num(&bp, &i, 0, 9999)))
1288 return (0);
1290 tm->tm_year = i - TM_YEAR_BASE;
1291 break;
1293 case 'y': /* The year within 100 years of the epoch. */
1294 LEGAL_ALT(ALT_E | ALT_O);
1295 if (!(conv_num(&bp, &i, 0, 99)))
1296 return (0);
1298 if (split_year) {
1299 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
1300 break;
1302 split_year = 1;
1303 if (i <= 68)
1304 tm->tm_year = i + 2000 - TM_YEAR_BASE;
1305 else
1306 tm->tm_year = i + 1900 - TM_YEAR_BASE;
1307 break;
1310 * Miscellaneous conversions.
1312 case 'n': /* Any kind of white-space. */
1313 case 't':
1314 LEGAL_ALT(0);
1315 while (ISSPACE(*bp))
1316 bp++;
1317 break;
1320 default: /* Unknown/unsupported conversion. */
1321 return (0);
1327 /* LINTED functional specification */
1328 return ((char *)bp);
1332 static int conv_num(const char * *buf, int *dest, int llim, int ulim) {
1333 int result = 0;
1335 /* The limit also determines the number of valid digits. */
1336 int rulim = ulim;
1338 if (**buf < '0' || **buf > '9')
1339 return (0);
1341 do {
1342 result *= 10;
1343 result += *(*buf)++ - '0';
1344 rulim /= 10;
1345 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
1347 if (result < llim || result > ulim)
1348 return (0);
1350 *dest = result;
1351 return (1);
1353 /*******************************************************************************
1354 * This file is part of the argtable3 library.
1356 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1357 * <sheitmann@users.sourceforge.net>
1358 * All rights reserved.
1360 * Redistribution and use in source and binary forms, with or without
1361 * modification, are permitted provided that the following conditions are met:
1362 * * Redistributions of source code must retain the above copyright
1363 * notice, this list of conditions and the following disclaimer.
1364 * * Redistributions in binary form must reproduce the above copyright
1365 * notice, this list of conditions and the following disclaimer in the
1366 * documentation and/or other materials provided with the distribution.
1367 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1368 * may be used to endorse or promote products derived from this software
1369 * without specific prior written permission.
1371 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1372 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1373 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1374 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1375 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1376 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1377 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1378 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1379 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1380 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1381 ******************************************************************************/
1383 #include <stdlib.h>
1385 #include "argtable3.h"
1388 static void arg_dbl_resetfn(struct arg_dbl *parent) {
1389 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1390 parent->count = 0;
1394 static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval) {
1395 int errorcode = 0;
1397 if (parent->count == parent->hdr.maxcount) {
1398 /* maximum number of arguments exceeded */
1399 errorcode = EMAXCOUNT;
1400 } else if (!argval) {
1401 /* a valid argument with no argument value was given. */
1402 /* This happens when an optional argument value was invoked. */
1403 /* leave parent argument value unaltered but still count the argument. */
1404 parent->count++;
1405 } else {
1406 double val;
1407 char *end;
1409 /* extract double from argval into val */
1410 val = strtod(argval, &end);
1412 /* if success then store result in parent->dval[] array otherwise return error*/
1413 if (*end == 0)
1414 parent->dval[parent->count++] = val;
1415 else
1416 errorcode = EBADDOUBLE;
1419 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1420 return errorcode;
1424 static int arg_dbl_checkfn(struct arg_dbl *parent) {
1425 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1427 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1428 return errorcode;
1432 static void arg_dbl_errorfn(
1433 struct arg_dbl *parent,
1434 FILE *fp,
1435 int errorcode,
1436 const char *argval,
1437 const char *progname) {
1438 const char *shortopts = parent->hdr.shortopts;
1439 const char *longopts = parent->hdr.longopts;
1440 const char *datatype = parent->hdr.datatype;
1442 /* make argval NULL safe */
1443 argval = argval ? argval : "";
1445 fprintf(fp, "%s: ", progname);
1446 switch (errorcode) {
1447 case EMINCOUNT:
1448 fputs("missing option ", fp);
1449 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1450 break;
1452 case EMAXCOUNT:
1453 fputs("excess option ", fp);
1454 arg_print_option(fp, shortopts, longopts, argval, "\n");
1455 break;
1457 case EBADDOUBLE:
1458 fprintf(fp, "invalid argument \"%s\" to option ", argval);
1459 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1460 break;
1465 struct arg_dbl *arg_dbl0(
1466 const char *shortopts,
1467 const char *longopts,
1468 const char *datatype,
1469 const char *glossary) {
1470 return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
1474 struct arg_dbl *arg_dbl1(
1475 const char *shortopts,
1476 const char *longopts,
1477 const char *datatype,
1478 const char *glossary) {
1479 return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
1483 struct arg_dbl *arg_dbln(
1484 const char *shortopts,
1485 const char *longopts,
1486 const char *datatype,
1487 int mincount,
1488 int maxcount,
1489 const char *glossary) {
1490 size_t nbytes;
1491 struct arg_dbl *result;
1493 /* foolproof things by ensuring maxcount is not less than mincount */
1494 maxcount = (maxcount < mincount) ? mincount : maxcount;
1496 nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
1497 + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1499 result = (struct arg_dbl *)malloc(nbytes);
1500 if (result) {
1501 size_t addr;
1502 size_t rem;
1504 /* init the arg_hdr struct */
1505 result->hdr.flag = ARG_HASVALUE;
1506 result->hdr.shortopts = shortopts;
1507 result->hdr.longopts = longopts;
1508 result->hdr.datatype = datatype ? datatype : "<double>";
1509 result->hdr.glossary = glossary;
1510 result->hdr.mincount = mincount;
1511 result->hdr.maxcount = maxcount;
1512 result->hdr.parent = result;
1513 result->hdr.resetfn = (arg_resetfn *)arg_dbl_resetfn;
1514 result->hdr.scanfn = (arg_scanfn *)arg_dbl_scanfn;
1515 result->hdr.checkfn = (arg_checkfn *)arg_dbl_checkfn;
1516 result->hdr.errorfn = (arg_errorfn *)arg_dbl_errorfn;
1518 /* Store the dval[maxcount] array on the first double boundary that
1519 * immediately follows the arg_dbl struct. We do the memory alignment
1520 * purely for SPARC and Motorola systems. They require floats and
1521 * doubles to be aligned on natural boundaries.
1523 addr = (size_t)(result + 1);
1524 rem = addr % sizeof(double);
1525 result->dval = (double *)(addr + sizeof(double) - rem);
1526 ARG_TRACE(("addr=%zu, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
1528 result->count = 0;
1531 ARG_TRACE(("arg_dbln() returns %p\n", result));
1532 return result;
1534 /*******************************************************************************
1535 * This file is part of the argtable3 library.
1537 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1538 * <sheitmann@users.sourceforge.net>
1539 * All rights reserved.
1541 * Redistribution and use in source and binary forms, with or without
1542 * modification, are permitted provided that the following conditions are met:
1543 * * Redistributions of source code must retain the above copyright
1544 * notice, this list of conditions and the following disclaimer.
1545 * * Redistributions in binary form must reproduce the above copyright
1546 * notice, this list of conditions and the following disclaimer in the
1547 * documentation and/or other materials provided with the distribution.
1548 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1549 * may be used to endorse or promote products derived from this software
1550 * without specific prior written permission.
1552 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1553 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1554 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1555 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1556 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1557 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1558 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1559 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1560 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1561 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1562 ******************************************************************************/
1564 #include <stdlib.h>
1566 #include "argtable3.h"
1569 static void arg_end_resetfn(struct arg_end *parent) {
1570 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1571 parent->count = 0;
1574 static void arg_end_errorfn(
1575 void *parent,
1576 FILE *fp,
1577 int error,
1578 const char *argval,
1579 const char *progname) {
1580 /* suppress unreferenced formal parameter warning */
1581 (void)parent;
1583 progname = progname ? progname : "";
1584 argval = argval ? argval : "";
1586 fprintf(fp, "%s: ", progname);
1587 switch (error) {
1588 case ARG_ELIMIT:
1589 fputs("too many errors to display", fp);
1590 break;
1591 case ARG_EMALLOC:
1592 fputs("insufficent memory", fp);
1593 break;
1594 case ARG_ENOMATCH:
1595 fprintf(fp, "unexpected argument \"%s\"", argval);
1596 break;
1597 case ARG_EMISSARG:
1598 fprintf(fp, "option \"%s\" requires an argument", argval);
1599 break;
1600 case ARG_ELONGOPT:
1601 fprintf(fp, "invalid option \"%s\"", argval);
1602 break;
1603 default:
1604 fprintf(fp, "invalid option \"-%c\"", error);
1605 break;
1608 fputc('\n', fp);
1612 struct arg_end *arg_end(int maxcount) {
1613 size_t nbytes;
1614 struct arg_end *result;
1616 nbytes = sizeof(struct arg_end)
1617 + maxcount * sizeof(int) /* storage for int error[maxcount] array*/
1618 + maxcount * sizeof(void *) /* storage for void* parent[maxcount] array */
1619 + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */
1621 result = (struct arg_end *)malloc(nbytes);
1622 if (result) {
1623 /* init the arg_hdr struct */
1624 result->hdr.flag = ARG_TERMINATOR;
1625 result->hdr.shortopts = NULL;
1626 result->hdr.longopts = NULL;
1627 result->hdr.datatype = NULL;
1628 result->hdr.glossary = NULL;
1629 result->hdr.mincount = 1;
1630 result->hdr.maxcount = maxcount;
1631 result->hdr.parent = result;
1632 result->hdr.resetfn = (arg_resetfn *)arg_end_resetfn;
1633 result->hdr.scanfn = NULL;
1634 result->hdr.checkfn = NULL;
1635 result->hdr.errorfn = (arg_errorfn *)arg_end_errorfn;
1637 /* store error[maxcount] array immediately after struct arg_end */
1638 result->error = (int *)(result + 1);
1640 /* store parent[maxcount] array immediately after error[] array */
1641 result->parent = (void * *)(result->error + maxcount);
1643 /* store argval[maxcount] array immediately after parent[] array */
1644 result->argval = (const char * *)(result->parent + maxcount);
1647 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
1648 return result;
1652 void arg_print_errors(FILE *fp, struct arg_end *end, const char *progname) {
1653 int i;
1654 ARG_TRACE(("arg_errors()\n"));
1655 for (i = 0; i < end->count; i++) {
1656 struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]);
1657 if (errorparent->errorfn)
1658 errorparent->errorfn(end->parent[i],
1660 end->error[i],
1661 end->argval[i],
1662 progname);
1665 /*******************************************************************************
1666 * This file is part of the argtable3 library.
1668 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1669 * <sheitmann@users.sourceforge.net>
1670 * All rights reserved.
1672 * Redistribution and use in source and binary forms, with or without
1673 * modification, are permitted provided that the following conditions are met:
1674 * * Redistributions of source code must retain the above copyright
1675 * notice, this list of conditions and the following disclaimer.
1676 * * Redistributions in binary form must reproduce the above copyright
1677 * notice, this list of conditions and the following disclaimer in the
1678 * documentation and/or other materials provided with the distribution.
1679 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1680 * may be used to endorse or promote products derived from this software
1681 * without specific prior written permission.
1683 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1684 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1685 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1686 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1687 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1688 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1689 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1690 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1691 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1692 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1693 ******************************************************************************/
1695 #include <string.h>
1696 #include <stdlib.h>
1698 #include "argtable3.h"
1700 #ifdef WIN32
1701 # define FILESEPARATOR1 '\\'
1702 # define FILESEPARATOR2 '/'
1703 #else
1704 # define FILESEPARATOR1 '/'
1705 # define FILESEPARATOR2 '/'
1706 #endif
1709 static void arg_file_resetfn(struct arg_file *parent) {
1710 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1711 parent->count = 0;
1715 /* Returns ptr to the base filename within *filename */
1716 static const char *arg_basename(const char *filename) {
1717 const char *result = NULL, *result1, *result2;
1719 /* Find the last occurrence of eother file separator character. */
1720 /* Two alternative file separator chars are supported as legal */
1721 /* file separators but not both together in the same filename. */
1722 result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
1723 result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
1725 if (result2)
1726 result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
1728 if (result1)
1729 result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
1731 if (!result)
1732 result = filename; /* neither file separator was found so basename is the whole filename */
1734 /* special cases of "." and ".." are not considered basenames */
1735 if (result && (strcmp(".", result) == 0 || strcmp("..", result) == 0))
1736 result = filename + strlen(filename);
1738 return result;
1742 /* Returns ptr to the file extension within *basename */
1743 static const char *arg_extension(const char *basename) {
1744 /* find the last occurrence of '.' in basename */
1745 const char *result = (basename ? strrchr(basename, '.') : NULL);
1747 /* if no '.' was found then return pointer to end of basename */
1748 if (basename && !result)
1749 result = basename + strlen(basename);
1751 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1752 if (basename && result == basename)
1753 result = basename + strlen(basename);
1755 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1756 if (basename && result && result[1] == '\0')
1757 result = basename + strlen(basename);
1759 return result;
1763 static int arg_file_scanfn(struct arg_file *parent, const char *argval) {
1764 int errorcode = 0;
1766 if (parent->count == parent->hdr.maxcount) {
1767 /* maximum number of arguments exceeded */
1768 errorcode = EMAXCOUNT;
1769 } else if (!argval) {
1770 /* a valid argument with no argument value was given. */
1771 /* This happens when an optional argument value was invoked. */
1772 /* leave parent arguiment value unaltered but still count the argument. */
1773 parent->count++;
1774 } else {
1775 parent->filename[parent->count] = argval;
1776 parent->basename[parent->count] = arg_basename(argval);
1777 parent->extension[parent->count] =
1778 arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
1779 parent->count++;
1782 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1783 return errorcode;
1787 static int arg_file_checkfn(struct arg_file *parent) {
1788 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1790 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1791 return errorcode;
1795 static void arg_file_errorfn(
1796 struct arg_file *parent,
1797 FILE *fp,
1798 int errorcode,
1799 const char *argval,
1800 const char *progname) {
1801 const char *shortopts = parent->hdr.shortopts;
1802 const char *longopts = parent->hdr.longopts;
1803 const char *datatype = parent->hdr.datatype;
1805 /* make argval NULL safe */
1806 argval = argval ? argval : "";
1808 fprintf(fp, "%s: ", progname);
1809 switch (errorcode) {
1810 case EMINCOUNT:
1811 fputs("missing option ", fp);
1812 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1813 break;
1815 case EMAXCOUNT:
1816 fputs("excess option ", fp);
1817 arg_print_option(fp, shortopts, longopts, argval, "\n");
1818 break;
1820 default:
1821 fprintf(fp, "unknown error at \"%s\"\n", argval);
1826 struct arg_file *arg_file0(
1827 const char *shortopts,
1828 const char *longopts,
1829 const char *datatype,
1830 const char *glossary) {
1831 return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
1835 struct arg_file *arg_file1(
1836 const char *shortopts,
1837 const char *longopts,
1838 const char *datatype,
1839 const char *glossary) {
1840 return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
1844 struct arg_file *arg_filen(
1845 const char *shortopts,
1846 const char *longopts,
1847 const char *datatype,
1848 int mincount,
1849 int maxcount,
1850 const char *glossary) {
1851 size_t nbytes;
1852 struct arg_file *result;
1854 /* foolproof things by ensuring maxcount is not less than mincount */
1855 maxcount = (maxcount < mincount) ? mincount : maxcount;
1857 nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
1858 + sizeof(char *) * maxcount /* storage for filename[maxcount] array */
1859 + sizeof(char *) * maxcount /* storage for basename[maxcount] array */
1860 + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */
1862 result = (struct arg_file *)malloc(nbytes);
1863 if (result) {
1864 int i;
1866 /* init the arg_hdr struct */
1867 result->hdr.flag = ARG_HASVALUE;
1868 result->hdr.shortopts = shortopts;
1869 result->hdr.longopts = longopts;
1870 result->hdr.glossary = glossary;
1871 result->hdr.datatype = datatype ? datatype : "<file>";
1872 result->hdr.mincount = mincount;
1873 result->hdr.maxcount = maxcount;
1874 result->hdr.parent = result;
1875 result->hdr.resetfn = (arg_resetfn *)arg_file_resetfn;
1876 result->hdr.scanfn = (arg_scanfn *)arg_file_scanfn;
1877 result->hdr.checkfn = (arg_checkfn *)arg_file_checkfn;
1878 result->hdr.errorfn = (arg_errorfn *)arg_file_errorfn;
1880 /* store the filename,basename,extension arrays immediately after the arg_file struct */
1881 result->filename = (const char * *)(result + 1);
1882 result->basename = result->filename + maxcount;
1883 result->extension = result->basename + maxcount;
1884 result->count = 0;
1886 /* foolproof the string pointers by initialising them with empty strings */
1887 for (i = 0; i < maxcount; i++) {
1888 result->filename[i] = "";
1889 result->basename[i] = "";
1890 result->extension[i] = "";
1894 ARG_TRACE(("arg_filen() returns %p\n", result));
1895 return result;
1897 /*******************************************************************************
1898 * This file is part of the argtable3 library.
1900 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1901 * <sheitmann@users.sourceforge.net>
1902 * All rights reserved.
1904 * Redistribution and use in source and binary forms, with or without
1905 * modification, are permitted provided that the following conditions are met:
1906 * * Redistributions of source code must retain the above copyright
1907 * notice, this list of conditions and the following disclaimer.
1908 * * Redistributions in binary form must reproduce the above copyright
1909 * notice, this list of conditions and the following disclaimer in the
1910 * documentation and/or other materials provided with the distribution.
1911 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1912 * may be used to endorse or promote products derived from this software
1913 * without specific prior written permission.
1915 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1916 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1917 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1918 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1919 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1920 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1921 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1922 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1923 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1924 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1925 ******************************************************************************/
1927 #include <stdlib.h>
1928 #include <limits.h>
1929 #include <ctype.h>
1931 #include "argtable3.h"
1934 static void arg_int_resetfn(struct arg_int *parent) {
1935 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1936 parent->count = 0;
1940 /* strtol0x() is like strtol() except that the numeric string is */
1941 /* expected to be prefixed by "0X" where X is a user supplied char. */
1942 /* The string may optionally be prefixed by white space and + or - */
1943 /* as in +0X123 or -0X123. */
1944 /* Once the prefix has been scanned, the remainder of the numeric */
1945 /* string is converted using strtol() with the given base. */
1946 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
1947 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
1948 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
1949 /* Failure of conversion is indicated by result where *endptr==str. */
1950 static long int strtol0X(const char *str,
1951 const char * *endptr,
1952 char X,
1953 int base) {
1954 long int val; /* stores result */
1955 int s = 1; /* sign is +1 or -1 */
1956 const char *ptr = str; /* ptr to current position in str */
1958 /* skip leading whitespace */
1959 while (ISSPACE(*ptr))
1960 ptr++;
1961 /* printf("1) %s\n",ptr); */
1963 /* scan optional sign character */
1964 switch (*ptr) {
1965 case '+':
1966 ptr++;
1967 s = 1;
1968 break;
1969 case '-':
1970 ptr++;
1971 s = -1;
1972 break;
1973 default:
1974 s = 1;
1975 break;
1977 /* printf("2) %s\n",ptr); */
1979 /* '0X' prefix */
1980 if ((*ptr++) != '0') {
1981 /* printf("failed to detect '0'\n"); */
1982 *endptr = str;
1983 return 0;
1985 /* printf("3) %s\n",ptr); */
1986 if (toupper(*ptr++) != toupper(X)) {
1987 /* printf("failed to detect '%c'\n",X); */
1988 *endptr = str;
1989 return 0;
1991 /* printf("4) %s\n",ptr); */
1993 /* attempt conversion on remainder of string using strtol() */
1994 val = strtol(ptr, (char * *)endptr, base);
1995 if (*endptr == ptr) {
1996 /* conversion failed */
1997 *endptr = str;
1998 return 0;
2001 /* success */
2002 return s * val;
2006 /* Returns 1 if str matches suffix (case insensitive). */
2007 /* Str may contain trailing whitespace, but nothing else. */
2008 static int detectsuffix(const char *str, const char *suffix) {
2009 /* scan pairwise through strings until mismatch detected */
2010 while (toupper(*str) == toupper(*suffix)) {
2011 /* printf("'%c' '%c'\n", *str, *suffix); */
2013 /* return 1 (success) if match persists until the string terminator */
2014 if (*str == '\0')
2015 return 1;
2017 /* next chars */
2018 str++;
2019 suffix++;
2021 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2023 /* return 0 (fail) if the matching did not consume the entire suffix */
2024 if (*suffix != 0)
2025 return 0; /* failed to consume entire suffix */
2027 /* skip any remaining whitespace in str */
2028 while (ISSPACE(*str))
2029 str++;
2031 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2032 return (*str == '\0') ? 1 : 0;
2036 static int arg_int_scanfn(struct arg_int *parent, const char *argval) {
2037 int errorcode = 0;
2039 if (parent->count == parent->hdr.maxcount) {
2040 /* maximum number of arguments exceeded */
2041 errorcode = EMAXCOUNT;
2042 } else if (!argval) {
2043 /* a valid argument with no argument value was given. */
2044 /* This happens when an optional argument value was invoked. */
2045 /* leave parent arguiment value unaltered but still count the argument. */
2046 parent->count++;
2047 } else {
2048 long int val;
2049 const char *end;
2051 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2052 val = strtol0X(argval, &end, 'X', 16);
2053 if (end == argval) {
2054 /* hex failed, attempt octal conversion (eg +0o123) */
2055 val = strtol0X(argval, &end, 'O', 8);
2056 if (end == argval) {
2057 /* octal failed, attempt binary conversion (eg +0B101) */
2058 val = strtol0X(argval, &end, 'B', 2);
2059 if (end == argval) {
2060 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2061 val = strtol(argval, (char * *)&end, 10);
2062 if (end == argval) {
2063 /* all supported number formats failed */
2064 return EBADINT;
2070 /* Safety check for integer overflow. WARNING: this check */
2071 /* achieves nothing on machines where size(int)==size(long). */
2072 if (val > INT_MAX || val < INT_MIN)
2073 #ifdef __STDC_WANT_SECURE_LIB__
2074 errorcode = EOVERFLOW_;
2075 #else
2076 errorcode = EOVERFLOW;
2077 #endif
2079 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2080 /* We need to be mindful of integer overflows when using such big numbers. */
2081 if (detectsuffix(end, "KB")) { /* kilobytes */
2082 if (val > (INT_MAX / 1024) || val < (INT_MIN / 1024))
2083 #ifdef __STDC_WANT_SECURE_LIB__
2084 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2085 #else
2086 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2087 #endif
2088 else
2089 val *= 1024; /* 1KB = 1024 */
2090 } else if (detectsuffix(end, "MB")) { /* megabytes */
2091 if (val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576))
2092 #ifdef __STDC_WANT_SECURE_LIB__
2093 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2094 #else
2095 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2096 #endif
2097 else
2098 val *= 1048576; /* 1MB = 1024*1024 */
2099 } else if (detectsuffix(end, "GB")) { /* gigabytes */
2100 if (val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824))
2101 #ifdef __STDC_WANT_SECURE_LIB__
2102 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2103 #else
2104 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2105 #endif
2106 else
2107 val *= 1073741824; /* 1GB = 1024*1024*1024 */
2108 } else if (!detectsuffix(end, ""))
2109 errorcode = EBADINT; /* invalid suffix detected */
2111 /* if success then store result in parent->ival[] array */
2112 if (errorcode == 0)
2113 parent->ival[parent->count++] = val;
2116 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2117 return errorcode;
2121 static int arg_int_checkfn(struct arg_int *parent) {
2122 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2123 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2124 return errorcode;
2128 static void arg_int_errorfn(
2129 struct arg_int *parent,
2130 FILE *fp,
2131 int errorcode,
2132 const char *argval,
2133 const char *progname) {
2134 const char *shortopts = parent->hdr.shortopts;
2135 const char *longopts = parent->hdr.longopts;
2136 const char *datatype = parent->hdr.datatype;
2138 /* make argval NULL safe */
2139 argval = argval ? argval : "";
2141 fprintf(fp, "%s: ", progname);
2142 switch (errorcode) {
2143 case EMINCOUNT:
2144 fputs("missing option ", fp);
2145 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2146 break;
2148 case EMAXCOUNT:
2149 fputs("excess option ", fp);
2150 arg_print_option(fp, shortopts, longopts, argval, "\n");
2151 break;
2153 case EBADINT:
2154 fprintf(fp, "invalid argument \"%s\" to option ", argval);
2155 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2156 break;
2158 #ifdef __STDC_WANT_SECURE_LIB__
2159 case EOVERFLOW_:
2160 #else
2161 case EOVERFLOW:
2162 #endif
2163 fputs("integer overflow at option ", fp);
2164 arg_print_option(fp, shortopts, longopts, datatype, " ");
2165 fprintf(fp, "(%s is too large)\n", argval);
2166 break;
2171 struct arg_int *arg_int0(
2172 const char *shortopts,
2173 const char *longopts,
2174 const char *datatype,
2175 const char *glossary) {
2176 return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
2180 struct arg_int *arg_int1(
2181 const char *shortopts,
2182 const char *longopts,
2183 const char *datatype,
2184 const char *glossary) {
2185 return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
2189 struct arg_int *arg_intn(
2190 const char *shortopts,
2191 const char *longopts,
2192 const char *datatype,
2193 int mincount,
2194 int maxcount,
2195 const char *glossary) {
2196 size_t nbytes;
2197 struct arg_int *result;
2199 /* foolproof things by ensuring maxcount is not less than mincount */
2200 maxcount = (maxcount < mincount) ? mincount : maxcount;
2202 nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
2203 + maxcount * sizeof(int); /* storage for ival[maxcount] array */
2205 result = (struct arg_int *)malloc(nbytes);
2206 if (result) {
2207 /* init the arg_hdr struct */
2208 result->hdr.flag = ARG_HASVALUE;
2209 result->hdr.shortopts = shortopts;
2210 result->hdr.longopts = longopts;
2211 result->hdr.datatype = datatype ? datatype : "<int>";
2212 result->hdr.glossary = glossary;
2213 result->hdr.mincount = mincount;
2214 result->hdr.maxcount = maxcount;
2215 result->hdr.parent = result;
2216 result->hdr.resetfn = (arg_resetfn *)arg_int_resetfn;
2217 result->hdr.scanfn = (arg_scanfn *)arg_int_scanfn;
2218 result->hdr.checkfn = (arg_checkfn *)arg_int_checkfn;
2219 result->hdr.errorfn = (arg_errorfn *)arg_int_errorfn;
2221 /* store the ival[maxcount] array immediately after the arg_int struct */
2222 result->ival = (int *)(result + 1);
2223 result->count = 0;
2226 ARG_TRACE(("arg_intn() returns %p\n", result));
2227 return result;
2229 /*******************************************************************************
2230 * This file is part of the argtable3 library.
2232 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2233 * <sheitmann@users.sourceforge.net>
2234 * All rights reserved.
2236 * Redistribution and use in source and binary forms, with or without
2237 * modification, are permitted provided that the following conditions are met:
2238 * * Redistributions of source code must retain the above copyright
2239 * notice, this list of conditions and the following disclaimer.
2240 * * Redistributions in binary form must reproduce the above copyright
2241 * notice, this list of conditions and the following disclaimer in the
2242 * documentation and/or other materials provided with the distribution.
2243 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2244 * may be used to endorse or promote products derived from this software
2245 * without specific prior written permission.
2247 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2248 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2249 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2250 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2251 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2252 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2253 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2254 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2255 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2256 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2257 ******************************************************************************/
2259 #include <stdlib.h>
2261 #include "argtable3.h"
2264 static void arg_lit_resetfn(struct arg_lit *parent) {
2265 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2266 parent->count = 0;
2270 static int arg_lit_scanfn(struct arg_lit *parent, const char *argval) {
2271 int errorcode = 0;
2272 if (parent->count < parent->hdr.maxcount)
2273 parent->count++;
2274 else
2275 errorcode = EMAXCOUNT;
2277 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,
2278 errorcode));
2279 return errorcode;
2283 static int arg_lit_checkfn(struct arg_lit *parent) {
2284 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2285 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
2286 return errorcode;
2290 static void arg_lit_errorfn(
2291 struct arg_lit *parent,
2292 FILE *fp,
2293 int errorcode,
2294 const char *argval,
2295 const char *progname) {
2296 const char *shortopts = parent->hdr.shortopts;
2297 const char *longopts = parent->hdr.longopts;
2298 const char *datatype = parent->hdr.datatype;
2300 switch (errorcode) {
2301 case EMINCOUNT:
2302 fprintf(fp, "%s: missing option ", progname);
2303 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2304 fprintf(fp, "\n");
2305 break;
2307 case EMAXCOUNT:
2308 fprintf(fp, "%s: extraneous option ", progname);
2309 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2310 break;
2313 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
2314 errorcode, argval, progname));
2318 struct arg_lit *arg_lit0(
2319 const char *shortopts,
2320 const char *longopts,
2321 const char *glossary) {
2322 return arg_litn(shortopts, longopts, 0, 1, glossary);
2326 struct arg_lit *arg_lit1(
2327 const char *shortopts,
2328 const char *longopts,
2329 const char *glossary) {
2330 return arg_litn(shortopts, longopts, 1, 1, glossary);
2334 struct arg_lit *arg_litn(
2335 const char *shortopts,
2336 const char *longopts,
2337 int mincount,
2338 int maxcount,
2339 const char *glossary) {
2340 struct arg_lit *result;
2342 /* foolproof things by ensuring maxcount is not less than mincount */
2343 maxcount = (maxcount < mincount) ? mincount : maxcount;
2345 result = (struct arg_lit *)malloc(sizeof(struct arg_lit));
2346 if (result) {
2347 /* init the arg_hdr struct */
2348 result->hdr.flag = 0;
2349 result->hdr.shortopts = shortopts;
2350 result->hdr.longopts = longopts;
2351 result->hdr.datatype = NULL;
2352 result->hdr.glossary = glossary;
2353 result->hdr.mincount = mincount;
2354 result->hdr.maxcount = maxcount;
2355 result->hdr.parent = result;
2356 result->hdr.resetfn = (arg_resetfn *)arg_lit_resetfn;
2357 result->hdr.scanfn = (arg_scanfn *)arg_lit_scanfn;
2358 result->hdr.checkfn = (arg_checkfn *)arg_lit_checkfn;
2359 result->hdr.errorfn = (arg_errorfn *)arg_lit_errorfn;
2361 /* init local variables */
2362 result->count = 0;
2365 ARG_TRACE(("arg_litn() returns %p\n", result));
2366 return result;
2368 /*******************************************************************************
2369 * This file is part of the argtable3 library.
2371 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2372 * <sheitmann@users.sourceforge.net>
2373 * All rights reserved.
2375 * Redistribution and use in source and binary forms, with or without
2376 * modification, are permitted provided that the following conditions are met:
2377 * * Redistributions of source code must retain the above copyright
2378 * notice, this list of conditions and the following disclaimer.
2379 * * Redistributions in binary form must reproduce the above copyright
2380 * notice, this list of conditions and the following disclaimer in the
2381 * documentation and/or other materials provided with the distribution.
2382 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2383 * may be used to endorse or promote products derived from this software
2384 * without specific prior written permission.
2386 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2387 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2388 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2389 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2390 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2391 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2392 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2393 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2394 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2395 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2396 ******************************************************************************/
2398 #include <stdlib.h>
2400 #include "argtable3.h"
2402 struct arg_rem *arg_rem(const char *datatype, const char *glossary) {
2403 struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem));
2404 if (result) {
2405 result->hdr.flag = 0;
2406 result->hdr.shortopts = NULL;
2407 result->hdr.longopts = NULL;
2408 result->hdr.datatype = datatype;
2409 result->hdr.glossary = glossary;
2410 result->hdr.mincount = 1;
2411 result->hdr.maxcount = 1;
2412 result->hdr.parent = result;
2413 result->hdr.resetfn = NULL;
2414 result->hdr.scanfn = NULL;
2415 result->hdr.checkfn = NULL;
2416 result->hdr.errorfn = NULL;
2419 ARG_TRACE(("arg_rem() returns %p\n", result));
2420 return result;
2423 /*******************************************************************************
2424 * This file is part of the argtable3 library.
2426 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2427 * <sheitmann@users.sourceforge.net>
2428 * All rights reserved.
2430 * Redistribution and use in source and binary forms, with or without
2431 * modification, are permitted provided that the following conditions are met:
2432 * * Redistributions of source code must retain the above copyright
2433 * notice, this list of conditions and the following disclaimer.
2434 * * Redistributions in binary form must reproduce the above copyright
2435 * notice, this list of conditions and the following disclaimer in the
2436 * documentation and/or other materials provided with the distribution.
2437 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2438 * may be used to endorse or promote products derived from this software
2439 * without specific prior written permission.
2441 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2442 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2443 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2444 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2445 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2446 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2447 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2448 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2449 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2450 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2451 ******************************************************************************/
2453 #include <stdlib.h>
2454 #include <string.h>
2456 #include "argtable3.h"
2459 #ifndef _TREX_H_
2460 #define _TREX_H_
2461 /***************************************************************
2462 T-Rex a tiny regular expression library
2464 Copyright (C) 2003-2006 Alberto Demichelis
2466 This software is provided 'as-is', without any express
2467 or implied warranty. In no event will the authors be held
2468 liable for any damages arising from the use of this software.
2470 Permission is granted to anyone to use this software for
2471 any purpose, including commercial applications, and to alter
2472 it and redistribute it freely, subject to the following restrictions:
2474 1. The origin of this software must not be misrepresented;
2475 you must not claim that you wrote the original software.
2476 If you use this software in a product, an acknowledgment
2477 in the product documentation would be appreciated but
2478 is not required.
2480 2. Altered source versions must be plainly marked as such,
2481 and must not be misrepresented as being the original software.
2483 3. This notice may not be removed or altered from any
2484 source distribution.
2486 ****************************************************************/
2488 #ifdef __cplusplus
2489 extern "C" {
2490 #endif
2492 #ifdef _UNICODE
2493 #define TRexChar unsigned short
2494 #define MAX_CHAR 0xFFFF
2495 #define _TREXC(c) L##c
2496 #define trex_strlen wcslen
2497 #define trex_printf wprintf
2498 #else
2499 #define TRexChar char
2500 #define MAX_CHAR 0xFF
2501 #define _TREXC(c) (c)
2502 #define trex_strlen strlen
2503 #define trex_printf printf
2504 #endif
2506 #ifndef TREX_API
2507 #define TREX_API extern
2508 #endif
2510 #define TRex_True 1
2511 #define TRex_False 0
2513 #define TREX_ICASE ARG_REX_ICASE
2515 typedef unsigned int TRexBool;
2516 typedef struct TRex TRex;
2518 typedef struct {
2519 const TRexChar *begin;
2520 int len;
2521 } TRexMatch;
2523 TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags);
2524 TREX_API void trex_free(TRex *exp);
2525 TREX_API TRexBool trex_match(TRex *exp, const TRexChar *text);
2526 TREX_API TRexBool trex_search(TRex *exp, const TRexChar *text, const TRexChar **out_begin, const TRexChar **out_end);
2527 TREX_API TRexBool trex_searchrange(TRex *exp, const TRexChar *text_begin, const TRexChar *text_end, const TRexChar **out_begin, const TRexChar **out_end);
2528 TREX_API int trex_getsubexpcount(TRex *exp);
2529 TREX_API TRexBool trex_getsubexp(TRex *exp, int n, TRexMatch *subexp);
2531 #ifdef __cplusplus
2533 #endif
2535 #endif
2539 struct privhdr {
2540 const char *pattern;
2541 int flags;
2545 static void arg_rex_resetfn(struct arg_rex *parent) {
2546 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2547 parent->count = 0;
2550 static int arg_rex_scanfn(struct arg_rex *parent, const char *argval) {
2551 int errorcode = 0;
2552 const TRexChar *error = NULL;
2553 TRex *rex = NULL;
2554 TRexBool is_match;
2556 if (parent->count == parent->hdr.maxcount) {
2557 /* maximum number of arguments exceeded */
2558 errorcode = EMAXCOUNT;
2559 } else if (!argval) {
2560 /* a valid argument with no argument value was given. */
2561 /* This happens when an optional argument value was invoked. */
2562 /* leave parent argument value unaltered but still count the argument. */
2563 parent->count++;
2564 } else {
2565 struct privhdr *priv = (struct privhdr *)parent->hdr.priv;
2567 /* test the current argument value for a match with the regular expression */
2568 /* if a match is detected, record the argument value in the arg_rex struct */
2570 rex = trex_compile(priv->pattern, &error, priv->flags);
2571 is_match = trex_match(rex, argval);
2572 if (!is_match)
2573 errorcode = EREGNOMATCH;
2574 else
2575 parent->sval[parent->count++] = argval;
2577 trex_free(rex);
2580 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
2581 return errorcode;
2584 static int arg_rex_checkfn(struct arg_rex *parent) {
2585 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2586 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2588 /* free the regex "program" we constructed in resetfn */
2589 //regfree(&(priv->regex));
2591 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2592 return errorcode;
2595 static void arg_rex_errorfn(struct arg_rex *parent,
2596 FILE *fp,
2597 int errorcode,
2598 const char *argval,
2599 const char *progname) {
2600 const char *shortopts = parent->hdr.shortopts;
2601 const char *longopts = parent->hdr.longopts;
2602 const char *datatype = parent->hdr.datatype;
2604 /* make argval NULL safe */
2605 argval = argval ? argval : "";
2607 fprintf(fp, "%s: ", progname);
2608 switch (errorcode) {
2609 case EMINCOUNT:
2610 fputs("missing option ", fp);
2611 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2612 break;
2614 case EMAXCOUNT:
2615 fputs("excess option ", fp);
2616 arg_print_option(fp, shortopts, longopts, argval, "\n");
2617 break;
2619 case EREGNOMATCH:
2620 fputs("illegal value ", fp);
2621 arg_print_option(fp, shortopts, longopts, argval, "\n");
2622 break;
2624 default: {
2625 //char errbuff[256];
2626 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2627 //printf("%s\n", errbuff);
2629 break;
2634 struct arg_rex *arg_rex0(const char *shortopts,
2635 const char *longopts,
2636 const char *pattern,
2637 const char *datatype,
2638 int flags,
2639 const char *glossary) {
2640 return arg_rexn(shortopts,
2641 longopts,
2642 pattern,
2643 datatype,
2646 flags,
2647 glossary);
2650 struct arg_rex *arg_rex1(const char *shortopts,
2651 const char *longopts,
2652 const char *pattern,
2653 const char *datatype,
2654 int flags,
2655 const char *glossary) {
2656 return arg_rexn(shortopts,
2657 longopts,
2658 pattern,
2659 datatype,
2662 flags,
2663 glossary);
2667 struct arg_rex *arg_rexn(const char *shortopts,
2668 const char *longopts,
2669 const char *pattern,
2670 const char *datatype,
2671 int mincount,
2672 int maxcount,
2673 int flags,
2674 const char *glossary) {
2675 size_t nbytes;
2676 struct arg_rex *result;
2677 struct privhdr *priv;
2678 int i;
2679 const TRexChar *error = NULL;
2680 TRex *rex = NULL;
2682 if (!pattern) {
2683 printf(
2684 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2685 printf("argtable: Bad argument table.\n");
2686 return NULL;
2689 /* foolproof things by ensuring maxcount is not less than mincount */
2690 maxcount = (maxcount < mincount) ? mincount : maxcount;
2692 nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */
2693 + sizeof(struct privhdr) /* storage for private arg_rex data */
2694 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
2696 result = (struct arg_rex *)malloc(nbytes);
2697 if (result == NULL)
2698 return result;
2700 /* init the arg_hdr struct */
2701 result->hdr.flag = ARG_HASVALUE;
2702 result->hdr.shortopts = shortopts;
2703 result->hdr.longopts = longopts;
2704 result->hdr.datatype = datatype ? datatype : pattern;
2705 result->hdr.glossary = glossary;
2706 result->hdr.mincount = mincount;
2707 result->hdr.maxcount = maxcount;
2708 result->hdr.parent = result;
2709 result->hdr.resetfn = (arg_resetfn *)arg_rex_resetfn;
2710 result->hdr.scanfn = (arg_scanfn *)arg_rex_scanfn;
2711 result->hdr.checkfn = (arg_checkfn *)arg_rex_checkfn;
2712 result->hdr.errorfn = (arg_errorfn *)arg_rex_errorfn;
2714 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2715 result->hdr.priv = result + 1;
2716 priv = (struct privhdr *)(result->hdr.priv);
2717 priv->pattern = pattern;
2718 priv->flags = flags;
2720 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2721 result->sval = (const char * *)(priv + 1);
2722 result->count = 0;
2724 /* foolproof the string pointers by initializing them to reference empty strings */
2725 for (i = 0; i < maxcount; i++)
2726 result->sval[i] = "";
2728 /* here we construct and destroy a regex representation of the regular
2729 * expression for no other reason than to force any regex errors to be
2730 * trapped now rather than later. If we don't, then errors may go undetected
2731 * until an argument is actually parsed.
2734 rex = trex_compile(priv->pattern, &error, priv->flags);
2735 if (rex == NULL) {
2736 ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
2737 ARG_LOG(("argtable: Bad argument table.\n"));
2740 trex_free(rex);
2742 ARG_TRACE(("arg_rexn() returns %p\n", result));
2743 return result;
2748 /* see copyright notice in trex.h */
2749 #include <string.h>
2750 #include <stdlib.h>
2751 #include <ctype.h>
2752 #include <setjmp.h>
2754 #ifdef _UINCODE
2755 #define scisprint iswprint
2756 #define scstrlen wcslen
2757 #define scprintf wprintf
2758 #define _SC(x) L(x)
2759 #else
2760 #define scisprint isprint
2761 #define scstrlen strlen
2762 #define scprintf printf
2763 #define _SC(x) (x)
2764 #endif
2766 #ifdef _DEBUG
2767 #include <stdio.h>
2769 static const TRexChar *g_nnames[] = {
2770 _SC("NONE"), _SC("OP_GREEDY"), _SC("OP_OR"),
2771 _SC("OP_EXPR"), _SC("OP_NOCAPEXPR"), _SC("OP_DOT"), _SC("OP_CLASS"),
2772 _SC("OP_CCLASS"), _SC("OP_NCLASS"), _SC("OP_RANGE"), _SC("OP_CHAR"),
2773 _SC("OP_EOL"), _SC("OP_BOL"), _SC("OP_WB")
2776 #endif
2777 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2778 #define OP_OR (MAX_CHAR+2)
2779 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2780 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2781 #define OP_DOT (MAX_CHAR+5)
2782 #define OP_CLASS (MAX_CHAR+6)
2783 #define OP_CCLASS (MAX_CHAR+7)
2784 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2785 #define OP_RANGE (MAX_CHAR+9)
2786 #define OP_CHAR (MAX_CHAR+10)
2787 #define OP_EOL (MAX_CHAR+11)
2788 #define OP_BOL (MAX_CHAR+12)
2789 #define OP_WB (MAX_CHAR+13)
2791 #define TREX_SYMBOL_ANY_CHAR ('.')
2792 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
2793 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
2794 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
2795 #define TREX_SYMBOL_BRANCH ('|')
2796 #define TREX_SYMBOL_END_OF_STRING ('$')
2797 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
2798 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
2801 typedef int TRexNodeType;
2803 typedef struct tagTRexNode {
2804 TRexNodeType type;
2805 int left;
2806 int right;
2807 int next;
2808 } TRexNode;
2810 struct TRex {
2811 const TRexChar *_eol;
2812 const TRexChar *_bol;
2813 const TRexChar *_p;
2814 int _first;
2815 int _op;
2816 TRexNode *_nodes;
2817 int _nallocated;
2818 int _nsize;
2819 int _nsubexpr;
2820 TRexMatch *_matches;
2821 int _currsubexp;
2822 void *_jmpbuf;
2823 const TRexChar **_error;
2824 int _flags;
2827 static int trex_list(TRex *exp);
2829 static int trex_newnode(TRex *exp, TRexNodeType type) {
2830 TRexNode n;
2831 int newid;
2832 n.type = type;
2833 n.next = n.right = n.left = -1;
2834 if (type == OP_EXPR)
2835 n.right = exp->_nsubexpr++;
2836 if (exp->_nallocated < (exp->_nsize + 1)) {
2837 exp->_nallocated *= 2;
2838 exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
2840 exp->_nodes[exp->_nsize++] = n;
2841 newid = exp->_nsize - 1;
2842 return (int)newid;
2845 static void trex_error(TRex *exp, const TRexChar *error) {
2846 if (exp->_error) *exp->_error = error;
2847 longjmp(*((jmp_buf *)exp->_jmpbuf), -1);
2850 static void trex_expect(TRex *exp, int n) {
2851 if ((*exp->_p) != n)
2852 trex_error(exp, _SC("expected paren"));
2853 exp->_p++;
2856 static TRexChar trex_escapechar(TRex *exp) {
2857 if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
2858 exp->_p++;
2859 switch (*exp->_p) {
2860 case 'v':
2861 exp->_p++;
2862 return '\v';
2863 case 'n':
2864 exp->_p++;
2865 return '\n';
2866 case 't':
2867 exp->_p++;
2868 return '\t';
2869 case 'r':
2870 exp->_p++;
2871 return '\r';
2872 case 'f':
2873 exp->_p++;
2874 return '\f';
2875 default:
2876 return (*exp->_p++);
2878 } else if (!scisprint(*exp->_p)) trex_error(exp, _SC("letter expected"));
2879 return (*exp->_p++);
2882 static int trex_charclass(TRex *exp, int classid) {
2883 int n = trex_newnode(exp, OP_CCLASS);
2884 exp->_nodes[n].left = classid;
2885 return n;
2888 static int trex_charnode(TRex *exp, TRexBool isclass) {
2889 TRexChar t;
2890 if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
2891 exp->_p++;
2892 switch (*exp->_p) {
2893 case 'n':
2894 exp->_p++;
2895 return trex_newnode(exp, '\n');
2896 case 't':
2897 exp->_p++;
2898 return trex_newnode(exp, '\t');
2899 case 'r':
2900 exp->_p++;
2901 return trex_newnode(exp, '\r');
2902 case 'f':
2903 exp->_p++;
2904 return trex_newnode(exp, '\f');
2905 case 'v':
2906 exp->_p++;
2907 return trex_newnode(exp, '\v');
2908 case 'a':
2909 case 'A':
2910 case 'w':
2911 case 'W':
2912 case 's':
2913 case 'S':
2914 case 'd':
2915 case 'D':
2916 case 'x':
2917 case 'X':
2918 case 'c':
2919 case 'C':
2920 case 'p':
2921 case 'P':
2922 case 'l':
2923 case 'u': {
2924 t = *exp->_p;
2925 exp->_p++;
2926 return trex_charclass(exp, t);
2928 case 'b':
2929 case 'B':
2930 if (!isclass) {
2931 int node = trex_newnode(exp, OP_WB);
2932 exp->_nodes[node].left = *exp->_p;
2933 exp->_p++;
2934 return node;
2935 } //else default
2936 default:
2937 t = *exp->_p;
2938 exp->_p++;
2939 return trex_newnode(exp, t);
2941 } else if (!scisprint(*exp->_p)) {
2943 trex_error(exp, _SC("letter expected"));
2945 t = *exp->_p;
2946 exp->_p++;
2947 return trex_newnode(exp, t);
2949 static int trex_class(TRex *exp) {
2950 int ret = -1;
2951 int first = -1, chain;
2952 if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
2953 ret = trex_newnode(exp, OP_NCLASS);
2954 exp->_p++;
2955 } else ret = trex_newnode(exp, OP_CLASS);
2957 if (*exp->_p == ']') trex_error(exp, _SC("empty class"));
2958 chain = ret;
2959 while (*exp->_p != ']' && exp->_p != exp->_eol) {
2960 if (*exp->_p == '-' && first != -1) {
2961 int r, t;
2962 if (*exp->_p++ == ']') {
2963 trex_error(exp, _SC("unfinished range"));
2966 r = trex_newnode(exp, OP_RANGE);
2967 if (first > *exp->_p) {
2968 trex_error(exp, _SC("invalid range"));
2971 if (exp->_nodes[first].type == OP_CCLASS) {
2972 trex_error(exp, _SC("cannot use character classes in ranges"));
2975 exp->_nodes[r].left = exp->_nodes[first].type;
2976 t = trex_escapechar(exp);
2977 exp->_nodes[r].right = t;
2978 exp->_nodes[chain].next = r;
2979 chain = r;
2980 first = -1;
2981 } else {
2982 if (first != -1) {
2983 int c = first;
2984 exp->_nodes[chain].next = c;
2985 chain = c;
2986 first = trex_charnode(exp, TRex_True);
2987 } else {
2988 first = trex_charnode(exp, TRex_True);
2992 if (first != -1) {
2993 int c = first;
2994 exp->_nodes[chain].next = c;
2996 /* hack? */
2997 exp->_nodes[ret].left = exp->_nodes[ret].next;
2998 exp->_nodes[ret].next = -1;
2999 return ret;
3002 static int trex_parsenumber(TRex *exp) {
3003 int ret = *exp->_p - '0';
3004 int positions = 10;
3005 exp->_p++;
3006 while (isdigit(*exp->_p)) {
3007 ret = ret * 10 + (*exp->_p++ -'0');
3008 if (positions == 1000000000) trex_error(exp, _SC("overflow in numeric constant"));
3009 positions *= 10;
3011 return ret;
3014 static int trex_element(TRex *exp) {
3015 int ret = -1;
3016 switch (*exp->_p) {
3017 case '(': {
3018 int expr, newn;
3019 exp->_p++;
3022 if (*exp->_p == '?') {
3023 exp->_p++;
3024 trex_expect(exp, ':');
3025 expr = trex_newnode(exp, OP_NOCAPEXPR);
3026 } else
3027 expr = trex_newnode(exp, OP_EXPR);
3028 newn = trex_list(exp);
3029 exp->_nodes[expr].left = newn;
3030 ret = expr;
3031 trex_expect(exp, ')');
3033 break;
3034 case '[':
3035 exp->_p++;
3036 ret = trex_class(exp);
3037 trex_expect(exp, ']');
3038 break;
3039 case TREX_SYMBOL_END_OF_STRING:
3040 exp->_p++;
3041 ret = trex_newnode(exp, OP_EOL);
3042 break;
3043 case TREX_SYMBOL_ANY_CHAR:
3044 exp->_p++;
3045 ret = trex_newnode(exp, OP_DOT);
3046 break;
3047 default:
3048 ret = trex_charnode(exp, TRex_False);
3049 break;
3053 TRexBool isgreedy = TRex_False;
3054 unsigned short p0 = 0, p1 = 0;
3055 switch (*exp->_p) {
3056 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE:
3057 p0 = 0;
3058 p1 = 0xFFFF;
3059 exp->_p++;
3060 isgreedy = TRex_True;
3061 break;
3062 case TREX_SYMBOL_GREEDY_ONE_OR_MORE:
3063 p0 = 1;
3064 p1 = 0xFFFF;
3065 exp->_p++;
3066 isgreedy = TRex_True;
3067 break;
3068 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE:
3069 p0 = 0;
3070 p1 = 1;
3071 exp->_p++;
3072 isgreedy = TRex_True;
3073 break;
3074 case '{':
3075 exp->_p++;
3076 if (!isdigit(*exp->_p)) trex_error(exp, _SC("number expected"));
3077 p0 = (unsigned short)trex_parsenumber(exp);
3078 /*******************************/
3079 switch (*exp->_p) {
3080 case '}':
3081 p1 = p0;
3082 exp->_p++;
3083 break;
3084 case ',':
3085 exp->_p++;
3086 p1 = 0xFFFF;
3087 if (isdigit(*exp->_p)) {
3088 p1 = (unsigned short)trex_parsenumber(exp);
3090 trex_expect(exp, '}');
3091 break;
3092 default:
3093 trex_error(exp, _SC(", or } expected"));
3095 /*******************************/
3096 isgreedy = TRex_True;
3097 break;
3100 if (isgreedy) {
3101 int nnode = trex_newnode(exp, OP_GREEDY);
3102 exp->_nodes[nnode].left = ret;
3103 exp->_nodes[nnode].right = ((p0) << 16) | p1;
3104 ret = nnode;
3107 if ((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
3108 int nnode = trex_element(exp);
3109 exp->_nodes[ret].next = nnode;
3112 return ret;
3115 static int trex_list(TRex *exp) {
3116 int ret = -1, e;
3117 if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
3118 exp->_p++;
3119 ret = trex_newnode(exp, OP_BOL);
3121 e = trex_element(exp);
3122 if (ret != -1) {
3123 exp->_nodes[ret].next = e;
3124 } else ret = e;
3126 if (*exp->_p == TREX_SYMBOL_BRANCH) {
3127 int temp, tright;
3128 exp->_p++;
3129 temp = trex_newnode(exp, OP_OR);
3130 exp->_nodes[temp].left = ret;
3131 tright = trex_list(exp);
3132 exp->_nodes[temp].right = tright;
3133 ret = temp;
3135 return ret;
3138 static TRexBool trex_matchcclass(int cclass, TRexChar c) {
3139 switch (cclass) {
3140 case 'a':
3141 return isalpha(c) ? TRex_True : TRex_False;
3142 case 'A':
3143 return !isalpha(c) ? TRex_True : TRex_False;
3144 case 'w':
3145 return (isalnum(c) || c == '_') ? TRex_True : TRex_False;
3146 case 'W':
3147 return (!isalnum(c) && c != '_') ? TRex_True : TRex_False;
3148 case 's':
3149 return ISSPACE(c) ? TRex_True : TRex_False;
3150 case 'S':
3151 return !ISSPACE(c) ? TRex_True : TRex_False;
3152 case 'd':
3153 return isdigit(c) ? TRex_True : TRex_False;
3154 case 'D':
3155 return !isdigit(c) ? TRex_True : TRex_False;
3156 case 'x':
3157 return isxdigit(c) ? TRex_True : TRex_False;
3158 case 'X':
3159 return !isxdigit(c) ? TRex_True : TRex_False;
3160 case 'c':
3161 return iscntrl(c) ? TRex_True : TRex_False;
3162 case 'C':
3163 return !iscntrl(c) ? TRex_True : TRex_False;
3164 case 'p':
3165 return ispunct(c) ? TRex_True : TRex_False;
3166 case 'P':
3167 return !ispunct(c) ? TRex_True : TRex_False;
3168 case 'l':
3169 return islower(c) ? TRex_True : TRex_False;
3170 case 'u':
3171 return isupper(c) ? TRex_True : TRex_False;
3173 return TRex_False; /*cannot happen*/
3176 static TRexBool trex_matchclass(TRex *exp, TRexNode *node, TRexChar c) {
3177 do {
3178 switch (node->type) {
3179 case OP_RANGE:
3180 if (exp->_flags & TREX_ICASE) {
3181 if (c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True;
3182 if (c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True;
3183 } else {
3184 if (c >= node->left && c <= node->right) return TRex_True;
3186 break;
3187 case OP_CCLASS:
3188 if (trex_matchcclass(node->left, c)) return TRex_True;
3189 break;
3190 default:
3191 if (exp->_flags & TREX_ICASE) {
3192 if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;
3193 } else {
3194 if (c == node->type)return TRex_True;
3198 } while ((node->next != -1) && (node = &exp->_nodes[node->next]));
3199 return TRex_False;
3202 static const TRexChar *trex_matchnode(TRex *exp, TRexNode *node, const TRexChar *str, TRexNode *next) {
3204 TRexNodeType type = node->type;
3205 switch (type) {
3206 case OP_GREEDY: {
3207 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3208 TRexNode *greedystop = NULL;
3209 int p0 = (node->right >> 16) & 0x0000FFFF, p1 = node->right & 0x0000FFFF, nmaches = 0;
3210 const TRexChar *s = str, *good = str;
3212 if (node->next != -1) {
3213 greedystop = &exp->_nodes[node->next];
3214 } else {
3215 greedystop = next;
3218 while ((nmaches == 0xFFFF || nmaches < p1)) {
3220 const TRexChar *stop;
3221 if (!(s = trex_matchnode(exp, &exp->_nodes[node->left], s, greedystop)))
3222 break;
3223 nmaches++;
3224 good = s;
3225 if (greedystop) {
3226 //checks that 0 matches satisfy the expression(if so skips)
3227 //if not would always stop(for instance if is a '?')
3228 if (greedystop->type != OP_GREEDY ||
3229 (greedystop->type == OP_GREEDY && ((greedystop->right >> 16) & 0x0000FFFF) != 0)) {
3230 TRexNode *gnext = NULL;
3231 if (greedystop->next != -1) {
3232 gnext = &exp->_nodes[greedystop->next];
3233 } else if (next && next->next != -1) {
3234 gnext = &exp->_nodes[next->next];
3236 stop = trex_matchnode(exp, greedystop, s, gnext);
3237 if (stop) {
3238 //if satisfied stop it
3239 if (p0 == p1 && p0 == nmaches) break;
3240 else if (nmaches >= p0 && p1 == 0xFFFF) break;
3241 else if (nmaches >= p0 && nmaches <= p1) break;
3246 if (s >= exp->_eol)
3247 break;
3249 if (p0 == p1 && p0 == nmaches) return good;
3250 else if (nmaches >= p0 && p1 == 0xFFFF) return good;
3251 else if (nmaches >= p0 && nmaches <= p1) return good;
3252 return NULL;
3254 case OP_OR: {
3255 const TRexChar *asd = str;
3256 TRexNode *temp = &exp->_nodes[node->left];
3257 while ((asd = trex_matchnode(exp, temp, asd, NULL))) {
3258 if (temp->next != -1)
3259 temp = &exp->_nodes[temp->next];
3260 else
3261 return asd;
3263 asd = str;
3264 temp = &exp->_nodes[node->right];
3265 while ((asd = trex_matchnode(exp, temp, asd, NULL))) {
3266 if (temp->next != -1)
3267 temp = &exp->_nodes[temp->next];
3268 else
3269 return asd;
3271 return NULL;
3273 case OP_EXPR:
3274 case OP_NOCAPEXPR: {
3275 TRexNode *n = &exp->_nodes[node->left];
3276 const TRexChar *cur = str;
3277 int capture = -1;
3278 if (node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
3279 capture = exp->_currsubexp;
3280 exp->_matches[capture].begin = cur;
3281 exp->_currsubexp++;
3284 do {
3285 TRexNode *subnext = NULL;
3286 if (n->next != -1) {
3287 subnext = &exp->_nodes[n->next];
3288 } else {
3289 subnext = next;
3291 if (!(cur = trex_matchnode(exp, n, cur, subnext))) {
3292 if (capture != -1) {
3293 exp->_matches[capture].begin = 0;
3294 exp->_matches[capture].len = 0;
3296 return NULL;
3298 } while ((n->next != -1) && (n = &exp->_nodes[n->next]));
3300 if (capture != -1)
3301 exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin);
3302 return cur;
3304 case OP_WB:
3305 if ((str == exp->_bol && !ISSPACE(*str))
3306 || ((str == exp->_eol && !ISSPACE(*(str - 1))))
3307 || ((!ISSPACE(*str) && ISSPACE(*(str + 1))))
3308 || ((ISSPACE(*str) && !ISSPACE(*(str + 1))))) {
3309 return (node->left == 'b') ? str : NULL;
3311 return (node->left == 'b') ? NULL : str;
3312 case OP_BOL:
3313 if (str == exp->_bol) return str;
3314 return NULL;
3315 case OP_EOL:
3316 if (str == exp->_eol) return str;
3317 return NULL;
3318 case OP_DOT:
3319 str++;
3320 return str;
3321 case OP_NCLASS:
3322 case OP_CLASS:
3323 if (trex_matchclass(exp, &exp->_nodes[node->left], *str) ? (type == OP_CLASS ? TRex_True : TRex_False) : (type == OP_NCLASS ? TRex_True : TRex_False)) {
3324 str++;
3325 return str;
3327 return NULL;
3328 case OP_CCLASS:
3329 if (trex_matchcclass(node->left, *str)) {
3330 str++;
3331 return str;
3333 return NULL;
3334 default: /* char */
3335 if (exp->_flags & TREX_ICASE) {
3336 if (*str != tolower(node->type) && *str != toupper(node->type)) return NULL;
3337 } else {
3338 if (*str != node->type) return NULL;
3340 str++;
3341 return str;
3343 return NULL;
3346 /* public api */
3347 TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags) {
3348 TRex *exp = (TRex *)malloc(sizeof(TRex));
3349 exp->_eol = exp->_bol = NULL;
3350 exp->_p = pattern;
3351 exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
3352 exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
3353 exp->_nsize = 0;
3354 exp->_matches = 0;
3355 exp->_nsubexpr = 0;
3356 exp->_first = trex_newnode(exp, OP_EXPR);
3357 exp->_error = error;
3358 exp->_jmpbuf = malloc(sizeof(jmp_buf));
3359 exp->_flags = flags;
3360 if (setjmp(*((jmp_buf *)exp->_jmpbuf)) == 0) {
3361 int res = trex_list(exp);
3362 exp->_nodes[exp->_first].left = res;
3363 if (*exp->_p != '\0')
3364 trex_error(exp, _SC("unexpected character"));
3365 #ifdef _DEBUG
3367 int nsize, i;
3368 TRexNode *t;
3369 nsize = exp->_nsize;
3370 t = &exp->_nodes[0];
3371 scprintf(_SC("\n"));
3372 for (i = 0; i < nsize; i++) {
3373 if (exp->_nodes[i].type > MAX_CHAR)
3374 scprintf(_SC("[%02d] %10s "), i, g_nnames[exp->_nodes[i].type - MAX_CHAR]);
3375 else
3376 scprintf(_SC("[%02d] %10c "), i, exp->_nodes[i].type);
3377 scprintf(_SC("left %02d right %02d next %02d\n"), exp->_nodes[i].left, exp->_nodes[i].right, exp->_nodes[i].next);
3379 scprintf(_SC("\n"));
3381 #endif
3382 exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
3383 memset(exp->_matches, 0, exp->_nsubexpr * sizeof(TRexMatch));
3384 } else {
3385 trex_free(exp);
3386 return NULL;
3388 return exp;
3391 void trex_free(TRex *exp) {
3392 if (exp) {
3393 if (exp->_nodes) free(exp->_nodes);
3394 if (exp->_jmpbuf) free(exp->_jmpbuf);
3395 if (exp->_matches) free(exp->_matches);
3396 free(exp);
3400 TRexBool trex_match(TRex *exp, const TRexChar *text) {
3401 const TRexChar *res = NULL;
3402 exp->_bol = text;
3403 exp->_eol = text + scstrlen(text);
3404 exp->_currsubexp = 0;
3405 res = trex_matchnode(exp, exp->_nodes, text, NULL);
3406 if (res == NULL || res != exp->_eol)
3407 return TRex_False;
3408 return TRex_True;
3411 TRexBool trex_searchrange(TRex *exp, const TRexChar *text_begin, const TRexChar *text_end, const TRexChar **out_begin, const TRexChar **out_end) {
3412 const TRexChar *cur = NULL;
3413 int node = exp->_first;
3414 if (text_begin >= text_end) return TRex_False;
3415 exp->_bol = text_begin;
3416 exp->_eol = text_end;
3417 do {
3418 cur = text_begin;
3419 while (node != -1) {
3420 exp->_currsubexp = 0;
3421 cur = trex_matchnode(exp, &exp->_nodes[node], cur, NULL);
3422 if (!cur)
3423 break;
3424 node = exp->_nodes[node].next;
3426 text_begin++;
3427 } while (cur == NULL && text_begin != text_end);
3429 if (cur == NULL)
3430 return TRex_False;
3432 --text_begin;
3434 if (out_begin) *out_begin = text_begin;
3435 if (out_end) *out_end = cur;
3436 return TRex_True;
3439 TRexBool trex_search(TRex *exp, const TRexChar *text, const TRexChar **out_begin, const TRexChar **out_end) {
3440 return trex_searchrange(exp, text, text + scstrlen(text), out_begin, out_end);
3443 int trex_getsubexpcount(TRex *exp) {
3444 return exp->_nsubexpr;
3447 TRexBool trex_getsubexp(TRex *exp, int n, TRexMatch *subexp) {
3448 if (n < 0 || n >= exp->_nsubexpr) return TRex_False;
3449 *subexp = exp->_matches[n];
3450 return TRex_True;
3452 /*******************************************************************************
3453 * This file is part of the argtable3 library.
3455 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3456 * <sheitmann@users.sourceforge.net>
3457 * All rights reserved.
3459 * Redistribution and use in source and binary forms, with or without
3460 * modification, are permitted provided that the following conditions are met:
3461 * * Redistributions of source code must retain the above copyright
3462 * notice, this list of conditions and the following disclaimer.
3463 * * Redistributions in binary form must reproduce the above copyright
3464 * notice, this list of conditions and the following disclaimer in the
3465 * documentation and/or other materials provided with the distribution.
3466 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3467 * may be used to endorse or promote products derived from this software
3468 * without specific prior written permission.
3470 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3471 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3472 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3473 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3474 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3475 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3476 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3477 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3478 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3479 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3480 ******************************************************************************/
3482 #include <stdlib.h>
3484 #include "argtable3.h"
3487 static void arg_str_resetfn(struct arg_str *parent) {
3488 int i;
3489 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
3490 parent->count = 0;
3491 for (i = 0; i < parent->count; i++) {
3492 parent->sval[i] = "";
3497 static int arg_str_scanfn(struct arg_str *parent, const char *argval) {
3498 int errorcode = 0;
3500 if (parent->count == parent->hdr.maxcount) {
3501 /* maximum number of arguments exceeded */
3502 errorcode = EMAXCOUNT;
3503 } else if (!argval) {
3504 /* a valid argument with no argument value was given. */
3505 /* This happens when an optional argument value was invoked. */
3506 /* leave parent arguiment value unaltered but still count the argument. */
3507 parent->count++;
3508 } else {
3509 parent->sval[parent->count++] = argval;
3512 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
3513 return errorcode;
3517 static int arg_str_checkfn(struct arg_str *parent) {
3518 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
3520 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
3521 return errorcode;
3525 static void arg_str_errorfn(
3526 struct arg_str *parent,
3527 FILE *fp,
3528 int errorcode,
3529 const char *argval,
3530 const char *progname) {
3531 const char *shortopts = parent->hdr.shortopts;
3532 const char *longopts = parent->hdr.longopts;
3533 const char *datatype = parent->hdr.datatype;
3535 /* make argval NULL safe */
3536 argval = argval ? argval : "";
3538 fprintf(fp, "%s: ", progname);
3539 switch (errorcode) {
3540 case EMINCOUNT:
3541 fputs("missing option ", fp);
3542 arg_print_option(fp, shortopts, longopts, datatype, "\n");
3543 break;
3545 case EMAXCOUNT:
3546 fputs("excess option ", fp);
3547 arg_print_option(fp, shortopts, longopts, argval, "\n");
3548 break;
3553 struct arg_str *arg_str0(
3554 const char *shortopts,
3555 const char *longopts,
3556 const char *datatype,
3557 const char *glossary) {
3558 return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
3562 struct arg_str *arg_str1(
3563 const char *shortopts,
3564 const char *longopts,
3565 const char *datatype,
3566 const char *glossary) {
3567 return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
3571 struct arg_str *arg_strn(
3572 const char *shortopts,
3573 const char *longopts,
3574 const char *datatype,
3575 int mincount,
3576 int maxcount,
3577 const char *glossary) {
3578 size_t nbytes;
3579 struct arg_str *result;
3581 /* should not allow this stupid error */
3582 /* we should return an error code warning this logic error */
3583 /* foolproof things by ensuring maxcount is not less than mincount */
3584 maxcount = (maxcount < mincount) ? mincount : maxcount;
3586 nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
3587 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
3589 result = (struct arg_str *)malloc(nbytes);
3590 if (result) {
3591 int i;
3593 /* init the arg_hdr struct */
3594 result->hdr.flag = ARG_HASVALUE;
3595 result->hdr.shortopts = shortopts;
3596 result->hdr.longopts = longopts;
3597 result->hdr.datatype = datatype ? datatype : "<string>";
3598 result->hdr.glossary = glossary;
3599 result->hdr.mincount = mincount;
3600 result->hdr.maxcount = maxcount;
3601 result->hdr.parent = result;
3602 result->hdr.resetfn = (arg_resetfn *)arg_str_resetfn;
3603 result->hdr.scanfn = (arg_scanfn *)arg_str_scanfn;
3604 result->hdr.checkfn = (arg_checkfn *)arg_str_checkfn;
3605 result->hdr.errorfn = (arg_errorfn *)arg_str_errorfn;
3607 /* store the sval[maxcount] array immediately after the arg_str struct */
3608 result->sval = (const char * *)(result + 1);
3609 result->count = 0;
3611 /* foolproof the string pointers by initialising them to reference empty strings */
3612 for (i = 0; i < maxcount; i++)
3613 result->sval[i] = "";
3616 ARG_TRACE(("arg_strn() returns %p\n", result));
3617 return result;
3619 /*******************************************************************************
3620 * This file is part of the argtable3 library.
3622 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3623 * <sheitmann@users.sourceforge.net>
3624 * All rights reserved.
3626 * Redistribution and use in source and binary forms, with or without
3627 * modification, are permitted provided that the following conditions are met:
3628 * * Redistributions of source code must retain the above copyright
3629 * notice, this list of conditions and the following disclaimer.
3630 * * Redistributions in binary form must reproduce the above copyright
3631 * notice, this list of conditions and the following disclaimer in the
3632 * documentation and/or other materials provided with the distribution.
3633 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3634 * may be used to endorse or promote products derived from this software
3635 * without specific prior written permission.
3637 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3638 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3639 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3640 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3641 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3642 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3643 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3644 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3645 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3646 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3647 ******************************************************************************/
3649 #include <stdlib.h>
3650 #include <string.h>
3651 #include <stdlib.h>
3652 #include <ctype.h>
3654 #include "argtable3.h"
3656 static
3657 void arg_register_error(struct arg_end *end,
3658 void *parent,
3659 int error,
3660 const char *argval) {
3661 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3662 if (end->count < end->hdr.maxcount) {
3663 end->error[end->count] = error;
3664 end->parent[end->count] = parent;
3665 end->argval[end->count] = argval;
3666 end->count++;
3667 } else {
3668 end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;
3669 end->parent[end->hdr.maxcount - 1] = end;
3670 end->argval[end->hdr.maxcount - 1] = NULL;
3676 * Return index of first table entry with a matching short option
3677 * or -1 if no match was found.
3679 static int find_shortoption(struct arg_hdr **table, char shortopt) {
3680 int tabindex;
3681 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
3682 if (table[tabindex]->shortopts &&
3683 strchr(table[tabindex]->shortopts, shortopt))
3684 return tabindex;
3686 return -1;
3689 struct longoptions {
3690 int getoptval;
3691 int noptions;
3692 struct option *options;
3695 #if 0
3696 static
3697 void dump_longoptions(struct longoptions *longoptions) {
3698 int i;
3699 printf("getoptval = %d\n", longoptions->getoptval);
3700 printf("noptions = %d\n", longoptions->noptions);
3701 for (i = 0; i < longoptions->noptions; i++) {
3702 printf("options[%d].name = \"%s\"\n",
3704 longoptions->options[i].name);
3705 printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);
3706 printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);
3707 printf("options[%d].val = %d\n", i, longoptions->options[i].val);
3710 #endif
3712 static struct longoptions *alloc_longoptions(struct arg_hdr **table) {
3713 struct longoptions *result;
3714 size_t nbytes;
3715 int noptions = 1;
3716 size_t longoptlen = 0;
3717 int tabindex;
3720 * Determine the total number of option structs required
3721 * by counting the number of comma separated long options
3722 * in all table entries and return the count in noptions.
3723 * note: noptions starts at 1 not 0 because we getoptlong
3724 * requires a NULL option entry to terminate the option array.
3725 * While we are at it, count the number of chars required
3726 * to store private copies of all the longoption strings
3727 * and return that count in logoptlen.
3729 tabindex = 0;
3730 do {
3731 const char *longopts = table[tabindex]->longopts;
3732 longoptlen += (longopts ? strlen(longopts) : 0) + 1;
3733 while (longopts) {
3734 noptions++;
3735 longopts = strchr(longopts + 1, ',');
3737 } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
3738 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3741 /* allocate storage for return data structure as: */
3742 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3743 nbytes = sizeof(struct longoptions)
3744 + sizeof(struct option) * noptions
3745 + longoptlen;
3746 result = (struct longoptions *)malloc(nbytes);
3747 if (result) {
3748 int option_index = 0;
3749 char *store;
3751 result->getoptval = 0;
3752 result->noptions = noptions;
3753 result->options = (struct option *)(result + 1);
3754 store = (char *)(result->options + noptions);
3756 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
3757 const char *longopts = table[tabindex]->longopts;
3759 while (longopts && *longopts) {
3760 char *storestart = store;
3762 /* copy progressive longopt strings into the store */
3763 while (*longopts != 0 && *longopts != ',')
3764 *store++ = *longopts++;
3765 *store++ = 0;
3766 if (*longopts == ',')
3767 longopts++;
3768 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3770 result->options[option_index].name = storestart;
3771 result->options[option_index].flag = &(result->getoptval);
3772 result->options[option_index].val = tabindex;
3773 if (table[tabindex]->flag & ARG_HASOPTVALUE)
3774 result->options[option_index].has_arg = 2;
3775 else if (table[tabindex]->flag & ARG_HASVALUE)
3776 result->options[option_index].has_arg = 1;
3777 else
3778 result->options[option_index].has_arg = 0;
3780 option_index++;
3783 /* terminate the options array with a zero-filled entry */
3784 result->options[option_index].name = 0;
3785 result->options[option_index].has_arg = 0;
3786 result->options[option_index].flag = 0;
3787 result->options[option_index].val = 0;
3790 /*dump_longoptions(result);*/
3791 return result;
3794 static char *alloc_shortoptions(struct arg_hdr **table) {
3795 char *result;
3796 size_t len = 2;
3797 int tabindex;
3799 /* determine the total number of option chars required */
3800 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
3801 struct arg_hdr *hdr = table[tabindex];
3802 len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);
3805 result = malloc(len);
3806 if (result) {
3807 char *res = result;
3809 /* add a leading ':' so getopt return codes distinguish */
3810 /* unrecognised option and options missing argument values */
3811 *res++ = ':';
3813 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
3814 struct arg_hdr *hdr = table[tabindex];
3815 const char *shortopts = hdr->shortopts;
3816 while (shortopts && *shortopts) {
3817 *res++ = *shortopts++;
3818 if (hdr->flag & ARG_HASVALUE)
3819 *res++ = ':';
3820 if (hdr->flag & ARG_HASOPTVALUE)
3821 *res++ = ':';
3824 /* null terminate the string */
3825 *res = 0;
3828 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
3829 return result;
3833 /* return index of the table terminator entry */
3834 static int arg_endindex(struct arg_hdr **table) {
3835 int tabindex = 0;
3836 while (!(table[tabindex]->flag & ARG_TERMINATOR))
3837 tabindex++;
3838 return tabindex;
3842 static void arg_parse_tagged(int argc,
3843 char **argv,
3844 struct arg_hdr **table,
3845 struct arg_end *endtable) {
3846 struct longoptions *longoptions;
3847 char *shortoptions;
3848 int copt;
3850 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
3852 /* allocate short and long option arrays for the given opttable[]. */
3853 /* if the allocs fail then put an error msg in the last table entry. */
3854 longoptions = alloc_longoptions(table);
3855 shortoptions = alloc_shortoptions(table);
3856 if (!longoptions || !shortoptions) {
3857 /* one or both memory allocs failed */
3858 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
3859 /* free anything that was allocated (this is null safe) */
3860 free(shortoptions);
3861 free(longoptions);
3862 return;
3865 /*dump_longoptions(longoptions);*/
3867 /* reset getopts internal option-index to zero, and disable error reporting */
3868 optind = 0;
3869 opterr = 0;
3871 /* fetch and process args using getopt_long */
3872 while ((copt =
3873 getopt_long(argc, argv, shortoptions, longoptions->options,
3874 NULL)) != -1) {
3876 printf("optarg='%s'\n",optarg);
3877 printf("optind=%d\n",optind);
3878 printf("copt=%c\n",(char)copt);
3879 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
3881 switch (copt) {
3882 case 0: {
3883 int tabindex = longoptions->getoptval;
3884 void *parent = table[tabindex]->parent;
3885 /*printf("long option detected from argtable[%d]\n", tabindex);*/
3886 if (optarg && optarg[0] == 0 &&
3887 (table[tabindex]->flag & ARG_HASVALUE)) {
3888 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
3889 arg_register_error(endtable, endtable, ARG_EMISSARG,
3890 argv[optind - 1]);
3891 /* continue to scan the (empty) argument value to enforce argument count checking */
3893 if (table[tabindex]->scanfn) {
3894 int errorcode = table[tabindex]->scanfn(parent, optarg);
3895 if (errorcode != 0)
3896 arg_register_error(endtable, parent, errorcode, optarg);
3899 break;
3901 case '?':
3903 * getopt_long() found an unrecognised short option.
3904 * if it was a short option its value is in optopt
3905 * if it was a long option then optopt=0
3907 switch (optopt) {
3908 case 0:
3909 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
3910 arg_register_error(endtable, endtable, ARG_ELONGOPT,
3911 argv[optind - 1]);
3912 break;
3913 default:
3914 /*printf("?* unrecognised short option '%c'\n",optopt);*/
3915 arg_register_error(endtable, endtable, optopt, NULL);
3916 break;
3918 break;
3920 case ':':
3922 * getopt_long() found an option with its argument missing.
3924 /*printf(": option %s requires an argument\n",argv[optind-1]); */
3925 arg_register_error(endtable, endtable, ARG_EMISSARG,
3926 argv[optind - 1]);
3927 break;
3929 default: {
3930 /* getopt_long() found a valid short option */
3931 int tabindex = find_shortoption(table, (char)copt);
3932 /*printf("short option detected from argtable[%d]\n", tabindex);*/
3933 if (tabindex == -1) {
3934 /* should never get here - but handle it just in case */
3935 /*printf("unrecognised short option %d\n",copt);*/
3936 arg_register_error(endtable, endtable, copt, NULL);
3937 } else {
3938 if (table[tabindex]->scanfn) {
3939 void *parent = table[tabindex]->parent;
3940 int errorcode = table[tabindex]->scanfn(parent, optarg);
3941 if (errorcode != 0)
3942 arg_register_error(endtable, parent, errorcode, optarg);
3945 break;
3950 free(shortoptions);
3951 free(longoptions);
3955 static void arg_parse_untagged(int argc,
3956 char **argv,
3957 struct arg_hdr **table,
3958 struct arg_end *endtable) {
3959 int tabindex = 0;
3960 int errorlast = 0;
3961 const char *optarglast = NULL;
3962 void *parentlast = NULL;
3964 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
3965 while (!(table[tabindex]->flag & ARG_TERMINATOR)) {
3966 void *parent;
3967 int errorcode;
3969 /* if we have exhausted our argv[optind] entries then we have finished */
3970 if (optind >= argc) {
3971 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
3972 return;
3975 /* skip table entries with non-null long or short options (they are not untagged entries) */
3976 if (table[tabindex]->longopts || table[tabindex]->shortopts) {
3977 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
3978 tabindex++;
3979 continue;
3982 /* skip table entries with NULL scanfn */
3983 if (!(table[tabindex]->scanfn)) {
3984 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
3985 tabindex++;
3986 continue;
3989 /* attempt to scan the current argv[optind] with the current */
3990 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
3991 /* try again with the next table[] entry. */
3992 parent = table[tabindex]->parent;
3993 errorcode = table[tabindex]->scanfn(parent, argv[optind]);
3994 if (errorcode == 0) {
3995 /* success, move onto next argv[optind] but stay with same table[tabindex] */
3996 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
3997 optind++;
3999 /* clear the last tentative error */
4000 errorlast = 0;
4001 } else {
4002 /* failure, try same argv[optind] with next table[tabindex] entry */
4003 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4004 tabindex++;
4006 /* remember this as a tentative error we may wish to reinstate later */
4007 errorlast = errorcode;
4008 optarglast = argv[optind];
4009 parentlast = parent;
4013 /* if a tenative error still remains at this point then register it as a proper error */
4014 if (errorlast) {
4015 arg_register_error(endtable, parentlast, errorlast, optarglast);
4016 optind++;
4019 /* only get here when not all argv[] entries were consumed */
4020 /* register an error for each unused argv[] entry */
4021 while (optind < argc) {
4022 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4023 arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
4026 return;
4030 static void arg_parse_check(struct arg_hdr **table, struct arg_end *endtable) {
4031 int tabindex = 0;
4032 /* printf("arg_parse_check()\n"); */
4033 do {
4034 if (table[tabindex]->checkfn) {
4035 void *parent = table[tabindex]->parent;
4036 int errorcode = table[tabindex]->checkfn(parent);
4037 if (errorcode != 0)
4038 arg_register_error(endtable, parent, errorcode, NULL);
4040 } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
4044 static void arg_reset(void **argtable) {
4045 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4046 int tabindex = 0;
4047 /*printf("arg_reset(%p)\n",argtable);*/
4048 do {
4049 if (table[tabindex]->resetfn)
4050 table[tabindex]->resetfn(table[tabindex]->parent);
4051 } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
4055 int arg_parse(int argc, char * *argv, void * *argtable) {
4056 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4057 struct arg_end *endtable;
4058 int endindex;
4059 char * *argvcopy = NULL;
4061 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4063 /* reset any argtable data from previous invocations */
4064 arg_reset(argtable);
4066 /* locate the first end-of-table marker within the array */
4067 endindex = arg_endindex(table);
4068 endtable = (struct arg_end *)table[endindex];
4070 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4071 /* Failure to trap this case results in an unwanted NULL result from */
4072 /* the malloc for argvcopy (next code block). */
4073 if (argc == 0) {
4074 /* We must still perform post-parse checks despite the absence of command line arguments */
4075 arg_parse_check(table, endtable);
4077 /* Now we are finished */
4078 return endtable->count;
4081 argvcopy = (char **)malloc(sizeof(char *) * (argc + 1));
4082 if (argvcopy) {
4083 int i;
4086 Fill in the local copy of argv[]. We need a local copy
4087 because getopt rearranges argv[] which adversely affects
4088 susbsequent parsing attempts.
4090 for (i = 0; i < argc; i++)
4091 argvcopy[i] = argv[i];
4093 argvcopy[argc] = NULL;
4095 /* parse the command line (local copy) for tagged options */
4096 arg_parse_tagged(argc, argvcopy, table, endtable);
4098 /* parse the command line (local copy) for untagged options */
4099 arg_parse_untagged(argc, argvcopy, table, endtable);
4101 /* if no errors so far then perform post-parse checks otherwise dont bother */
4102 if (endtable->count == 0)
4103 arg_parse_check(table, endtable);
4105 /* release the local copt of argv[] */
4106 free(argvcopy);
4107 } else {
4108 /* memory alloc failed */
4109 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4112 return endtable->count;
4117 * Concatenate contents of src[] string onto *pdest[] string.
4118 * The *pdest pointer is altered to point to the end of the
4119 * target string and *pndest is decremented by the same number
4120 * of chars.
4121 * Does not append more than *pndest chars into *pdest[]
4122 * so as to prevent buffer overruns.
4123 * Its something like strncat() but more efficient for repeated
4124 * calls on the same destination string.
4125 * Example of use:
4126 * char dest[30] = "good"
4127 * size_t ndest = sizeof(dest);
4128 * char *pdest = dest;
4129 * arg_char(&pdest,"bye ",&ndest);
4130 * arg_char(&pdest,"cruel ",&ndest);
4131 * arg_char(&pdest,"world!",&ndest);
4132 * Results in:
4133 * dest[] == "goodbye cruel world!"
4134 * ndest == 10
4136 static void arg_cat(char **pdest, const char *src, size_t *pndest) {
4137 char *dest = *pdest;
4138 // PM3 fix: leave room for null terminate char
4139 char *end = dest + *pndest - 1;
4141 /*locate null terminator of dest string */
4142 while (dest < end && *dest != 0)
4143 dest++;
4145 /* concat src string to dest string */
4146 while (dest < end && *src != 0)
4147 *dest++ = *src++;
4149 /* null terminate dest string */
4150 *dest = 0;
4152 /* update *pdest and *pndest */
4153 *pndest = end - dest;
4154 *pdest = dest;
4158 static void arg_cat_option(char *dest,
4159 size_t ndest,
4160 const char *shortopts,
4161 const char *longopts,
4162 const char *datatype,
4163 int optvalue) {
4164 if (shortopts) {
4165 char option[3];
4167 /* note: option array[] is initialiazed dynamically here to satisfy */
4168 /* a deficiency in the watcom compiler wrt static array initializers. */
4169 option[0] = '-';
4170 option[1] = shortopts[0];
4171 option[2] = 0;
4173 arg_cat(&dest, option, &ndest);
4174 if (datatype) {
4175 arg_cat(&dest, " ", &ndest);
4176 if (optvalue) {
4177 arg_cat(&dest, "[", &ndest);
4178 arg_cat(&dest, datatype, &ndest);
4179 arg_cat(&dest, "]", &ndest);
4180 } else
4181 arg_cat(&dest, datatype, &ndest);
4183 } else if (longopts) {
4184 size_t ncspn;
4186 /* add "--" tag prefix */
4187 arg_cat(&dest, "--", &ndest);
4189 /* add comma separated option tag */
4190 ncspn = strcspn(longopts, ",");
4191 #ifdef __STDC_WANT_SECURE_LIB__
4192 strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest);
4193 #else
4194 strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
4195 #endif
4197 if (datatype) {
4198 arg_cat(&dest, "=", &ndest);
4199 if (optvalue) {
4200 arg_cat(&dest, "[", &ndest);
4201 arg_cat(&dest, datatype, &ndest);
4202 arg_cat(&dest, "]", &ndest);
4203 } else
4204 arg_cat(&dest, datatype, &ndest);
4206 } else if (datatype) {
4207 if (optvalue) {
4208 arg_cat(&dest, "[", &ndest);
4209 arg_cat(&dest, datatype, &ndest);
4210 arg_cat(&dest, "]", &ndest);
4211 } else
4212 arg_cat(&dest, datatype, &ndest);
4216 static void arg_cat_optionv(char *dest,
4217 size_t ndest,
4218 const char *shortopts,
4219 const char *longopts,
4220 const char *datatype,
4221 int optvalue,
4222 const char *separator) {
4223 separator = separator ? separator : "";
4225 if (shortopts) {
4226 const char *c = shortopts;
4227 while (*c) {
4228 /* "-a|-b|-c" */
4229 char shortopt[3];
4231 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4232 /* a deficiency in the watcom compiler wrt static array initializers. */
4233 shortopt[0] = '-';
4234 shortopt[1] = *c;
4235 shortopt[2] = 0;
4237 arg_cat(&dest, shortopt, &ndest);
4238 if (*++c)
4239 arg_cat(&dest, separator, &ndest);
4243 /* put separator between long opts and short opts */
4244 if (shortopts && longopts)
4245 arg_cat(&dest, separator, &ndest);
4247 if (longopts) {
4248 const char *c = longopts;
4249 while (*c) {
4250 size_t ncspn;
4252 /* add "--" tag prefix */
4253 arg_cat(&dest, "--", &ndest);
4255 /* add comma separated option tag */
4256 ncspn = strcspn(c, ",");
4257 #ifdef __STDC_WANT_SECURE_LIB__
4258 strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest);
4259 #else
4260 strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
4261 #endif
4262 c += ncspn;
4264 /* add given separator in place of comma */
4265 if (*c == ',') {
4266 arg_cat(&dest, separator, &ndest);
4267 c++;
4272 if (datatype) {
4273 if (longopts)
4274 arg_cat(&dest, "=", &ndest);
4275 else if (shortopts)
4276 arg_cat(&dest, " ", &ndest);
4278 if (optvalue) {
4279 arg_cat(&dest, "[", &ndest);
4280 arg_cat(&dest, datatype, &ndest);
4281 arg_cat(&dest, "]", &ndest);
4282 } else
4283 arg_cat(&dest, datatype, &ndest);
4288 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4289 void arg_print_option(FILE *fp,
4290 const char *shortopts,
4291 const char *longopts,
4292 const char *datatype,
4293 const char *suffix) {
4294 char syntax[200] = "";
4295 suffix = suffix ? suffix : "";
4297 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4298 arg_cat_optionv(syntax,
4299 sizeof(syntax),
4300 shortopts,
4301 longopts,
4302 datatype,
4304 "|");
4306 fputs(syntax, fp);
4307 fputs(suffix, fp);
4312 * Print a GNU style [OPTION] string in which all short options that
4313 * do not take argument values are presented in abbreviated form, as
4314 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4316 static
4317 void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table) {
4318 int tabindex;
4319 const char *format1 = " -%c";
4320 const char *format2 = " [-%c";
4321 const char *suffix = "";
4323 /* print all mandatory switches that are without argument values */
4324 for (tabindex = 0;
4325 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4326 tabindex++) {
4327 /* skip optional options */
4328 if (table[tabindex]->mincount < 1)
4329 continue;
4331 /* skip non-short options */
4332 if (table[tabindex]->shortopts == NULL)
4333 continue;
4335 /* skip options that take argument values */
4336 if (table[tabindex]->flag & ARG_HASVALUE)
4337 continue;
4339 /* print the short option (only the first short option char, ignore multiple choices)*/
4340 fprintf(fp, format1, table[tabindex]->shortopts[0]);
4341 format1 = "%c";
4342 format2 = "[%c";
4345 /* print all optional switches that are without argument values */
4346 for (tabindex = 0;
4347 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4348 tabindex++) {
4349 /* skip mandatory args */
4350 if (table[tabindex]->mincount > 0)
4351 continue;
4353 /* skip args without short options */
4354 if (table[tabindex]->shortopts == NULL)
4355 continue;
4357 /* skip args with values */
4358 if (table[tabindex]->flag & ARG_HASVALUE)
4359 continue;
4361 /* print first short option */
4362 fprintf(fp, format2, table[tabindex]->shortopts[0]);
4363 format2 = "%c";
4364 suffix = "]";
4367 fprintf(fp, "%s", suffix);
4371 void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) {
4372 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4373 int i, tabindex;
4375 /* print GNU style [OPTION] string */
4376 arg_print_gnuswitch(fp, table);
4378 /* print remaining options in abbreviated style */
4379 for (tabindex = 0;
4380 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4381 tabindex++) {
4382 char syntax[200] = "";
4383 const char *shortopts, *longopts, *datatype;
4385 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4386 if (table[tabindex]->shortopts &&
4387 !(table[tabindex]->flag & ARG_HASVALUE))
4388 continue;
4390 shortopts = table[tabindex]->shortopts;
4391 longopts = table[tabindex]->longopts;
4392 datatype = table[tabindex]->datatype;
4393 arg_cat_option(syntax,
4394 sizeof(syntax),
4395 shortopts,
4396 longopts,
4397 datatype,
4398 table[tabindex]->flag & ARG_HASOPTVALUE);
4400 if (strlen(syntax) > 0) {
4401 /* print mandatory instances of this option */
4402 for (i = 0; i < table[tabindex]->mincount; i++)
4403 fprintf(fp, " %s", syntax);
4405 /* print optional instances enclosed in "[..]" */
4406 switch (table[tabindex]->maxcount - table[tabindex]->mincount) {
4407 case 0:
4408 break;
4409 case 1:
4410 fprintf(fp, " [%s]", syntax);
4411 break;
4412 case 2:
4413 fprintf(fp, " [%s] [%s]", syntax, syntax);
4414 break;
4415 default:
4416 fprintf(fp, " [%s]...", syntax);
4417 break;
4422 if (suffix)
4423 fprintf(fp, "%s", suffix);
4427 void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix) {
4428 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4429 int i, tabindex;
4431 /* print remaining options in abbreviated style */
4432 for (tabindex = 0;
4433 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4434 tabindex++) {
4435 char syntax[200] = "";
4436 const char *shortopts, *longopts, *datatype;
4438 shortopts = table[tabindex]->shortopts;
4439 longopts = table[tabindex]->longopts;
4440 datatype = table[tabindex]->datatype;
4441 arg_cat_optionv(syntax,
4442 sizeof(syntax),
4443 shortopts,
4444 longopts,
4445 datatype,
4446 table[tabindex]->flag & ARG_HASOPTVALUE,
4447 "|");
4449 /* print mandatory options */
4450 for (i = 0; i < table[tabindex]->mincount; i++)
4451 fprintf(fp, " %s", syntax);
4453 /* print optional args enclosed in "[..]" */
4454 switch (table[tabindex]->maxcount - table[tabindex]->mincount) {
4455 case 0:
4456 break;
4457 case 1:
4458 fprintf(fp, " [%s]", syntax);
4459 break;
4460 case 2:
4461 fprintf(fp, " [%s] [%s]", syntax, syntax);
4462 break;
4463 default:
4464 fprintf(fp, " [%s]...", syntax);
4465 break;
4469 if (suffix)
4470 fprintf(fp, "%s", suffix);
4474 void arg_print_glossary(FILE *fp, void * *argtable, const char *format) {
4475 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4476 int tabindex;
4478 format = format ? format : " %-20s %s\n";
4479 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
4480 if (table[tabindex]->glossary) {
4481 char syntax[200] = "";
4482 const char *shortopts = table[tabindex]->shortopts;
4483 const char *longopts = table[tabindex]->longopts;
4484 const char *datatype = table[tabindex]->datatype;
4485 const char *glossary = table[tabindex]->glossary;
4486 arg_cat_optionv(syntax,
4487 sizeof(syntax),
4488 shortopts,
4489 longopts,
4490 datatype,
4491 table[tabindex]->flag & ARG_HASOPTVALUE,
4492 ", ");
4493 fprintf(fp, format, syntax, glossary);
4500 * Print a piece of text formatted, which means in a column with a
4501 * left and a right margin. The lines are wrapped at whitspaces next
4502 * to right margin. The function does not indent the first line, but
4503 * only the following ones.
4505 * Example:
4506 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4507 * will result in the following output:
4509 * Some
4510 * text
4511 * that
4512 * doesn'
4513 * t fit.
4515 * Too long lines will be wrapped in the middle of a word.
4517 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4518 * will result in the following output:
4520 * Some
4521 * text
4522 * that
4523 * doesn'
4524 * t fit.
4526 * As you see, the first line is not indented. This enables output of
4527 * lines, which start in a line where output already happened.
4529 * Author: Uli Fouquet
4531 static
4532 void arg_print_formatted(FILE *fp,
4533 const unsigned lmargin,
4534 const unsigned rmargin,
4535 const char *text) {
4536 const unsigned textlen = (unsigned)strlen(text);
4537 unsigned line_start = 0;
4538 unsigned line_end = textlen + 1;
4539 const unsigned colwidth = (rmargin - lmargin) + 1;
4541 /* Someone doesn't like us... */
4542 if (line_end == line_start) {
4543 fprintf(fp, "%s\n", text);
4546 while (line_end - 1 > line_start) {
4547 /* Eat leading whitespaces. This is essential because while
4548 wrapping lines, there will often be a whitespace at beginning
4549 of line */
4550 while (ISSPACE(*(text + line_start)))
4551 { line_start++; }
4553 if ((line_end - line_start) > colwidth)
4554 { line_end = line_start + colwidth; }
4556 /* Find last whitespace, that fits into line */
4557 while ((line_end > line_start)
4558 && (line_end - line_start > colwidth)
4559 && !ISSPACE(*(text + line_end)))
4560 { line_end--; }
4562 /* Do not print trailing whitespace. If this text
4563 has got only one line, line_end now points to the
4564 last char due to initialization. */
4565 line_end--;
4567 /* Output line of text */
4568 while (line_start < line_end) {
4569 fputc(*(text + line_start), fp);
4570 line_start++;
4572 fputc('\n', fp);
4574 /* Initialize another line */
4575 if (line_end + 1 < textlen) {
4576 unsigned i;
4578 for (i = 0; i < lmargin; i++)
4579 { fputc(' ', fp); }
4581 line_end = textlen;
4584 /* If we have to print another line, get also the last char. */
4585 line_end++;
4587 } /* lines of text */
4591 * Prints the glossary in strict GNU format.
4592 * Differences to arg_print_glossary() are:
4593 * - wraps lines after 80 chars
4594 * - indents lines without shortops
4595 * - does not accept formatstrings
4597 * Contributed by Uli Fouquet
4599 void arg_print_glossary_gnu(FILE *fp, void * *argtable) {
4600 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4601 int tabindex;
4603 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
4604 if (table[tabindex]->glossary) {
4605 char syntax[200] = "";
4606 const char *shortopts = table[tabindex]->shortopts;
4607 const char *longopts = table[tabindex]->longopts;
4608 const char *datatype = table[tabindex]->datatype;
4609 const char *glossary = table[tabindex]->glossary;
4611 if (!shortopts && longopts) {
4612 /* Indent trailing line by 4 spaces... */
4613 memset(syntax, ' ', 4);
4614 *(syntax + 4) = '\0';
4617 arg_cat_optionv(syntax,
4618 sizeof(syntax),
4619 shortopts,
4620 longopts,
4621 datatype,
4622 table[tabindex]->flag & ARG_HASOPTVALUE,
4623 ", ");
4625 /* If syntax fits not into column, print glossary in new line... */
4626 if (strlen(syntax) > 25) {
4627 fprintf(fp, " %-25s %s\n", syntax, "");
4628 *syntax = '\0';
4631 fprintf(fp, " %-25s ", syntax);
4632 arg_print_formatted(fp, 28, 79, glossary);
4634 } /* for each table entry */
4636 fputc('\n', fp);
4641 * Checks the argtable[] array for NULL entries and returns 1
4642 * if any are found, zero otherwise.
4644 int arg_nullcheck(void * *argtable) {
4645 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4646 int tabindex;
4647 /*printf("arg_nullcheck(%p)\n",argtable);*/
4649 if (!table)
4650 return 1;
4652 tabindex = 0;
4653 do {
4654 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4655 if (!table[tabindex])
4656 return 1;
4657 } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
4659 return 0;
4663 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4664 * The flaw results in memory leak in the (very rare) case that an intermediate
4665 * entry in the argtable array failed its memory allocation while others following
4666 * that entry were still allocated ok. Those subsequent allocations will not be
4667 * deallocated by arg_free().
4668 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4669 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4670 * with the newer arg_freetable() function.
4671 * We still keep arg_free() for backwards compatibility.
4673 void arg_free(void * *argtable) {
4674 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4675 int tabindex = 0;
4676 int flag;
4677 /*printf("arg_free(%p)\n",argtable);*/
4678 do {
4680 if we encounter a NULL entry then somewhat incorrectly we presume
4681 we have come to the end of the array. It isnt strictly true because
4682 an intermediate entry could be NULL with other non-NULL entries to follow.
4683 The subsequent argtable entries would then not be freed as they should.
4685 if (table[tabindex] == NULL)
4686 break;
4688 flag = table[tabindex]->flag;
4689 free(table[tabindex]);
4690 table[tabindex++] = NULL;
4692 } while (!(flag & ARG_TERMINATOR));
4695 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4696 void arg_freetable(void * *argtable, size_t n) {
4697 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4698 size_t tabindex = 0;
4699 /*printf("arg_freetable(%p)\n",argtable);*/
4700 for (tabindex = 0; tabindex < n; tabindex++) {
4701 if (table[tabindex] == NULL)
4702 continue;
4704 free(table[tabindex]);
4705 table[tabindex] = NULL;