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>
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 /*******************************************************************************
34 * This file is part of the argtable3 library.
36 * Copyright (C) 2013 Tom G. Huang
37 * <tomghuang@gmail.com>
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions are met:
42 * * Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * * Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * * Neither the name of STEWART HEITMANN nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
52 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
55 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
56 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
58 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 ******************************************************************************/
66 #define ARG_ENABLE_TRACE 0
67 #define ARG_ENABLE_LOG 1
86 #define ARG_TRACE(x) \
87 __pragma(warning(push)) \
88 __pragma(warning(disable:4127)) \
89 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \
90 __pragma(warning(pop))
93 __pragma(warning(push)) \
94 __pragma(warning(disable:4127)) \
95 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
96 __pragma(warning(pop))
98 #define ARG_TRACE(x) \
99 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
102 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
105 extern void dbg_printf(const char *fmt, ...);
113 /*******************************************************************************
114 * This file is part of the argtable3 library.
116 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
117 * <sheitmann@users.sourceforge.net>
118 * All rights reserved.
120 * Redistribution and use in source and binary forms, with or without
121 * modification, are permitted provided that the following conditions are met:
122 * * Redistributions of source code must retain the above copyright
123 * notice, this list of conditions and the following disclaimer.
124 * * Redistributions in binary form must reproduce the above copyright
125 * notice, this list of conditions and the following disclaimer in the
126 * documentation and/or other materials provided with the distribution.
127 * * Neither the name of STEWART HEITMANN nor the names of its contributors
128 * may be used to endorse or promote products derived from this software
129 * without specific prior written permission.
131 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
132 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
133 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
134 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
135 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
136 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
137 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
138 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
139 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
140 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
141 ******************************************************************************/
147 void dbg_printf(const char *fmt, ...)
151 vfprintf(stderr, fmt, args);
155 /* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
156 /* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */
157 /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
160 * Copyright (c) 2000 The NetBSD Foundation, Inc.
161 * All rights reserved.
163 * This code is derived from software contributed to The NetBSD Foundation
164 * by Dieter Baron and Thomas Klausner.
166 * Redistribution and use in source and binary forms, with or without
167 * modification, are permitted provided that the following conditions
169 * 1. Redistributions of source code must retain the above copyright
170 * notice, this list of conditions and the following disclaimer.
171 * 2. Redistributions in binary form must reproduce the above copyright
172 * notice, this list of conditions and the following disclaimer in the
173 * documentation and/or other materials provided with the distribution.
174 * 3. All advertising materials mentioning features or use of this software
175 * must display the following acknowledgement:
176 * This product includes software developed by the NetBSD
177 * Foundation, Inc. and its contributors.
178 * 4. Neither the name of The NetBSD Foundation nor the names of its
179 * contributors may be used to endorse or promote products derived
180 * from this software without specific prior written permission.
182 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
183 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
184 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
185 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
186 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
187 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
188 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
189 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
190 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
191 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
192 * POSSIBILITY OF SUCH DAMAGE.
199 #include <sys/cdefs.h>
203 * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
205 #define no_argument 0
206 #define required_argument 1
207 #define optional_argument 2
210 /* name of long option */
213 * one of no_argument, required_argument, and optional_argument:
214 * whether option takes an argument
217 /* if not NULL, set *flag to val when option found */
219 /* if flag not NULL, value to set *flag to; else return value */
227 int getopt_long(int, char * const *, const char *,
228 const struct option *, int *);
229 int getopt_long_only(int, char * const *, const char *,
230 const struct option *, int *);
231 #ifndef _GETOPT_DEFINED
232 #define _GETOPT_DEFINED
233 int getopt(int, char * const *, const char *);
234 int getsubopt(char **, char * const *, char **);
236 extern char *optarg; /* getopt(3) external variables */
241 extern char *suboptarg; /* getsubopt(3) external variable */
242 #endif /* _GETOPT_DEFINED */
247 #endif /* !_GETOPT_H_ */
248 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
249 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
250 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
253 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
255 * Permission to use, copy, modify, and distribute this software for any
256 * purpose with or without fee is hereby granted, provided that the above
257 * copyright notice and this permission notice appear in all copies.
259 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
260 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
261 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
262 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
263 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
264 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
265 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
267 * Sponsored in part by the Defense Advanced Research Projects
268 * Agency (DARPA) and Air Force Research Laboratory, Air Force
269 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
273 //static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $";
276 * Copyright (c) 2000 The NetBSD Foundation, Inc.
277 * All rights reserved.
279 * This code is derived from software contributed to The NetBSD Foundation
280 * by Dieter Baron and Thomas Klausner.
282 * Redistribution and use in source and binary forms, with or without
283 * modification, are permitted provided that the following conditions
285 * 1. Redistributions of source code must retain the above copyright
286 * notice, this list of conditions and the following disclaimer.
287 * 2. Redistributions in binary form must reproduce the above copyright
288 * notice, this list of conditions and the following disclaimer in the
289 * documentation and/or other materials provided with the distribution.
291 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
292 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
293 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
294 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
295 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
296 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
297 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
298 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
299 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
301 * POSSIBILITY OF SUCH DAMAGE.
308 // Define this to replace system getopt
310 //#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
312 #ifdef REPLACE_GETOPT
313 int opterr = 1; /* if error message should be printed */
314 int optind = 1; /* index into parent argv vector */
315 int optopt = '?'; /* character checked for validity */
316 int optreset; /* reset getopt */
317 char *optarg; /* argument associated with option */
320 #define PRINT_ERROR ((opterr) && (*options != ':'))
322 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
323 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
324 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
327 #define BADCH (int)'?'
328 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
329 #define INORDER (int)1
333 static int getopt_internal(int, char * const *, const char *,
334 const struct option *, int *, int);
335 static int parse_long_options(char * const *, const char *,
336 const struct option *, int *, int);
337 static int gcd(int, int);
338 static void permute_args(int, int, int, char * const *);
340 static char *place = EMSG; /* option letter processing */
342 /* XXX: set optreset to 1 rather than these two */
343 static int nonopt_start = -1; /* first non option argument (for permute) */
344 static int nonopt_end = -1; /* first option after non options (for permute) */
347 static const char recargchar[] = "option requires an argument -- %c";
348 static const char recargstring[] = "option requires an argument -- %s";
349 static const char ambig[] = "ambiguous option -- %.*s";
350 static const char noarg[] = "option doesn't take an argument -- %.*s";
351 static const char illoptchar[] = "unknown option -- %c";
352 static const char illoptstring[] = "unknown option -- %s";
355 #if defined(_WIN32) || defined(ESP_PLATFORM)
357 /* Windows needs warnx(). We change the definition though:
358 * 1. (another) global is defined, opterrmsg, which holds the error message
359 * 2. errors are always printed out on stderr w/o the program name
360 * Note that opterrmsg always gets set no matter what opterr is set to. The
361 * error message will not be printed if opterr is 0 as usual.
367 extern char opterrmsg[128];
368 char opterrmsg[128]; /* buffer for the last error message */
370 static void warnx(const char *fmt, ...)
375 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
376 implementation specifics and manually suppress the warning.
378 memset(opterrmsg, 0, sizeof opterrmsg);
380 vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
383 #pragma warning(suppress: 6053)
385 fprintf(stderr, "%s\n", opterrmsg);
393 * Compute the greatest common divisor of a and b.
411 * Exchange the block from nonopt_start to nonopt_end with the block
412 * from nonopt_end to opt_end (keeping the same order of arguments
416 permute_args(int panonopt_start, int panonopt_end, int opt_end,
419 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
423 * compute lengths of blocks and number and size of cycles
425 nnonopts = panonopt_end - panonopt_start;
426 nopts = opt_end - panonopt_end;
427 ncycle = gcd(nnonopts, nopts);
428 cyclelen = (opt_end - panonopt_start) / ncycle;
430 for (i = 0; i < ncycle; i++) {
431 cstart = panonopt_end+i;
433 for (j = 0; j < cyclelen; j++) {
434 if (pos >= panonopt_end)
439 /* LINTED const cast */
440 ((char **) nargv)[pos] = nargv[cstart];
441 /* LINTED const cast */
442 ((char **)nargv)[cstart] = swap;
448 * parse_long_options --
449 * Parse long options in argc/argv argument vector.
450 * Returns -1 if short_too is set and the option does not match long_options.
453 parse_long_options(char * const *nargv, const char *options,
454 const struct option *long_options, int *idx, int short_too)
456 char *current_argv, *has_equal;
457 size_t current_argv_len;
460 current_argv = place;
465 if ((has_equal = strchr(current_argv, '=')) != NULL) {
466 /* argument found (--option=arg) */
467 current_argv_len = has_equal - current_argv;
470 current_argv_len = strlen(current_argv);
472 for (i = 0; long_options[i].name; i++) {
473 /* find matching long option */
474 if (strncmp(current_argv, long_options[i].name,
478 if (strlen(long_options[i].name) == current_argv_len) {
484 * If this is a known short option, don't allow
485 * a partial match of a single character.
487 if (short_too && current_argv_len == 1)
490 if (match == -1) /* partial match */
493 /* ambiguous abbreviation */
495 warnx(ambig, (int)current_argv_len,
501 if (match != -1) { /* option found */
502 if (long_options[match].has_arg == no_argument
505 warnx(noarg, (int)current_argv_len,
508 * XXX: GNU sets optopt to val regardless of flag
510 if (long_options[match].flag == NULL)
511 optopt = long_options[match].val;
516 if (long_options[match].has_arg == required_argument ||
517 long_options[match].has_arg == optional_argument) {
520 else if (long_options[match].has_arg ==
523 * optional argument doesn't use next nargv
525 optarg = nargv[optind++];
528 if ((long_options[match].has_arg == required_argument)
529 && (optarg == NULL)) {
531 * Missing argument; leading ':' indicates no error
532 * should be generated.
538 * XXX: GNU sets optopt to val regardless of flag
540 if (long_options[match].flag == NULL)
541 optopt = long_options[match].val;
547 } else { /* unknown option */
553 warnx(illoptstring, current_argv);
559 if (long_options[match].flag) {
560 *long_options[match].flag = long_options[match].val;
563 return (long_options[match].val);
568 * Parse argc/argv argument vector. Called by user level routines.
571 getopt_internal(int nargc, char * const *nargv, const char *options,
572 const struct option *long_options, int *idx, int flags)
574 char *oli; /* option letter list index */
575 int optchar, short_too;
576 static int posixly_correct = -1;
582 * Disable GNU extensions if POSIXLY_CORRECT is set or options
583 * string begins with a '+'.
585 if (posixly_correct == -1)
586 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
587 if (posixly_correct || *options == '+')
588 flags &= ~FLAG_PERMUTE;
589 else if (*options == '-')
590 flags |= FLAG_ALLARGS;
591 if (*options == '+' || *options == '-')
595 * XXX Some GNU programs (like cvs) set optind to 0 instead of
596 * XXX using optreset. Work around this braindamage.
599 optind = optreset = 1;
603 nonopt_start = nonopt_end = -1;
605 if (optreset || !*place) { /* update scanning pointer */
607 if (optind >= nargc) { /* end of argument vector */
609 if (nonopt_end != -1) {
610 /* do permutation, if we have to */
611 permute_args(nonopt_start, nonopt_end,
613 optind -= nonopt_end - nonopt_start;
615 else if (nonopt_start != -1) {
617 * If we skipped non-options, set optind
618 * to the first of them.
620 optind = nonopt_start;
622 nonopt_start = nonopt_end = -1;
625 if (*(place = nargv[optind]) != '-' ||
626 (place[1] == '\0' && strchr(options, '-') == NULL)) {
627 place = EMSG; /* found non-option */
628 if (flags & FLAG_ALLARGS) {
631 * return non-option as argument to option 1
633 optarg = nargv[optind++];
636 if (!(flags & FLAG_PERMUTE)) {
638 * If no permutation wanted, stop parsing
639 * at first non-option.
644 if (nonopt_start == -1)
645 nonopt_start = optind;
646 else if (nonopt_end != -1) {
647 permute_args(nonopt_start, nonopt_end,
649 nonopt_start = optind -
650 (nonopt_end - nonopt_start);
654 /* process next argument */
657 if (nonopt_start != -1 && nonopt_end == -1)
661 * If we have "-" do nothing, if "--" we are done.
663 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
667 * We found an option (--), so if we skipped
668 * non-options, we have to permute.
670 if (nonopt_end != -1) {
671 permute_args(nonopt_start, nonopt_end,
673 optind -= nonopt_end - nonopt_start;
675 nonopt_start = nonopt_end = -1;
681 * Check long options if:
682 * 1) we were passed some
683 * 2) the arg is not just "-"
684 * 3) either the arg starts with -- we are getopt_long_only()
686 if (long_options != NULL && place != nargv[optind] &&
687 (*place == '-' || (flags & FLAG_LONGONLY))) {
690 place++; /* --foo long option */
691 else if (*place != ':' && strchr(options, *place) != NULL)
692 short_too = 1; /* could be short option too */
694 optchar = parse_long_options(nargv, options, long_options,
702 if ((optchar = (int)*place++) == (int)':' ||
703 (optchar == (int)'-' && *place != '\0') ||
704 (oli = strchr(options, optchar)) == NULL) {
706 * If the user specified "-" and '-' isn't listed in
707 * options, return -1 (non-option) as per POSIX.
708 * Otherwise, it is an unknown option character (or ':').
710 if (optchar == (int)'-' && *place == '\0')
715 warnx(illoptchar, optchar);
719 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
721 if (*place) /* no space */
723 else if (++optind >= nargc) { /* no arg */
726 warnx(recargchar, optchar);
729 } else /* white space */
730 place = nargv[optind];
731 optchar = parse_long_options(nargv, options, long_options,
736 if (*++oli != ':') { /* doesn't take argument */
739 } else { /* takes (optional) argument */
741 if (*place) /* no white space */
743 else if (oli[1] != ':') { /* arg not optional */
744 if (++optind >= nargc) { /* no arg */
747 warnx(recargchar, optchar);
751 optarg = nargv[optind];
756 /* dump back option letter */
763 * Parse argc/argv argument vector.
765 * [eventually this will replace the BSD getopt]
768 getopt(int nargc, char * const *nargv, const char *options)
772 * We don't pass FLAG_PERMUTE to getopt_internal() since
773 * the BSD getopt(3) (unlike GNU) has never done this.
775 * Furthermore, since many privileged programs call getopt()
776 * before dropping privileges it makes sense to keep things
777 * as simple (and bug-free) as possible.
779 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
785 * Parse argc/argv argument vector.
788 getopt_long(int nargc, char * const *nargv, const char *options,
789 const struct option *long_options, int *idx)
792 return (getopt_internal(nargc, nargv, options, long_options, idx,
797 * getopt_long_only --
798 * Parse argc/argv argument vector.
801 getopt_long_only(int nargc, char * const *nargv, const char *options,
802 const struct option *long_options, int *idx)
805 return (getopt_internal(nargc, nargv, options, long_options, idx,
806 FLAG_PERMUTE|FLAG_LONGONLY));
808 #endif /* REPLACE_GETOPT */
809 /*******************************************************************************
810 * This file is part of the argtable3 library.
812 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
813 * <sheitmann@users.sourceforge.net>
814 * All rights reserved.
816 * Redistribution and use in source and binary forms, with or without
817 * modification, are permitted provided that the following conditions are met:
818 * * Redistributions of source code must retain the above copyright
819 * notice, this list of conditions and the following disclaimer.
820 * * Redistributions in binary form must reproduce the above copyright
821 * notice, this list of conditions and the following disclaimer in the
822 * documentation and/or other materials provided with the distribution.
823 * * Neither the name of STEWART HEITMANN nor the names of its contributors
824 * may be used to endorse or promote products derived from this software
825 * without specific prior written permission.
827 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
828 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
829 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
830 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
831 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
832 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
833 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
834 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
835 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
836 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
837 ******************************************************************************/
842 #include "argtable3.h"
845 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm);
848 static void arg_date_resetfn(struct arg_date *parent)
850 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
855 static int arg_date_scanfn(struct arg_date *parent, const char *argval)
859 if (parent->count == parent->hdr.maxcount)
861 errorcode = EMAXCOUNT;
865 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
871 struct tm tm = parent->tmval[parent->count];
873 /* parse the given argument value, store result in parent->tmval[] */
874 pend = arg_strptime(argval, parent->format, &tm);
875 if (pend && pend[0] == '\0')
876 parent->tmval[parent->count++] = tm;
878 errorcode = EBADDATE;
881 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
886 static int arg_date_checkfn(struct arg_date *parent)
888 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
890 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
895 static void arg_date_errorfn(
896 struct arg_date *parent,
900 const char *progname)
902 const char *shortopts = parent->hdr.shortopts;
903 const char *longopts = parent->hdr.longopts;
904 const char *datatype = parent->hdr.datatype;
906 /* make argval NULL safe */
907 argval = argval ? argval : "";
909 fprintf(fp, "%s: ", progname);
913 fputs("missing option ", fp);
914 arg_print_option(fp, shortopts, longopts, datatype, "\n");
918 fputs("excess option ", fp);
919 arg_print_option(fp, shortopts, longopts, argval, "\n");
927 fprintf(fp, "illegal timestamp format \"%s\"\n", argval);
928 memset(&tm, 0, sizeof(tm));
929 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
930 strftime(buff, sizeof(buff), parent->format, &tm);
931 printf("correct format is \"%s\"\n", buff);
938 struct arg_date * arg_date0(
939 const char * shortopts,
940 const char * longopts,
942 const char *datatype,
943 const char *glossary)
945 return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
949 struct arg_date * arg_date1(
950 const char * shortopts,
951 const char * longopts,
953 const char *datatype,
954 const char *glossary)
956 return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
960 struct arg_date * arg_daten(
961 const char * shortopts,
962 const char * longopts,
964 const char *datatype,
967 const char *glossary)
970 struct arg_date *result;
972 /* foolproof things by ensuring maxcount is not less than mincount */
973 maxcount = (maxcount < mincount) ? mincount : maxcount;
975 /* default time format is the national date format for the locale */
979 nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
980 + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
982 /* allocate storage for the arg_date struct + tmval[] array. */
983 /* we use calloc because we want the tmval[] array zero filled. */
984 result = (struct arg_date *)calloc(1, nbytes);
987 /* init the arg_hdr struct */
988 result->hdr.flag = ARG_HASVALUE;
989 result->hdr.shortopts = shortopts;
990 result->hdr.longopts = longopts;
991 result->hdr.datatype = datatype ? datatype : format;
992 result->hdr.glossary = glossary;
993 result->hdr.mincount = mincount;
994 result->hdr.maxcount = maxcount;
995 result->hdr.parent = result;
996 result->hdr.resetfn = (arg_resetfn *)arg_date_resetfn;
997 result->hdr.scanfn = (arg_scanfn *)arg_date_scanfn;
998 result->hdr.checkfn = (arg_checkfn *)arg_date_checkfn;
999 result->hdr.errorfn = (arg_errorfn *)arg_date_errorfn;
1001 /* store the tmval[maxcount] array immediately after the arg_date struct */
1002 result->tmval = (struct tm *)(result + 1);
1004 /* init the remaining arg_date member variables */
1006 result->format = format;
1009 ARG_TRACE(("arg_daten() returns %p\n", result));
1015 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1016 * All rights reserved.
1018 * This code was contributed to The NetBSD Foundation by Klaus Klein.
1019 * Heavily optimised by David Laight
1021 * Redistribution and use in source and binary forms, with or without
1022 * modification, are permitted provided that the following conditions
1024 * 1. Redistributions of source code must retain the above copyright
1025 * notice, this list of conditions and the following disclaimer.
1026 * 2. Redistributions in binary form must reproduce the above copyright
1027 * notice, this list of conditions and the following disclaimer in the
1028 * documentation and/or other materials provided with the distribution.
1030 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1031 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1032 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1033 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1034 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1035 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1036 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1037 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1038 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1039 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1040 * POSSIBILITY OF SUCH DAMAGE.
1048 * We do not implement alternate representations. However, we always
1049 * check whether a given modifier is allowed for a certain conversion.
1053 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
1054 #define TM_YEAR_BASE (1900)
1056 static int conv_num(const char * *, int *, int, int);
1058 static const char *day[7] = {
1059 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
1060 "Friday", "Saturday"
1063 static const char *abday[7] = {
1064 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1067 static const char *mon[12] = {
1068 "January", "February", "March", "April", "May", "June", "July",
1069 "August", "September", "October", "November", "December"
1072 static const char *abmon[12] = {
1073 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1074 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1077 static const char *am_pm[2] = {
1082 static int arg_strcasecmp(const char *s1, const char *s2)
1084 const unsigned char *us1 = (const unsigned char *)s1;
1085 const unsigned char *us2 = (const unsigned char *)s2;
1086 while (tolower(*us1) == tolower(*us2++))
1090 return tolower(*us1) - tolower(*--us2);
1094 static int arg_strncasecmp(const char *s1, const char *s2, size_t n)
1098 const unsigned char *us1 = (const unsigned char *)s1;
1099 const unsigned char *us2 = (const unsigned char *)s2;
1102 if (tolower(*us1) != tolower(*us2++))
1103 return tolower(*us1) - tolower(*--us2);
1114 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm)
1119 int alt_format, i, split_year = 0;
1123 while ((c = *fmt) != '\0') {
1124 /* Clear `alternate' modifier prior to new conversion. */
1127 /* Eat up white-space. */
1128 if (isspace((int) c)) {
1129 while (isspace((int) *bp))
1136 if ((c = *fmt++) != '%')
1143 case '%': /* "%%" is converted to "%". */
1150 * "Alternative" modifiers. Just set the appropriate flag
1151 * and start over again.
1153 case 'E': /* "%E?" alternative conversion modifier. */
1155 alt_format |= ALT_E;
1158 case 'O': /* "%O?" alternative conversion modifier. */
1160 alt_format |= ALT_O;
1164 * "Complex" conversion rules, implemented through recursion.
1166 case 'c': /* Date and time, using the locale's format. */
1168 bp = arg_strptime(bp, "%x %X", tm);
1173 case 'D': /* The date as "%m/%d/%y". */
1175 bp = arg_strptime(bp, "%m/%d/%y", tm);
1180 case 'R': /* The time as "%H:%M". */
1182 bp = arg_strptime(bp, "%H:%M", tm);
1187 case 'r': /* The time in 12-hour clock representation. */
1189 bp = arg_strptime(bp, "%I:%M:%S %p", tm);
1194 case 'T': /* The time as "%H:%M:%S". */
1196 bp = arg_strptime(bp, "%H:%M:%S", tm);
1201 case 'X': /* The time, using the locale's format. */
1203 bp = arg_strptime(bp, "%H:%M:%S", tm);
1208 case 'x': /* The date, using the locale's format. */
1210 bp = arg_strptime(bp, "%m/%d/%y", tm);
1216 * "Elementary" conversion rules.
1218 case 'A': /* The day of week, using the locale's form. */
1221 for (i = 0; i < 7; i++) {
1223 len = strlen(day[i]);
1224 if (arg_strncasecmp(day[i], bp, len) == 0)
1227 /* Abbreviated name. */
1228 len = strlen(abday[i]);
1229 if (arg_strncasecmp(abday[i], bp, len) == 0)
1233 /* Nothing matched. */
1241 case 'B': /* The month, using the locale's form. */
1245 for (i = 0; i < 12; i++) {
1247 len = strlen(mon[i]);
1248 if (arg_strncasecmp(mon[i], bp, len) == 0)
1251 /* Abbreviated name. */
1252 len = strlen(abmon[i]);
1253 if (arg_strncasecmp(abmon[i], bp, len) == 0)
1257 /* Nothing matched. */
1265 case 'C': /* The century number. */
1267 if (!(conv_num(&bp, &i, 0, 99)))
1271 tm->tm_year = (tm->tm_year % 100) + (i * 100);
1273 tm->tm_year = i * 100;
1278 case 'd': /* The day of month. */
1281 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
1285 case 'k': /* The hour (24-hour clock representation). */
1290 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
1294 case 'l': /* The hour (12-hour clock representation). */
1299 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
1301 if (tm->tm_hour == 12)
1305 case 'j': /* The day of year. */
1307 if (!(conv_num(&bp, &i, 1, 366)))
1309 tm->tm_yday = i - 1;
1312 case 'M': /* The minute. */
1314 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
1318 case 'm': /* The month. */
1320 if (!(conv_num(&bp, &i, 1, 12)))
1325 case 'p': /* The locale's equivalent of AM/PM. */
1328 if (arg_strcasecmp(am_pm[0], bp) == 0) {
1329 if (tm->tm_hour > 11)
1332 bp += strlen(am_pm[0]);
1336 else if (arg_strcasecmp(am_pm[1], bp) == 0) {
1337 if (tm->tm_hour > 11)
1341 bp += strlen(am_pm[1]);
1345 /* Nothing matched. */
1348 case 'S': /* The seconds. */
1350 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
1354 case 'U': /* The week of year, beginning on sunday. */
1355 case 'W': /* The week of year, beginning on monday. */
1358 * XXX This is bogus, as we can not assume any valid
1359 * information present in the tm structure at this
1360 * point to calculate a real value, so just check the
1363 if (!(conv_num(&bp, &i, 0, 53)))
1367 case 'w': /* The day of week, beginning on sunday. */
1369 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
1373 case 'Y': /* The year. */
1375 if (!(conv_num(&bp, &i, 0, 9999)))
1378 tm->tm_year = i - TM_YEAR_BASE;
1381 case 'y': /* The year within 100 years of the epoch. */
1382 LEGAL_ALT(ALT_E | ALT_O);
1383 if (!(conv_num(&bp, &i, 0, 99)))
1387 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
1392 tm->tm_year = i + 2000 - TM_YEAR_BASE;
1394 tm->tm_year = i + 1900 - TM_YEAR_BASE;
1398 * Miscellaneous conversions.
1400 case 'n': /* Any kind of white-space. */
1403 while (isspace((int) *bp))
1408 default: /* Unknown/unsupported conversion. */
1415 /* LINTED functional specification */
1416 return ((char *)bp);
1420 static int conv_num(const char * *buf, int *dest, int llim, int ulim)
1424 /* The limit also determines the number of valid digits. */
1427 if (**buf < '0' || **buf > '9')
1432 result += *(*buf)++ - '0';
1434 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
1436 if (result < llim || result > ulim)
1442 /*******************************************************************************
1443 * This file is part of the argtable3 library.
1445 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1446 * <sheitmann@users.sourceforge.net>
1447 * All rights reserved.
1449 * Redistribution and use in source and binary forms, with or without
1450 * modification, are permitted provided that the following conditions are met:
1451 * * Redistributions of source code must retain the above copyright
1452 * notice, this list of conditions and the following disclaimer.
1453 * * Redistributions in binary form must reproduce the above copyright
1454 * notice, this list of conditions and the following disclaimer in the
1455 * documentation and/or other materials provided with the distribution.
1456 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1457 * may be used to endorse or promote products derived from this software
1458 * without specific prior written permission.
1460 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1461 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1462 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1463 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1464 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1465 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1466 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1467 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1468 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1469 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1470 ******************************************************************************/
1474 #include "argtable3.h"
1477 static void arg_dbl_resetfn(struct arg_dbl *parent)
1479 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1484 static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval)
1488 if (parent->count == parent->hdr.maxcount)
1490 /* maximum number of arguments exceeded */
1491 errorcode = EMAXCOUNT;
1495 /* a valid argument with no argument value was given. */
1496 /* This happens when an optional argument value was invoked. */
1497 /* leave parent argument value unaltered but still count the argument. */
1505 /* extract double from argval into val */
1506 val = strtod(argval, &end);
1508 /* if success then store result in parent->dval[] array otherwise return error*/
1510 parent->dval[parent->count++] = val;
1512 errorcode = EBADDOUBLE;
1515 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1520 static int arg_dbl_checkfn(struct arg_dbl *parent)
1522 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1524 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1529 static void arg_dbl_errorfn(
1530 struct arg_dbl *parent,
1534 const char *progname)
1536 const char *shortopts = parent->hdr.shortopts;
1537 const char *longopts = parent->hdr.longopts;
1538 const char *datatype = parent->hdr.datatype;
1540 /* make argval NULL safe */
1541 argval = argval ? argval : "";
1543 fprintf(fp, "%s: ", progname);
1547 fputs("missing option ", fp);
1548 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1552 fputs("excess option ", fp);
1553 arg_print_option(fp, shortopts, longopts, argval, "\n");
1557 fprintf(fp, "invalid argument \"%s\" to option ", argval);
1558 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1564 struct arg_dbl * arg_dbl0(
1565 const char * shortopts,
1566 const char * longopts,
1567 const char *datatype,
1568 const char *glossary)
1570 return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
1574 struct arg_dbl * arg_dbl1(
1575 const char * shortopts,
1576 const char * longopts,
1577 const char *datatype,
1578 const char *glossary)
1580 return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
1584 struct arg_dbl * arg_dbln(
1585 const char * shortopts,
1586 const char * longopts,
1587 const char *datatype,
1590 const char *glossary)
1593 struct arg_dbl *result;
1595 /* foolproof things by ensuring maxcount is not less than mincount */
1596 maxcount = (maxcount < mincount) ? mincount : maxcount;
1598 nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
1599 + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1601 result = (struct arg_dbl *)malloc(nbytes);
1607 /* init the arg_hdr struct */
1608 result->hdr.flag = ARG_HASVALUE;
1609 result->hdr.shortopts = shortopts;
1610 result->hdr.longopts = longopts;
1611 result->hdr.datatype = datatype ? datatype : "<double>";
1612 result->hdr.glossary = glossary;
1613 result->hdr.mincount = mincount;
1614 result->hdr.maxcount = maxcount;
1615 result->hdr.parent = result;
1616 result->hdr.resetfn = (arg_resetfn *)arg_dbl_resetfn;
1617 result->hdr.scanfn = (arg_scanfn *)arg_dbl_scanfn;
1618 result->hdr.checkfn = (arg_checkfn *)arg_dbl_checkfn;
1619 result->hdr.errorfn = (arg_errorfn *)arg_dbl_errorfn;
1621 /* Store the dval[maxcount] array on the first double boundary that
1622 * immediately follows the arg_dbl struct. We do the memory alignment
1623 * purely for SPARC and Motorola systems. They require floats and
1624 * doubles to be aligned on natural boundaries.
1626 addr = (size_t)(result + 1);
1627 rem = addr % sizeof(double);
1628 result->dval = (double *)(addr + sizeof(double) - rem);
1629 ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
1634 ARG_TRACE(("arg_dbln() returns %p\n", result));
1637 /*******************************************************************************
1638 * This file is part of the argtable3 library.
1640 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1641 * <sheitmann@users.sourceforge.net>
1642 * All rights reserved.
1644 * Redistribution and use in source and binary forms, with or without
1645 * modification, are permitted provided that the following conditions are met:
1646 * * Redistributions of source code must retain the above copyright
1647 * notice, this list of conditions and the following disclaimer.
1648 * * Redistributions in binary form must reproduce the above copyright
1649 * notice, this list of conditions and the following disclaimer in the
1650 * documentation and/or other materials provided with the distribution.
1651 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1652 * may be used to endorse or promote products derived from this software
1653 * without specific prior written permission.
1655 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1656 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1657 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1658 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1659 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1660 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1661 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1662 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1663 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1664 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1665 ******************************************************************************/
1669 #include "argtable3.h"
1672 static void arg_end_resetfn(struct arg_end *parent)
1674 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1678 static void arg_end_errorfn(
1683 const char *progname)
1685 /* suppress unreferenced formal parameter warning */
1688 progname = progname ? progname : "";
1689 argval = argval ? argval : "";
1691 fprintf(fp, "%s: ", progname);
1695 fputs("too many errors to display", fp);
1698 fputs("insufficent memory", fp);
1701 fprintf(fp, "unexpected argument \"%s\"", argval);
1704 fprintf(fp, "option \"%s\" requires an argument", argval);
1707 fprintf(fp, "invalid option \"%s\"", argval);
1710 fprintf(fp, "invalid option \"-%c\"", error);
1718 struct arg_end * arg_end(int maxcount)
1721 struct arg_end *result;
1723 nbytes = sizeof(struct arg_end)
1724 + maxcount * sizeof(int) /* storage for int error[maxcount] array*/
1725 + maxcount * sizeof(void *) /* storage for void* parent[maxcount] array */
1726 + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */
1728 result = (struct arg_end *)malloc(nbytes);
1731 /* init the arg_hdr struct */
1732 result->hdr.flag = ARG_TERMINATOR;
1733 result->hdr.shortopts = NULL;
1734 result->hdr.longopts = NULL;
1735 result->hdr.datatype = NULL;
1736 result->hdr.glossary = NULL;
1737 result->hdr.mincount = 1;
1738 result->hdr.maxcount = maxcount;
1739 result->hdr.parent = result;
1740 result->hdr.resetfn = (arg_resetfn *)arg_end_resetfn;
1741 result->hdr.scanfn = NULL;
1742 result->hdr.checkfn = NULL;
1743 result->hdr.errorfn = (arg_errorfn *)arg_end_errorfn;
1745 /* store error[maxcount] array immediately after struct arg_end */
1746 result->error = (int *)(result + 1);
1748 /* store parent[maxcount] array immediately after error[] array */
1749 result->parent = (void * *)(result->error + maxcount );
1751 /* store argval[maxcount] array immediately after parent[] array */
1752 result->argval = (const char * *)(result->parent + maxcount );
1755 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
1760 void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname)
1763 ARG_TRACE(("arg_errors()\n"));
1764 for (i = 0; i < end->count; i++)
1766 struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]);
1767 if (errorparent->errorfn)
1768 errorparent->errorfn(end->parent[i],
1775 /*******************************************************************************
1776 * This file is part of the argtable3 library.
1778 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1779 * <sheitmann@users.sourceforge.net>
1780 * All rights reserved.
1782 * Redistribution and use in source and binary forms, with or without
1783 * modification, are permitted provided that the following conditions are met:
1784 * * Redistributions of source code must retain the above copyright
1785 * notice, this list of conditions and the following disclaimer.
1786 * * Redistributions in binary form must reproduce the above copyright
1787 * notice, this list of conditions and the following disclaimer in the
1788 * documentation and/or other materials provided with the distribution.
1789 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1790 * may be used to endorse or promote products derived from this software
1791 * without specific prior written permission.
1793 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1794 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1795 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1796 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1797 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1798 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1799 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1800 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1801 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1802 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1803 ******************************************************************************/
1808 #include "argtable3.h"
1811 # define FILESEPARATOR1 '\\'
1812 # define FILESEPARATOR2 '/'
1814 # define FILESEPARATOR1 '/'
1815 # define FILESEPARATOR2 '/'
1819 static void arg_file_resetfn(struct arg_file *parent)
1821 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1826 /* Returns ptr to the base filename within *filename */
1827 static const char * arg_basename(const char *filename)
1829 const char *result = NULL, *result1, *result2;
1831 /* Find the last occurrence of eother file separator character. */
1832 /* Two alternative file separator chars are supported as legal */
1833 /* file separators but not both together in the same filename. */
1834 result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
1835 result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
1838 result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
1841 result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
1844 result = filename; /* neither file separator was found so basename is the whole filename */
1846 /* special cases of "." and ".." are not considered basenames */
1847 if (result && ( strcmp(".", result) == 0 || strcmp("..", result) == 0 ))
1848 result = filename + strlen(filename);
1854 /* Returns ptr to the file extension within *basename */
1855 static const char * arg_extension(const char *basename)
1857 /* find the last occurrence of '.' in basename */
1858 const char *result = (basename ? strrchr(basename, '.') : NULL);
1860 /* if no '.' was found then return pointer to end of basename */
1861 if (basename && !result)
1862 result = basename + strlen(basename);
1864 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1865 if (basename && result == basename)
1866 result = basename + strlen(basename);
1868 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1869 if (basename && result && result[1] == '\0')
1870 result = basename + strlen(basename);
1876 static int arg_file_scanfn(struct arg_file *parent, const char *argval)
1880 if (parent->count == parent->hdr.maxcount)
1882 /* maximum number of arguments exceeded */
1883 errorcode = EMAXCOUNT;
1887 /* a valid argument with no argument value was given. */
1888 /* This happens when an optional argument value was invoked. */
1889 /* leave parent arguiment value unaltered but still count the argument. */
1894 parent->filename[parent->count] = argval;
1895 parent->basename[parent->count] = arg_basename(argval);
1896 parent->extension[parent->count] =
1897 arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
1901 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1906 static int arg_file_checkfn(struct arg_file *parent)
1908 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1910 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1915 static void arg_file_errorfn(
1916 struct arg_file *parent,
1920 const char *progname)
1922 const char *shortopts = parent->hdr.shortopts;
1923 const char *longopts = parent->hdr.longopts;
1924 const char *datatype = parent->hdr.datatype;
1926 /* make argval NULL safe */
1927 argval = argval ? argval : "";
1929 fprintf(fp, "%s: ", progname);
1933 fputs("missing option ", fp);
1934 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1938 fputs("excess option ", fp);
1939 arg_print_option(fp, shortopts, longopts, argval, "\n");
1943 fprintf(fp, "unknown error at \"%s\"\n", argval);
1948 struct arg_file * arg_file0(
1949 const char * shortopts,
1950 const char * longopts,
1951 const char *datatype,
1952 const char *glossary)
1954 return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
1958 struct arg_file * arg_file1(
1959 const char * shortopts,
1960 const char * longopts,
1961 const char *datatype,
1962 const char *glossary)
1964 return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
1968 struct arg_file * arg_filen(
1969 const char * shortopts,
1970 const char * longopts,
1971 const char *datatype,
1974 const char *glossary)
1977 struct arg_file *result;
1979 /* foolproof things by ensuring maxcount is not less than mincount */
1980 maxcount = (maxcount < mincount) ? mincount : maxcount;
1982 nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
1983 + sizeof(char *) * maxcount /* storage for filename[maxcount] array */
1984 + sizeof(char *) * maxcount /* storage for basename[maxcount] array */
1985 + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */
1987 result = (struct arg_file *)malloc(nbytes);
1992 /* init the arg_hdr struct */
1993 result->hdr.flag = ARG_HASVALUE;
1994 result->hdr.shortopts = shortopts;
1995 result->hdr.longopts = longopts;
1996 result->hdr.glossary = glossary;
1997 result->hdr.datatype = datatype ? datatype : "<file>";
1998 result->hdr.mincount = mincount;
1999 result->hdr.maxcount = maxcount;
2000 result->hdr.parent = result;
2001 result->hdr.resetfn = (arg_resetfn *)arg_file_resetfn;
2002 result->hdr.scanfn = (arg_scanfn *)arg_file_scanfn;
2003 result->hdr.checkfn = (arg_checkfn *)arg_file_checkfn;
2004 result->hdr.errorfn = (arg_errorfn *)arg_file_errorfn;
2006 /* store the filename,basename,extension arrays immediately after the arg_file struct */
2007 result->filename = (const char * *)(result + 1);
2008 result->basename = result->filename + maxcount;
2009 result->extension = result->basename + maxcount;
2012 /* foolproof the string pointers by initialising them with empty strings */
2013 for (i = 0; i < maxcount; i++)
2015 result->filename[i] = "";
2016 result->basename[i] = "";
2017 result->extension[i] = "";
2021 ARG_TRACE(("arg_filen() returns %p\n", result));
2024 /*******************************************************************************
2025 * This file is part of the argtable3 library.
2027 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2028 * <sheitmann@users.sourceforge.net>
2029 * All rights reserved.
2031 * Redistribution and use in source and binary forms, with or without
2032 * modification, are permitted provided that the following conditions are met:
2033 * * Redistributions of source code must retain the above copyright
2034 * notice, this list of conditions and the following disclaimer.
2035 * * Redistributions in binary form must reproduce the above copyright
2036 * notice, this list of conditions and the following disclaimer in the
2037 * documentation and/or other materials provided with the distribution.
2038 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2039 * may be used to endorse or promote products derived from this software
2040 * without specific prior written permission.
2042 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2043 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2044 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2045 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2046 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2047 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2048 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2049 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2050 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2051 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2052 ******************************************************************************/
2058 #include "argtable3.h"
2061 static void arg_int_resetfn(struct arg_int *parent)
2063 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2068 /* strtol0x() is like strtol() except that the numeric string is */
2069 /* expected to be prefixed by "0X" where X is a user supplied char. */
2070 /* The string may optionally be prefixed by white space and + or - */
2071 /* as in +0X123 or -0X123. */
2072 /* Once the prefix has been scanned, the remainder of the numeric */
2073 /* string is converted using strtol() with the given base. */
2074 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
2075 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
2076 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
2077 /* Failure of conversion is indicated by result where *endptr==str. */
2078 static long int strtol0X(const char * str,
2079 const char * *endptr,
2083 long int val; /* stores result */
2084 int s = 1; /* sign is +1 or -1 */
2085 const char *ptr = str; /* ptr to current position in str */
2087 /* skip leading whitespace */
2088 while (isspace((int) *ptr))
2090 /* printf("1) %s\n",ptr); */
2092 /* scan optional sign character */
2107 /* printf("2) %s\n",ptr); */
2110 if ((*ptr++) != '0')
2112 /* printf("failed to detect '0'\n"); */
2116 /* printf("3) %s\n",ptr); */
2117 if (toupper((int) *ptr++) != toupper((int) X))
2119 /* printf("failed to detect '%c'\n",X); */
2123 /* printf("4) %s\n",ptr); */
2125 /* attempt conversion on remainder of string using strtol() */
2126 val = strtol(ptr, (char * *)endptr, base);
2129 /* conversion failed */
2139 /* Returns 1 if str matches suffix (case insensitive). */
2140 /* Str may contain trailing whitespace, but nothing else. */
2141 static int detectsuffix(const char *str, const char *suffix)
2143 /* scan pairwise through strings until mismatch detected */
2144 while( toupper((int) *str) == toupper((int) *suffix) )
2146 /* printf("'%c' '%c'\n", *str, *suffix); */
2148 /* return 1 (success) if match persists until the string terminator */
2156 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2158 /* return 0 (fail) if the matching did not consume the entire suffix */
2160 return 0; /* failed to consume entire suffix */
2162 /* skip any remaining whitespace in str */
2163 while (isspace((int) *str))
2166 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2167 return (*str == '\0') ? 1 : 0;
2171 static int arg_int_scanfn(struct arg_int *parent, const char *argval)
2175 if (parent->count == parent->hdr.maxcount)
2177 /* maximum number of arguments exceeded */
2178 errorcode = EMAXCOUNT;
2182 /* a valid argument with no argument value was given. */
2183 /* This happens when an optional argument value was invoked. */
2184 /* leave parent arguiment value unaltered but still count the argument. */
2192 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2193 val = strtol0X(argval, &end, 'X', 16);
2196 /* hex failed, attempt octal conversion (eg +0o123) */
2197 val = strtol0X(argval, &end, 'O', 8);
2200 /* octal failed, attempt binary conversion (eg +0B101) */
2201 val = strtol0X(argval, &end, 'B', 2);
2204 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2205 val = strtol(argval, (char * *)&end, 10);
2208 /* all supported number formats failed */
2215 /* Safety check for integer overflow. WARNING: this check */
2216 /* achieves nothing on machines where size(int)==size(long). */
2217 if ( val > INT_MAX || val < INT_MIN )
2218 errorcode = EOVERFLOW;
2220 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2221 /* We need to be mindful of integer overflows when using such big numbers. */
2222 if (detectsuffix(end, "KB")) /* kilobytes */
2224 if ( val > (INT_MAX / 1024) || val < (INT_MIN / 1024) )
2225 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2227 val *= 1024; /* 1KB = 1024 */
2229 else if (detectsuffix(end, "MB")) /* megabytes */
2231 if ( val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576) )
2232 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2234 val *= 1048576; /* 1MB = 1024*1024 */
2236 else if (detectsuffix(end, "GB")) /* gigabytes */
2238 if ( val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824) )
2239 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2241 val *= 1073741824; /* 1GB = 1024*1024*1024 */
2243 else if (!detectsuffix(end, ""))
2244 errorcode = EBADINT; /* invalid suffix detected */
2246 /* if success then store result in parent->ival[] array */
2248 parent->ival[parent->count++] = val;
2251 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2256 static int arg_int_checkfn(struct arg_int *parent)
2258 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2259 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2264 static void arg_int_errorfn(
2265 struct arg_int *parent,
2269 const char *progname)
2271 const char *shortopts = parent->hdr.shortopts;
2272 const char *longopts = parent->hdr.longopts;
2273 const char *datatype = parent->hdr.datatype;
2275 /* make argval NULL safe */
2276 argval = argval ? argval : "";
2278 fprintf(fp, "%s: ", progname);
2282 fputs("missing option ", fp);
2283 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2287 fputs("excess option ", fp);
2288 arg_print_option(fp, shortopts, longopts, argval, "\n");
2292 fprintf(fp, "invalid argument \"%s\" to option ", argval);
2293 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2297 fputs("integer overflow at option ", fp);
2298 arg_print_option(fp, shortopts, longopts, datatype, " ");
2299 fprintf(fp, "(%s is too large)\n", argval);
2305 struct arg_int * arg_int0(
2306 const char *shortopts,
2307 const char *longopts,
2308 const char *datatype,
2309 const char *glossary)
2311 return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
2315 struct arg_int * arg_int1(
2316 const char *shortopts,
2317 const char *longopts,
2318 const char *datatype,
2319 const char *glossary)
2321 return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
2325 struct arg_int * arg_intn(
2326 const char *shortopts,
2327 const char *longopts,
2328 const char *datatype,
2331 const char *glossary)
2334 struct arg_int *result;
2336 /* foolproof things by ensuring maxcount is not less than mincount */
2337 maxcount = (maxcount < mincount) ? mincount : maxcount;
2339 nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
2340 + maxcount * sizeof(int); /* storage for ival[maxcount] array */
2342 result = (struct arg_int *)malloc(nbytes);
2345 /* init the arg_hdr struct */
2346 result->hdr.flag = ARG_HASVALUE;
2347 result->hdr.shortopts = shortopts;
2348 result->hdr.longopts = longopts;
2349 result->hdr.datatype = datatype ? datatype : "<int>";
2350 result->hdr.glossary = glossary;
2351 result->hdr.mincount = mincount;
2352 result->hdr.maxcount = maxcount;
2353 result->hdr.parent = result;
2354 result->hdr.resetfn = (arg_resetfn *)arg_int_resetfn;
2355 result->hdr.scanfn = (arg_scanfn *)arg_int_scanfn;
2356 result->hdr.checkfn = (arg_checkfn *)arg_int_checkfn;
2357 result->hdr.errorfn = (arg_errorfn *)arg_int_errorfn;
2359 /* store the ival[maxcount] array immediately after the arg_int struct */
2360 result->ival = (int *)(result + 1);
2364 ARG_TRACE(("arg_intn() returns %p\n", result));
2367 /*******************************************************************************
2368 * This file is part of the argtable3 library.
2370 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2371 * <sheitmann@users.sourceforge.net>
2372 * All rights reserved.
2374 * Redistribution and use in source and binary forms, with or without
2375 * modification, are permitted provided that the following conditions are met:
2376 * * Redistributions of source code must retain the above copyright
2377 * notice, this list of conditions and the following disclaimer.
2378 * * Redistributions in binary form must reproduce the above copyright
2379 * notice, this list of conditions and the following disclaimer in the
2380 * documentation and/or other materials provided with the distribution.
2381 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2382 * may be used to endorse or promote products derived from this software
2383 * without specific prior written permission.
2385 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2386 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2387 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2388 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2389 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2390 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2391 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2392 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2393 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2394 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2395 ******************************************************************************/
2399 #include "argtable3.h"
2402 static void arg_lit_resetfn(struct arg_lit *parent)
2404 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2409 static int arg_lit_scanfn(struct arg_lit *parent, const char *argval)
2412 if (parent->count < parent->hdr.maxcount )
2415 errorcode = EMAXCOUNT;
2417 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,
2423 static int arg_lit_checkfn(struct arg_lit *parent)
2425 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2426 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
2431 static void arg_lit_errorfn(
2432 struct arg_lit *parent,
2436 const char *progname)
2438 const char *shortopts = parent->hdr.shortopts;
2439 const char *longopts = parent->hdr.longopts;
2440 const char *datatype = parent->hdr.datatype;
2445 fprintf(fp, "%s: missing option ", progname);
2446 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2451 fprintf(fp, "%s: extraneous option ", progname);
2452 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2456 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
2457 errorcode, argval, progname));
2461 struct arg_lit * arg_lit0(
2462 const char * shortopts,
2463 const char * longopts,
2464 const char * glossary)
2466 return arg_litn(shortopts, longopts, 0, 1, glossary);
2470 struct arg_lit * arg_lit1(
2471 const char *shortopts,
2472 const char *longopts,
2473 const char *glossary)
2475 return arg_litn(shortopts, longopts, 1, 1, glossary);
2479 struct arg_lit * arg_litn(
2480 const char *shortopts,
2481 const char *longopts,
2484 const char *glossary)
2486 struct arg_lit *result;
2488 /* foolproof things by ensuring maxcount is not less than mincount */
2489 maxcount = (maxcount < mincount) ? mincount : maxcount;
2491 result = (struct arg_lit *)malloc(sizeof(struct arg_lit));
2494 /* init the arg_hdr struct */
2495 result->hdr.flag = 0;
2496 result->hdr.shortopts = shortopts;
2497 result->hdr.longopts = longopts;
2498 result->hdr.datatype = NULL;
2499 result->hdr.glossary = glossary;
2500 result->hdr.mincount = mincount;
2501 result->hdr.maxcount = maxcount;
2502 result->hdr.parent = result;
2503 result->hdr.resetfn = (arg_resetfn *)arg_lit_resetfn;
2504 result->hdr.scanfn = (arg_scanfn *)arg_lit_scanfn;
2505 result->hdr.checkfn = (arg_checkfn *)arg_lit_checkfn;
2506 result->hdr.errorfn = (arg_errorfn *)arg_lit_errorfn;
2508 /* init local variables */
2512 ARG_TRACE(("arg_litn() returns %p\n", result));
2515 /*******************************************************************************
2516 * This file is part of the argtable3 library.
2518 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2519 * <sheitmann@users.sourceforge.net>
2520 * All rights reserved.
2522 * Redistribution and use in source and binary forms, with or without
2523 * modification, are permitted provided that the following conditions are met:
2524 * * Redistributions of source code must retain the above copyright
2525 * notice, this list of conditions and the following disclaimer.
2526 * * Redistributions in binary form must reproduce the above copyright
2527 * notice, this list of conditions and the following disclaimer in the
2528 * documentation and/or other materials provided with the distribution.
2529 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2530 * may be used to endorse or promote products derived from this software
2531 * without specific prior written permission.
2533 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2534 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2535 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2536 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2537 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2538 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2539 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2540 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2541 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2542 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543 ******************************************************************************/
2547 #include "argtable3.h"
2549 struct arg_rem *arg_rem(const char *datatype, const char *glossary)
2551 struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem));
2554 result->hdr.flag = 0;
2555 result->hdr.shortopts = NULL;
2556 result->hdr.longopts = NULL;
2557 result->hdr.datatype = datatype;
2558 result->hdr.glossary = glossary;
2559 result->hdr.mincount = 1;
2560 result->hdr.maxcount = 1;
2561 result->hdr.parent = result;
2562 result->hdr.resetfn = NULL;
2563 result->hdr.scanfn = NULL;
2564 result->hdr.checkfn = NULL;
2565 result->hdr.errorfn = NULL;
2568 ARG_TRACE(("arg_rem() returns %p\n", result));
2572 /*******************************************************************************
2573 * This file is part of the argtable3 library.
2575 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2576 * <sheitmann@users.sourceforge.net>
2577 * All rights reserved.
2579 * Redistribution and use in source and binary forms, with or without
2580 * modification, are permitted provided that the following conditions are met:
2581 * * Redistributions of source code must retain the above copyright
2582 * notice, this list of conditions and the following disclaimer.
2583 * * Redistributions in binary form must reproduce the above copyright
2584 * notice, this list of conditions and the following disclaimer in the
2585 * documentation and/or other materials provided with the distribution.
2586 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2587 * may be used to endorse or promote products derived from this software
2588 * without specific prior written permission.
2590 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2591 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2592 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2593 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2594 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2595 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2596 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2597 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2598 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2599 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2600 ******************************************************************************/
2605 #include "argtable3.h"
2610 /***************************************************************
2611 T-Rex a tiny regular expression library
2613 Copyright (C) 2003-2006 Alberto Demichelis
2615 This software is provided 'as-is', without any express
2616 or implied warranty. In no event will the authors be held
2617 liable for any damages arising from the use of this software.
2619 Permission is granted to anyone to use this software for
2620 any purpose, including commercial applications, and to alter
2621 it and redistribute it freely, subject to the following restrictions:
2623 1. The origin of this software must not be misrepresented;
2624 you must not claim that you wrote the original software.
2625 If you use this software in a product, an acknowledgment
2626 in the product documentation would be appreciated but
2629 2. Altered source versions must be plainly marked as such,
2630 and must not be misrepresented as being the original software.
2632 3. This notice may not be removed or altered from any
2633 source distribution.
2635 ****************************************************************/
2642 #define TRexChar unsigned short
2643 #define MAX_CHAR 0xFFFF
2644 #define _TREXC(c) L##c
2645 #define trex_strlen wcslen
2646 #define trex_printf wprintf
2648 #define TRexChar char
2649 #define MAX_CHAR 0xFF
2650 #define _TREXC(c) (c)
2651 #define trex_strlen strlen
2652 #define trex_printf printf
2656 #define TREX_API extern
2660 #define TRex_False 0
2662 #define TREX_ICASE ARG_REX_ICASE
2664 typedef unsigned int TRexBool;
2665 typedef struct TRex TRex;
2668 const TRexChar *begin;
2672 TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags);
2673 TREX_API void trex_free(TRex *exp);
2674 TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);
2675 TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
2676 TREX_API TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);
2677 TREX_API int trex_getsubexpcount(TRex* exp);
2678 TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
2690 const char *pattern;
2695 static void arg_rex_resetfn(struct arg_rex *parent)
2697 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2701 static int arg_rex_scanfn(struct arg_rex *parent, const char *argval)
2704 const TRexChar *error = NULL;
2706 TRexBool is_match = TRex_False;
2708 if (parent->count == parent->hdr.maxcount )
2710 /* maximum number of arguments exceeded */
2711 errorcode = EMAXCOUNT;
2715 /* a valid argument with no argument value was given. */
2716 /* This happens when an optional argument value was invoked. */
2717 /* leave parent argument value unaltered but still count the argument. */
2722 struct privhdr *priv = (struct privhdr *)parent->hdr.priv;
2724 /* test the current argument value for a match with the regular expression */
2725 /* if a match is detected, record the argument value in the arg_rex struct */
2727 rex = trex_compile(priv->pattern, &error, priv->flags);
2728 is_match = trex_match(rex, argval);
2730 errorcode = EREGNOMATCH;
2732 parent->sval[parent->count++] = argval;
2737 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode));
2741 static int arg_rex_checkfn(struct arg_rex *parent)
2743 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2744 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2746 /* free the regex "program" we constructed in resetfn */
2747 //regfree(&(priv->regex));
2749 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2753 static void arg_rex_errorfn(struct arg_rex *parent,
2757 const char *progname)
2759 const char *shortopts = parent->hdr.shortopts;
2760 const char *longopts = parent->hdr.longopts;
2761 const char *datatype = parent->hdr.datatype;
2763 /* make argval NULL safe */
2764 argval = argval ? argval : "";
2766 fprintf(fp, "%s: ", progname);
2770 fputs("missing option ", fp);
2771 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2775 fputs("excess option ", fp);
2776 arg_print_option(fp, shortopts, longopts, argval, "\n");
2780 fputs("illegal value ", fp);
2781 arg_print_option(fp, shortopts, longopts, argval, "\n");
2786 //char errbuff[256];
2787 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2788 //printf("%s\n", errbuff);
2795 struct arg_rex * arg_rex0(const char * shortopts,
2796 const char * longopts,
2797 const char * pattern,
2798 const char *datatype,
2800 const char *glossary)
2802 return arg_rexn(shortopts,
2812 struct arg_rex * arg_rex1(const char * shortopts,
2813 const char * longopts,
2814 const char * pattern,
2815 const char *datatype,
2817 const char *glossary)
2819 return arg_rexn(shortopts,
2830 struct arg_rex * arg_rexn(const char * shortopts,
2831 const char * longopts,
2832 const char * pattern,
2833 const char *datatype,
2837 const char *glossary)
2840 struct arg_rex *result;
2841 struct privhdr *priv;
2843 const TRexChar *error = NULL;
2849 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2850 printf("argtable: Bad argument table.\n");
2854 /* foolproof things by ensuring maxcount is not less than mincount */
2855 maxcount = (maxcount < mincount) ? mincount : maxcount;
2857 nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */
2858 + sizeof(struct privhdr) /* storage for private arg_rex data */
2859 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
2861 result = (struct arg_rex *)malloc(nbytes);
2865 /* init the arg_hdr struct */
2866 result->hdr.flag = ARG_HASVALUE;
2867 result->hdr.shortopts = shortopts;
2868 result->hdr.longopts = longopts;
2869 result->hdr.datatype = datatype ? datatype : pattern;
2870 result->hdr.glossary = glossary;
2871 result->hdr.mincount = mincount;
2872 result->hdr.maxcount = maxcount;
2873 result->hdr.parent = result;
2874 result->hdr.resetfn = (arg_resetfn *)arg_rex_resetfn;
2875 result->hdr.scanfn = (arg_scanfn *)arg_rex_scanfn;
2876 result->hdr.checkfn = (arg_checkfn *)arg_rex_checkfn;
2877 result->hdr.errorfn = (arg_errorfn *)arg_rex_errorfn;
2879 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2880 result->hdr.priv = result + 1;
2881 priv = (struct privhdr *)(result->hdr.priv);
2882 priv->pattern = pattern;
2883 priv->flags = flags;
2885 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2886 result->sval = (const char * *)(priv + 1);
2889 /* foolproof the string pointers by initializing them to reference empty strings */
2890 for (i = 0; i < maxcount; i++)
2891 result->sval[i] = "";
2893 /* here we construct and destroy a regex representation of the regular
2894 * expression for no other reason than to force any regex errors to be
2895 * trapped now rather than later. If we don't, then errors may go undetected
2896 * until an argument is actually parsed.
2899 rex = trex_compile(priv->pattern, &error, priv->flags);
2902 ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
2903 ARG_LOG(("argtable: Bad argument table.\n"));
2908 ARG_TRACE(("arg_rexn() returns %p\n", result));
2914 /* see copyright notice in trex.h */
2921 #define scisprint iswprint
2922 #define scstrlen wcslen
2923 #define scprintf wprintf
2926 #define scisprint isprint
2927 #define scstrlen strlen
2928 #define scprintf printf
2935 static const TRexChar *g_nnames[] =
2937 _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
2938 _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
2939 _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
2940 _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
2944 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2945 #define OP_OR (MAX_CHAR+2)
2946 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2947 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2948 #define OP_DOT (MAX_CHAR+5)
2949 #define OP_CLASS (MAX_CHAR+6)
2950 #define OP_CCLASS (MAX_CHAR+7)
2951 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2952 #define OP_RANGE (MAX_CHAR+9)
2953 #define OP_CHAR (MAX_CHAR+10)
2954 #define OP_EOL (MAX_CHAR+11)
2955 #define OP_BOL (MAX_CHAR+12)
2956 #define OP_WB (MAX_CHAR+13)
2958 #define TREX_SYMBOL_ANY_CHAR ('.')
2959 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
2960 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
2961 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
2962 #define TREX_SYMBOL_BRANCH ('|')
2963 #define TREX_SYMBOL_END_OF_STRING ('$')
2964 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
2965 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
2968 typedef int TRexNodeType;
2970 typedef struct tagTRexNode{
2978 const TRexChar *_eol;
2979 const TRexChar *_bol;
2987 TRexMatch *_matches;
2990 const TRexChar **_error;
2994 static int trex_list(TRex *exp);
2996 static int trex_newnode(TRex *exp, TRexNodeType type)
3001 n.next = n.right = n.left = -1;
3003 n.right = exp->_nsubexpr++;
3004 if(exp->_nallocated < (exp->_nsize + 1)) {
3005 exp->_nallocated *= 2;
3006 exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
3008 exp->_nodes[exp->_nsize++] = n;
3009 newid = exp->_nsize - 1;
3013 static void trex_error(TRex *exp,const TRexChar *error)
3015 if(exp->_error) *exp->_error = error;
3016 longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
3019 static void trex_expect(TRex *exp, int n){
3021 trex_error(exp, _SC("expected paren"));
3025 static TRexChar trex_escapechar(TRex *exp)
3027 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
3030 case 'v': exp->_p++; return '\v';
3031 case 'n': exp->_p++; return '\n';
3032 case 't': exp->_p++; return '\t';
3033 case 'r': exp->_p++; return '\r';
3034 case 'f': exp->_p++; return '\f';
3035 default: return (*exp->_p++);
3037 } else if(!scisprint((int) *exp->_p)) trex_error(exp,_SC("letter expected"));
3038 return (*exp->_p++);
3041 static int trex_charclass(TRex *exp,int classid)
3043 int n = trex_newnode(exp,OP_CCLASS);
3044 exp->_nodes[n].left = classid;
3048 static int trex_charnode(TRex *exp,TRexBool isclass)
3051 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
3054 case 'n': exp->_p++; return trex_newnode(exp,'\n');
3055 case 't': exp->_p++; return trex_newnode(exp,'\t');
3056 case 'r': exp->_p++; return trex_newnode(exp,'\r');
3057 case 'f': exp->_p++; return trex_newnode(exp,'\f');
3058 case 'v': exp->_p++; return trex_newnode(exp,'\v');
3059 case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
3060 case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
3061 case 'p': case 'P': case 'l': case 'u':
3063 t = *exp->_p; exp->_p++;
3064 return trex_charclass(exp,t);
3069 int node = trex_newnode(exp,OP_WB);
3070 exp->_nodes[node].left = *exp->_p;
3076 t = *exp->_p; exp->_p++;
3077 return trex_newnode(exp,t);
3080 else if(!scisprint((int) *exp->_p)) {
3082 trex_error(exp,_SC("letter expected"));
3084 t = *exp->_p; exp->_p++;
3085 return trex_newnode(exp,t);
3087 static int trex_class(TRex *exp)
3090 int first = -1,chain;
3091 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
3092 ret = trex_newnode(exp,OP_NCLASS);
3094 }else ret = trex_newnode(exp,OP_CLASS);
3096 if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
3098 while(*exp->_p != ']' && exp->_p != exp->_eol) {
3099 if(*exp->_p == '-' && first != -1){
3101 if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
3102 r = trex_newnode(exp,OP_RANGE);
3103 if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
3104 if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
3105 exp->_nodes[r].left = exp->_nodes[first].type;
3106 t = trex_escapechar(exp);
3107 exp->_nodes[r].right = t;
3108 exp->_nodes[chain].next = r;
3115 exp->_nodes[chain].next = c;
3117 first = trex_charnode(exp,TRex_True);
3120 first = trex_charnode(exp,TRex_True);
3126 exp->_nodes[chain].next = c;
3131 exp->_nodes[ret].left = exp->_nodes[ret].next;
3132 exp->_nodes[ret].next = -1;
3136 static int trex_parsenumber(TRex *exp)
3138 int ret = *exp->_p-'0';
3141 while(isdigit((int) *exp->_p)) {
3142 ret = ret*10+(*exp->_p++-'0');
3143 if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
3149 static int trex_element(TRex *exp)
3159 if(*exp->_p =='?') {
3161 trex_expect(exp,':');
3162 expr = trex_newnode(exp,OP_NOCAPEXPR);
3165 expr = trex_newnode(exp,OP_EXPR);
3166 newn = trex_list(exp);
3167 exp->_nodes[expr].left = newn;
3169 trex_expect(exp,')');
3174 ret = trex_class(exp);
3175 trex_expect(exp,']');
3177 case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
3178 case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
3180 ret = trex_charnode(exp,TRex_False);
3185 TRexBool isgreedy = TRex_False;
3186 unsigned short p0 = 0, p1 = 0;
3188 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3189 case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3190 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
3193 if(!isdigit((int) *exp->_p)) trex_error(exp,_SC("number expected"));
3194 p0 = (unsigned short)trex_parsenumber(exp);
3195 /*******************************/
3203 if(isdigit((int) *exp->_p)){
3204 p1 = (unsigned short)trex_parsenumber(exp);
3206 trex_expect(exp,'}');
3209 trex_error(exp,_SC(", or } expected"));
3211 /*******************************/
3212 isgreedy = TRex_True;
3217 int nnode = trex_newnode(exp,OP_GREEDY);
3218 exp->_nodes[nnode].left = ret;
3219 exp->_nodes[nnode].right = ((p0)<<16)|p1;
3223 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')) {
3224 int nnode = trex_element(exp);
3225 exp->_nodes[ret].next = nnode;
3231 static int trex_list(TRex *exp)
3234 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
3236 ret = trex_newnode(exp,OP_BOL);
3238 e = trex_element(exp);
3240 exp->_nodes[ret].next = e;
3244 if(*exp->_p == TREX_SYMBOL_BRANCH) {
3247 temp = trex_newnode(exp,OP_OR);
3248 exp->_nodes[temp].left = ret;
3249 tright = trex_list(exp);
3250 exp->_nodes[temp].right = tright;
3256 static TRexBool trex_matchcclass(int cclass,TRexChar ch)
3260 case 'a': return isalpha(c)?TRex_True:TRex_False;
3261 case 'A': return !isalpha(c)?TRex_True:TRex_False;
3262 case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
3263 case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
3264 case 's': return isspace(c)?TRex_True:TRex_False;
3265 case 'S': return !isspace(c)?TRex_True:TRex_False;
3266 case 'd': return isdigit(c)?TRex_True:TRex_False;
3267 case 'D': return !isdigit(c)?TRex_True:TRex_False;
3268 case 'x': return isxdigit(c)?TRex_True:TRex_False;
3269 case 'X': return !isxdigit(c)?TRex_True:TRex_False;
3270 case 'c': return iscntrl(c)?TRex_True:TRex_False;
3271 case 'C': return !iscntrl(c)?TRex_True:TRex_False;
3272 case 'p': return ispunct(c)?TRex_True:TRex_False;
3273 case 'P': return !ispunct(c)?TRex_True:TRex_False;
3274 case 'l': return islower(c)?TRex_True:TRex_False;
3275 case 'u': return isupper(c)?TRex_True:TRex_False;
3277 return TRex_False; /*cannot happen*/
3280 static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
3283 switch(node->type) {
3285 if (exp->_flags & TREX_ICASE)
3287 if(c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True;
3288 if(c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True;
3292 if(c >= node->left && c <= node->right) return TRex_True;
3296 if(trex_matchcclass(node->left,c)) return TRex_True;
3299 if (exp->_flags & TREX_ICASE)
3301 if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;
3305 if(c == node->type)return TRex_True;
3309 } while((node->next != -1) && (node = &exp->_nodes[node->next]));
3313 static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
3316 TRexNodeType type = node->type;
3319 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3320 TRexNode *greedystop = NULL;
3321 int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
3322 const TRexChar *s=str, *good = str;
3324 if(node->next != -1) {
3325 greedystop = &exp->_nodes[node->next];
3331 while((nmaches == 0xFFFF || nmaches < p1)) {
3333 const TRexChar *stop;
3334 if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
3339 //checks that 0 matches satisfy the expression(if so skips)
3340 //if not would always stop(for instance if is a '?')
3341 if(greedystop->type != OP_GREEDY ||
3342 (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
3344 TRexNode *gnext = NULL;
3345 if(greedystop->next != -1) {
3346 gnext = &exp->_nodes[greedystop->next];
3347 }else if(next && next->next != -1){
3348 gnext = &exp->_nodes[next->next];
3350 stop = trex_matchnode(exp,greedystop,s,gnext);
3352 //if satisfied stop it
3353 if(p0 == p1 && p0 == nmaches) break;
3354 else if(nmaches >= p0 && p1 == 0xFFFF) break;
3355 else if(nmaches >= p0 && nmaches <= p1) break;
3363 if(p0 == p1 && p0 == nmaches) return good;
3364 else if(nmaches >= p0 && p1 == 0xFFFF) return good;
3365 else if(nmaches >= p0 && nmaches <= p1) return good;
3369 const TRexChar *asd = str;
3370 TRexNode *temp=&exp->_nodes[node->left];
3371 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3372 if(temp->next != -1)
3373 temp = &exp->_nodes[temp->next];
3378 temp = &exp->_nodes[node->right];
3379 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3380 if(temp->next != -1)
3381 temp = &exp->_nodes[temp->next];
3390 TRexNode *n = &exp->_nodes[node->left];
3391 const TRexChar *cur = str;
3393 if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
3394 capture = exp->_currsubexp;
3395 exp->_matches[capture].begin = cur;
3400 TRexNode *subnext = NULL;
3402 subnext = &exp->_nodes[n->next];
3406 if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
3408 exp->_matches[capture].begin = 0;
3409 exp->_matches[capture].len = 0;
3413 } while((n->next != -1) && (n = &exp->_nodes[n->next]));
3416 exp->_matches[capture].len = cur - exp->_matches[capture].begin;
3420 if((str == exp->_bol && !isspace((int) *str))
3421 || ((str == exp->_eol && !isspace((int) *(str-1))))
3422 || ((!isspace((int) *str) && isspace((int) *(str+1))))
3423 || ((isspace((int) *str) && !isspace((int) *(str+1)))) ) {
3424 return (node->left == 'b')?str:NULL;
3426 return (node->left == 'b')?NULL:str;
3428 if(str == exp->_bol) return str;
3431 if(str == exp->_eol) return str;
3438 if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
3444 if(trex_matchcclass(node->left,*str)) {
3450 if (exp->_flags & TREX_ICASE)
3452 if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL;
3456 if (*str != node->type) return NULL;
3465 TRex *trex_compile(const TRexChar *pattern,const TRexChar **error,int flags)
3467 TRex *exp = (TRex *)malloc(sizeof(TRex));
3468 exp->_eol = exp->_bol = NULL;
3470 exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
3471 exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
3475 exp->_first = trex_newnode(exp,OP_EXPR);
3476 exp->_error = error;
3477 exp->_jmpbuf = malloc(sizeof(jmp_buf));
3478 exp->_flags = flags;
3479 if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
3480 int res = trex_list(exp);
3481 exp->_nodes[exp->_first].left = res;
3483 trex_error(exp,_SC("unexpected character"));
3488 nsize = exp->_nsize;
3489 t = &exp->_nodes[0];
3490 scprintf(_SC("\n"));
3491 for(i = 0;i < nsize; i++) {
3492 if(exp->_nodes[i].type>MAX_CHAR)
3493 scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
3495 scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
3496 scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
3498 scprintf(_SC("\n"));
3501 exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
3502 memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
3511 void trex_free(TRex *exp)
3514 if(exp->_nodes) free(exp->_nodes);
3515 if(exp->_jmpbuf) free(exp->_jmpbuf);
3516 if(exp->_matches) free(exp->_matches);
3521 TRexBool trex_match(TRex* exp,const TRexChar* text)
3523 const TRexChar* res = NULL;
3525 exp->_eol = text + scstrlen(text);
3526 exp->_currsubexp = 0;
3527 res = trex_matchnode(exp,exp->_nodes,text,NULL);
3528 if(res == NULL || res != exp->_eol)
3533 TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
3535 const TRexChar *cur = NULL;
3536 int node = exp->_first;
3537 if(text_begin >= text_end) return TRex_False;
3538 exp->_bol = text_begin;
3539 exp->_eol = text_end;
3543 exp->_currsubexp = 0;
3544 cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
3547 node = exp->_nodes[node].next;
3550 } while(cur == NULL && text_begin != text_end);
3557 if(out_begin) *out_begin = text_begin;
3558 if(out_end) *out_end = cur;
3562 TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
3564 return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
3567 int trex_getsubexpcount(TRex* exp)
3569 return exp->_nsubexpr;
3572 TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
3574 if( n<0 || n >= exp->_nsubexpr) return TRex_False;
3575 *subexp = exp->_matches[n];
3578 /*******************************************************************************
3579 * This file is part of the argtable3 library.
3581 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3582 * <sheitmann@users.sourceforge.net>
3583 * All rights reserved.
3585 * Redistribution and use in source and binary forms, with or without
3586 * modification, are permitted provided that the following conditions are met:
3587 * * Redistributions of source code must retain the above copyright
3588 * notice, this list of conditions and the following disclaimer.
3589 * * Redistributions in binary form must reproduce the above copyright
3590 * notice, this list of conditions and the following disclaimer in the
3591 * documentation and/or other materials provided with the distribution.
3592 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3593 * may be used to endorse or promote products derived from this software
3594 * without specific prior written permission.
3596 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3597 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3598 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3599 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3600 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3601 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3602 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3603 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3604 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3605 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3606 ******************************************************************************/
3610 #include "argtable3.h"
3613 static void arg_str_resetfn(struct arg_str *parent)
3615 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
3620 static int arg_str_scanfn(struct arg_str *parent, const char *argval)
3624 if (parent->count == parent->hdr.maxcount)
3626 /* maximum number of arguments exceeded */
3627 errorcode = EMAXCOUNT;
3631 /* a valid argument with no argument value was given. */
3632 /* This happens when an optional argument value was invoked. */
3633 /* leave parent arguiment value unaltered but still count the argument. */
3638 parent->sval[parent->count++] = argval;
3641 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
3646 static int arg_str_checkfn(struct arg_str *parent)
3648 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
3650 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
3655 static void arg_str_errorfn(
3656 struct arg_str *parent,
3660 const char *progname)
3662 const char *shortopts = parent->hdr.shortopts;
3663 const char *longopts = parent->hdr.longopts;
3664 const char *datatype = parent->hdr.datatype;
3666 /* make argval NULL safe */
3667 argval = argval ? argval : "";
3669 fprintf(fp, "%s: ", progname);
3673 fputs("missing option ", fp);
3674 arg_print_option(fp, shortopts, longopts, datatype, "\n");
3678 fputs("excess option ", fp);
3679 arg_print_option(fp, shortopts, longopts, argval, "\n");
3685 struct arg_str * arg_str0(
3686 const char *shortopts,
3687 const char *longopts,
3688 const char *datatype,
3689 const char *glossary)
3691 return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
3695 struct arg_str * arg_str1(
3696 const char *shortopts,
3697 const char *longopts,
3698 const char *datatype,
3699 const char *glossary)
3701 return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
3705 struct arg_str * arg_strn(
3706 const char *shortopts,
3707 const char *longopts,
3708 const char *datatype,
3711 const char *glossary)
3714 struct arg_str *result;
3716 /* should not allow this stupid error */
3717 /* we should return an error code warning this logic error */
3718 /* foolproof things by ensuring maxcount is not less than mincount */
3719 maxcount = (maxcount < mincount) ? mincount : maxcount;
3721 nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
3722 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
3724 result = (struct arg_str *)malloc(nbytes);
3729 /* init the arg_hdr struct */
3730 result->hdr.flag = ARG_HASVALUE;
3731 result->hdr.shortopts = shortopts;
3732 result->hdr.longopts = longopts;
3733 result->hdr.datatype = datatype ? datatype : "<string>";
3734 result->hdr.glossary = glossary;
3735 result->hdr.mincount = mincount;
3736 result->hdr.maxcount = maxcount;
3737 result->hdr.parent = result;
3738 result->hdr.resetfn = (arg_resetfn *)arg_str_resetfn;
3739 result->hdr.scanfn = (arg_scanfn *)arg_str_scanfn;
3740 result->hdr.checkfn = (arg_checkfn *)arg_str_checkfn;
3741 result->hdr.errorfn = (arg_errorfn *)arg_str_errorfn;
3743 /* store the sval[maxcount] array immediately after the arg_str struct */
3744 result->sval = (const char * *)(result + 1);
3747 /* foolproof the string pointers by initialising them to reference empty strings */
3748 for (i = 0; i < maxcount; i++)
3749 result->sval[i] = "";
3752 ARG_TRACE(("arg_strn() returns %p\n", result));
3755 /*******************************************************************************
3756 * This file is part of the argtable3 library.
3758 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3759 * <sheitmann@users.sourceforge.net>
3760 * All rights reserved.
3762 * Redistribution and use in source and binary forms, with or without
3763 * modification, are permitted provided that the following conditions are met:
3764 * * Redistributions of source code must retain the above copyright
3765 * notice, this list of conditions and the following disclaimer.
3766 * * Redistributions in binary form must reproduce the above copyright
3767 * notice, this list of conditions and the following disclaimer in the
3768 * documentation and/or other materials provided with the distribution.
3769 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3770 * may be used to endorse or promote products derived from this software
3771 * without specific prior written permission.
3773 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3774 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3775 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3776 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3777 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3778 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3779 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3780 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3781 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3782 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3783 ******************************************************************************/
3790 #include "argtable3.h"
3793 void arg_register_error(struct arg_end *end,
3798 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3799 if (end->count < end->hdr.maxcount)
3801 end->error[end->count] = error;
3802 end->parent[end->count] = parent;
3803 end->argval[end->count] = argval;
3808 end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;
3809 end->parent[end->hdr.maxcount - 1] = end;
3810 end->argval[end->hdr.maxcount - 1] = NULL;
3816 * Return index of first table entry with a matching short option
3817 * or -1 if no match was found.
3820 int find_shortoption(struct arg_hdr * *table, char shortopt)
3823 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3825 if (table[tabindex]->shortopts &&
3826 strchr(table[tabindex]->shortopts, shortopt))
3837 struct option *options;
3842 void dump_longoptions(struct longoptions * longoptions)
3845 printf("getoptval = %d\n", longoptions->getoptval);
3846 printf("noptions = %d\n", longoptions->noptions);
3847 for (i = 0; i < longoptions->noptions; i++)
3849 printf("options[%d].name = \"%s\"\n",
3851 longoptions->options[i].name);
3852 printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);
3853 printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);
3854 printf("options[%d].val = %d\n", i, longoptions->options[i].val);
3860 struct longoptions * alloc_longoptions(struct arg_hdr * *table)
3862 struct longoptions *result;
3865 size_t longoptlen = 0;
3869 * Determine the total number of option structs required
3870 * by counting the number of comma separated long options
3871 * in all table entries and return the count in noptions.
3872 * note: noptions starts at 1 not 0 because we getoptlong
3873 * requires a NULL option entry to terminate the option array.
3874 * While we are at it, count the number of chars required
3875 * to store private copies of all the longoption strings
3876 * and return that count in logoptlen.
3881 const char *longopts = table[tabindex]->longopts;
3882 longoptlen += (longopts ? strlen(longopts) : 0) + 1;
3886 longopts = strchr(longopts + 1, ',');
3888 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
3889 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3892 /* allocate storage for return data structure as: */
3893 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3894 nbytes = sizeof(struct longoptions)
3895 + sizeof(struct option) * noptions
3897 result = (struct longoptions *)malloc(nbytes);
3900 int option_index = 0;
3903 result->getoptval = 0;
3904 result->noptions = noptions;
3905 result->options = (struct option *)(result + 1);
3906 store = (char *)(result->options + noptions);
3908 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3910 const char *longopts = table[tabindex]->longopts;
3912 while(longopts && *longopts)
3914 char *storestart = store;
3916 /* copy progressive longopt strings into the store */
3917 while (*longopts != 0 && *longopts != ',')
3918 *store++ = *longopts++;
3920 if (*longopts == ',')
3922 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3924 result->options[option_index].name = storestart;
3925 result->options[option_index].flag = &(result->getoptval);
3926 result->options[option_index].val = tabindex;
3927 if (table[tabindex]->flag & ARG_HASOPTVALUE)
3928 result->options[option_index].has_arg = 2;
3929 else if (table[tabindex]->flag & ARG_HASVALUE)
3930 result->options[option_index].has_arg = 1;
3932 result->options[option_index].has_arg = 0;
3937 /* terminate the options array with a zero-filled entry */
3938 result->options[option_index].name = 0;
3939 result->options[option_index].has_arg = 0;
3940 result->options[option_index].flag = 0;
3941 result->options[option_index].val = 0;
3944 /*dump_longoptions(result);*/
3949 char * alloc_shortoptions(struct arg_hdr * *table)
3955 /* determine the total number of option chars required */
3956 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3958 struct arg_hdr *hdr = table[tabindex];
3959 len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);
3962 result = malloc(len);
3967 /* add a leading ':' so getopt return codes distinguish */
3968 /* unrecognised option and options missing argument values */
3971 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3973 struct arg_hdr *hdr = table[tabindex];
3974 const char *shortopts = hdr->shortopts;
3975 while(shortopts && *shortopts)
3977 *res++ = *shortopts++;
3978 if (hdr->flag & ARG_HASVALUE)
3980 if (hdr->flag & ARG_HASOPTVALUE)
3984 /* null terminate the string */
3988 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
3993 /* return index of the table terminator entry */
3995 int arg_endindex(struct arg_hdr * *table)
3998 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4005 void arg_parse_tagged(int argc,
4007 struct arg_hdr * *table,
4008 struct arg_end *endtable)
4010 struct longoptions *longoptions;
4014 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4016 /* allocate short and long option arrays for the given opttable[]. */
4017 /* if the allocs fail then put an error msg in the last table entry. */
4018 longoptions = alloc_longoptions(table);
4019 shortoptions = alloc_shortoptions(table);
4020 if (!longoptions || !shortoptions)
4022 /* one or both memory allocs failed */
4023 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4024 /* free anything that was allocated (this is null safe) */
4030 /*dump_longoptions(longoptions);*/
4032 /* reset getopts internal option-index to zero, and disable error reporting */
4036 /* fetch and process args using getopt_long */
4038 getopt_long(argc, argv, shortoptions, longoptions->options,
4042 printf("optarg='%s'\n",optarg);
4043 printf("optind=%d\n",optind);
4044 printf("copt=%c\n",(char)copt);
4045 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
4051 int tabindex = longoptions->getoptval;
4052 void *parent = table[tabindex]->parent;
4053 /*printf("long option detected from argtable[%d]\n", tabindex);*/
4054 if (optarg && optarg[0] == 0 &&
4055 (table[tabindex]->flag & ARG_HASVALUE))
4057 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
4058 arg_register_error(endtable, endtable, ARG_EMISSARG,
4060 /* continue to scan the (empty) argument value to enforce argument count checking */
4062 if (table[tabindex]->scanfn)
4064 int errorcode = table[tabindex]->scanfn(parent, optarg);
4066 arg_register_error(endtable, parent, errorcode, optarg);
4073 * getopt_long() found an unrecognised short option.
4074 * if it was a short option its value is in optopt
4075 * if it was a long option then optopt=0
4080 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4081 arg_register_error(endtable, endtable, ARG_ELONGOPT,
4085 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4086 arg_register_error(endtable, endtable, optopt, NULL);
4093 * getopt_long() found an option with its argument missing.
4095 /*printf(": option %s requires an argument\n",argv[optind-1]); */
4096 arg_register_error(endtable, endtable, ARG_EMISSARG,
4102 /* getopt_long() found a valid short option */
4103 int tabindex = find_shortoption(table, (char)copt);
4104 /*printf("short option detected from argtable[%d]\n", tabindex);*/
4107 /* should never get here - but handle it just in case */
4108 /*printf("unrecognised short option %d\n",copt);*/
4109 arg_register_error(endtable, endtable, copt, NULL);
4113 if (table[tabindex]->scanfn)
4115 void *parent = table[tabindex]->parent;
4116 int errorcode = table[tabindex]->scanfn(parent, optarg);
4118 arg_register_error(endtable, parent, errorcode, optarg);
4132 void arg_parse_untagged(int argc,
4134 struct arg_hdr * *table,
4135 struct arg_end *endtable)
4139 const char *optarglast = NULL;
4140 void *parentlast = NULL;
4142 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4143 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4148 /* if we have exhausted our argv[optind] entries then we have finished */
4151 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4155 /* skip table entries with non-null long or short options (they are not untagged entries) */
4156 if (table[tabindex]->longopts || table[tabindex]->shortopts)
4158 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
4163 /* skip table entries with NULL scanfn */
4164 if (!(table[tabindex]->scanfn))
4166 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4171 /* attempt to scan the current argv[optind] with the current */
4172 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
4173 /* try again with the next table[] entry. */
4174 parent = table[tabindex]->parent;
4175 errorcode = table[tabindex]->scanfn(parent, argv[optind]);
4178 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4179 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4182 /* clear the last tentative error */
4187 /* failure, try same argv[optind] with next table[tabindex] entry */
4188 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4191 /* remember this as a tentative error we may wish to reinstate later */
4192 errorlast = errorcode;
4193 optarglast = argv[optind];
4194 parentlast = parent;
4199 /* if a tenative error still remains at this point then register it as a proper error */
4202 arg_register_error(endtable, parentlast, errorlast, optarglast);
4206 /* only get here when not all argv[] entries were consumed */
4207 /* register an error for each unused argv[] entry */
4208 while (optind < argc)
4210 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4211 arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
4219 void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable)
4222 /* printf("arg_parse_check()\n"); */
4225 if (table[tabindex]->checkfn)
4227 void *parent = table[tabindex]->parent;
4228 int errorcode = table[tabindex]->checkfn(parent);
4230 arg_register_error(endtable, parent, errorcode, NULL);
4232 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4237 void arg_reset(void * *argtable)
4239 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4241 /*printf("arg_reset(%p)\n",argtable);*/
4244 if (table[tabindex]->resetfn)
4245 table[tabindex]->resetfn(table[tabindex]->parent);
4246 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4250 int arg_parse(int argc, char * *argv, void * *argtable)
4252 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4253 struct arg_end *endtable;
4255 char * *argvcopy = NULL;
4257 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4259 /* reset any argtable data from previous invocations */
4260 arg_reset(argtable);
4262 /* locate the first end-of-table marker within the array */
4263 endindex = arg_endindex(table);
4264 endtable = (struct arg_end *)table[endindex];
4266 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4267 /* Failure to trap this case results in an unwanted NULL result from */
4268 /* the malloc for argvcopy (next code block). */
4271 /* We must still perform post-parse checks despite the absence of command line arguments */
4272 arg_parse_check(table, endtable);
4274 /* Now we are finished */
4275 return endtable->count;
4278 argvcopy = (char **)malloc(sizeof(char *) * (argc + 1));
4284 Fill in the local copy of argv[]. We need a local copy
4285 because getopt rearranges argv[] which adversely affects
4286 susbsequent parsing attempts.
4288 for (i = 0; i < argc; i++)
4289 argvcopy[i] = argv[i];
4291 argvcopy[argc] = NULL;
4293 /* parse the command line (local copy) for tagged options */
4294 arg_parse_tagged(argc, argvcopy, table, endtable);
4296 /* parse the command line (local copy) for untagged options */
4297 arg_parse_untagged(argc, argvcopy, table, endtable);
4299 /* if no errors so far then perform post-parse checks otherwise dont bother */
4300 if (endtable->count == 0)
4301 arg_parse_check(table, endtable);
4303 /* release the local copt of argv[] */
4308 /* memory alloc failed */
4309 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4312 return endtable->count;
4317 * Concatenate contents of src[] string onto *pdest[] string.
4318 * The *pdest pointer is altered to point to the end of the
4319 * target string and *pndest is decremented by the same number
4321 * Does not append more than *pndest chars into *pdest[]
4322 * so as to prevent buffer overruns.
4323 * Its something like strncat() but more efficient for repeated
4324 * calls on the same destination string.
4326 * char dest[30] = "good"
4327 * size_t ndest = sizeof(dest);
4328 * char *pdest = dest;
4329 * arg_char(&pdest,"bye ",&ndest);
4330 * arg_char(&pdest,"cruel ",&ndest);
4331 * arg_char(&pdest,"world!",&ndest);
4333 * dest[] == "goodbye cruel world!"
4337 void arg_cat(char * *pdest, const char *src, size_t *pndest)
4339 char *dest = *pdest;
4340 char *end = dest + *pndest;
4342 /*locate null terminator of dest string */
4343 while(dest < end && *dest != 0)
4346 /* concat src string to dest string */
4347 while(dest < end && *src != 0)
4350 /* null terminate dest string */
4353 /* update *pdest and *pndest */
4354 *pndest = end - dest;
4360 void arg_cat_option(char *dest,
4362 const char *shortopts,
4363 const char *longopts,
4364 const char *datatype,
4371 /* note: option array[] is initialiazed dynamically here to satisfy */
4372 /* a deficiency in the watcom compiler wrt static array initializers. */
4374 option[1] = shortopts[0];
4377 arg_cat(&dest, option, &ndest);
4380 arg_cat(&dest, " ", &ndest);
4383 arg_cat(&dest, "[", &ndest);
4384 arg_cat(&dest, datatype, &ndest);
4385 arg_cat(&dest, "]", &ndest);
4388 arg_cat(&dest, datatype, &ndest);
4395 /* add "--" tag prefix */
4396 arg_cat(&dest, "--", &ndest);
4398 /* add comma separated option tag */
4399 ncspn = strcspn(longopts, ",");
4400 strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
4404 arg_cat(&dest, "=", &ndest);
4407 arg_cat(&dest, "[", &ndest);
4408 arg_cat(&dest, datatype, &ndest);
4409 arg_cat(&dest, "]", &ndest);
4412 arg_cat(&dest, datatype, &ndest);
4419 arg_cat(&dest, "[", &ndest);
4420 arg_cat(&dest, datatype, &ndest);
4421 arg_cat(&dest, "]", &ndest);
4424 arg_cat(&dest, datatype, &ndest);
4429 void arg_cat_optionv(char *dest,
4431 const char *shortopts,
4432 const char *longopts,
4433 const char *datatype,
4435 const char *separator)
4437 separator = separator ? separator : "";
4441 const char *c = shortopts;
4447 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4448 /* a deficiency in the watcom compiler wrt static array initializers. */
4453 arg_cat(&dest, shortopt, &ndest);
4455 arg_cat(&dest, separator, &ndest);
4459 /* put separator between long opts and short opts */
4460 if (shortopts && longopts)
4461 arg_cat(&dest, separator, &ndest);
4465 const char *c = longopts;
4470 /* add "--" tag prefix */
4471 arg_cat(&dest, "--", &ndest);
4473 /* add comma separated option tag */
4474 ncspn = strcspn(c, ",");
4475 strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
4478 /* add given separator in place of comma */
4481 arg_cat(&dest, separator, &ndest);
4490 arg_cat(&dest, "=", &ndest);
4492 arg_cat(&dest, " ", &ndest);
4496 arg_cat(&dest, "[", &ndest);
4497 arg_cat(&dest, datatype, &ndest);
4498 arg_cat(&dest, "]", &ndest);
4501 arg_cat(&dest, datatype, &ndest);
4506 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4507 void arg_print_option(FILE *fp,
4508 const char *shortopts,
4509 const char *longopts,
4510 const char *datatype,
4513 char syntax[200] = "";
4514 suffix = suffix ? suffix : "";
4516 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4517 arg_cat_optionv(syntax,
4531 * Print a GNU style [OPTION] string in which all short options that
4532 * do not take argument values are presented in abbreviated form, as
4533 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4536 void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table)
4539 const char *format1 = " -%c";
4540 const char *format2 = " [-%c";
4541 const char *suffix = "";
4543 /* print all mandatory switches that are without argument values */
4545 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4548 /* skip optional options */
4549 if (table[tabindex]->mincount < 1)
4552 /* skip non-short options */
4553 if (table[tabindex]->shortopts == NULL)
4556 /* skip options that take argument values */
4557 if (table[tabindex]->flag & ARG_HASVALUE)
4560 /* print the short option (only the first short option char, ignore multiple choices)*/
4561 fprintf(fp, format1, table[tabindex]->shortopts[0]);
4566 /* print all optional switches that are without argument values */
4568 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4571 /* skip mandatory args */
4572 if (table[tabindex]->mincount > 0)
4575 /* skip args without short options */
4576 if (table[tabindex]->shortopts == NULL)
4579 /* skip args with values */
4580 if (table[tabindex]->flag & ARG_HASVALUE)
4583 /* print first short option */
4584 fprintf(fp, format2, table[tabindex]->shortopts[0]);
4589 fprintf(fp, "%s", suffix);
4593 void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix)
4595 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4598 /* print GNU style [OPTION] string */
4599 arg_print_gnuswitch(fp, table);
4601 /* print remaining options in abbreviated style */
4603 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4606 char syntax[200] = "";
4607 const char *shortopts, *longopts, *datatype;
4609 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4610 if (table[tabindex]->shortopts &&
4611 !(table[tabindex]->flag & ARG_HASVALUE))
4614 shortopts = table[tabindex]->shortopts;
4615 longopts = table[tabindex]->longopts;
4616 datatype = table[tabindex]->datatype;
4617 arg_cat_option(syntax,
4622 table[tabindex]->flag & ARG_HASOPTVALUE);
4624 if (strlen(syntax) > 0)
4626 /* print mandatory instances of this option */
4627 for (i = 0; i < table[tabindex]->mincount; i++)
4628 fprintf(fp, " %s", syntax);
4630 /* print optional instances enclosed in "[..]" */
4631 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4636 fprintf(fp, " [%s]", syntax);
4639 fprintf(fp, " [%s] [%s]", syntax, syntax);
4642 fprintf(fp, " [%s]...", syntax);
4649 fprintf(fp, "%s", suffix);
4653 void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix)
4655 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4658 /* print remaining options in abbreviated style */
4660 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4663 char syntax[200] = "";
4664 const char *shortopts, *longopts, *datatype;
4666 shortopts = table[tabindex]->shortopts;
4667 longopts = table[tabindex]->longopts;
4668 datatype = table[tabindex]->datatype;
4669 arg_cat_optionv(syntax,
4674 table[tabindex]->flag & ARG_HASOPTVALUE,
4677 /* print mandatory options */
4678 for (i = 0; i < table[tabindex]->mincount; i++)
4679 fprintf(fp, " %s", syntax);
4681 /* print optional args enclosed in "[..]" */
4682 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4687 fprintf(fp, " [%s]", syntax);
4690 fprintf(fp, " [%s] [%s]", syntax, syntax);
4693 fprintf(fp, " [%s]...", syntax);
4699 fprintf(fp, "%s", suffix);
4703 void arg_print_glossary(FILE *fp, void * *argtable, const char *format)
4705 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4708 format = format ? format : " %-20s %s\n";
4709 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4711 if (table[tabindex]->glossary)
4713 char syntax[200] = "";
4714 const char *shortopts = table[tabindex]->shortopts;
4715 const char *longopts = table[tabindex]->longopts;
4716 const char *datatype = table[tabindex]->datatype;
4717 const char *glossary = table[tabindex]->glossary;
4718 arg_cat_optionv(syntax,
4723 table[tabindex]->flag & ARG_HASOPTVALUE,
4725 fprintf(fp, format, syntax, glossary);
4732 * Print a piece of text formatted, which means in a column with a
4733 * left and a right margin. The lines are wrapped at whitspaces next
4734 * to right margin. The function does not indent the first line, but
4735 * only the following ones.
4738 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4739 * will result in the following output:
4747 * Too long lines will be wrapped in the middle of a word.
4749 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4750 * will result in the following output:
4758 * As you see, the first line is not indented. This enables output of
4759 * lines, which start in a line where output already happened.
4761 * Author: Uli Fouquet
4763 void arg_print_formatted( FILE *fp,
4764 const unsigned lmargin,
4765 const unsigned rmargin,
4768 const unsigned textlen = strlen( text );
4769 unsigned line_start = 0;
4770 unsigned line_end = textlen + 1;
4771 const unsigned colwidth = (rmargin - lmargin) + 1;
4773 /* Someone doesn't like us... */
4774 if ( line_end < line_start )
4775 { fprintf( fp, "%s\n", text ); }
4777 while (line_end - 1 > line_start )
4779 /* Eat leading whitespaces. This is essential because while
4780 wrapping lines, there will often be a whitespace at beginning
4782 while ( isspace((int) *(text + line_start)) )
4785 if ((line_end - line_start) > colwidth )
4786 { line_end = line_start + colwidth; }
4788 /* Find last whitespace, that fits into line */
4789 while ( ( line_end > line_start )
4790 && ( line_end - line_start > colwidth )
4791 && !isspace((int) *(text + line_end)))
4794 /* Do not print trailing whitespace. If this text
4795 has got only one line, line_end now points to the
4796 last char due to initialization. */
4799 /* Output line of text */
4800 while ( line_start < line_end )
4802 fputc(*(text + line_start), fp );
4807 /* Initialize another line */
4808 if ( line_end + 1 < textlen )
4812 for (i = 0; i < lmargin; i++ )
4813 { fputc( ' ', fp ); }
4818 /* If we have to print another line, get also the last char. */
4821 } /* lines of text */
4825 * Prints the glossary in strict GNU format.
4826 * Differences to arg_print_glossary() are:
4827 * - wraps lines after 80 chars
4828 * - indents lines without shortops
4829 * - does not accept formatstrings
4831 * Contributed by Uli Fouquet
4833 void arg_print_glossary_gnu(FILE *fp, void * *argtable )
4835 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4838 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4840 if (table[tabindex]->glossary)
4842 char syntax[200] = "";
4843 const char *shortopts = table[tabindex]->shortopts;
4844 const char *longopts = table[tabindex]->longopts;
4845 const char *datatype = table[tabindex]->datatype;
4846 const char *glossary = table[tabindex]->glossary;
4848 if ( !shortopts && longopts )
4850 /* Indent trailing line by 4 spaces... */
4851 memset( syntax, ' ', 4 );
4852 *(syntax + 4) = '\0';
4855 arg_cat_optionv(syntax,
4860 table[tabindex]->flag & ARG_HASOPTVALUE,
4863 /* If syntax fits not into column, print glossary in new line... */
4864 if ( strlen(syntax) > 25 )
4866 fprintf( fp, " %-25s %s\n", syntax, "" );
4870 fprintf( fp, " %-25s ", syntax );
4871 arg_print_formatted( fp, 28, 79, glossary );
4873 } /* for each table entry */
4880 * Checks the argtable[] array for NULL entries and returns 1
4881 * if any are found, zero otherwise.
4883 int arg_nullcheck(void * *argtable)
4885 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4887 /*printf("arg_nullcheck(%p)\n",argtable);*/
4895 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4896 if (!table[tabindex])
4898 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4905 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4906 * The flaw results in memory leak in the (very rare) case that an intermediate
4907 * entry in the argtable array failed its memory allocation while others following
4908 * that entry were still allocated ok. Those subsequent allocations will not be
4909 * deallocated by arg_free().
4910 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4911 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4912 * with the newer arg_freetable() function.
4913 * We still keep arg_free() for backwards compatibility.
4915 void arg_free(void * *argtable)
4917 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4920 /*printf("arg_free(%p)\n",argtable);*/
4924 if we encounter a NULL entry then somewhat incorrectly we presume
4925 we have come to the end of the array. It isnt strictly true because
4926 an intermediate entry could be NULL with other non-NULL entries to follow.
4927 The subsequent argtable entries would then not be freed as they should.
4929 if (table[tabindex] == NULL)
4932 flag = table[tabindex]->flag;
4933 free(table[tabindex]);
4934 table[tabindex++] = NULL;
4936 } while(!(flag & ARG_TERMINATOR));
4939 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4940 void arg_freetable(void * *argtable, size_t n)
4942 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4943 size_t tabindex = 0;
4944 /*printf("arg_freetable(%p)\n",argtable);*/
4945 for (tabindex = 0; tabindex < n; tabindex++)
4947 if (table[tabindex] == NULL)
4950 free(table[tabindex]);
4951 table[tabindex] = NULL;