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 #pragma GCC diagnostic ignored "-Wclobbered"
35 /*******************************************************************************
36 * This file is part of the argtable3 library.
38 * Copyright (C) 2013 Tom G. Huang
39 * <tomghuang@gmail.com>
40 * All rights reserved.
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions are met:
44 * * Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * * Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * * Neither the name of STEWART HEITMANN nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
57 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
58 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
59 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
60 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
62 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 ******************************************************************************/
68 #define ARG_ENABLE_TRACE 0
69 #define ARG_ENABLE_LOG 1
88 #define ARG_TRACE(x) \
89 __pragma(warning(push)) \
90 __pragma(warning(disable:4127)) \
91 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \
92 __pragma(warning(pop))
95 __pragma(warning(push)) \
96 __pragma(warning(disable:4127)) \
97 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
98 __pragma(warning(pop))
100 #define ARG_TRACE(x) \
101 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
104 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
107 extern void dbg_printf(const char *fmt, ...);
115 /*******************************************************************************
116 * This file is part of the argtable3 library.
118 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
119 * <sheitmann@users.sourceforge.net>
120 * All rights reserved.
122 * Redistribution and use in source and binary forms, with or without
123 * modification, are permitted provided that the following conditions are met:
124 * * Redistributions of source code must retain the above copyright
125 * notice, this list of conditions and the following disclaimer.
126 * * Redistributions in binary form must reproduce the above copyright
127 * notice, this list of conditions and the following disclaimer in the
128 * documentation and/or other materials provided with the distribution.
129 * * Neither the name of STEWART HEITMANN nor the names of its contributors
130 * may be used to endorse or promote products derived from this software
131 * without specific prior written permission.
133 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
134 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
135 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
136 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
137 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
138 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
139 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
140 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
141 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
142 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
143 ******************************************************************************/
149 void dbg_printf(const char *fmt, ...)
153 vfprintf(stderr, fmt, args);
157 /* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
158 /* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */
159 /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
162 * Copyright (c) 2000 The NetBSD Foundation, Inc.
163 * All rights reserved.
165 * This code is derived from software contributed to The NetBSD Foundation
166 * by Dieter Baron and Thomas Klausner.
168 * Redistribution and use in source and binary forms, with or without
169 * modification, are permitted provided that the following conditions
171 * 1. Redistributions of source code must retain the above copyright
172 * notice, this list of conditions and the following disclaimer.
173 * 2. Redistributions in binary form must reproduce the above copyright
174 * notice, this list of conditions and the following disclaimer in the
175 * documentation and/or other materials provided with the distribution.
176 * 3. All advertising materials mentioning features or use of this software
177 * must display the following acknowledgement:
178 * This product includes software developed by the NetBSD
179 * Foundation, Inc. and its contributors.
180 * 4. Neither the name of The NetBSD Foundation nor the names of its
181 * contributors may be used to endorse or promote products derived
182 * from this software without specific prior written permission.
184 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
185 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
186 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
187 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
188 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
189 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
190 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
191 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
192 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
193 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
194 * POSSIBILITY OF SUCH DAMAGE.
201 #include <sys/cdefs.h>
205 * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
207 #define no_argument 0
208 #define required_argument 1
209 #define optional_argument 2
212 /* name of long option */
215 * one of no_argument, required_argument, and optional_argument:
216 * whether option takes an argument
219 /* if not NULL, set *flag to val when option found */
221 /* if flag not NULL, value to set *flag to; else return value */
229 int getopt_long(int, char * const *, const char *,
230 const struct option *, int *);
231 int getopt_long_only(int, char * const *, const char *,
232 const struct option *, int *);
233 #ifndef _GETOPT_DEFINED
234 #define _GETOPT_DEFINED
235 int getopt(int, char * const *, const char *);
236 int getsubopt(char **, char * const *, char **);
238 extern char *optarg; /* getopt(3) external variables */
243 extern char *suboptarg; /* getsubopt(3) external variable */
244 #endif /* _GETOPT_DEFINED */
249 #endif /* !_GETOPT_H_ */
250 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
251 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
252 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
255 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
257 * Permission to use, copy, modify, and distribute this software for any
258 * purpose with or without fee is hereby granted, provided that the above
259 * copyright notice and this permission notice appear in all copies.
261 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
262 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
263 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
264 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
265 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
266 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
267 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
269 * Sponsored in part by the Defense Advanced Research Projects
270 * Agency (DARPA) and Air Force Research Laboratory, Air Force
271 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
275 //static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $";
278 * Copyright (c) 2000 The NetBSD Foundation, Inc.
279 * All rights reserved.
281 * This code is derived from software contributed to The NetBSD Foundation
282 * by Dieter Baron and Thomas Klausner.
284 * Redistribution and use in source and binary forms, with or without
285 * modification, are permitted provided that the following conditions
287 * 1. Redistributions of source code must retain the above copyright
288 * notice, this list of conditions and the following disclaimer.
289 * 2. Redistributions in binary form must reproduce the above copyright
290 * notice, this list of conditions and the following disclaimer in the
291 * documentation and/or other materials provided with the distribution.
293 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
294 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
295 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
296 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
297 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
298 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
299 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
300 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
301 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
303 * POSSIBILITY OF SUCH DAMAGE.
310 // Define this to replace system getopt
312 //#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
314 #ifdef REPLACE_GETOPT
315 int opterr = 1; /* if error message should be printed */
316 int optind = 1; /* index into parent argv vector */
317 int optopt = '?'; /* character checked for validity */
318 int optreset; /* reset getopt */
319 char *optarg; /* argument associated with option */
322 #define PRINT_ERROR ((opterr) && (*options != ':'))
324 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
325 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
326 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
329 #define BADCH (int)'?'
330 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
331 #define INORDER (int)1
335 static int getopt_internal(int, char * const *, const char *,
336 const struct option *, int *, int);
337 static int parse_long_options(char * const *, const char *,
338 const struct option *, int *, int);
339 static int gcd(int, int);
340 static void permute_args(int, int, int, char * const *);
342 static char *place = EMSG; /* option letter processing */
344 /* XXX: set optreset to 1 rather than these two */
345 static int nonopt_start = -1; /* first non option argument (for permute) */
346 static int nonopt_end = -1; /* first option after non options (for permute) */
349 static const char recargchar[] = "option requires an argument -- %c";
350 static const char recargstring[] = "option requires an argument -- %s";
351 static const char ambig[] = "ambiguous option -- %.*s";
352 static const char noarg[] = "option doesn't take an argument -- %.*s";
353 static const char illoptchar[] = "unknown option -- %c";
354 static const char illoptstring[] = "unknown option -- %s";
357 #if defined(_WIN32) || defined(ESP_PLATFORM)
359 /* Windows needs warnx(). We change the definition though:
360 * 1. (another) global is defined, opterrmsg, which holds the error message
361 * 2. errors are always printed out on stderr w/o the program name
362 * Note that opterrmsg always gets set no matter what opterr is set to. The
363 * error message will not be printed if opterr is 0 as usual.
369 extern char opterrmsg[128];
370 char opterrmsg[128]; /* buffer for the last error message */
372 static void warnx(const char *fmt, ...)
377 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
378 implementation specifics and manually suppress the warning.
380 memset(opterrmsg, 0, sizeof opterrmsg);
382 vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
385 #pragma warning(suppress: 6053)
387 fprintf(stderr, "%s\n", opterrmsg);
395 * Compute the greatest common divisor of a and b.
413 * Exchange the block from nonopt_start to nonopt_end with the block
414 * from nonopt_end to opt_end (keeping the same order of arguments
418 permute_args(int panonopt_start, int panonopt_end, int opt_end,
421 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
425 * compute lengths of blocks and number and size of cycles
427 nnonopts = panonopt_end - panonopt_start;
428 nopts = opt_end - panonopt_end;
429 ncycle = gcd(nnonopts, nopts);
430 cyclelen = (opt_end - panonopt_start) / ncycle;
432 for (i = 0; i < ncycle; i++) {
433 cstart = panonopt_end+i;
435 for (j = 0; j < cyclelen; j++) {
436 if (pos >= panonopt_end)
441 /* LINTED const cast */
442 ((char **) nargv)[pos] = nargv[cstart];
443 /* LINTED const cast */
444 ((char **)nargv)[cstart] = swap;
450 * parse_long_options --
451 * Parse long options in argc/argv argument vector.
452 * Returns -1 if short_too is set and the option does not match long_options.
455 parse_long_options(char * const *nargv, const char *options,
456 const struct option *long_options, int *idx, int short_too)
458 char *current_argv, *has_equal;
459 size_t current_argv_len;
462 current_argv = place;
467 if ((has_equal = strchr(current_argv, '=')) != NULL) {
468 /* argument found (--option=arg) */
469 current_argv_len = has_equal - current_argv;
472 current_argv_len = strlen(current_argv);
474 for (i = 0; long_options[i].name; i++) {
475 /* find matching long option */
476 if (strncmp(current_argv, long_options[i].name,
480 if (strlen(long_options[i].name) == current_argv_len) {
486 * If this is a known short option, don't allow
487 * a partial match of a single character.
489 if (short_too && current_argv_len == 1)
492 if (match == -1) /* partial match */
495 /* ambiguous abbreviation */
497 warnx(ambig, (int)current_argv_len,
503 if (match != -1) { /* option found */
504 if (long_options[match].has_arg == no_argument
507 warnx(noarg, (int)current_argv_len,
510 * XXX: GNU sets optopt to val regardless of flag
512 if (long_options[match].flag == NULL)
513 optopt = long_options[match].val;
518 if (long_options[match].has_arg == required_argument ||
519 long_options[match].has_arg == optional_argument) {
522 else if (long_options[match].has_arg ==
525 * optional argument doesn't use next nargv
527 optarg = nargv[optind++];
530 if ((long_options[match].has_arg == required_argument)
531 && (optarg == NULL)) {
533 * Missing argument; leading ':' indicates no error
534 * should be generated.
540 * XXX: GNU sets optopt to val regardless of flag
542 if (long_options[match].flag == NULL)
543 optopt = long_options[match].val;
549 } else { /* unknown option */
555 warnx(illoptstring, current_argv);
561 if (long_options[match].flag) {
562 *long_options[match].flag = long_options[match].val;
565 return (long_options[match].val);
570 * Parse argc/argv argument vector. Called by user level routines.
573 getopt_internal(int nargc, char * const *nargv, const char *options,
574 const struct option *long_options, int *idx, int flags)
576 char *oli; /* option letter list index */
577 int optchar, short_too;
578 static int posixly_correct = -1;
584 * Disable GNU extensions if POSIXLY_CORRECT is set or options
585 * string begins with a '+'.
587 if (posixly_correct == -1)
588 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
589 if (posixly_correct || *options == '+')
590 flags &= ~FLAG_PERMUTE;
591 else if (*options == '-')
592 flags |= FLAG_ALLARGS;
593 if (*options == '+' || *options == '-')
597 * XXX Some GNU programs (like cvs) set optind to 0 instead of
598 * XXX using optreset. Work around this braindamage.
601 optind = optreset = 1;
605 nonopt_start = nonopt_end = -1;
607 if (optreset || !*place) { /* update scanning pointer */
609 if (optind >= nargc) { /* end of argument vector */
611 if (nonopt_end != -1) {
612 /* do permutation, if we have to */
613 permute_args(nonopt_start, nonopt_end,
615 optind -= nonopt_end - nonopt_start;
617 else if (nonopt_start != -1) {
619 * If we skipped non-options, set optind
620 * to the first of them.
622 optind = nonopt_start;
624 nonopt_start = nonopt_end = -1;
627 if (*(place = nargv[optind]) != '-' ||
628 (place[1] == '\0' && strchr(options, '-') == NULL)) {
629 place = EMSG; /* found non-option */
630 if (flags & FLAG_ALLARGS) {
633 * return non-option as argument to option 1
635 optarg = nargv[optind++];
638 if (!(flags & FLAG_PERMUTE)) {
640 * If no permutation wanted, stop parsing
641 * at first non-option.
646 if (nonopt_start == -1)
647 nonopt_start = optind;
648 else if (nonopt_end != -1) {
649 permute_args(nonopt_start, nonopt_end,
651 nonopt_start = optind -
652 (nonopt_end - nonopt_start);
656 /* process next argument */
659 if (nonopt_start != -1 && nonopt_end == -1)
663 * If we have "-" do nothing, if "--" we are done.
665 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
669 * We found an option (--), so if we skipped
670 * non-options, we have to permute.
672 if (nonopt_end != -1) {
673 permute_args(nonopt_start, nonopt_end,
675 optind -= nonopt_end - nonopt_start;
677 nonopt_start = nonopt_end = -1;
683 * Check long options if:
684 * 1) we were passed some
685 * 2) the arg is not just "-"
686 * 3) either the arg starts with -- we are getopt_long_only()
688 if (long_options != NULL && place != nargv[optind] &&
689 (*place == '-' || (flags & FLAG_LONGONLY))) {
692 place++; /* --foo long option */
693 else if (*place != ':' && strchr(options, *place) != NULL)
694 short_too = 1; /* could be short option too */
696 optchar = parse_long_options(nargv, options, long_options,
704 if ((optchar = (int)*place++) == (int)':' ||
705 (optchar == (int)'-' && *place != '\0') ||
706 (oli = strchr(options, optchar)) == NULL) {
708 * If the user specified "-" and '-' isn't listed in
709 * options, return -1 (non-option) as per POSIX.
710 * Otherwise, it is an unknown option character (or ':').
712 if (optchar == (int)'-' && *place == '\0')
717 warnx(illoptchar, optchar);
721 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
723 if (*place) /* no space */
725 else if (++optind >= nargc) { /* no arg */
728 warnx(recargchar, optchar);
731 } else /* white space */
732 place = nargv[optind];
733 optchar = parse_long_options(nargv, options, long_options,
738 if (*++oli != ':') { /* doesn't take argument */
741 } else { /* takes (optional) argument */
743 if (*place) /* no white space */
745 else if (oli[1] != ':') { /* arg not optional */
746 if (++optind >= nargc) { /* no arg */
749 warnx(recargchar, optchar);
753 optarg = nargv[optind];
758 /* dump back option letter */
765 * Parse argc/argv argument vector.
767 * [eventually this will replace the BSD getopt]
770 getopt(int nargc, char * const *nargv, const char *options)
774 * We don't pass FLAG_PERMUTE to getopt_internal() since
775 * the BSD getopt(3) (unlike GNU) has never done this.
777 * Furthermore, since many privileged programs call getopt()
778 * before dropping privileges it makes sense to keep things
779 * as simple (and bug-free) as possible.
781 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
787 * Parse argc/argv argument vector.
790 getopt_long(int nargc, char * const *nargv, const char *options,
791 const struct option *long_options, int *idx)
794 return (getopt_internal(nargc, nargv, options, long_options, idx,
799 * getopt_long_only --
800 * Parse argc/argv argument vector.
803 getopt_long_only(int nargc, char * const *nargv, const char *options,
804 const struct option *long_options, int *idx)
807 return (getopt_internal(nargc, nargv, options, long_options, idx,
808 FLAG_PERMUTE|FLAG_LONGONLY));
810 #endif /* REPLACE_GETOPT */
811 /*******************************************************************************
812 * This file is part of the argtable3 library.
814 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
815 * <sheitmann@users.sourceforge.net>
816 * All rights reserved.
818 * Redistribution and use in source and binary forms, with or without
819 * modification, are permitted provided that the following conditions are met:
820 * * Redistributions of source code must retain the above copyright
821 * notice, this list of conditions and the following disclaimer.
822 * * Redistributions in binary form must reproduce the above copyright
823 * notice, this list of conditions and the following disclaimer in the
824 * documentation and/or other materials provided with the distribution.
825 * * Neither the name of STEWART HEITMANN nor the names of its contributors
826 * may be used to endorse or promote products derived from this software
827 * without specific prior written permission.
829 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
830 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
831 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
832 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
833 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
834 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
835 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
836 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
837 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
838 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
839 ******************************************************************************/
844 #include "argtable3.h"
847 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm);
850 static void arg_date_resetfn(struct arg_date *parent)
852 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
857 static int arg_date_scanfn(struct arg_date *parent, const char *argval)
861 if (parent->count == parent->hdr.maxcount)
863 errorcode = EMAXCOUNT;
867 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
873 struct tm tm = parent->tmval[parent->count];
875 /* parse the given argument value, store result in parent->tmval[] */
876 pend = arg_strptime(argval, parent->format, &tm);
877 if (pend && pend[0] == '\0')
878 parent->tmval[parent->count++] = tm;
880 errorcode = EBADDATE;
883 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
888 static int arg_date_checkfn(struct arg_date *parent)
890 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
892 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
897 static void arg_date_errorfn(
898 struct arg_date *parent,
902 const char *progname)
904 const char *shortopts = parent->hdr.shortopts;
905 const char *longopts = parent->hdr.longopts;
906 const char *datatype = parent->hdr.datatype;
908 /* make argval NULL safe */
909 argval = argval ? argval : "";
911 fprintf(fp, "%s: ", progname);
915 fputs("missing option ", fp);
916 arg_print_option(fp, shortopts, longopts, datatype, "\n");
920 fputs("excess option ", fp);
921 arg_print_option(fp, shortopts, longopts, argval, "\n");
929 fprintf(fp, "illegal timestamp format \"%s\"\n", argval);
930 memset(&tm, 0, sizeof(tm));
931 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
932 strftime(buff, sizeof(buff), parent->format, &tm);
933 printf("correct format is \"%s\"\n", buff);
940 struct arg_date * arg_date0(
941 const char * shortopts,
942 const char * longopts,
944 const char *datatype,
945 const char *glossary)
947 return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
951 struct arg_date * arg_date1(
952 const char * shortopts,
953 const char * longopts,
955 const char *datatype,
956 const char *glossary)
958 return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
962 struct arg_date * arg_daten(
963 const char * shortopts,
964 const char * longopts,
966 const char *datatype,
969 const char *glossary)
972 struct arg_date *result;
974 /* foolproof things by ensuring maxcount is not less than mincount */
975 maxcount = (maxcount < mincount) ? mincount : maxcount;
977 /* default time format is the national date format for the locale */
981 nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
982 + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
984 /* allocate storage for the arg_date struct + tmval[] array. */
985 /* we use calloc because we want the tmval[] array zero filled. */
986 result = (struct arg_date *)calloc(1, nbytes);
989 /* init the arg_hdr struct */
990 result->hdr.flag = ARG_HASVALUE;
991 result->hdr.shortopts = shortopts;
992 result->hdr.longopts = longopts;
993 result->hdr.datatype = datatype ? datatype : format;
994 result->hdr.glossary = glossary;
995 result->hdr.mincount = mincount;
996 result->hdr.maxcount = maxcount;
997 result->hdr.parent = result;
998 result->hdr.resetfn = (arg_resetfn *)arg_date_resetfn;
999 result->hdr.scanfn = (arg_scanfn *)arg_date_scanfn;
1000 result->hdr.checkfn = (arg_checkfn *)arg_date_checkfn;
1001 result->hdr.errorfn = (arg_errorfn *)arg_date_errorfn;
1003 /* store the tmval[maxcount] array immediately after the arg_date struct */
1004 result->tmval = (struct tm *)(result + 1);
1006 /* init the remaining arg_date member variables */
1008 result->format = format;
1011 ARG_TRACE(("arg_daten() returns %p\n", result));
1017 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1018 * All rights reserved.
1020 * This code was contributed to The NetBSD Foundation by Klaus Klein.
1021 * Heavily optimised by David Laight
1023 * Redistribution and use in source and binary forms, with or without
1024 * modification, are permitted provided that the following conditions
1026 * 1. Redistributions of source code must retain the above copyright
1027 * notice, this list of conditions and the following disclaimer.
1028 * 2. Redistributions in binary form must reproduce the above copyright
1029 * notice, this list of conditions and the following disclaimer in the
1030 * documentation and/or other materials provided with the distribution.
1032 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1033 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1034 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1035 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1036 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1037 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1038 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1039 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1040 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1041 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1042 * POSSIBILITY OF SUCH DAMAGE.
1050 * We do not implement alternate representations. However, we always
1051 * check whether a given modifier is allowed for a certain conversion.
1055 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
1056 #define TM_YEAR_BASE (1900)
1058 static int conv_num(const char * *, int *, int, int);
1060 static const char *day[7] = {
1061 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
1062 "Friday", "Saturday"
1065 static const char *abday[7] = {
1066 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1069 static const char *mon[12] = {
1070 "January", "February", "March", "April", "May", "June", "July",
1071 "August", "September", "October", "November", "December"
1074 static const char *abmon[12] = {
1075 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1076 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1079 static const char *am_pm[2] = {
1084 static int arg_strcasecmp(const char *s1, const char *s2)
1086 const unsigned char *us1 = (const unsigned char *)s1;
1087 const unsigned char *us2 = (const unsigned char *)s2;
1088 while (tolower(*us1) == tolower(*us2++))
1092 return tolower(*us1) - tolower(*--us2);
1096 static int arg_strncasecmp(const char *s1, const char *s2, size_t n)
1100 const unsigned char *us1 = (const unsigned char *)s1;
1101 const unsigned char *us2 = (const unsigned char *)s2;
1104 if (tolower(*us1) != tolower(*us2++))
1105 return tolower(*us1) - tolower(*--us2);
1116 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm)
1121 int alt_format, i, split_year = 0;
1125 while ((c = *fmt) != '\0') {
1126 /* Clear `alternate' modifier prior to new conversion. */
1129 /* Eat up white-space. */
1130 if (isspace((int) c)) {
1131 while (isspace((int) *bp))
1138 if ((c = *fmt++) != '%')
1145 case '%': /* "%%" is converted to "%". */
1152 * "Alternative" modifiers. Just set the appropriate flag
1153 * and start over again.
1155 case 'E': /* "%E?" alternative conversion modifier. */
1157 alt_format |= ALT_E;
1160 case 'O': /* "%O?" alternative conversion modifier. */
1162 alt_format |= ALT_O;
1166 * "Complex" conversion rules, implemented through recursion.
1168 case 'c': /* Date and time, using the locale's format. */
1170 bp = arg_strptime(bp, "%x %X", tm);
1175 case 'D': /* The date as "%m/%d/%y". */
1177 bp = arg_strptime(bp, "%m/%d/%y", tm);
1182 case 'R': /* The time as "%H:%M". */
1184 bp = arg_strptime(bp, "%H:%M", tm);
1189 case 'r': /* The time in 12-hour clock representation. */
1191 bp = arg_strptime(bp, "%I:%M:%S %p", tm);
1196 case 'T': /* The time as "%H:%M:%S". */
1198 bp = arg_strptime(bp, "%H:%M:%S", tm);
1203 case 'X': /* The time, using the locale's format. */
1205 bp = arg_strptime(bp, "%H:%M:%S", tm);
1210 case 'x': /* The date, using the locale's format. */
1212 bp = arg_strptime(bp, "%m/%d/%y", tm);
1218 * "Elementary" conversion rules.
1220 case 'A': /* The day of week, using the locale's form. */
1223 for (i = 0; i < 7; i++) {
1225 len = strlen(day[i]);
1226 if (arg_strncasecmp(day[i], bp, len) == 0)
1229 /* Abbreviated name. */
1230 len = strlen(abday[i]);
1231 if (arg_strncasecmp(abday[i], bp, len) == 0)
1235 /* Nothing matched. */
1243 case 'B': /* The month, using the locale's form. */
1247 for (i = 0; i < 12; i++) {
1249 len = strlen(mon[i]);
1250 if (arg_strncasecmp(mon[i], bp, len) == 0)
1253 /* Abbreviated name. */
1254 len = strlen(abmon[i]);
1255 if (arg_strncasecmp(abmon[i], bp, len) == 0)
1259 /* Nothing matched. */
1267 case 'C': /* The century number. */
1269 if (!(conv_num(&bp, &i, 0, 99)))
1273 tm->tm_year = (tm->tm_year % 100) + (i * 100);
1275 tm->tm_year = i * 100;
1280 case 'd': /* The day of month. */
1283 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
1287 case 'k': /* The hour (24-hour clock representation). */
1292 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
1296 case 'l': /* The hour (12-hour clock representation). */
1301 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
1303 if (tm->tm_hour == 12)
1307 case 'j': /* The day of year. */
1309 if (!(conv_num(&bp, &i, 1, 366)))
1311 tm->tm_yday = i - 1;
1314 case 'M': /* The minute. */
1316 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
1320 case 'm': /* The month. */
1322 if (!(conv_num(&bp, &i, 1, 12)))
1327 case 'p': /* The locale's equivalent of AM/PM. */
1330 if (arg_strcasecmp(am_pm[0], bp) == 0) {
1331 if (tm->tm_hour > 11)
1334 bp += strlen(am_pm[0]);
1338 else if (arg_strcasecmp(am_pm[1], bp) == 0) {
1339 if (tm->tm_hour > 11)
1343 bp += strlen(am_pm[1]);
1347 /* Nothing matched. */
1350 case 'S': /* The seconds. */
1352 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
1356 case 'U': /* The week of year, beginning on sunday. */
1357 case 'W': /* The week of year, beginning on monday. */
1360 * XXX This is bogus, as we can not assume any valid
1361 * information present in the tm structure at this
1362 * point to calculate a real value, so just check the
1365 if (!(conv_num(&bp, &i, 0, 53)))
1369 case 'w': /* The day of week, beginning on sunday. */
1371 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
1375 case 'Y': /* The year. */
1377 if (!(conv_num(&bp, &i, 0, 9999)))
1380 tm->tm_year = i - TM_YEAR_BASE;
1383 case 'y': /* The year within 100 years of the epoch. */
1384 LEGAL_ALT(ALT_E | ALT_O);
1385 if (!(conv_num(&bp, &i, 0, 99)))
1389 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
1394 tm->tm_year = i + 2000 - TM_YEAR_BASE;
1396 tm->tm_year = i + 1900 - TM_YEAR_BASE;
1400 * Miscellaneous conversions.
1402 case 'n': /* Any kind of white-space. */
1405 while (isspace((int) *bp))
1410 default: /* Unknown/unsupported conversion. */
1417 /* LINTED functional specification */
1418 return ((char *)bp);
1422 static int conv_num(const char * *buf, int *dest, int llim, int ulim)
1426 /* The limit also determines the number of valid digits. */
1429 if (**buf < '0' || **buf > '9')
1434 result += *(*buf)++ - '0';
1436 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
1438 if (result < llim || result > ulim)
1444 /*******************************************************************************
1445 * This file is part of the argtable3 library.
1447 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1448 * <sheitmann@users.sourceforge.net>
1449 * All rights reserved.
1451 * Redistribution and use in source and binary forms, with or without
1452 * modification, are permitted provided that the following conditions are met:
1453 * * Redistributions of source code must retain the above copyright
1454 * notice, this list of conditions and the following disclaimer.
1455 * * Redistributions in binary form must reproduce the above copyright
1456 * notice, this list of conditions and the following disclaimer in the
1457 * documentation and/or other materials provided with the distribution.
1458 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1459 * may be used to endorse or promote products derived from this software
1460 * without specific prior written permission.
1462 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1463 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1464 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1465 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1466 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1467 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1468 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1469 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1470 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1471 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1472 ******************************************************************************/
1476 #include "argtable3.h"
1479 static void arg_dbl_resetfn(struct arg_dbl *parent)
1481 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1486 static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval)
1490 if (parent->count == parent->hdr.maxcount)
1492 /* maximum number of arguments exceeded */
1493 errorcode = EMAXCOUNT;
1497 /* a valid argument with no argument value was given. */
1498 /* This happens when an optional argument value was invoked. */
1499 /* leave parent argument value unaltered but still count the argument. */
1507 /* extract double from argval into val */
1508 val = strtod(argval, &end);
1510 /* if success then store result in parent->dval[] array otherwise return error*/
1512 parent->dval[parent->count++] = val;
1514 errorcode = EBADDOUBLE;
1517 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1522 static int arg_dbl_checkfn(struct arg_dbl *parent)
1524 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1526 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1531 static void arg_dbl_errorfn(
1532 struct arg_dbl *parent,
1536 const char *progname)
1538 const char *shortopts = parent->hdr.shortopts;
1539 const char *longopts = parent->hdr.longopts;
1540 const char *datatype = parent->hdr.datatype;
1542 /* make argval NULL safe */
1543 argval = argval ? argval : "";
1545 fprintf(fp, "%s: ", progname);
1549 fputs("missing option ", fp);
1550 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1554 fputs("excess option ", fp);
1555 arg_print_option(fp, shortopts, longopts, argval, "\n");
1559 fprintf(fp, "invalid argument \"%s\" to option ", argval);
1560 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1566 struct arg_dbl * arg_dbl0(
1567 const char * shortopts,
1568 const char * longopts,
1569 const char *datatype,
1570 const char *glossary)
1572 return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
1576 struct arg_dbl * arg_dbl1(
1577 const char * shortopts,
1578 const char * longopts,
1579 const char *datatype,
1580 const char *glossary)
1582 return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
1586 struct arg_dbl * arg_dbln(
1587 const char * shortopts,
1588 const char * longopts,
1589 const char *datatype,
1592 const char *glossary)
1595 struct arg_dbl *result;
1597 /* foolproof things by ensuring maxcount is not less than mincount */
1598 maxcount = (maxcount < mincount) ? mincount : maxcount;
1600 nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
1601 + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1603 result = (struct arg_dbl *)malloc(nbytes);
1609 /* init the arg_hdr struct */
1610 result->hdr.flag = ARG_HASVALUE;
1611 result->hdr.shortopts = shortopts;
1612 result->hdr.longopts = longopts;
1613 result->hdr.datatype = datatype ? datatype : "<double>";
1614 result->hdr.glossary = glossary;
1615 result->hdr.mincount = mincount;
1616 result->hdr.maxcount = maxcount;
1617 result->hdr.parent = result;
1618 result->hdr.resetfn = (arg_resetfn *)arg_dbl_resetfn;
1619 result->hdr.scanfn = (arg_scanfn *)arg_dbl_scanfn;
1620 result->hdr.checkfn = (arg_checkfn *)arg_dbl_checkfn;
1621 result->hdr.errorfn = (arg_errorfn *)arg_dbl_errorfn;
1623 /* Store the dval[maxcount] array on the first double boundary that
1624 * immediately follows the arg_dbl struct. We do the memory alignment
1625 * purely for SPARC and Motorola systems. They require floats and
1626 * doubles to be aligned on natural boundaries.
1628 addr = (size_t)(result + 1);
1629 rem = addr % sizeof(double);
1630 result->dval = (double *)(addr + sizeof(double) - rem);
1631 ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
1636 ARG_TRACE(("arg_dbln() returns %p\n", result));
1639 /*******************************************************************************
1640 * This file is part of the argtable3 library.
1642 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1643 * <sheitmann@users.sourceforge.net>
1644 * All rights reserved.
1646 * Redistribution and use in source and binary forms, with or without
1647 * modification, are permitted provided that the following conditions are met:
1648 * * Redistributions of source code must retain the above copyright
1649 * notice, this list of conditions and the following disclaimer.
1650 * * Redistributions in binary form must reproduce the above copyright
1651 * notice, this list of conditions and the following disclaimer in the
1652 * documentation and/or other materials provided with the distribution.
1653 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1654 * may be used to endorse or promote products derived from this software
1655 * without specific prior written permission.
1657 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1658 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1659 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1660 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1661 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1662 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1663 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1664 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1665 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1666 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1667 ******************************************************************************/
1671 #include "argtable3.h"
1674 static void arg_end_resetfn(struct arg_end *parent)
1676 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1680 static void arg_end_errorfn(
1685 const char *progname)
1687 /* suppress unreferenced formal parameter warning */
1690 progname = progname ? progname : "";
1691 argval = argval ? argval : "";
1693 fprintf(fp, "%s: ", progname);
1697 fputs("too many errors to display", fp);
1700 fputs("insufficent memory", fp);
1703 fprintf(fp, "unexpected argument \"%s\"", argval);
1706 fprintf(fp, "option \"%s\" requires an argument", argval);
1709 fprintf(fp, "invalid option \"%s\"", argval);
1712 fprintf(fp, "invalid option \"-%c\"", error);
1720 struct arg_end * arg_end(int maxcount)
1723 struct arg_end *result;
1725 nbytes = sizeof(struct arg_end)
1726 + maxcount * sizeof(int) /* storage for int error[maxcount] array*/
1727 + maxcount * sizeof(void *) /* storage for void* parent[maxcount] array */
1728 + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */
1730 result = (struct arg_end *)malloc(nbytes);
1733 /* init the arg_hdr struct */
1734 result->hdr.flag = ARG_TERMINATOR;
1735 result->hdr.shortopts = NULL;
1736 result->hdr.longopts = NULL;
1737 result->hdr.datatype = NULL;
1738 result->hdr.glossary = NULL;
1739 result->hdr.mincount = 1;
1740 result->hdr.maxcount = maxcount;
1741 result->hdr.parent = result;
1742 result->hdr.resetfn = (arg_resetfn *)arg_end_resetfn;
1743 result->hdr.scanfn = NULL;
1744 result->hdr.checkfn = NULL;
1745 result->hdr.errorfn = (arg_errorfn *)arg_end_errorfn;
1747 /* store error[maxcount] array immediately after struct arg_end */
1748 result->error = (int *)(result + 1);
1750 /* store parent[maxcount] array immediately after error[] array */
1751 result->parent = (void * *)(result->error + maxcount );
1753 /* store argval[maxcount] array immediately after parent[] array */
1754 result->argval = (const char * *)(result->parent + maxcount );
1757 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
1762 void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname)
1765 ARG_TRACE(("arg_errors()\n"));
1766 for (i = 0; i < end->count; i++)
1768 struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]);
1769 if (errorparent->errorfn)
1770 errorparent->errorfn(end->parent[i],
1777 /*******************************************************************************
1778 * This file is part of the argtable3 library.
1780 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1781 * <sheitmann@users.sourceforge.net>
1782 * All rights reserved.
1784 * Redistribution and use in source and binary forms, with or without
1785 * modification, are permitted provided that the following conditions are met:
1786 * * Redistributions of source code must retain the above copyright
1787 * notice, this list of conditions and the following disclaimer.
1788 * * Redistributions in binary form must reproduce the above copyright
1789 * notice, this list of conditions and the following disclaimer in the
1790 * documentation and/or other materials provided with the distribution.
1791 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1792 * may be used to endorse or promote products derived from this software
1793 * without specific prior written permission.
1795 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1796 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1797 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1798 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1799 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1800 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1801 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1802 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1803 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1804 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1805 ******************************************************************************/
1810 #include "argtable3.h"
1813 # define FILESEPARATOR1 '\\'
1814 # define FILESEPARATOR2 '/'
1816 # define FILESEPARATOR1 '/'
1817 # define FILESEPARATOR2 '/'
1821 static void arg_file_resetfn(struct arg_file *parent)
1823 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1828 /* Returns ptr to the base filename within *filename */
1829 static const char * arg_basename(const char *filename)
1831 const char *result = NULL, *result1, *result2;
1833 /* Find the last occurrence of eother file separator character. */
1834 /* Two alternative file separator chars are supported as legal */
1835 /* file separators but not both together in the same filename. */
1836 result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
1837 result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
1840 result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
1843 result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
1846 result = filename; /* neither file separator was found so basename is the whole filename */
1848 /* special cases of "." and ".." are not considered basenames */
1849 if (result && ( strcmp(".", result) == 0 || strcmp("..", result) == 0 ))
1850 result = filename + strlen(filename);
1856 /* Returns ptr to the file extension within *basename */
1857 static const char * arg_extension(const char *basename)
1859 /* find the last occurrence of '.' in basename */
1860 const char *result = (basename ? strrchr(basename, '.') : NULL);
1862 /* if no '.' was found then return pointer to end of basename */
1863 if (basename && !result)
1864 result = basename + strlen(basename);
1866 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1867 if (basename && result == basename)
1868 result = basename + strlen(basename);
1870 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1871 if (basename && result && result[1] == '\0')
1872 result = basename + strlen(basename);
1878 static int arg_file_scanfn(struct arg_file *parent, const char *argval)
1882 if (parent->count == parent->hdr.maxcount)
1884 /* maximum number of arguments exceeded */
1885 errorcode = EMAXCOUNT;
1889 /* a valid argument with no argument value was given. */
1890 /* This happens when an optional argument value was invoked. */
1891 /* leave parent arguiment value unaltered but still count the argument. */
1896 parent->filename[parent->count] = argval;
1897 parent->basename[parent->count] = arg_basename(argval);
1898 parent->extension[parent->count] =
1899 arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
1903 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1908 static int arg_file_checkfn(struct arg_file *parent)
1910 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1912 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1917 static void arg_file_errorfn(
1918 struct arg_file *parent,
1922 const char *progname)
1924 const char *shortopts = parent->hdr.shortopts;
1925 const char *longopts = parent->hdr.longopts;
1926 const char *datatype = parent->hdr.datatype;
1928 /* make argval NULL safe */
1929 argval = argval ? argval : "";
1931 fprintf(fp, "%s: ", progname);
1935 fputs("missing option ", fp);
1936 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1940 fputs("excess option ", fp);
1941 arg_print_option(fp, shortopts, longopts, argval, "\n");
1945 fprintf(fp, "unknown error at \"%s\"\n", argval);
1950 struct arg_file * arg_file0(
1951 const char * shortopts,
1952 const char * longopts,
1953 const char *datatype,
1954 const char *glossary)
1956 return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
1960 struct arg_file * arg_file1(
1961 const char * shortopts,
1962 const char * longopts,
1963 const char *datatype,
1964 const char *glossary)
1966 return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
1970 struct arg_file * arg_filen(
1971 const char * shortopts,
1972 const char * longopts,
1973 const char *datatype,
1976 const char *glossary)
1979 struct arg_file *result;
1981 /* foolproof things by ensuring maxcount is not less than mincount */
1982 maxcount = (maxcount < mincount) ? mincount : maxcount;
1984 nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
1985 + sizeof(char *) * maxcount /* storage for filename[maxcount] array */
1986 + sizeof(char *) * maxcount /* storage for basename[maxcount] array */
1987 + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */
1989 result = (struct arg_file *)malloc(nbytes);
1994 /* init the arg_hdr struct */
1995 result->hdr.flag = ARG_HASVALUE;
1996 result->hdr.shortopts = shortopts;
1997 result->hdr.longopts = longopts;
1998 result->hdr.glossary = glossary;
1999 result->hdr.datatype = datatype ? datatype : "<file>";
2000 result->hdr.mincount = mincount;
2001 result->hdr.maxcount = maxcount;
2002 result->hdr.parent = result;
2003 result->hdr.resetfn = (arg_resetfn *)arg_file_resetfn;
2004 result->hdr.scanfn = (arg_scanfn *)arg_file_scanfn;
2005 result->hdr.checkfn = (arg_checkfn *)arg_file_checkfn;
2006 result->hdr.errorfn = (arg_errorfn *)arg_file_errorfn;
2008 /* store the filename,basename,extension arrays immediately after the arg_file struct */
2009 result->filename = (const char * *)(result + 1);
2010 result->basename = result->filename + maxcount;
2011 result->extension = result->basename + maxcount;
2014 /* foolproof the string pointers by initialising them with empty strings */
2015 for (i = 0; i < maxcount; i++)
2017 result->filename[i] = "";
2018 result->basename[i] = "";
2019 result->extension[i] = "";
2023 ARG_TRACE(("arg_filen() returns %p\n", result));
2026 /*******************************************************************************
2027 * This file is part of the argtable3 library.
2029 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2030 * <sheitmann@users.sourceforge.net>
2031 * All rights reserved.
2033 * Redistribution and use in source and binary forms, with or without
2034 * modification, are permitted provided that the following conditions are met:
2035 * * Redistributions of source code must retain the above copyright
2036 * notice, this list of conditions and the following disclaimer.
2037 * * Redistributions in binary form must reproduce the above copyright
2038 * notice, this list of conditions and the following disclaimer in the
2039 * documentation and/or other materials provided with the distribution.
2040 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2041 * may be used to endorse or promote products derived from this software
2042 * without specific prior written permission.
2044 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2045 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2046 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2047 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2048 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2049 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2050 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2051 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2052 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2053 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2054 ******************************************************************************/
2060 #include "argtable3.h"
2063 static void arg_int_resetfn(struct arg_int *parent)
2065 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2070 /* strtol0x() is like strtol() except that the numeric string is */
2071 /* expected to be prefixed by "0X" where X is a user supplied char. */
2072 /* The string may optionally be prefixed by white space and + or - */
2073 /* as in +0X123 or -0X123. */
2074 /* Once the prefix has been scanned, the remainder of the numeric */
2075 /* string is converted using strtol() with the given base. */
2076 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
2077 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
2078 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
2079 /* Failure of conversion is indicated by result where *endptr==str. */
2080 static long int strtol0X(const char * str,
2081 const char * *endptr,
2085 long int val; /* stores result */
2086 int s = 1; /* sign is +1 or -1 */
2087 const char *ptr = str; /* ptr to current position in str */
2089 /* skip leading whitespace */
2090 while (isspace((int) *ptr))
2092 /* printf("1) %s\n",ptr); */
2094 /* scan optional sign character */
2109 /* printf("2) %s\n",ptr); */
2112 if ((*ptr++) != '0')
2114 /* printf("failed to detect '0'\n"); */
2118 /* printf("3) %s\n",ptr); */
2119 if (toupper((int) *ptr++) != toupper((int) X))
2121 /* printf("failed to detect '%c'\n",X); */
2125 /* printf("4) %s\n",ptr); */
2127 /* attempt conversion on remainder of string using strtol() */
2128 val = strtol(ptr, (char * *)endptr, base);
2131 /* conversion failed */
2141 /* Returns 1 if str matches suffix (case insensitive). */
2142 /* Str may contain trailing whitespace, but nothing else. */
2143 static int detectsuffix(const char *str, const char *suffix)
2145 /* scan pairwise through strings until mismatch detected */
2146 while( toupper((int) *str) == toupper((int) *suffix) )
2148 /* printf("'%c' '%c'\n", *str, *suffix); */
2150 /* return 1 (success) if match persists until the string terminator */
2158 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2160 /* return 0 (fail) if the matching did not consume the entire suffix */
2162 return 0; /* failed to consume entire suffix */
2164 /* skip any remaining whitespace in str */
2165 while (isspace((int) *str))
2168 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2169 return (*str == '\0') ? 1 : 0;
2173 static int arg_int_scanfn(struct arg_int *parent, const char *argval)
2177 if (parent->count == parent->hdr.maxcount)
2179 /* maximum number of arguments exceeded */
2180 errorcode = EMAXCOUNT;
2184 /* a valid argument with no argument value was given. */
2185 /* This happens when an optional argument value was invoked. */
2186 /* leave parent arguiment value unaltered but still count the argument. */
2194 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2195 val = strtol0X(argval, &end, 'X', 16);
2198 /* hex failed, attempt octal conversion (eg +0o123) */
2199 val = strtol0X(argval, &end, 'O', 8);
2202 /* octal failed, attempt binary conversion (eg +0B101) */
2203 val = strtol0X(argval, &end, 'B', 2);
2206 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2207 val = strtol(argval, (char * *)&end, 10);
2210 /* all supported number formats failed */
2217 /* Safety check for integer overflow. WARNING: this check */
2218 /* achieves nothing on machines where size(int)==size(long). */
2219 if ( val > INT_MAX || val < INT_MIN )
2220 errorcode = EOVERFLOW;
2222 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2223 /* We need to be mindful of integer overflows when using such big numbers. */
2224 if (detectsuffix(end, "KB")) /* kilobytes */
2226 if ( val > (INT_MAX / 1024) || val < (INT_MIN / 1024) )
2227 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2229 val *= 1024; /* 1KB = 1024 */
2231 else if (detectsuffix(end, "MB")) /* megabytes */
2233 if ( val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576) )
2234 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2236 val *= 1048576; /* 1MB = 1024*1024 */
2238 else if (detectsuffix(end, "GB")) /* gigabytes */
2240 if ( val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824) )
2241 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2243 val *= 1073741824; /* 1GB = 1024*1024*1024 */
2245 else if (!detectsuffix(end, ""))
2246 errorcode = EBADINT; /* invalid suffix detected */
2248 /* if success then store result in parent->ival[] array */
2250 parent->ival[parent->count++] = val;
2253 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2258 static int arg_int_checkfn(struct arg_int *parent)
2260 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2261 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2266 static void arg_int_errorfn(
2267 struct arg_int *parent,
2271 const char *progname)
2273 const char *shortopts = parent->hdr.shortopts;
2274 const char *longopts = parent->hdr.longopts;
2275 const char *datatype = parent->hdr.datatype;
2277 /* make argval NULL safe */
2278 argval = argval ? argval : "";
2280 fprintf(fp, "%s: ", progname);
2284 fputs("missing option ", fp);
2285 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2289 fputs("excess option ", fp);
2290 arg_print_option(fp, shortopts, longopts, argval, "\n");
2294 fprintf(fp, "invalid argument \"%s\" to option ", argval);
2295 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2299 fputs("integer overflow at option ", fp);
2300 arg_print_option(fp, shortopts, longopts, datatype, " ");
2301 fprintf(fp, "(%s is too large)\n", argval);
2307 struct arg_int * arg_int0(
2308 const char *shortopts,
2309 const char *longopts,
2310 const char *datatype,
2311 const char *glossary)
2313 return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
2317 struct arg_int * arg_int1(
2318 const char *shortopts,
2319 const char *longopts,
2320 const char *datatype,
2321 const char *glossary)
2323 return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
2327 struct arg_int * arg_intn(
2328 const char *shortopts,
2329 const char *longopts,
2330 const char *datatype,
2333 const char *glossary)
2336 struct arg_int *result;
2338 /* foolproof things by ensuring maxcount is not less than mincount */
2339 maxcount = (maxcount < mincount) ? mincount : maxcount;
2341 nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
2342 + maxcount * sizeof(int); /* storage for ival[maxcount] array */
2344 result = (struct arg_int *)malloc(nbytes);
2347 /* init the arg_hdr struct */
2348 result->hdr.flag = ARG_HASVALUE;
2349 result->hdr.shortopts = shortopts;
2350 result->hdr.longopts = longopts;
2351 result->hdr.datatype = datatype ? datatype : "<int>";
2352 result->hdr.glossary = glossary;
2353 result->hdr.mincount = mincount;
2354 result->hdr.maxcount = maxcount;
2355 result->hdr.parent = result;
2356 result->hdr.resetfn = (arg_resetfn *)arg_int_resetfn;
2357 result->hdr.scanfn = (arg_scanfn *)arg_int_scanfn;
2358 result->hdr.checkfn = (arg_checkfn *)arg_int_checkfn;
2359 result->hdr.errorfn = (arg_errorfn *)arg_int_errorfn;
2361 /* store the ival[maxcount] array immediately after the arg_int struct */
2362 result->ival = (int *)(result + 1);
2366 ARG_TRACE(("arg_intn() returns %p\n", result));
2369 /*******************************************************************************
2370 * This file is part of the argtable3 library.
2372 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2373 * <sheitmann@users.sourceforge.net>
2374 * All rights reserved.
2376 * Redistribution and use in source and binary forms, with or without
2377 * modification, are permitted provided that the following conditions are met:
2378 * * Redistributions of source code must retain the above copyright
2379 * notice, this list of conditions and the following disclaimer.
2380 * * Redistributions in binary form must reproduce the above copyright
2381 * notice, this list of conditions and the following disclaimer in the
2382 * documentation and/or other materials provided with the distribution.
2383 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2384 * may be used to endorse or promote products derived from this software
2385 * without specific prior written permission.
2387 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2388 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2389 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2390 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2391 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2392 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2393 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2394 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2395 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2396 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2397 ******************************************************************************/
2401 #include "argtable3.h"
2404 static void arg_lit_resetfn(struct arg_lit *parent)
2406 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2411 static int arg_lit_scanfn(struct arg_lit *parent, const char *argval)
2414 if (parent->count < parent->hdr.maxcount )
2417 errorcode = EMAXCOUNT;
2419 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,
2425 static int arg_lit_checkfn(struct arg_lit *parent)
2427 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2428 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
2433 static void arg_lit_errorfn(
2434 struct arg_lit *parent,
2438 const char *progname)
2440 const char *shortopts = parent->hdr.shortopts;
2441 const char *longopts = parent->hdr.longopts;
2442 const char *datatype = parent->hdr.datatype;
2447 fprintf(fp, "%s: missing option ", progname);
2448 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2453 fprintf(fp, "%s: extraneous option ", progname);
2454 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2458 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
2459 errorcode, argval, progname));
2463 struct arg_lit * arg_lit0(
2464 const char * shortopts,
2465 const char * longopts,
2466 const char * glossary)
2468 return arg_litn(shortopts, longopts, 0, 1, glossary);
2472 struct arg_lit * arg_lit1(
2473 const char *shortopts,
2474 const char *longopts,
2475 const char *glossary)
2477 return arg_litn(shortopts, longopts, 1, 1, glossary);
2481 struct arg_lit * arg_litn(
2482 const char *shortopts,
2483 const char *longopts,
2486 const char *glossary)
2488 struct arg_lit *result;
2490 /* foolproof things by ensuring maxcount is not less than mincount */
2491 maxcount = (maxcount < mincount) ? mincount : maxcount;
2493 result = (struct arg_lit *)malloc(sizeof(struct arg_lit));
2496 /* init the arg_hdr struct */
2497 result->hdr.flag = 0;
2498 result->hdr.shortopts = shortopts;
2499 result->hdr.longopts = longopts;
2500 result->hdr.datatype = NULL;
2501 result->hdr.glossary = glossary;
2502 result->hdr.mincount = mincount;
2503 result->hdr.maxcount = maxcount;
2504 result->hdr.parent = result;
2505 result->hdr.resetfn = (arg_resetfn *)arg_lit_resetfn;
2506 result->hdr.scanfn = (arg_scanfn *)arg_lit_scanfn;
2507 result->hdr.checkfn = (arg_checkfn *)arg_lit_checkfn;
2508 result->hdr.errorfn = (arg_errorfn *)arg_lit_errorfn;
2510 /* init local variables */
2514 ARG_TRACE(("arg_litn() returns %p\n", result));
2517 /*******************************************************************************
2518 * This file is part of the argtable3 library.
2520 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2521 * <sheitmann@users.sourceforge.net>
2522 * All rights reserved.
2524 * Redistribution and use in source and binary forms, with or without
2525 * modification, are permitted provided that the following conditions are met:
2526 * * Redistributions of source code must retain the above copyright
2527 * notice, this list of conditions and the following disclaimer.
2528 * * Redistributions in binary form must reproduce the above copyright
2529 * notice, this list of conditions and the following disclaimer in the
2530 * documentation and/or other materials provided with the distribution.
2531 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2532 * may be used to endorse or promote products derived from this software
2533 * without specific prior written permission.
2535 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2536 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2537 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2538 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2539 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2540 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2541 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2542 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2543 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2544 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2545 ******************************************************************************/
2549 #include "argtable3.h"
2551 struct arg_rem *arg_rem(const char *datatype, const char *glossary)
2553 struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem));
2556 result->hdr.flag = 0;
2557 result->hdr.shortopts = NULL;
2558 result->hdr.longopts = NULL;
2559 result->hdr.datatype = datatype;
2560 result->hdr.glossary = glossary;
2561 result->hdr.mincount = 1;
2562 result->hdr.maxcount = 1;
2563 result->hdr.parent = result;
2564 result->hdr.resetfn = NULL;
2565 result->hdr.scanfn = NULL;
2566 result->hdr.checkfn = NULL;
2567 result->hdr.errorfn = NULL;
2570 ARG_TRACE(("arg_rem() returns %p\n", result));
2574 /*******************************************************************************
2575 * This file is part of the argtable3 library.
2577 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2578 * <sheitmann@users.sourceforge.net>
2579 * All rights reserved.
2581 * Redistribution and use in source and binary forms, with or without
2582 * modification, are permitted provided that the following conditions are met:
2583 * * Redistributions of source code must retain the above copyright
2584 * notice, this list of conditions and the following disclaimer.
2585 * * Redistributions in binary form must reproduce the above copyright
2586 * notice, this list of conditions and the following disclaimer in the
2587 * documentation and/or other materials provided with the distribution.
2588 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2589 * may be used to endorse or promote products derived from this software
2590 * without specific prior written permission.
2592 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2593 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2594 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2595 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2596 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2597 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2598 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2599 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2600 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2601 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2602 ******************************************************************************/
2607 #include "argtable3.h"
2612 /***************************************************************
2613 T-Rex a tiny regular expression library
2615 Copyright (C) 2003-2006 Alberto Demichelis
2617 This software is provided 'as-is', without any express
2618 or implied warranty. In no event will the authors be held
2619 liable for any damages arising from the use of this software.
2621 Permission is granted to anyone to use this software for
2622 any purpose, including commercial applications, and to alter
2623 it and redistribute it freely, subject to the following restrictions:
2625 1. The origin of this software must not be misrepresented;
2626 you must not claim that you wrote the original software.
2627 If you use this software in a product, an acknowledgment
2628 in the product documentation would be appreciated but
2631 2. Altered source versions must be plainly marked as such,
2632 and must not be misrepresented as being the original software.
2634 3. This notice may not be removed or altered from any
2635 source distribution.
2637 ****************************************************************/
2644 #define TRexChar unsigned short
2645 #define MAX_CHAR 0xFFFF
2646 #define _TREXC(c) L##c
2647 #define trex_strlen wcslen
2648 #define trex_printf wprintf
2650 #define TRexChar char
2651 #define MAX_CHAR 0xFF
2652 #define _TREXC(c) (c)
2653 #define trex_strlen strlen
2654 #define trex_printf printf
2658 #define TREX_API extern
2662 #define TRex_False 0
2664 #define TREX_ICASE ARG_REX_ICASE
2666 typedef unsigned int TRexBool;
2667 typedef struct TRex TRex;
2670 const TRexChar *begin;
2674 TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags);
2675 TREX_API void trex_free(TRex *exp);
2676 TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);
2677 TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
2678 TREX_API TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);
2679 TREX_API int trex_getsubexpcount(TRex* exp);
2680 TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
2692 const char *pattern;
2697 static void arg_rex_resetfn(struct arg_rex *parent)
2699 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2703 static int arg_rex_scanfn(struct arg_rex *parent, const char *argval)
2706 const TRexChar *error = NULL;
2708 TRexBool is_match = TRex_False;
2710 if (parent->count == parent->hdr.maxcount )
2712 /* maximum number of arguments exceeded */
2713 errorcode = EMAXCOUNT;
2717 /* a valid argument with no argument value was given. */
2718 /* This happens when an optional argument value was invoked. */
2719 /* leave parent argument value unaltered but still count the argument. */
2724 struct privhdr *priv = (struct privhdr *)parent->hdr.priv;
2726 /* test the current argument value for a match with the regular expression */
2727 /* if a match is detected, record the argument value in the arg_rex struct */
2729 rex = trex_compile(priv->pattern, &error, priv->flags);
2730 is_match = trex_match(rex, argval);
2732 errorcode = EREGNOMATCH;
2734 parent->sval[parent->count++] = argval;
2739 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode));
2743 static int arg_rex_checkfn(struct arg_rex *parent)
2745 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2746 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2748 /* free the regex "program" we constructed in resetfn */
2749 //regfree(&(priv->regex));
2751 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2755 static void arg_rex_errorfn(struct arg_rex *parent,
2759 const char *progname)
2761 const char *shortopts = parent->hdr.shortopts;
2762 const char *longopts = parent->hdr.longopts;
2763 const char *datatype = parent->hdr.datatype;
2765 /* make argval NULL safe */
2766 argval = argval ? argval : "";
2768 fprintf(fp, "%s: ", progname);
2772 fputs("missing option ", fp);
2773 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2777 fputs("excess option ", fp);
2778 arg_print_option(fp, shortopts, longopts, argval, "\n");
2782 fputs("illegal value ", fp);
2783 arg_print_option(fp, shortopts, longopts, argval, "\n");
2788 //char errbuff[256];
2789 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2790 //printf("%s\n", errbuff);
2797 struct arg_rex * arg_rex0(const char * shortopts,
2798 const char * longopts,
2799 const char * pattern,
2800 const char *datatype,
2802 const char *glossary)
2804 return arg_rexn(shortopts,
2814 struct arg_rex * arg_rex1(const char * shortopts,
2815 const char * longopts,
2816 const char * pattern,
2817 const char *datatype,
2819 const char *glossary)
2821 return arg_rexn(shortopts,
2832 struct arg_rex * arg_rexn(const char * shortopts,
2833 const char * longopts,
2834 const char * pattern,
2835 const char *datatype,
2839 const char *glossary)
2842 struct arg_rex *result;
2843 struct privhdr *priv;
2845 const TRexChar *error = NULL;
2851 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2852 printf("argtable: Bad argument table.\n");
2856 /* foolproof things by ensuring maxcount is not less than mincount */
2857 maxcount = (maxcount < mincount) ? mincount : maxcount;
2859 nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */
2860 + sizeof(struct privhdr) /* storage for private arg_rex data */
2861 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
2863 result = (struct arg_rex *)malloc(nbytes);
2867 /* init the arg_hdr struct */
2868 result->hdr.flag = ARG_HASVALUE;
2869 result->hdr.shortopts = shortopts;
2870 result->hdr.longopts = longopts;
2871 result->hdr.datatype = datatype ? datatype : pattern;
2872 result->hdr.glossary = glossary;
2873 result->hdr.mincount = mincount;
2874 result->hdr.maxcount = maxcount;
2875 result->hdr.parent = result;
2876 result->hdr.resetfn = (arg_resetfn *)arg_rex_resetfn;
2877 result->hdr.scanfn = (arg_scanfn *)arg_rex_scanfn;
2878 result->hdr.checkfn = (arg_checkfn *)arg_rex_checkfn;
2879 result->hdr.errorfn = (arg_errorfn *)arg_rex_errorfn;
2881 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2882 result->hdr.priv = result + 1;
2883 priv = (struct privhdr *)(result->hdr.priv);
2884 priv->pattern = pattern;
2885 priv->flags = flags;
2887 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2888 result->sval = (const char * *)(priv + 1);
2891 /* foolproof the string pointers by initializing them to reference empty strings */
2892 for (i = 0; i < maxcount; i++)
2893 result->sval[i] = "";
2895 /* here we construct and destroy a regex representation of the regular
2896 * expression for no other reason than to force any regex errors to be
2897 * trapped now rather than later. If we don't, then errors may go undetected
2898 * until an argument is actually parsed.
2901 rex = trex_compile(priv->pattern, &error, priv->flags);
2904 ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
2905 ARG_LOG(("argtable: Bad argument table.\n"));
2910 ARG_TRACE(("arg_rexn() returns %p\n", result));
2916 /* see copyright notice in trex.h */
2923 #define scisprint iswprint
2924 #define scstrlen wcslen
2925 #define scprintf wprintf
2928 #define scisprint isprint
2929 #define scstrlen strlen
2930 #define scprintf printf
2937 static const TRexChar *g_nnames[] =
2939 _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
2940 _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
2941 _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
2942 _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
2946 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2947 #define OP_OR (MAX_CHAR+2)
2948 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2949 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2950 #define OP_DOT (MAX_CHAR+5)
2951 #define OP_CLASS (MAX_CHAR+6)
2952 #define OP_CCLASS (MAX_CHAR+7)
2953 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2954 #define OP_RANGE (MAX_CHAR+9)
2955 #define OP_CHAR (MAX_CHAR+10)
2956 #define OP_EOL (MAX_CHAR+11)
2957 #define OP_BOL (MAX_CHAR+12)
2958 #define OP_WB (MAX_CHAR+13)
2960 #define TREX_SYMBOL_ANY_CHAR ('.')
2961 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
2962 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
2963 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
2964 #define TREX_SYMBOL_BRANCH ('|')
2965 #define TREX_SYMBOL_END_OF_STRING ('$')
2966 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
2967 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
2970 typedef int TRexNodeType;
2972 typedef struct tagTRexNode{
2980 const TRexChar *_eol;
2981 const TRexChar *_bol;
2989 TRexMatch *_matches;
2992 const TRexChar **_error;
2996 static int trex_list(TRex *exp);
2998 static int trex_newnode(TRex *exp, TRexNodeType type)
3003 n.next = n.right = n.left = -1;
3005 n.right = exp->_nsubexpr++;
3006 if(exp->_nallocated < (exp->_nsize + 1)) {
3007 exp->_nallocated *= 2;
3008 exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
3010 exp->_nodes[exp->_nsize++] = n;
3011 newid = exp->_nsize - 1;
3015 static void trex_error(TRex *exp,const TRexChar *error)
3017 if(exp->_error) *exp->_error = error;
3018 longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
3021 static void trex_expect(TRex *exp, int n){
3023 trex_error(exp, _SC("expected paren"));
3027 static TRexChar trex_escapechar(TRex *exp)
3029 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
3032 case 'v': exp->_p++; return '\v';
3033 case 'n': exp->_p++; return '\n';
3034 case 't': exp->_p++; return '\t';
3035 case 'r': exp->_p++; return '\r';
3036 case 'f': exp->_p++; return '\f';
3037 default: return (*exp->_p++);
3039 } else if(!scisprint((int) *exp->_p)) trex_error(exp,_SC("letter expected"));
3040 return (*exp->_p++);
3043 static int trex_charclass(TRex *exp,int classid)
3045 int n = trex_newnode(exp,OP_CCLASS);
3046 exp->_nodes[n].left = classid;
3050 static int trex_charnode(TRex *exp,TRexBool isclass)
3053 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
3056 case 'n': exp->_p++; return trex_newnode(exp,'\n');
3057 case 't': exp->_p++; return trex_newnode(exp,'\t');
3058 case 'r': exp->_p++; return trex_newnode(exp,'\r');
3059 case 'f': exp->_p++; return trex_newnode(exp,'\f');
3060 case 'v': exp->_p++; return trex_newnode(exp,'\v');
3061 case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
3062 case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
3063 case 'p': case 'P': case 'l': case 'u':
3065 t = *exp->_p; exp->_p++;
3066 return trex_charclass(exp,t);
3071 int node = trex_newnode(exp,OP_WB);
3072 exp->_nodes[node].left = *exp->_p;
3078 t = *exp->_p; exp->_p++;
3079 return trex_newnode(exp,t);
3082 else if(!scisprint((int) *exp->_p)) {
3084 trex_error(exp,_SC("letter expected"));
3086 t = *exp->_p; exp->_p++;
3087 return trex_newnode(exp,t);
3089 static int trex_class(TRex *exp)
3092 int first = -1,chain;
3093 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
3094 ret = trex_newnode(exp,OP_NCLASS);
3096 }else ret = trex_newnode(exp,OP_CLASS);
3098 if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
3100 while(*exp->_p != ']' && exp->_p != exp->_eol) {
3101 if(*exp->_p == '-' && first != -1){
3103 if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
3104 r = trex_newnode(exp,OP_RANGE);
3105 if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
3106 if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
3107 exp->_nodes[r].left = exp->_nodes[first].type;
3108 t = trex_escapechar(exp);
3109 exp->_nodes[r].right = t;
3110 exp->_nodes[chain].next = r;
3117 exp->_nodes[chain].next = c;
3119 first = trex_charnode(exp,TRex_True);
3122 first = trex_charnode(exp,TRex_True);
3128 exp->_nodes[chain].next = c;
3133 exp->_nodes[ret].left = exp->_nodes[ret].next;
3134 exp->_nodes[ret].next = -1;
3138 static int trex_parsenumber(TRex *exp)
3140 int ret = *exp->_p-'0';
3143 while(isdigit((int) *exp->_p)) {
3144 ret = ret*10+(*exp->_p++-'0');
3145 if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
3151 static int trex_element(TRex *exp)
3161 if(*exp->_p =='?') {
3163 trex_expect(exp,':');
3164 expr = trex_newnode(exp,OP_NOCAPEXPR);
3167 expr = trex_newnode(exp,OP_EXPR);
3168 newn = trex_list(exp);
3169 exp->_nodes[expr].left = newn;
3171 trex_expect(exp,')');
3176 ret = trex_class(exp);
3177 trex_expect(exp,']');
3179 case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
3180 case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
3182 ret = trex_charnode(exp,TRex_False);
3187 TRexBool isgreedy = TRex_False;
3188 unsigned short p0 = 0, p1 = 0;
3190 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3191 case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3192 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
3195 if(!isdigit((int) *exp->_p)) trex_error(exp,_SC("number expected"));
3196 p0 = (unsigned short)trex_parsenumber(exp);
3197 /*******************************/
3205 if(isdigit((int) *exp->_p)){
3206 p1 = (unsigned short)trex_parsenumber(exp);
3208 trex_expect(exp,'}');
3211 trex_error(exp,_SC(", or } expected"));
3213 /*******************************/
3214 isgreedy = TRex_True;
3219 int nnode = trex_newnode(exp,OP_GREEDY);
3220 exp->_nodes[nnode].left = ret;
3221 exp->_nodes[nnode].right = ((p0)<<16)|p1;
3225 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')) {
3226 int nnode = trex_element(exp);
3227 exp->_nodes[ret].next = nnode;
3233 static int trex_list(TRex *exp)
3236 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
3238 ret = trex_newnode(exp,OP_BOL);
3240 e = trex_element(exp);
3242 exp->_nodes[ret].next = e;
3246 if(*exp->_p == TREX_SYMBOL_BRANCH) {
3249 temp = trex_newnode(exp,OP_OR);
3250 exp->_nodes[temp].left = ret;
3251 tright = trex_list(exp);
3252 exp->_nodes[temp].right = tright;
3258 static TRexBool trex_matchcclass(int cclass,TRexChar ch)
3262 case 'a': return isalpha(c)?TRex_True:TRex_False;
3263 case 'A': return !isalpha(c)?TRex_True:TRex_False;
3264 case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
3265 case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
3266 case 's': return isspace(c)?TRex_True:TRex_False;
3267 case 'S': return !isspace(c)?TRex_True:TRex_False;
3268 case 'd': return isdigit(c)?TRex_True:TRex_False;
3269 case 'D': return !isdigit(c)?TRex_True:TRex_False;
3270 case 'x': return isxdigit(c)?TRex_True:TRex_False;
3271 case 'X': return !isxdigit(c)?TRex_True:TRex_False;
3272 case 'c': return iscntrl(c)?TRex_True:TRex_False;
3273 case 'C': return !iscntrl(c)?TRex_True:TRex_False;
3274 case 'p': return ispunct(c)?TRex_True:TRex_False;
3275 case 'P': return !ispunct(c)?TRex_True:TRex_False;
3276 case 'l': return islower(c)?TRex_True:TRex_False;
3277 case 'u': return isupper(c)?TRex_True:TRex_False;
3279 return TRex_False; /*cannot happen*/
3282 static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
3285 switch(node->type) {
3287 if (exp->_flags & TREX_ICASE)
3289 if(c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True;
3290 if(c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True;
3294 if(c >= node->left && c <= node->right) return TRex_True;
3298 if(trex_matchcclass(node->left,c)) return TRex_True;
3301 if (exp->_flags & TREX_ICASE)
3303 if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;
3307 if(c == node->type)return TRex_True;
3311 } while((node->next != -1) && (node = &exp->_nodes[node->next]));
3315 static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
3318 TRexNodeType type = node->type;
3321 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3322 TRexNode *greedystop = NULL;
3323 int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
3324 const TRexChar *s=str, *good = str;
3326 if(node->next != -1) {
3327 greedystop = &exp->_nodes[node->next];
3333 while((nmaches == 0xFFFF || nmaches < p1)) {
3335 const TRexChar *stop;
3336 if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
3341 //checks that 0 matches satisfy the expression(if so skips)
3342 //if not would always stop(for instance if is a '?')
3343 if(greedystop->type != OP_GREEDY ||
3344 (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
3346 TRexNode *gnext = NULL;
3347 if(greedystop->next != -1) {
3348 gnext = &exp->_nodes[greedystop->next];
3349 }else if(next && next->next != -1){
3350 gnext = &exp->_nodes[next->next];
3352 stop = trex_matchnode(exp,greedystop,s,gnext);
3354 //if satisfied stop it
3355 if(p0 == p1 && p0 == nmaches) break;
3356 else if(nmaches >= p0 && p1 == 0xFFFF) break;
3357 else if(nmaches >= p0 && nmaches <= p1) break;
3365 if(p0 == p1 && p0 == nmaches) return good;
3366 else if(nmaches >= p0 && p1 == 0xFFFF) return good;
3367 else if(nmaches >= p0 && nmaches <= p1) return good;
3371 const TRexChar *asd = str;
3372 TRexNode *temp=&exp->_nodes[node->left];
3373 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3374 if(temp->next != -1)
3375 temp = &exp->_nodes[temp->next];
3380 temp = &exp->_nodes[node->right];
3381 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3382 if(temp->next != -1)
3383 temp = &exp->_nodes[temp->next];
3392 TRexNode *n = &exp->_nodes[node->left];
3393 const TRexChar *cur = str;
3395 if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
3396 capture = exp->_currsubexp;
3397 exp->_matches[capture].begin = cur;
3402 TRexNode *subnext = NULL;
3404 subnext = &exp->_nodes[n->next];
3408 if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
3410 exp->_matches[capture].begin = 0;
3411 exp->_matches[capture].len = 0;
3415 } while((n->next != -1) && (n = &exp->_nodes[n->next]));
3418 exp->_matches[capture].len = cur - exp->_matches[capture].begin;
3422 if((str == exp->_bol && !isspace((int) *str))
3423 || ((str == exp->_eol && !isspace((int) *(str-1))))
3424 || ((!isspace((int) *str) && isspace((int) *(str+1))))
3425 || ((isspace((int) *str) && !isspace((int) *(str+1)))) ) {
3426 return (node->left == 'b')?str:NULL;
3428 return (node->left == 'b')?NULL:str;
3430 if(str == exp->_bol) return str;
3433 if(str == exp->_eol) return str;
3440 if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
3446 if(trex_matchcclass(node->left,*str)) {
3452 if (exp->_flags & TREX_ICASE)
3454 if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL;
3458 if (*str != node->type) return NULL;
3467 TRex *trex_compile(const TRexChar *pattern,const TRexChar **error,int flags)
3469 TRex *exp = (TRex *)malloc(sizeof(TRex));
3470 exp->_eol = exp->_bol = NULL;
3472 exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
3473 exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
3477 exp->_first = trex_newnode(exp,OP_EXPR);
3478 exp->_error = error;
3479 exp->_jmpbuf = malloc(sizeof(jmp_buf));
3480 exp->_flags = flags;
3481 if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
3482 int res = trex_list(exp);
3483 exp->_nodes[exp->_first].left = res;
3485 trex_error(exp,_SC("unexpected character"));
3490 nsize = exp->_nsize;
3491 t = &exp->_nodes[0];
3492 scprintf(_SC("\n"));
3493 for(i = 0;i < nsize; i++) {
3494 if(exp->_nodes[i].type>MAX_CHAR)
3495 scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
3497 scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
3498 scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
3500 scprintf(_SC("\n"));
3503 exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
3504 memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
3513 void trex_free(TRex *exp)
3516 if(exp->_nodes) free(exp->_nodes);
3517 if(exp->_jmpbuf) free(exp->_jmpbuf);
3518 if(exp->_matches) free(exp->_matches);
3523 TRexBool trex_match(TRex* exp,const TRexChar* text)
3525 const TRexChar* res = NULL;
3527 exp->_eol = text + scstrlen(text);
3528 exp->_currsubexp = 0;
3529 res = trex_matchnode(exp,exp->_nodes,text,NULL);
3530 if(res == NULL || res != exp->_eol)
3535 TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
3537 const TRexChar *cur = NULL;
3538 int node = exp->_first;
3539 if(text_begin >= text_end) return TRex_False;
3540 exp->_bol = text_begin;
3541 exp->_eol = text_end;
3545 exp->_currsubexp = 0;
3546 cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
3549 node = exp->_nodes[node].next;
3552 } while(cur == NULL && text_begin != text_end);
3559 if(out_begin) *out_begin = text_begin;
3560 if(out_end) *out_end = cur;
3564 TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
3566 return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
3569 int trex_getsubexpcount(TRex* exp)
3571 return exp->_nsubexpr;
3574 TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
3576 if( n<0 || n >= exp->_nsubexpr) return TRex_False;
3577 *subexp = exp->_matches[n];
3580 /*******************************************************************************
3581 * This file is part of the argtable3 library.
3583 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3584 * <sheitmann@users.sourceforge.net>
3585 * All rights reserved.
3587 * Redistribution and use in source and binary forms, with or without
3588 * modification, are permitted provided that the following conditions are met:
3589 * * Redistributions of source code must retain the above copyright
3590 * notice, this list of conditions and the following disclaimer.
3591 * * Redistributions in binary form must reproduce the above copyright
3592 * notice, this list of conditions and the following disclaimer in the
3593 * documentation and/or other materials provided with the distribution.
3594 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3595 * may be used to endorse or promote products derived from this software
3596 * without specific prior written permission.
3598 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3599 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3600 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3601 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3602 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3603 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3604 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3605 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3606 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3607 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3608 ******************************************************************************/
3612 #include "argtable3.h"
3615 static void arg_str_resetfn(struct arg_str *parent)
3617 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
3622 static int arg_str_scanfn(struct arg_str *parent, const char *argval)
3626 if (parent->count == parent->hdr.maxcount)
3628 /* maximum number of arguments exceeded */
3629 errorcode = EMAXCOUNT;
3633 /* a valid argument with no argument value was given. */
3634 /* This happens when an optional argument value was invoked. */
3635 /* leave parent arguiment value unaltered but still count the argument. */
3640 parent->sval[parent->count++] = argval;
3643 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
3648 static int arg_str_checkfn(struct arg_str *parent)
3650 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
3652 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
3657 static void arg_str_errorfn(
3658 struct arg_str *parent,
3662 const char *progname)
3664 const char *shortopts = parent->hdr.shortopts;
3665 const char *longopts = parent->hdr.longopts;
3666 const char *datatype = parent->hdr.datatype;
3668 /* make argval NULL safe */
3669 argval = argval ? argval : "";
3671 fprintf(fp, "%s: ", progname);
3675 fputs("missing option ", fp);
3676 arg_print_option(fp, shortopts, longopts, datatype, "\n");
3680 fputs("excess option ", fp);
3681 arg_print_option(fp, shortopts, longopts, argval, "\n");
3687 struct arg_str * arg_str0(
3688 const char *shortopts,
3689 const char *longopts,
3690 const char *datatype,
3691 const char *glossary)
3693 return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
3697 struct arg_str * arg_str1(
3698 const char *shortopts,
3699 const char *longopts,
3700 const char *datatype,
3701 const char *glossary)
3703 return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
3707 struct arg_str * arg_strn(
3708 const char *shortopts,
3709 const char *longopts,
3710 const char *datatype,
3713 const char *glossary)
3716 struct arg_str *result;
3718 /* should not allow this stupid error */
3719 /* we should return an error code warning this logic error */
3720 /* foolproof things by ensuring maxcount is not less than mincount */
3721 maxcount = (maxcount < mincount) ? mincount : maxcount;
3723 nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
3724 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
3726 result = (struct arg_str *)malloc(nbytes);
3731 /* init the arg_hdr struct */
3732 result->hdr.flag = ARG_HASVALUE;
3733 result->hdr.shortopts = shortopts;
3734 result->hdr.longopts = longopts;
3735 result->hdr.datatype = datatype ? datatype : "<string>";
3736 result->hdr.glossary = glossary;
3737 result->hdr.mincount = mincount;
3738 result->hdr.maxcount = maxcount;
3739 result->hdr.parent = result;
3740 result->hdr.resetfn = (arg_resetfn *)arg_str_resetfn;
3741 result->hdr.scanfn = (arg_scanfn *)arg_str_scanfn;
3742 result->hdr.checkfn = (arg_checkfn *)arg_str_checkfn;
3743 result->hdr.errorfn = (arg_errorfn *)arg_str_errorfn;
3745 /* store the sval[maxcount] array immediately after the arg_str struct */
3746 result->sval = (const char * *)(result + 1);
3749 /* foolproof the string pointers by initialising them to reference empty strings */
3750 for (i = 0; i < maxcount; i++)
3751 result->sval[i] = "";
3754 ARG_TRACE(("arg_strn() returns %p\n", result));
3757 /*******************************************************************************
3758 * This file is part of the argtable3 library.
3760 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3761 * <sheitmann@users.sourceforge.net>
3762 * All rights reserved.
3764 * Redistribution and use in source and binary forms, with or without
3765 * modification, are permitted provided that the following conditions are met:
3766 * * Redistributions of source code must retain the above copyright
3767 * notice, this list of conditions and the following disclaimer.
3768 * * Redistributions in binary form must reproduce the above copyright
3769 * notice, this list of conditions and the following disclaimer in the
3770 * documentation and/or other materials provided with the distribution.
3771 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3772 * may be used to endorse or promote products derived from this software
3773 * without specific prior written permission.
3775 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3776 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3777 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3778 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3779 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3780 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3781 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3782 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3783 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3784 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3785 ******************************************************************************/
3792 #include "argtable3.h"
3795 void arg_register_error(struct arg_end *end,
3800 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3801 if (end->count < end->hdr.maxcount)
3803 end->error[end->count] = error;
3804 end->parent[end->count] = parent;
3805 end->argval[end->count] = argval;
3810 end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;
3811 end->parent[end->hdr.maxcount - 1] = end;
3812 end->argval[end->hdr.maxcount - 1] = NULL;
3818 * Return index of first table entry with a matching short option
3819 * or -1 if no match was found.
3822 int find_shortoption(struct arg_hdr * *table, char shortopt)
3825 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3827 if (table[tabindex]->shortopts &&
3828 strchr(table[tabindex]->shortopts, shortopt))
3839 struct option *options;
3844 void dump_longoptions(struct longoptions * longoptions)
3847 printf("getoptval = %d\n", longoptions->getoptval);
3848 printf("noptions = %d\n", longoptions->noptions);
3849 for (i = 0; i < longoptions->noptions; i++)
3851 printf("options[%d].name = \"%s\"\n",
3853 longoptions->options[i].name);
3854 printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);
3855 printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);
3856 printf("options[%d].val = %d\n", i, longoptions->options[i].val);
3862 struct longoptions * alloc_longoptions(struct arg_hdr * *table)
3864 struct longoptions *result;
3867 size_t longoptlen = 0;
3871 * Determine the total number of option structs required
3872 * by counting the number of comma separated long options
3873 * in all table entries and return the count in noptions.
3874 * note: noptions starts at 1 not 0 because we getoptlong
3875 * requires a NULL option entry to terminate the option array.
3876 * While we are at it, count the number of chars required
3877 * to store private copies of all the longoption strings
3878 * and return that count in logoptlen.
3883 const char *longopts = table[tabindex]->longopts;
3884 longoptlen += (longopts ? strlen(longopts) : 0) + 1;
3888 longopts = strchr(longopts + 1, ',');
3890 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
3891 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3894 /* allocate storage for return data structure as: */
3895 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3896 nbytes = sizeof(struct longoptions)
3897 + sizeof(struct option) * noptions
3899 result = (struct longoptions *)malloc(nbytes);
3902 int option_index = 0;
3905 result->getoptval = 0;
3906 result->noptions = noptions;
3907 result->options = (struct option *)(result + 1);
3908 store = (char *)(result->options + noptions);
3910 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3912 const char *longopts = table[tabindex]->longopts;
3914 while(longopts && *longopts)
3916 char *storestart = store;
3918 /* copy progressive longopt strings into the store */
3919 while (*longopts != 0 && *longopts != ',')
3920 *store++ = *longopts++;
3922 if (*longopts == ',')
3924 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3926 result->options[option_index].name = storestart;
3927 result->options[option_index].flag = &(result->getoptval);
3928 result->options[option_index].val = tabindex;
3929 if (table[tabindex]->flag & ARG_HASOPTVALUE)
3930 result->options[option_index].has_arg = 2;
3931 else if (table[tabindex]->flag & ARG_HASVALUE)
3932 result->options[option_index].has_arg = 1;
3934 result->options[option_index].has_arg = 0;
3939 /* terminate the options array with a zero-filled entry */
3940 result->options[option_index].name = 0;
3941 result->options[option_index].has_arg = 0;
3942 result->options[option_index].flag = 0;
3943 result->options[option_index].val = 0;
3946 /*dump_longoptions(result);*/
3951 char * alloc_shortoptions(struct arg_hdr * *table)
3957 /* determine the total number of option chars required */
3958 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3960 struct arg_hdr *hdr = table[tabindex];
3961 len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);
3964 result = malloc(len);
3969 /* add a leading ':' so getopt return codes distinguish */
3970 /* unrecognised option and options missing argument values */
3973 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3975 struct arg_hdr *hdr = table[tabindex];
3976 const char *shortopts = hdr->shortopts;
3977 while(shortopts && *shortopts)
3979 *res++ = *shortopts++;
3980 if (hdr->flag & ARG_HASVALUE)
3982 if (hdr->flag & ARG_HASOPTVALUE)
3986 /* null terminate the string */
3990 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
3995 /* return index of the table terminator entry */
3997 int arg_endindex(struct arg_hdr * *table)
4000 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4007 void arg_parse_tagged(int argc,
4009 struct arg_hdr * *table,
4010 struct arg_end *endtable)
4012 struct longoptions *longoptions;
4016 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4018 /* allocate short and long option arrays for the given opttable[]. */
4019 /* if the allocs fail then put an error msg in the last table entry. */
4020 longoptions = alloc_longoptions(table);
4021 shortoptions = alloc_shortoptions(table);
4022 if (!longoptions || !shortoptions)
4024 /* one or both memory allocs failed */
4025 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4026 /* free anything that was allocated (this is null safe) */
4032 /*dump_longoptions(longoptions);*/
4034 /* reset getopts internal option-index to zero, and disable error reporting */
4038 /* fetch and process args using getopt_long */
4040 getopt_long(argc, argv, shortoptions, longoptions->options,
4044 printf("optarg='%s'\n",optarg);
4045 printf("optind=%d\n",optind);
4046 printf("copt=%c\n",(char)copt);
4047 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
4053 int tabindex = longoptions->getoptval;
4054 void *parent = table[tabindex]->parent;
4055 /*printf("long option detected from argtable[%d]\n", tabindex);*/
4056 if (optarg && optarg[0] == 0 &&
4057 (table[tabindex]->flag & ARG_HASVALUE))
4059 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
4060 arg_register_error(endtable, endtable, ARG_EMISSARG,
4062 /* continue to scan the (empty) argument value to enforce argument count checking */
4064 if (table[tabindex]->scanfn)
4066 int errorcode = table[tabindex]->scanfn(parent, optarg);
4068 arg_register_error(endtable, parent, errorcode, optarg);
4075 * getopt_long() found an unrecognised short option.
4076 * if it was a short option its value is in optopt
4077 * if it was a long option then optopt=0
4082 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4083 arg_register_error(endtable, endtable, ARG_ELONGOPT,
4087 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4088 arg_register_error(endtable, endtable, optopt, NULL);
4095 * getopt_long() found an option with its argument missing.
4097 /*printf(": option %s requires an argument\n",argv[optind-1]); */
4098 arg_register_error(endtable, endtable, ARG_EMISSARG,
4104 /* getopt_long() found a valid short option */
4105 int tabindex = find_shortoption(table, (char)copt);
4106 /*printf("short option detected from argtable[%d]\n", tabindex);*/
4109 /* should never get here - but handle it just in case */
4110 /*printf("unrecognised short option %d\n",copt);*/
4111 arg_register_error(endtable, endtable, copt, NULL);
4115 if (table[tabindex]->scanfn)
4117 void *parent = table[tabindex]->parent;
4118 int errorcode = table[tabindex]->scanfn(parent, optarg);
4120 arg_register_error(endtable, parent, errorcode, optarg);
4134 void arg_parse_untagged(int argc,
4136 struct arg_hdr * *table,
4137 struct arg_end *endtable)
4141 const char *optarglast = NULL;
4142 void *parentlast = NULL;
4144 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4145 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4150 /* if we have exhausted our argv[optind] entries then we have finished */
4153 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4157 /* skip table entries with non-null long or short options (they are not untagged entries) */
4158 if (table[tabindex]->longopts || table[tabindex]->shortopts)
4160 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
4165 /* skip table entries with NULL scanfn */
4166 if (!(table[tabindex]->scanfn))
4168 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4173 /* attempt to scan the current argv[optind] with the current */
4174 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
4175 /* try again with the next table[] entry. */
4176 parent = table[tabindex]->parent;
4177 errorcode = table[tabindex]->scanfn(parent, argv[optind]);
4180 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4181 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4184 /* clear the last tentative error */
4189 /* failure, try same argv[optind] with next table[tabindex] entry */
4190 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4193 /* remember this as a tentative error we may wish to reinstate later */
4194 errorlast = errorcode;
4195 optarglast = argv[optind];
4196 parentlast = parent;
4201 /* if a tenative error still remains at this point then register it as a proper error */
4204 arg_register_error(endtable, parentlast, errorlast, optarglast);
4208 /* only get here when not all argv[] entries were consumed */
4209 /* register an error for each unused argv[] entry */
4210 while (optind < argc)
4212 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4213 arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
4221 void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable)
4224 /* printf("arg_parse_check()\n"); */
4227 if (table[tabindex]->checkfn)
4229 void *parent = table[tabindex]->parent;
4230 int errorcode = table[tabindex]->checkfn(parent);
4232 arg_register_error(endtable, parent, errorcode, NULL);
4234 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4239 void arg_reset(void * *argtable)
4241 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4243 /*printf("arg_reset(%p)\n",argtable);*/
4246 if (table[tabindex]->resetfn)
4247 table[tabindex]->resetfn(table[tabindex]->parent);
4248 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4252 int arg_parse(int argc, char * *argv, void * *argtable)
4254 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4255 struct arg_end *endtable;
4257 char * *argvcopy = NULL;
4259 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4261 /* reset any argtable data from previous invocations */
4262 arg_reset(argtable);
4264 /* locate the first end-of-table marker within the array */
4265 endindex = arg_endindex(table);
4266 endtable = (struct arg_end *)table[endindex];
4268 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4269 /* Failure to trap this case results in an unwanted NULL result from */
4270 /* the malloc for argvcopy (next code block). */
4273 /* We must still perform post-parse checks despite the absence of command line arguments */
4274 arg_parse_check(table, endtable);
4276 /* Now we are finished */
4277 return endtable->count;
4280 argvcopy = (char **)malloc(sizeof(char *) * (argc + 1));
4286 Fill in the local copy of argv[]. We need a local copy
4287 because getopt rearranges argv[] which adversely affects
4288 susbsequent parsing attempts.
4290 for (i = 0; i < argc; i++)
4291 argvcopy[i] = argv[i];
4293 argvcopy[argc] = NULL;
4295 /* parse the command line (local copy) for tagged options */
4296 arg_parse_tagged(argc, argvcopy, table, endtable);
4298 /* parse the command line (local copy) for untagged options */
4299 arg_parse_untagged(argc, argvcopy, table, endtable);
4301 /* if no errors so far then perform post-parse checks otherwise dont bother */
4302 if (endtable->count == 0)
4303 arg_parse_check(table, endtable);
4305 /* release the local copt of argv[] */
4310 /* memory alloc failed */
4311 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4314 return endtable->count;
4319 * Concatenate contents of src[] string onto *pdest[] string.
4320 * The *pdest pointer is altered to point to the end of the
4321 * target string and *pndest is decremented by the same number
4323 * Does not append more than *pndest chars into *pdest[]
4324 * so as to prevent buffer overruns.
4325 * Its something like strncat() but more efficient for repeated
4326 * calls on the same destination string.
4328 * char dest[30] = "good"
4329 * size_t ndest = sizeof(dest);
4330 * char *pdest = dest;
4331 * arg_char(&pdest,"bye ",&ndest);
4332 * arg_char(&pdest,"cruel ",&ndest);
4333 * arg_char(&pdest,"world!",&ndest);
4335 * dest[] == "goodbye cruel world!"
4339 void arg_cat(char * *pdest, const char *src, size_t *pndest)
4341 char *dest = *pdest;
4342 char *end = dest + *pndest;
4344 /*locate null terminator of dest string */
4345 while(dest < end && *dest != 0)
4348 /* concat src string to dest string */
4349 while(dest < end && *src != 0)
4352 /* null terminate dest string */
4355 /* update *pdest and *pndest */
4356 *pndest = end - dest;
4362 void arg_cat_option(char *dest,
4364 const char *shortopts,
4365 const char *longopts,
4366 const char *datatype,
4373 /* note: option array[] is initialiazed dynamically here to satisfy */
4374 /* a deficiency in the watcom compiler wrt static array initializers. */
4376 option[1] = shortopts[0];
4379 arg_cat(&dest, option, &ndest);
4382 arg_cat(&dest, " ", &ndest);
4385 arg_cat(&dest, "[", &ndest);
4386 arg_cat(&dest, datatype, &ndest);
4387 arg_cat(&dest, "]", &ndest);
4390 arg_cat(&dest, datatype, &ndest);
4397 /* add "--" tag prefix */
4398 arg_cat(&dest, "--", &ndest);
4400 /* add comma separated option tag */
4401 ncspn = strcspn(longopts, ",");
4402 strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
4406 arg_cat(&dest, "=", &ndest);
4409 arg_cat(&dest, "[", &ndest);
4410 arg_cat(&dest, datatype, &ndest);
4411 arg_cat(&dest, "]", &ndest);
4414 arg_cat(&dest, datatype, &ndest);
4421 arg_cat(&dest, "[", &ndest);
4422 arg_cat(&dest, datatype, &ndest);
4423 arg_cat(&dest, "]", &ndest);
4426 arg_cat(&dest, datatype, &ndest);
4431 void arg_cat_optionv(char *dest,
4433 const char *shortopts,
4434 const char *longopts,
4435 const char *datatype,
4437 const char *separator)
4439 separator = separator ? separator : "";
4443 const char *c = shortopts;
4449 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4450 /* a deficiency in the watcom compiler wrt static array initializers. */
4455 arg_cat(&dest, shortopt, &ndest);
4457 arg_cat(&dest, separator, &ndest);
4461 /* put separator between long opts and short opts */
4462 if (shortopts && longopts)
4463 arg_cat(&dest, separator, &ndest);
4467 const char *c = longopts;
4472 /* add "--" tag prefix */
4473 arg_cat(&dest, "--", &ndest);
4475 /* add comma separated option tag */
4476 ncspn = strcspn(c, ",");
4477 strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
4480 /* add given separator in place of comma */
4483 arg_cat(&dest, separator, &ndest);
4492 arg_cat(&dest, "=", &ndest);
4494 arg_cat(&dest, " ", &ndest);
4498 arg_cat(&dest, "[", &ndest);
4499 arg_cat(&dest, datatype, &ndest);
4500 arg_cat(&dest, "]", &ndest);
4503 arg_cat(&dest, datatype, &ndest);
4508 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4509 void arg_print_option(FILE *fp,
4510 const char *shortopts,
4511 const char *longopts,
4512 const char *datatype,
4515 char syntax[200] = "";
4516 suffix = suffix ? suffix : "";
4518 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4519 arg_cat_optionv(syntax,
4533 * Print a GNU style [OPTION] string in which all short options that
4534 * do not take argument values are presented in abbreviated form, as
4535 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4538 void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table)
4541 const char *format1 = " -%c";
4542 const char *format2 = " [-%c";
4543 const char *suffix = "";
4545 /* print all mandatory switches that are without argument values */
4547 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4550 /* skip optional options */
4551 if (table[tabindex]->mincount < 1)
4554 /* skip non-short options */
4555 if (table[tabindex]->shortopts == NULL)
4558 /* skip options that take argument values */
4559 if (table[tabindex]->flag & ARG_HASVALUE)
4562 /* print the short option (only the first short option char, ignore multiple choices)*/
4563 fprintf(fp, format1, table[tabindex]->shortopts[0]);
4568 /* print all optional switches that are without argument values */
4570 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4573 /* skip mandatory args */
4574 if (table[tabindex]->mincount > 0)
4577 /* skip args without short options */
4578 if (table[tabindex]->shortopts == NULL)
4581 /* skip args with values */
4582 if (table[tabindex]->flag & ARG_HASVALUE)
4585 /* print first short option */
4586 fprintf(fp, format2, table[tabindex]->shortopts[0]);
4591 fprintf(fp, "%s", suffix);
4595 void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix)
4597 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4600 /* print GNU style [OPTION] string */
4601 arg_print_gnuswitch(fp, table);
4603 /* print remaining options in abbreviated style */
4605 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4608 char syntax[200] = "";
4609 const char *shortopts, *longopts, *datatype;
4611 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4612 if (table[tabindex]->shortopts &&
4613 !(table[tabindex]->flag & ARG_HASVALUE))
4616 shortopts = table[tabindex]->shortopts;
4617 longopts = table[tabindex]->longopts;
4618 datatype = table[tabindex]->datatype;
4619 arg_cat_option(syntax,
4624 table[tabindex]->flag & ARG_HASOPTVALUE);
4626 if (strlen(syntax) > 0)
4628 /* print mandatory instances of this option */
4629 for (i = 0; i < table[tabindex]->mincount; i++)
4630 fprintf(fp, " %s", syntax);
4632 /* print optional instances enclosed in "[..]" */
4633 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4638 fprintf(fp, " [%s]", syntax);
4641 fprintf(fp, " [%s] [%s]", syntax, syntax);
4644 fprintf(fp, " [%s]...", syntax);
4651 fprintf(fp, "%s", suffix);
4655 void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix)
4657 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4660 /* print remaining options in abbreviated style */
4662 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4665 char syntax[200] = "";
4666 const char *shortopts, *longopts, *datatype;
4668 shortopts = table[tabindex]->shortopts;
4669 longopts = table[tabindex]->longopts;
4670 datatype = table[tabindex]->datatype;
4671 arg_cat_optionv(syntax,
4676 table[tabindex]->flag & ARG_HASOPTVALUE,
4679 /* print mandatory options */
4680 for (i = 0; i < table[tabindex]->mincount; i++)
4681 fprintf(fp, " %s", syntax);
4683 /* print optional args enclosed in "[..]" */
4684 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4689 fprintf(fp, " [%s]", syntax);
4692 fprintf(fp, " [%s] [%s]", syntax, syntax);
4695 fprintf(fp, " [%s]...", syntax);
4701 fprintf(fp, "%s", suffix);
4705 void arg_print_glossary(FILE *fp, void * *argtable, const char *format)
4707 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4710 format = format ? format : " %-20s %s\n";
4711 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4713 if (table[tabindex]->glossary)
4715 char syntax[200] = "";
4716 const char *shortopts = table[tabindex]->shortopts;
4717 const char *longopts = table[tabindex]->longopts;
4718 const char *datatype = table[tabindex]->datatype;
4719 const char *glossary = table[tabindex]->glossary;
4720 arg_cat_optionv(syntax,
4725 table[tabindex]->flag & ARG_HASOPTVALUE,
4727 fprintf(fp, format, syntax, glossary);
4734 * Print a piece of text formatted, which means in a column with a
4735 * left and a right margin. The lines are wrapped at whitspaces next
4736 * to right margin. The function does not indent the first line, but
4737 * only the following ones.
4740 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4741 * will result in the following output:
4749 * Too long lines will be wrapped in the middle of a word.
4751 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4752 * will result in the following output:
4760 * As you see, the first line is not indented. This enables output of
4761 * lines, which start in a line where output already happened.
4763 * Author: Uli Fouquet
4765 void arg_print_formatted( FILE *fp,
4766 const unsigned lmargin,
4767 const unsigned rmargin,
4770 const unsigned textlen = strlen( text );
4771 unsigned line_start = 0;
4772 unsigned line_end = textlen + 1;
4773 const unsigned colwidth = (rmargin - lmargin) + 1;
4775 /* Someone doesn't like us... */
4776 if ( line_end < line_start )
4777 { fprintf( fp, "%s\n", text ); }
4779 while (line_end - 1 > line_start )
4781 /* Eat leading whitespaces. This is essential because while
4782 wrapping lines, there will often be a whitespace at beginning
4784 while ( isspace((int) *(text + line_start)) )
4787 if ((line_end - line_start) > colwidth )
4788 { line_end = line_start + colwidth; }
4790 /* Find last whitespace, that fits into line */
4791 while ( ( line_end > line_start )
4792 && ( line_end - line_start > colwidth )
4793 && !isspace((int) *(text + line_end)))
4796 /* Do not print trailing whitespace. If this text
4797 has got only one line, line_end now points to the
4798 last char due to initialization. */
4801 /* Output line of text */
4802 while ( line_start < line_end )
4804 fputc(*(text + line_start), fp );
4809 /* Initialize another line */
4810 if ( line_end + 1 < textlen )
4814 for (i = 0; i < lmargin; i++ )
4815 { fputc( ' ', fp ); }
4820 /* If we have to print another line, get also the last char. */
4823 } /* lines of text */
4827 * Prints the glossary in strict GNU format.
4828 * Differences to arg_print_glossary() are:
4829 * - wraps lines after 80 chars
4830 * - indents lines without shortops
4831 * - does not accept formatstrings
4833 * Contributed by Uli Fouquet
4835 void arg_print_glossary_gnu(FILE *fp, void * *argtable )
4837 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4840 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4842 if (table[tabindex]->glossary)
4844 char syntax[200] = "";
4845 const char *shortopts = table[tabindex]->shortopts;
4846 const char *longopts = table[tabindex]->longopts;
4847 const char *datatype = table[tabindex]->datatype;
4848 const char *glossary = table[tabindex]->glossary;
4850 if ( !shortopts && longopts )
4852 /* Indent trailing line by 4 spaces... */
4853 memset( syntax, ' ', 4 );
4854 *(syntax + 4) = '\0';
4857 arg_cat_optionv(syntax,
4862 table[tabindex]->flag & ARG_HASOPTVALUE,
4865 /* If syntax fits not into column, print glossary in new line... */
4866 if ( strlen(syntax) > 25 )
4868 fprintf( fp, " %-25s %s\n", syntax, "" );
4872 fprintf( fp, " %-25s ", syntax );
4873 arg_print_formatted( fp, 28, 79, glossary );
4875 } /* for each table entry */
4882 * Checks the argtable[] array for NULL entries and returns 1
4883 * if any are found, zero otherwise.
4885 int arg_nullcheck(void * *argtable)
4887 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4889 /*printf("arg_nullcheck(%p)\n",argtable);*/
4897 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4898 if (!table[tabindex])
4900 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4907 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4908 * The flaw results in memory leak in the (very rare) case that an intermediate
4909 * entry in the argtable array failed its memory allocation while others following
4910 * that entry were still allocated ok. Those subsequent allocations will not be
4911 * deallocated by arg_free().
4912 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4913 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4914 * with the newer arg_freetable() function.
4915 * We still keep arg_free() for backwards compatibility.
4917 void arg_free(void * *argtable)
4919 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4922 /*printf("arg_free(%p)\n",argtable);*/
4926 if we encounter a NULL entry then somewhat incorrectly we presume
4927 we have come to the end of the array. It isnt strictly true because
4928 an intermediate entry could be NULL with other non-NULL entries to follow.
4929 The subsequent argtable entries would then not be freed as they should.
4931 if (table[tabindex] == NULL)
4934 flag = table[tabindex]->flag;
4935 free(table[tabindex]);
4936 table[tabindex++] = NULL;
4938 } while(!(flag & ARG_TERMINATOR));
4941 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4942 void arg_freetable(void * *argtable, size_t n)
4944 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4945 size_t tabindex = 0;
4946 /*printf("arg_freetable(%p)\n",argtable);*/
4947 for (tabindex = 0; tabindex < n; tabindex++)
4949 if (table[tabindex] == NULL)
4952 free(table[tabindex]);
4953 table[tabindex] = NULL;