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 // On Windows isspace crashes app in case of using Unicode character set and string to be above ASCII
34 // so you have to use _istspace instead of space
37 #define ISSPACE _istspace
39 #define ISSPACE isspace
42 /*******************************************************************************
43 * This file is part of the argtable3 library.
45 * Copyright (C) 2013 Tom G. Huang
46 * <tomghuang@gmail.com>
47 * All rights reserved.
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions are met:
51 * * Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * * Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * * Neither the name of STEWART HEITMANN nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
60 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
61 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
64 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
66 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
67 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
69 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 ******************************************************************************/
75 #define ARG_ENABLE_TRACE 0
76 #define ARG_ENABLE_LOG 1
87 // The same name define EOVERFLOW in errno.h on windows platform or android
88 #if defined(__STDC_WANT_SECURE_LIB__) || defined(__ANDROID__) || defined(ANDROID)
100 #define ARG_TRACE(x) \
101 __pragma(warning(push)) \
102 __pragma(warning(disable:4127)) \
103 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \
104 __pragma(warning(pop))
107 __pragma(warning(push)) \
108 __pragma(warning(disable:4127)) \
109 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
110 __pragma(warning(pop))
112 #define ARG_TRACE(x) \
113 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
116 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
119 extern void dbg_printf(const char *fmt
, ...);
127 /*******************************************************************************
128 * This file is part of the argtable3 library.
130 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
131 * <sheitmann@users.sourceforge.net>
132 * All rights reserved.
134 * Redistribution and use in source and binary forms, with or without
135 * modification, are permitted provided that the following conditions are met:
136 * * Redistributions of source code must retain the above copyright
137 * notice, this list of conditions and the following disclaimer.
138 * * Redistributions in binary form must reproduce the above copyright
139 * notice, this list of conditions and the following disclaimer in the
140 * documentation and/or other materials provided with the distribution.
141 * * Neither the name of STEWART HEITMANN nor the names of its contributors
142 * may be used to endorse or promote products derived from this software
143 * without specific prior written permission.
145 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
146 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
147 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
148 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
149 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
150 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
151 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
152 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
153 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
154 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
155 ******************************************************************************/
161 void dbg_printf(const char *fmt
, ...) {
164 vfprintf(stderr
, fmt
, args
);
170 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
171 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
172 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
175 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
177 * Permission to use, copy, modify, and distribute this software for any
178 * purpose with or without fee is hereby granted, provided that the above
179 * copyright notice and this permission notice appear in all copies.
181 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
182 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
183 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
184 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
185 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
186 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
187 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
189 * Sponsored in part by the Defense Advanced Research Projects
190 * Agency (DARPA) and Air Force Research Laboratory, Air Force
191 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
194 // $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $"
197 * Copyright (c) 2000 The NetBSD Foundation, Inc.
198 * All rights reserved.
200 * This code is derived from software contributed to The NetBSD Foundation
201 * by Dieter Baron and Thomas Klausner.
203 * Redistribution and use in source and binary forms, with or without
204 * modification, are permitted provided that the following conditions
206 * 1. Redistributions of source code must retain the above copyright
207 * notice, this list of conditions and the following disclaimer.
208 * 2. Redistributions in binary form must reproduce the above copyright
209 * notice, this list of conditions and the following disclaimer in the
210 * documentation and/or other materials provided with the distribution.
212 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
213 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
215 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
216 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
217 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
218 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
219 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
220 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
221 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
222 * POSSIBILITY OF SUCH DAMAGE.
233 #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
235 #ifdef REPLACE_GETOPT
236 int opterr
= 1; /* if error message should be printed */
237 int optind
= 1; /* index into parent argv vector */
238 int optopt
= '?'; /* character checked for validity */
239 int optreset
; /* reset getopt */
240 const char *optarg
; /* argument associated with option */
243 #define PRINT_ERROR ((opterr) && (*options != ':'))
245 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
246 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
247 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
250 #define BADCH (int)'?'
251 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
252 #define INORDER (int)1
256 static int getopt_internal(int, char *const *, const char *,
257 const struct option
*, int *, int);
258 static int parse_long_options(char *const *, const char *,
259 const struct option
*, int *, int);
260 static int gcd(int, int);
261 static void permute_args(int, int, int, char *const *);
263 static const char *place
= EMSG
; /* option letter processing */
265 /* XXX: set optreset to 1 rather than these two */
266 static int nonopt_start
= -1; /* first non option argument (for permute) */
267 static int nonopt_end
= -1; /* first option after non options (for permute) */
270 static const char recargchar
[] = "option requires an argument -- %c";
271 static const char recargstring
[] = "option requires an argument -- %s";
272 static const char ambig
[] = "ambiguous option -- %.*s";
273 static const char noarg
[] = "option doesn't take an argument -- %.*s";
274 static const char illoptchar
[] = "unknown option -- %c";
275 static const char illoptstring
[] = "unknown option -- %s";
281 /* Windows needs warnx(). We change the definition though:
282 * 1. (another) global is defined, opterrmsg, which holds the error message
283 * 2. errors are always printed out on stderr w/o the program name
284 * Note that opterrmsg always gets set no matter what opterr is set to. The
285 * error message will not be printed if opterr is 0 as usual.
291 #define MAX_OPTER_MSG_SIZE 128
293 extern char opterrmsg
[MAX_OPTER_MSG_SIZE
];
294 char opterrmsg
[MAX_OPTER_MSG_SIZE
]; /* buffer for the last error message */
296 static void warnx(const char *fmt
, ...) {
300 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
301 implementation specifics and manually suppress the warning.
303 memset(opterrmsg
, 0, sizeof opterrmsg
);
305 #ifdef __STDC_WANT_SECURE_LIB__
306 _vsnprintf_s(opterrmsg
, MAX_OPTER_MSG_SIZE
, sizeof(opterrmsg
) - 1, fmt
, ap
);
308 _vsnprintf(opterrmsg
, sizeof(opterrmsg
) - 1, fmt
, ap
);
312 fprintf(stderr
, "%s\n", opterrmsg
);
321 * Compute the greatest common divisor of a and b.
338 * Exchange the block from nonopt_start to nonopt_end with the block
339 * from nonopt_end to opt_end (keeping the same order of arguments
343 permute_args(int panonopt_start
, int panonopt_end
, int opt_end
,
344 char *const *nargv
) {
347 * compute lengths of blocks and number and size of cycles
349 int nnonopts
= panonopt_end
- panonopt_start
;
350 int nopts
= opt_end
- panonopt_end
;
351 int ncycle
= gcd(nnonopts
, nopts
);
352 int cyclelen
= (opt_end
- panonopt_start
) / ncycle
;
354 for (int i
= 0; i
< ncycle
; i
++) {
355 int cstart
= panonopt_end
+ i
;
357 for (int j
= 0; j
< cyclelen
; j
++) {
358 if (pos
>= panonopt_end
)
362 char *swap
= nargv
[pos
];
363 /* LINTED const cast */
364 ((char **) nargv
)[pos
] = nargv
[cstart
];
365 /* LINTED const cast */
366 ((char **)nargv
)[cstart
] = swap
;
372 * parse_long_options --
373 * Parse long options in argc/argv argument vector.
374 * Returns -1 if short_too is set and the option does not match long_options.
377 parse_long_options(char *const *nargv
, const char *options
,
378 const struct option
*long_options
, int *idx
, int short_too
) {
379 const char *current_argv
, *has_equal
;
380 size_t current_argv_len
;
383 current_argv
= place
;
388 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
389 /* argument found (--option=arg) */
390 current_argv_len
= has_equal
- current_argv
;
393 current_argv_len
= strlen(current_argv
);
395 for (i
= 0; long_options
[i
].name
; i
++) {
396 /* find matching long option */
397 if (strncmp(current_argv
, long_options
[i
].name
,
401 if (strlen(long_options
[i
].name
) == current_argv_len
) {
407 * If this is a known short option, don't allow
408 * a partial match of a single character.
410 if (short_too
&& current_argv_len
== 1)
413 if (match
== -1) /* partial match */
416 /* ambiguous abbreviation */
418 warnx(ambig
, (int)current_argv_len
,
424 if (match
!= -1) { /* option found */
425 if (long_options
[match
].has_arg
== no_argument
428 warnx(noarg
, (int)current_argv_len
,
431 * XXX: GNU sets optopt to val regardless of flag
433 if (long_options
[match
].flag
== NULL
)
434 optopt
= long_options
[match
].val
;
439 if (long_options
[match
].has_arg
== required_argument
||
440 long_options
[match
].has_arg
== optional_argument
) {
443 else if (long_options
[match
].has_arg
==
446 * optional argument doesn't use next nargv
448 optarg
= nargv
[optind
++];
451 if ((long_options
[match
].has_arg
== required_argument
)
452 && (optarg
== NULL
)) {
454 * Missing argument; leading ':' indicates no error
455 * should be generated.
461 * XXX: GNU sets optopt to val regardless of flag
463 if (long_options
[match
].flag
== NULL
)
464 optopt
= long_options
[match
].val
;
470 } else { /* unknown option */
476 warnx(illoptstring
, current_argv
);
482 if (long_options
[match
].flag
) {
483 *long_options
[match
].flag
= long_options
[match
].val
;
486 return (long_options
[match
].val
);
491 * Parse argc/argv argument vector. Called by user level routines.
494 getopt_internal(int nargc
, char *const *nargv
, const char *options
,
495 const struct option
*long_options
, int *idx
, int flags
) {
496 char *oli
; /* option letter list index */
497 int optchar
, short_too
;
498 static int posixly_correct
= -1;
499 #ifdef __STDC_WANT_SECURE_LIB__
501 size_t buffer_size
= 0;
509 * Disable GNU extensions if POSIXLY_CORRECT is set or options
510 * string begins with a '+'.
513 #ifdef __STDC_WANT_SECURE_LIB__
514 if (posixly_correct
== -1) {
515 err
= _dupenv_s(&buffer
, &buffer_size
, "POSIXLY_CORRECT") == 0;
516 posixly_correct
= buffer
!= NULL
;
517 if (buffer
!= NULL
&& err
== 0) {
522 if (posixly_correct
== -1)
523 posixly_correct
= (getenv("POSIXLY_CORRECT") != NULL
);
525 if (posixly_correct
|| *options
== '+')
526 flags
&= ~FLAG_PERMUTE
;
527 else if (*options
== '-')
528 flags
|= FLAG_ALLARGS
;
529 if (*options
== '+' || *options
== '-')
533 * XXX Some GNU programs (like cvs) set optind to 0 instead of
534 * XXX using optreset. Work around this braindamage.
537 optind
= optreset
= 1;
541 nonopt_start
= nonopt_end
= -1;
543 if (optreset
|| !*place
) { /* update scanning pointer */
545 if (optind
>= nargc
) { /* end of argument vector */
547 if (nonopt_end
!= -1) {
548 /* do permutation, if we have to */
549 permute_args(nonopt_start
, nonopt_end
,
551 optind
-= nonopt_end
- nonopt_start
;
552 } else if (nonopt_start
!= -1) {
554 * If we skipped non-options, set optind
555 * to the first of them.
557 optind
= nonopt_start
;
559 nonopt_start
= nonopt_end
= -1;
562 if (*(place
= nargv
[optind
]) != '-' ||
563 (place
[1] == '\0' && strchr(options
, '-') == NULL
)) {
564 place
= EMSG
; /* found non-option */
565 if (flags
& FLAG_ALLARGS
) {
568 * return non-option as argument to option 1
570 optarg
= nargv
[optind
++];
573 if (!(flags
& FLAG_PERMUTE
)) {
575 * If no permutation wanted, stop parsing
576 * at first non-option.
581 if (nonopt_start
== -1)
582 nonopt_start
= optind
;
583 else if (nonopt_end
!= -1) {
584 permute_args(nonopt_start
, nonopt_end
,
586 nonopt_start
= optind
-
587 (nonopt_end
- nonopt_start
);
591 /* process next argument */
594 if (nonopt_start
!= -1 && nonopt_end
== -1)
598 * If we have "-" do nothing, if "--" we are done.
600 if (place
[1] != '\0' && *++place
== '-' && place
[1] == '\0') {
604 * We found an option (--), so if we skipped
605 * non-options, we have to permute.
607 if (nonopt_end
!= -1) {
608 permute_args(nonopt_start
, nonopt_end
,
610 optind
-= nonopt_end
- nonopt_start
;
612 nonopt_start
= nonopt_end
= -1;
618 * Check long options if:
619 * 1) we were passed some
620 * 2) the arg is not just "-"
621 * 3) either the arg starts with -- we are getopt_long_only()
623 if (long_options
!= NULL
&& place
!= nargv
[optind
] &&
624 (*place
== '-' || (flags
& FLAG_LONGONLY
))) {
627 place
++; /* --foo long option */
628 else if (*place
!= ':' && strchr(options
, *place
) != NULL
)
629 short_too
= 1; /* could be short option too */
631 optchar
= parse_long_options(nargv
, options
, long_options
,
639 if ((optchar
= (int) * place
++) == (int)':' ||
640 (optchar
== (int)'-' && *place
!= '\0') ||
641 (oli
= strchr(options
, optchar
)) == NULL
) {
643 * If the user specified "-" and '-' isn't listed in
644 * options, return -1 (non-option) as per POSIX.
645 * Otherwise, it is an unknown option character (or ':').
647 if (optchar
== (int)'-' && *place
== '\0')
652 warnx(illoptchar
, optchar
);
656 if (long_options
!= NULL
&& optchar
== 'W' && oli
[1] == ';') {
658 if (*place
) /* no space */
660 else if (++optind
>= nargc
) { /* no arg */
663 warnx(recargchar
, optchar
);
666 } else /* white space */
667 place
= nargv
[optind
];
668 optchar
= parse_long_options(nargv
, options
, long_options
,
673 if (*++oli
!= ':') { /* doesn't take argument */
676 } else { /* takes (optional) argument */
678 if (*place
) /* no white space */
680 else if (oli
[1] != ':') { /* arg not optional */
681 if (++optind
>= nargc
) { /* no arg */
684 warnx(recargchar
, optchar
);
688 optarg
= nargv
[optind
];
693 /* dump back option letter */
697 #ifdef REPLACE_GETOPT
700 * Parse argc/argv argument vector.
702 * [eventually this will replace the BSD getopt]
705 getopt(int nargc
, char *const *nargv
, const char *options
) {
708 * We don't pass FLAG_PERMUTE to getopt_internal() since
709 * the BSD getopt(3) (unlike GNU) has never done this.
711 * Furthermore, since many privileged programs call getopt()
712 * before dropping privileges it makes sense to keep things
713 * as simple (and bug-free) as possible.
715 return (getopt_internal(nargc
, nargv
, options
, NULL
, NULL
, 0));
717 #endif /* REPLACE_GETOPT */
721 * Parse argc/argv argument vector.
724 getopt_long(int nargc
, char *const *nargv
, const char *options
,
725 const struct option
*long_options
, int *idx
) {
727 return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
,
732 * getopt_long_only --
733 * Parse argc/argv argument vector.
736 getopt_long_only(int nargc
, char *const *nargv
, const char *options
,
737 const struct option
*long_options
, int *idx
) {
739 return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
,
740 FLAG_PERMUTE
| FLAG_LONGONLY
));
742 /*******************************************************************************
743 * This file is part of the argtable3 library.
745 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
746 * <sheitmann@users.sourceforge.net>
747 * All rights reserved.
749 * Redistribution and use in source and binary forms, with or without
750 * modification, are permitted provided that the following conditions are met:
751 * * Redistributions of source code must retain the above copyright
752 * notice, this list of conditions and the following disclaimer.
753 * * Redistributions in binary form must reproduce the above copyright
754 * notice, this list of conditions and the following disclaimer in the
755 * documentation and/or other materials provided with the distribution.
756 * * Neither the name of STEWART HEITMANN nor the names of its contributors
757 * may be used to endorse or promote products derived from this software
758 * without specific prior written permission.
760 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
761 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
762 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
763 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
764 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
765 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
766 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
767 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
768 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
769 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
770 ******************************************************************************/
775 #include "argtable3.h"
778 char *arg_strptime(const char *buf
, const char *fmt
, struct tm
*tm
);
781 static void arg_date_resetfn(struct arg_date
*parent
) {
782 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
787 static int arg_date_scanfn(struct arg_date
*parent
, const char *argval
) {
790 if (parent
->count
== parent
->hdr
.maxcount
) {
791 errorcode
= EMAXCOUNT
;
792 } else if (!argval
) {
793 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
797 struct tm tm
= parent
->tmval
[parent
->count
];
799 /* parse the given argument value, store result in parent->tmval[] */
800 pend
= arg_strptime(argval
, parent
->format
, &tm
);
801 if (pend
&& pend
[0] == '\0')
802 parent
->tmval
[parent
->count
++] = tm
;
804 errorcode
= EBADDATE
;
807 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
812 static int arg_date_checkfn(struct arg_date
*parent
) {
813 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
815 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
820 static void arg_date_errorfn(
821 struct arg_date
*parent
,
825 const char *progname
) {
826 const char *shortopts
= parent
->hdr
.shortopts
;
827 const char *longopts
= parent
->hdr
.longopts
;
828 const char *datatype
= parent
->hdr
.datatype
;
830 /* make argval NULL safe */
831 argval
= argval
? argval
: "";
833 fprintf(fp
, "%s: ", progname
);
836 fputs("missing option ", fp
);
837 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
841 fputs("excess option ", fp
);
842 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
849 fprintf(fp
, "illegal timestamp format \"%s\"\n", argval
);
850 memset(&tm
, 0, sizeof(tm
));
851 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm
);
852 strftime(buff
, sizeof(buff
), parent
->format
, &tm
);
853 printf("correct format is \"%s\"\n", buff
);
860 struct arg_date
*arg_date0(
861 const char *shortopts
,
862 const char *longopts
,
864 const char *datatype
,
865 const char *glossary
) {
866 return arg_daten(shortopts
, longopts
, format
, datatype
, 0, 1, glossary
);
870 struct arg_date
*arg_date1(
871 const char *shortopts
,
872 const char *longopts
,
874 const char *datatype
,
875 const char *glossary
) {
876 return arg_daten(shortopts
, longopts
, format
, datatype
, 1, 1, glossary
);
880 struct arg_date
*arg_daten(
881 const char *shortopts
,
882 const char *longopts
,
884 const char *datatype
,
887 const char *glossary
) {
889 struct arg_date
*result
;
891 /* foolproof things by ensuring maxcount is not less than mincount */
892 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
894 /* default time format is the national date format for the locale */
898 nbytes
= sizeof(struct arg_date
) /* storage for struct arg_date */
899 + maxcount
* sizeof(struct tm
); /* storage for tmval[maxcount] array */
901 /* allocate storage for the arg_date struct + tmval[] array. */
902 /* we use calloc because we want the tmval[] array zero filled. */
903 result
= (struct arg_date
*)calloc(1, nbytes
);
905 /* init the arg_hdr struct */
906 result
->hdr
.flag
= ARG_HASVALUE
;
907 result
->hdr
.shortopts
= shortopts
;
908 result
->hdr
.longopts
= longopts
;
909 result
->hdr
.datatype
= datatype
? datatype
: format
;
910 result
->hdr
.glossary
= glossary
;
911 result
->hdr
.mincount
= mincount
;
912 result
->hdr
.maxcount
= maxcount
;
913 result
->hdr
.parent
= result
;
914 result
->hdr
.resetfn
= (arg_resetfn
*)arg_date_resetfn
;
915 result
->hdr
.scanfn
= (arg_scanfn
*)arg_date_scanfn
;
916 result
->hdr
.checkfn
= (arg_checkfn
*)arg_date_checkfn
;
917 result
->hdr
.errorfn
= (arg_errorfn
*)arg_date_errorfn
;
919 /* store the tmval[maxcount] array immediately after the arg_date struct */
920 result
->tmval
= (struct tm
*)(result
+ 1);
922 /* init the remaining arg_date member variables */
924 result
->format
= format
;
927 ARG_TRACE(("arg_daten() returns %p\n", result
));
933 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
934 * All rights reserved.
936 * This code was contributed to The NetBSD Foundation by Klaus Klein.
937 * Heavily optimised by David Laight
939 * Redistribution and use in source and binary forms, with or without
940 * modification, are permitted provided that the following conditions
942 * 1. Redistributions of source code must retain the above copyright
943 * notice, this list of conditions and the following disclaimer.
944 * 2. Redistributions in binary form must reproduce the above copyright
945 * notice, this list of conditions and the following disclaimer in the
946 * documentation and/or other materials provided with the distribution.
948 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
949 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
950 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
951 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
952 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
953 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
954 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
955 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
956 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
957 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
958 * POSSIBILITY OF SUCH DAMAGE.
966 * We do not implement alternate representations. However, we always
967 * check whether a given modifier is allowed for a certain conversion.
971 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
972 #define TM_YEAR_BASE (1900)
974 static int conv_num(const char * *, int *, int, int);
976 static const char *day
[7] = {
977 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
981 static const char *abday
[7] = {
982 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
985 static const char *mon
[12] = {
986 "January", "February", "March", "April", "May", "June", "July",
987 "August", "September", "October", "November", "December"
990 static const char *abmon
[12] = {
991 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
992 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
995 static const char *am_pm
[2] = {
1000 static int arg_strcasecmp(const char *s1
, const char *s2
) {
1001 const unsigned char *us1
= (const unsigned char *)s1
;
1002 const unsigned char *us2
= (const unsigned char *)s2
;
1003 while (tolower(*us1
) == tolower(*us2
++))
1007 return tolower(*us1
) - tolower(*--us2
);
1011 static int arg_strncasecmp(const char *s1
, const char *s2
, size_t n
) {
1013 const unsigned char *us1
= (const unsigned char *)s1
;
1014 const unsigned char *us2
= (const unsigned char *)s2
;
1016 if (tolower(*us1
) != tolower(*us2
++))
1017 return tolower(*us1
) - tolower(*--us2
);
1028 char *arg_strptime(const char *buf
, const char *fmt
, struct tm
*tm
) {
1032 int alt_format
, i
, split_year
= 0;
1036 while ((c
= *fmt
) != '\0') {
1037 /* Clear `alternate' modifier prior to new conversion. */
1040 /* Eat up white-space. */
1042 while (ISSPACE(*bp
))
1049 if ((c
= *fmt
++) != '%')
1054 switch (c
= *fmt
++) {
1055 case '%': /* "%%" is converted to "%". */
1062 * "Alternative" modifiers. Just set the appropriate flag
1063 * and start over again.
1065 case 'E': /* "%E?" alternative conversion modifier. */
1067 alt_format
|= ALT_E
;
1070 case 'O': /* "%O?" alternative conversion modifier. */
1072 alt_format
|= ALT_O
;
1076 * "Complex" conversion rules, implemented through recursion.
1078 case 'c': /* Date and time, using the locale's format. */
1080 bp
= arg_strptime(bp
, "%x %X", tm
);
1085 case 'D': /* The date as "%m/%d/%y". */
1087 bp
= arg_strptime(bp
, "%m/%d/%y", tm
);
1092 case 'R': /* The time as "%H:%M". */
1094 bp
= arg_strptime(bp
, "%H:%M", tm
);
1099 case 'r': /* The time in 12-hour clock representation. */
1101 bp
= arg_strptime(bp
, "%I:%M:%S %p", tm
);
1106 case 'T': /* The time as "%H:%M:%S". */
1108 bp
= arg_strptime(bp
, "%H:%M:%S", tm
);
1113 case 'X': /* The time, using the locale's format. */
1115 bp
= arg_strptime(bp
, "%H:%M:%S", tm
);
1120 case 'x': /* The date, using the locale's format. */
1122 bp
= arg_strptime(bp
, "%m/%d/%y", tm
);
1128 * "Elementary" conversion rules.
1130 case 'A': /* The day of week, using the locale's form. */
1133 for (i
= 0; i
< 7; i
++) {
1135 len
= strlen(day
[i
]);
1136 if (arg_strncasecmp(day
[i
], bp
, len
) == 0)
1139 /* Abbreviated name. */
1140 len
= strlen(abday
[i
]);
1141 if (arg_strncasecmp(abday
[i
], bp
, len
) == 0)
1145 /* Nothing matched. */
1153 case 'B': /* The month, using the locale's form. */
1157 for (i
= 0; i
< 12; i
++) {
1159 len
= strlen(mon
[i
]);
1160 if (arg_strncasecmp(mon
[i
], bp
, len
) == 0)
1163 /* Abbreviated name. */
1164 len
= strlen(abmon
[i
]);
1165 if (arg_strncasecmp(abmon
[i
], bp
, len
) == 0)
1169 /* Nothing matched. */
1177 case 'C': /* The century number. */
1179 if (!(conv_num(&bp
, &i
, 0, 99)))
1183 tm
->tm_year
= (tm
->tm_year
% 100) + (i
* 100);
1185 tm
->tm_year
= i
* 100;
1190 case 'd': /* The day of month. */
1193 if (!(conv_num(&bp
, &tm
->tm_mday
, 1, 31)))
1197 case 'k': /* The hour (24-hour clock representation). */
1202 if (!(conv_num(&bp
, &tm
->tm_hour
, 0, 23)))
1206 case 'l': /* The hour (12-hour clock representation). */
1211 if (!(conv_num(&bp
, &tm
->tm_hour
, 1, 12)))
1213 if (tm
->tm_hour
== 12)
1217 case 'j': /* The day of year. */
1219 if (!(conv_num(&bp
, &i
, 1, 366)))
1221 tm
->tm_yday
= i
- 1;
1224 case 'M': /* The minute. */
1226 if (!(conv_num(&bp
, &tm
->tm_min
, 0, 59)))
1230 case 'm': /* The month. */
1232 if (!(conv_num(&bp
, &i
, 1, 12)))
1237 case 'p': /* The locale's equivalent of AM/PM. */
1240 if (arg_strcasecmp(am_pm
[0], bp
) == 0) {
1241 if (tm
->tm_hour
> 11)
1244 bp
+= strlen(am_pm
[0]);
1248 else if (arg_strcasecmp(am_pm
[1], bp
) == 0) {
1249 if (tm
->tm_hour
> 11)
1253 bp
+= strlen(am_pm
[1]);
1257 /* Nothing matched. */
1260 case 'S': /* The seconds. */
1262 if (!(conv_num(&bp
, &tm
->tm_sec
, 0, 61)))
1266 case 'U': /* The week of year, beginning on sunday. */
1267 case 'W': /* The week of year, beginning on monday. */
1270 * XXX This is bogus, as we can not assume any valid
1271 * information present in the tm structure at this
1272 * point to calculate a real value, so just check the
1275 if (!(conv_num(&bp
, &i
, 0, 53)))
1279 case 'w': /* The day of week, beginning on sunday. */
1281 if (!(conv_num(&bp
, &tm
->tm_wday
, 0, 6)))
1285 case 'Y': /* The year. */
1287 if (!(conv_num(&bp
, &i
, 0, 9999)))
1290 tm
->tm_year
= i
- TM_YEAR_BASE
;
1293 case 'y': /* The year within 100 years of the epoch. */
1294 LEGAL_ALT(ALT_E
| ALT_O
);
1295 if (!(conv_num(&bp
, &i
, 0, 99)))
1299 tm
->tm_year
= ((tm
->tm_year
/ 100) * 100) + i
;
1304 tm
->tm_year
= i
+ 2000 - TM_YEAR_BASE
;
1306 tm
->tm_year
= i
+ 1900 - TM_YEAR_BASE
;
1310 * Miscellaneous conversions.
1312 case 'n': /* Any kind of white-space. */
1315 while (ISSPACE(*bp
))
1320 default: /* Unknown/unsupported conversion. */
1327 /* LINTED functional specification */
1328 return ((char *)bp
);
1332 static int conv_num(const char * *buf
, int *dest
, int llim
, int ulim
) {
1335 /* The limit also determines the number of valid digits. */
1338 if (**buf
< '0' || **buf
> '9')
1343 result
+= *(*buf
)++ - '0';
1345 } while ((result
* 10 <= ulim
) && rulim
&& **buf
>= '0' && **buf
<= '9');
1347 if (result
< llim
|| result
> ulim
)
1353 /*******************************************************************************
1354 * This file is part of the argtable3 library.
1356 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1357 * <sheitmann@users.sourceforge.net>
1358 * All rights reserved.
1360 * Redistribution and use in source and binary forms, with or without
1361 * modification, are permitted provided that the following conditions are met:
1362 * * Redistributions of source code must retain the above copyright
1363 * notice, this list of conditions and the following disclaimer.
1364 * * Redistributions in binary form must reproduce the above copyright
1365 * notice, this list of conditions and the following disclaimer in the
1366 * documentation and/or other materials provided with the distribution.
1367 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1368 * may be used to endorse or promote products derived from this software
1369 * without specific prior written permission.
1371 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1372 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1373 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1374 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1375 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1376 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1377 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1378 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1379 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1380 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1381 ******************************************************************************/
1385 #include "argtable3.h"
1388 static void arg_dbl_resetfn(struct arg_dbl
*parent
) {
1389 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1394 static int arg_dbl_scanfn(struct arg_dbl
*parent
, const char *argval
) {
1397 if (parent
->count
== parent
->hdr
.maxcount
) {
1398 /* maximum number of arguments exceeded */
1399 errorcode
= EMAXCOUNT
;
1400 } else if (!argval
) {
1401 /* a valid argument with no argument value was given. */
1402 /* This happens when an optional argument value was invoked. */
1403 /* leave parent argument value unaltered but still count the argument. */
1409 /* extract double from argval into val */
1410 val
= strtod(argval
, &end
);
1412 /* if success then store result in parent->dval[] array otherwise return error*/
1414 parent
->dval
[parent
->count
++] = val
;
1416 errorcode
= EBADDOUBLE
;
1419 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1424 static int arg_dbl_checkfn(struct arg_dbl
*parent
) {
1425 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
1427 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1432 static void arg_dbl_errorfn(
1433 struct arg_dbl
*parent
,
1437 const char *progname
) {
1438 const char *shortopts
= parent
->hdr
.shortopts
;
1439 const char *longopts
= parent
->hdr
.longopts
;
1440 const char *datatype
= parent
->hdr
.datatype
;
1442 /* make argval NULL safe */
1443 argval
= argval
? argval
: "";
1445 fprintf(fp
, "%s: ", progname
);
1446 switch (errorcode
) {
1448 fputs("missing option ", fp
);
1449 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1453 fputs("excess option ", fp
);
1454 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
1458 fprintf(fp
, "invalid argument \"%s\" to option ", argval
);
1459 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1465 struct arg_dbl
*arg_dbl0(
1466 const char *shortopts
,
1467 const char *longopts
,
1468 const char *datatype
,
1469 const char *glossary
) {
1470 return arg_dbln(shortopts
, longopts
, datatype
, 0, 1, glossary
);
1474 struct arg_dbl
*arg_dbl1(
1475 const char *shortopts
,
1476 const char *longopts
,
1477 const char *datatype
,
1478 const char *glossary
) {
1479 return arg_dbln(shortopts
, longopts
, datatype
, 1, 1, glossary
);
1483 struct arg_dbl
*arg_dbln(
1484 const char *shortopts
,
1485 const char *longopts
,
1486 const char *datatype
,
1489 const char *glossary
) {
1491 struct arg_dbl
*result
;
1493 /* foolproof things by ensuring maxcount is not less than mincount */
1494 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
1496 nbytes
= sizeof(struct arg_dbl
) /* storage for struct arg_dbl */
1497 + (maxcount
+ 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1499 result
= (struct arg_dbl
*)malloc(nbytes
);
1504 /* init the arg_hdr struct */
1505 result
->hdr
.flag
= ARG_HASVALUE
;
1506 result
->hdr
.shortopts
= shortopts
;
1507 result
->hdr
.longopts
= longopts
;
1508 result
->hdr
.datatype
= datatype
? datatype
: "<double>";
1509 result
->hdr
.glossary
= glossary
;
1510 result
->hdr
.mincount
= mincount
;
1511 result
->hdr
.maxcount
= maxcount
;
1512 result
->hdr
.parent
= result
;
1513 result
->hdr
.resetfn
= (arg_resetfn
*)arg_dbl_resetfn
;
1514 result
->hdr
.scanfn
= (arg_scanfn
*)arg_dbl_scanfn
;
1515 result
->hdr
.checkfn
= (arg_checkfn
*)arg_dbl_checkfn
;
1516 result
->hdr
.errorfn
= (arg_errorfn
*)arg_dbl_errorfn
;
1518 /* Store the dval[maxcount] array on the first double boundary that
1519 * immediately follows the arg_dbl struct. We do the memory alignment
1520 * purely for SPARC and Motorola systems. They require floats and
1521 * doubles to be aligned on natural boundaries.
1523 addr
= (size_t)(result
+ 1);
1524 rem
= addr
% sizeof(double);
1525 result
->dval
= (double *)(addr
+ sizeof(double) - rem
);
1526 ARG_TRACE(("addr=%zu, dval=%p, sizeof(double)=%d rem=%d\n", addr
, result
->dval
, (int)sizeof(double), (int)rem
));
1531 ARG_TRACE(("arg_dbln() returns %p\n", result
));
1534 /*******************************************************************************
1535 * This file is part of the argtable3 library.
1537 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1538 * <sheitmann@users.sourceforge.net>
1539 * All rights reserved.
1541 * Redistribution and use in source and binary forms, with or without
1542 * modification, are permitted provided that the following conditions are met:
1543 * * Redistributions of source code must retain the above copyright
1544 * notice, this list of conditions and the following disclaimer.
1545 * * Redistributions in binary form must reproduce the above copyright
1546 * notice, this list of conditions and the following disclaimer in the
1547 * documentation and/or other materials provided with the distribution.
1548 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1549 * may be used to endorse or promote products derived from this software
1550 * without specific prior written permission.
1552 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1553 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1554 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1555 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1556 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1557 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1558 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1559 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1560 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1561 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1562 ******************************************************************************/
1566 #include "argtable3.h"
1569 static void arg_end_resetfn(struct arg_end
*parent
) {
1570 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1574 static void arg_end_errorfn(
1579 const char *progname
) {
1580 /* suppress unreferenced formal parameter warning */
1583 progname
= progname
? progname
: "";
1584 argval
= argval
? argval
: "";
1586 fprintf(fp
, "%s: ", progname
);
1589 fputs("too many errors to display", fp
);
1592 fputs("insufficent memory", fp
);
1595 fprintf(fp
, "unexpected argument \"%s\"", argval
);
1598 fprintf(fp
, "option \"%s\" requires an argument", argval
);
1601 fprintf(fp
, "invalid option \"%s\"", argval
);
1604 fprintf(fp
, "invalid option \"-%c\"", error
);
1612 struct arg_end
*arg_end(int maxcount
) {
1614 struct arg_end
*result
;
1616 nbytes
= sizeof(struct arg_end
)
1617 + maxcount
* sizeof(int) /* storage for int error[maxcount] array*/
1618 + maxcount
* sizeof(void *) /* storage for void* parent[maxcount] array */
1619 + maxcount
* sizeof(char *); /* storage for char* argval[maxcount] array */
1621 result
= (struct arg_end
*)malloc(nbytes
);
1623 /* init the arg_hdr struct */
1624 result
->hdr
.flag
= ARG_TERMINATOR
;
1625 result
->hdr
.shortopts
= NULL
;
1626 result
->hdr
.longopts
= NULL
;
1627 result
->hdr
.datatype
= NULL
;
1628 result
->hdr
.glossary
= NULL
;
1629 result
->hdr
.mincount
= 1;
1630 result
->hdr
.maxcount
= maxcount
;
1631 result
->hdr
.parent
= result
;
1632 result
->hdr
.resetfn
= (arg_resetfn
*)arg_end_resetfn
;
1633 result
->hdr
.scanfn
= NULL
;
1634 result
->hdr
.checkfn
= NULL
;
1635 result
->hdr
.errorfn
= (arg_errorfn
*)arg_end_errorfn
;
1637 /* store error[maxcount] array immediately after struct arg_end */
1638 result
->error
= (int *)(result
+ 1);
1640 /* store parent[maxcount] array immediately after error[] array */
1641 result
->parent
= (void * *)(result
->error
+ maxcount
);
1643 /* store argval[maxcount] array immediately after parent[] array */
1644 result
->argval
= (const char * *)(result
->parent
+ maxcount
);
1647 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount
, result
));
1652 void arg_print_errors(FILE *fp
, struct arg_end
*end
, const char *progname
) {
1654 ARG_TRACE(("arg_errors()\n"));
1655 for (i
= 0; i
< end
->count
; i
++) {
1656 struct arg_hdr
*errorparent
= (struct arg_hdr
*)(end
->parent
[i
]);
1657 if (errorparent
->errorfn
)
1658 errorparent
->errorfn(end
->parent
[i
],
1665 /*******************************************************************************
1666 * This file is part of the argtable3 library.
1668 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1669 * <sheitmann@users.sourceforge.net>
1670 * All rights reserved.
1672 * Redistribution and use in source and binary forms, with or without
1673 * modification, are permitted provided that the following conditions are met:
1674 * * Redistributions of source code must retain the above copyright
1675 * notice, this list of conditions and the following disclaimer.
1676 * * Redistributions in binary form must reproduce the above copyright
1677 * notice, this list of conditions and the following disclaimer in the
1678 * documentation and/or other materials provided with the distribution.
1679 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1680 * may be used to endorse or promote products derived from this software
1681 * without specific prior written permission.
1683 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1684 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1685 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1686 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1687 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1688 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1689 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1690 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1691 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1692 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1693 ******************************************************************************/
1698 #include "argtable3.h"
1701 # define FILESEPARATOR1 '\\'
1702 # define FILESEPARATOR2 '/'
1704 # define FILESEPARATOR1 '/'
1705 # define FILESEPARATOR2 '/'
1709 static void arg_file_resetfn(struct arg_file
*parent
) {
1710 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1715 /* Returns ptr to the base filename within *filename */
1716 static const char *arg_basename(const char *filename
) {
1717 const char *result
= NULL
, *result1
, *result2
;
1719 /* Find the last occurrence of eother file separator character. */
1720 /* Two alternative file separator chars are supported as legal */
1721 /* file separators but not both together in the same filename. */
1722 result1
= (filename
? strrchr(filename
, FILESEPARATOR1
) : NULL
);
1723 result2
= (filename
? strrchr(filename
, FILESEPARATOR2
) : NULL
);
1726 result
= result2
+ 1; /* using FILESEPARATOR2 (the alternative file separator) */
1729 result
= result1
+ 1; /* using FILESEPARATOR1 (the preferred file separator) */
1732 result
= filename
; /* neither file separator was found so basename is the whole filename */
1734 /* special cases of "." and ".." are not considered basenames */
1735 if (result
&& (strcmp(".", result
) == 0 || strcmp("..", result
) == 0))
1736 result
= filename
+ strlen(filename
);
1742 /* Returns ptr to the file extension within *basename */
1743 static const char *arg_extension(const char *basename
) {
1744 /* find the last occurrence of '.' in basename */
1745 const char *result
= (basename
? strrchr(basename
, '.') : NULL
);
1747 /* if no '.' was found then return pointer to end of basename */
1748 if (basename
&& !result
)
1749 result
= basename
+ strlen(basename
);
1751 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1752 if (basename
&& result
== basename
)
1753 result
= basename
+ strlen(basename
);
1755 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1756 if (basename
&& result
&& result
[1] == '\0')
1757 result
= basename
+ strlen(basename
);
1763 static int arg_file_scanfn(struct arg_file
*parent
, const char *argval
) {
1766 if (parent
->count
== parent
->hdr
.maxcount
) {
1767 /* maximum number of arguments exceeded */
1768 errorcode
= EMAXCOUNT
;
1769 } else if (!argval
) {
1770 /* a valid argument with no argument value was given. */
1771 /* This happens when an optional argument value was invoked. */
1772 /* leave parent arguiment value unaltered but still count the argument. */
1775 parent
->filename
[parent
->count
] = argval
;
1776 parent
->basename
[parent
->count
] = arg_basename(argval
);
1777 parent
->extension
[parent
->count
] =
1778 arg_extension(parent
->basename
[parent
->count
]); /* only seek extensions within the basename (not the file path)*/
1782 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1787 static int arg_file_checkfn(struct arg_file
*parent
) {
1788 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
1790 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1795 static void arg_file_errorfn(
1796 struct arg_file
*parent
,
1800 const char *progname
) {
1801 const char *shortopts
= parent
->hdr
.shortopts
;
1802 const char *longopts
= parent
->hdr
.longopts
;
1803 const char *datatype
= parent
->hdr
.datatype
;
1805 /* make argval NULL safe */
1806 argval
= argval
? argval
: "";
1808 fprintf(fp
, "%s: ", progname
);
1809 switch (errorcode
) {
1811 fputs("missing option ", fp
);
1812 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1816 fputs("excess option ", fp
);
1817 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
1821 fprintf(fp
, "unknown error at \"%s\"\n", argval
);
1826 struct arg_file
*arg_file0(
1827 const char *shortopts
,
1828 const char *longopts
,
1829 const char *datatype
,
1830 const char *glossary
) {
1831 return arg_filen(shortopts
, longopts
, datatype
, 0, 1, glossary
);
1835 struct arg_file
*arg_file1(
1836 const char *shortopts
,
1837 const char *longopts
,
1838 const char *datatype
,
1839 const char *glossary
) {
1840 return arg_filen(shortopts
, longopts
, datatype
, 1, 1, glossary
);
1844 struct arg_file
*arg_filen(
1845 const char *shortopts
,
1846 const char *longopts
,
1847 const char *datatype
,
1850 const char *glossary
) {
1852 struct arg_file
*result
;
1854 /* foolproof things by ensuring maxcount is not less than mincount */
1855 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
1857 nbytes
= sizeof(struct arg_file
) /* storage for struct arg_file */
1858 + sizeof(char *) * maxcount
/* storage for filename[maxcount] array */
1859 + sizeof(char *) * maxcount
/* storage for basename[maxcount] array */
1860 + sizeof(char *) * maxcount
; /* storage for extension[maxcount] array */
1862 result
= (struct arg_file
*)malloc(nbytes
);
1866 /* init the arg_hdr struct */
1867 result
->hdr
.flag
= ARG_HASVALUE
;
1868 result
->hdr
.shortopts
= shortopts
;
1869 result
->hdr
.longopts
= longopts
;
1870 result
->hdr
.glossary
= glossary
;
1871 result
->hdr
.datatype
= datatype
? datatype
: "<file>";
1872 result
->hdr
.mincount
= mincount
;
1873 result
->hdr
.maxcount
= maxcount
;
1874 result
->hdr
.parent
= result
;
1875 result
->hdr
.resetfn
= (arg_resetfn
*)arg_file_resetfn
;
1876 result
->hdr
.scanfn
= (arg_scanfn
*)arg_file_scanfn
;
1877 result
->hdr
.checkfn
= (arg_checkfn
*)arg_file_checkfn
;
1878 result
->hdr
.errorfn
= (arg_errorfn
*)arg_file_errorfn
;
1880 /* store the filename,basename,extension arrays immediately after the arg_file struct */
1881 result
->filename
= (const char * *)(result
+ 1);
1882 result
->basename
= result
->filename
+ maxcount
;
1883 result
->extension
= result
->basename
+ maxcount
;
1886 /* foolproof the string pointers by initialising them with empty strings */
1887 for (i
= 0; i
< maxcount
; i
++) {
1888 result
->filename
[i
] = "";
1889 result
->basename
[i
] = "";
1890 result
->extension
[i
] = "";
1894 ARG_TRACE(("arg_filen() returns %p\n", result
));
1897 /*******************************************************************************
1898 * This file is part of the argtable3 library.
1900 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1901 * <sheitmann@users.sourceforge.net>
1902 * All rights reserved.
1904 * Redistribution and use in source and binary forms, with or without
1905 * modification, are permitted provided that the following conditions are met:
1906 * * Redistributions of source code must retain the above copyright
1907 * notice, this list of conditions and the following disclaimer.
1908 * * Redistributions in binary form must reproduce the above copyright
1909 * notice, this list of conditions and the following disclaimer in the
1910 * documentation and/or other materials provided with the distribution.
1911 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1912 * may be used to endorse or promote products derived from this software
1913 * without specific prior written permission.
1915 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1916 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1917 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1918 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1919 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1920 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1921 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1922 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1923 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1924 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1925 ******************************************************************************/
1931 #include "argtable3.h"
1934 static void arg_int_resetfn(struct arg_int
*parent
) {
1935 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1940 /* strtol0x() is like strtol() except that the numeric string is */
1941 /* expected to be prefixed by "0X" where X is a user supplied char. */
1942 /* The string may optionally be prefixed by white space and + or - */
1943 /* as in +0X123 or -0X123. */
1944 /* Once the prefix has been scanned, the remainder of the numeric */
1945 /* string is converted using strtol() with the given base. */
1946 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
1947 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
1948 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
1949 /* Failure of conversion is indicated by result where *endptr==str. */
1950 static long int strtol0X(const char *str
,
1951 const char * *endptr
,
1954 long int val
; /* stores result */
1955 int s
= 1; /* sign is +1 or -1 */
1956 const char *ptr
= str
; /* ptr to current position in str */
1958 /* skip leading whitespace */
1959 while (ISSPACE(*ptr
))
1961 /* printf("1) %s\n",ptr); */
1963 /* scan optional sign character */
1977 /* printf("2) %s\n",ptr); */
1980 if ((*ptr
++) != '0') {
1981 /* printf("failed to detect '0'\n"); */
1985 /* printf("3) %s\n",ptr); */
1986 if (toupper(*ptr
++) != toupper(X
)) {
1987 /* printf("failed to detect '%c'\n",X); */
1991 /* printf("4) %s\n",ptr); */
1993 /* attempt conversion on remainder of string using strtol() */
1994 val
= strtol(ptr
, (char * *)endptr
, base
);
1995 if (*endptr
== ptr
) {
1996 /* conversion failed */
2006 /* Returns 1 if str matches suffix (case insensitive). */
2007 /* Str may contain trailing whitespace, but nothing else. */
2008 static int detectsuffix(const char *str
, const char *suffix
) {
2009 /* scan pairwise through strings until mismatch detected */
2010 while (toupper(*str
) == toupper(*suffix
)) {
2011 /* printf("'%c' '%c'\n", *str, *suffix); */
2013 /* return 1 (success) if match persists until the string terminator */
2021 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2023 /* return 0 (fail) if the matching did not consume the entire suffix */
2025 return 0; /* failed to consume entire suffix */
2027 /* skip any remaining whitespace in str */
2028 while (ISSPACE(*str
))
2031 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2032 return (*str
== '\0') ? 1 : 0;
2036 static int arg_int_scanfn(struct arg_int
*parent
, const char *argval
) {
2039 if (parent
->count
== parent
->hdr
.maxcount
) {
2040 /* maximum number of arguments exceeded */
2041 errorcode
= EMAXCOUNT
;
2042 } else if (!argval
) {
2043 /* a valid argument with no argument value was given. */
2044 /* This happens when an optional argument value was invoked. */
2045 /* leave parent arguiment value unaltered but still count the argument. */
2051 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2052 val
= strtol0X(argval
, &end
, 'X', 16);
2053 if (end
== argval
) {
2054 /* hex failed, attempt octal conversion (eg +0o123) */
2055 val
= strtol0X(argval
, &end
, 'O', 8);
2056 if (end
== argval
) {
2057 /* octal failed, attempt binary conversion (eg +0B101) */
2058 val
= strtol0X(argval
, &end
, 'B', 2);
2059 if (end
== argval
) {
2060 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2061 val
= strtol(argval
, (char * *)&end
, 10);
2062 if (end
== argval
) {
2063 /* all supported number formats failed */
2070 /* Safety check for integer overflow. WARNING: this check */
2071 /* achieves nothing on machines where size(int)==size(long). */
2072 if (val
> INT_MAX
|| val
< INT_MIN
)
2073 #ifdef __STDC_WANT_SECURE_LIB__
2074 errorcode
= EOVERFLOW_
;
2076 errorcode
= EOVERFLOW
;
2079 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2080 /* We need to be mindful of integer overflows when using such big numbers. */
2081 if (detectsuffix(end
, "KB")) { /* kilobytes */
2082 if (val
> (INT_MAX
/ 1024) || val
< (INT_MIN
/ 1024))
2083 #ifdef __STDC_WANT_SECURE_LIB__
2084 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2086 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2089 val
*= 1024; /* 1KB = 1024 */
2090 } else if (detectsuffix(end
, "MB")) { /* megabytes */
2091 if (val
> (INT_MAX
/ 1048576) || val
< (INT_MIN
/ 1048576))
2092 #ifdef __STDC_WANT_SECURE_LIB__
2093 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2095 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2098 val
*= 1048576; /* 1MB = 1024*1024 */
2099 } else if (detectsuffix(end
, "GB")) { /* gigabytes */
2100 if (val
> (INT_MAX
/ 1073741824) || val
< (INT_MIN
/ 1073741824))
2101 #ifdef __STDC_WANT_SECURE_LIB__
2102 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2104 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2107 val
*= 1073741824; /* 1GB = 1024*1024*1024 */
2108 } else if (!detectsuffix(end
, ""))
2109 errorcode
= EBADINT
; /* invalid suffix detected */
2111 /* if success then store result in parent->ival[] array */
2113 parent
->ival
[parent
->count
++] = val
;
2116 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2121 static int arg_int_checkfn(struct arg_int
*parent
) {
2122 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2123 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2128 static void arg_int_errorfn(
2129 struct arg_int
*parent
,
2133 const char *progname
) {
2134 const char *shortopts
= parent
->hdr
.shortopts
;
2135 const char *longopts
= parent
->hdr
.longopts
;
2136 const char *datatype
= parent
->hdr
.datatype
;
2138 /* make argval NULL safe */
2139 argval
= argval
? argval
: "";
2141 fprintf(fp
, "%s: ", progname
);
2142 switch (errorcode
) {
2144 fputs("missing option ", fp
);
2145 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2149 fputs("excess option ", fp
);
2150 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2154 fprintf(fp
, "invalid argument \"%s\" to option ", argval
);
2155 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2158 #ifdef __STDC_WANT_SECURE_LIB__
2163 fputs("integer overflow at option ", fp
);
2164 arg_print_option(fp
, shortopts
, longopts
, datatype
, " ");
2165 fprintf(fp
, "(%s is too large)\n", argval
);
2171 struct arg_int
*arg_int0(
2172 const char *shortopts
,
2173 const char *longopts
,
2174 const char *datatype
,
2175 const char *glossary
) {
2176 return arg_intn(shortopts
, longopts
, datatype
, 0, 1, glossary
);
2180 struct arg_int
*arg_int1(
2181 const char *shortopts
,
2182 const char *longopts
,
2183 const char *datatype
,
2184 const char *glossary
) {
2185 return arg_intn(shortopts
, longopts
, datatype
, 1, 1, glossary
);
2189 struct arg_int
*arg_intn(
2190 const char *shortopts
,
2191 const char *longopts
,
2192 const char *datatype
,
2195 const char *glossary
) {
2197 struct arg_int
*result
;
2199 /* foolproof things by ensuring maxcount is not less than mincount */
2200 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2202 nbytes
= sizeof(struct arg_int
) /* storage for struct arg_int */
2203 + maxcount
* sizeof(int); /* storage for ival[maxcount] array */
2205 result
= (struct arg_int
*)malloc(nbytes
);
2207 /* init the arg_hdr struct */
2208 result
->hdr
.flag
= ARG_HASVALUE
;
2209 result
->hdr
.shortopts
= shortopts
;
2210 result
->hdr
.longopts
= longopts
;
2211 result
->hdr
.datatype
= datatype
? datatype
: "<int>";
2212 result
->hdr
.glossary
= glossary
;
2213 result
->hdr
.mincount
= mincount
;
2214 result
->hdr
.maxcount
= maxcount
;
2215 result
->hdr
.parent
= result
;
2216 result
->hdr
.resetfn
= (arg_resetfn
*)arg_int_resetfn
;
2217 result
->hdr
.scanfn
= (arg_scanfn
*)arg_int_scanfn
;
2218 result
->hdr
.checkfn
= (arg_checkfn
*)arg_int_checkfn
;
2219 result
->hdr
.errorfn
= (arg_errorfn
*)arg_int_errorfn
;
2221 /* store the ival[maxcount] array immediately after the arg_int struct */
2222 result
->ival
= (int *)(result
+ 1);
2226 ARG_TRACE(("arg_intn() returns %p\n", result
));
2229 /*******************************************************************************
2230 * This file is part of the argtable3 library.
2232 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2233 * <sheitmann@users.sourceforge.net>
2234 * All rights reserved.
2236 * Redistribution and use in source and binary forms, with or without
2237 * modification, are permitted provided that the following conditions are met:
2238 * * Redistributions of source code must retain the above copyright
2239 * notice, this list of conditions and the following disclaimer.
2240 * * Redistributions in binary form must reproduce the above copyright
2241 * notice, this list of conditions and the following disclaimer in the
2242 * documentation and/or other materials provided with the distribution.
2243 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2244 * may be used to endorse or promote products derived from this software
2245 * without specific prior written permission.
2247 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2248 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2249 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2250 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2251 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2252 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2253 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2254 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2255 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2256 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2257 ******************************************************************************/
2261 #include "argtable3.h"
2264 static void arg_lit_resetfn(struct arg_lit
*parent
) {
2265 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2270 static int arg_lit_scanfn(struct arg_lit
*parent
, const char *argval
) {
2272 if (parent
->count
< parent
->hdr
.maxcount
)
2275 errorcode
= EMAXCOUNT
;
2277 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__
, parent
, argval
,
2283 static int arg_lit_checkfn(struct arg_lit
*parent
) {
2284 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2285 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
2290 static void arg_lit_errorfn(
2291 struct arg_lit
*parent
,
2295 const char *progname
) {
2296 const char *shortopts
= parent
->hdr
.shortopts
;
2297 const char *longopts
= parent
->hdr
.longopts
;
2298 const char *datatype
= parent
->hdr
.datatype
;
2300 switch (errorcode
) {
2302 fprintf(fp
, "%s: missing option ", progname
);
2303 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2308 fprintf(fp
, "%s: extraneous option ", progname
);
2309 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2313 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__
, parent
, fp
,
2314 errorcode
, argval
, progname
));
2318 struct arg_lit
*arg_lit0(
2319 const char *shortopts
,
2320 const char *longopts
,
2321 const char *glossary
) {
2322 return arg_litn(shortopts
, longopts
, 0, 1, glossary
);
2326 struct arg_lit
*arg_lit1(
2327 const char *shortopts
,
2328 const char *longopts
,
2329 const char *glossary
) {
2330 return arg_litn(shortopts
, longopts
, 1, 1, glossary
);
2334 struct arg_lit
*arg_litn(
2335 const char *shortopts
,
2336 const char *longopts
,
2339 const char *glossary
) {
2340 struct arg_lit
*result
;
2342 /* foolproof things by ensuring maxcount is not less than mincount */
2343 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2345 result
= (struct arg_lit
*)malloc(sizeof(struct arg_lit
));
2347 /* init the arg_hdr struct */
2348 result
->hdr
.flag
= 0;
2349 result
->hdr
.shortopts
= shortopts
;
2350 result
->hdr
.longopts
= longopts
;
2351 result
->hdr
.datatype
= NULL
;
2352 result
->hdr
.glossary
= glossary
;
2353 result
->hdr
.mincount
= mincount
;
2354 result
->hdr
.maxcount
= maxcount
;
2355 result
->hdr
.parent
= result
;
2356 result
->hdr
.resetfn
= (arg_resetfn
*)arg_lit_resetfn
;
2357 result
->hdr
.scanfn
= (arg_scanfn
*)arg_lit_scanfn
;
2358 result
->hdr
.checkfn
= (arg_checkfn
*)arg_lit_checkfn
;
2359 result
->hdr
.errorfn
= (arg_errorfn
*)arg_lit_errorfn
;
2361 /* init local variables */
2365 ARG_TRACE(("arg_litn() returns %p\n", result
));
2368 /*******************************************************************************
2369 * This file is part of the argtable3 library.
2371 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2372 * <sheitmann@users.sourceforge.net>
2373 * All rights reserved.
2375 * Redistribution and use in source and binary forms, with or without
2376 * modification, are permitted provided that the following conditions are met:
2377 * * Redistributions of source code must retain the above copyright
2378 * notice, this list of conditions and the following disclaimer.
2379 * * Redistributions in binary form must reproduce the above copyright
2380 * notice, this list of conditions and the following disclaimer in the
2381 * documentation and/or other materials provided with the distribution.
2382 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2383 * may be used to endorse or promote products derived from this software
2384 * without specific prior written permission.
2386 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2387 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2388 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2389 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2390 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2391 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2392 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2393 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2394 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2395 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2396 ******************************************************************************/
2400 #include "argtable3.h"
2402 struct arg_rem
*arg_rem(const char *datatype
, const char *glossary
) {
2403 struct arg_rem
*result
= (struct arg_rem
*)malloc(sizeof(struct arg_rem
));
2405 result
->hdr
.flag
= 0;
2406 result
->hdr
.shortopts
= NULL
;
2407 result
->hdr
.longopts
= NULL
;
2408 result
->hdr
.datatype
= datatype
;
2409 result
->hdr
.glossary
= glossary
;
2410 result
->hdr
.mincount
= 1;
2411 result
->hdr
.maxcount
= 1;
2412 result
->hdr
.parent
= result
;
2413 result
->hdr
.resetfn
= NULL
;
2414 result
->hdr
.scanfn
= NULL
;
2415 result
->hdr
.checkfn
= NULL
;
2416 result
->hdr
.errorfn
= NULL
;
2419 ARG_TRACE(("arg_rem() returns %p\n", result
));
2423 /*******************************************************************************
2424 * This file is part of the argtable3 library.
2426 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2427 * <sheitmann@users.sourceforge.net>
2428 * All rights reserved.
2430 * Redistribution and use in source and binary forms, with or without
2431 * modification, are permitted provided that the following conditions are met:
2432 * * Redistributions of source code must retain the above copyright
2433 * notice, this list of conditions and the following disclaimer.
2434 * * Redistributions in binary form must reproduce the above copyright
2435 * notice, this list of conditions and the following disclaimer in the
2436 * documentation and/or other materials provided with the distribution.
2437 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2438 * may be used to endorse or promote products derived from this software
2439 * without specific prior written permission.
2441 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2442 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2443 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2444 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2445 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2446 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2447 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2448 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2449 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2450 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2451 ******************************************************************************/
2456 #include "argtable3.h"
2461 /***************************************************************
2462 T-Rex a tiny regular expression library
2464 Copyright (C) 2003-2006 Alberto Demichelis
2466 This software is provided 'as-is', without any express
2467 or implied warranty. In no event will the authors be held
2468 liable for any damages arising from the use of this software.
2470 Permission is granted to anyone to use this software for
2471 any purpose, including commercial applications, and to alter
2472 it and redistribute it freely, subject to the following restrictions:
2474 1. The origin of this software must not be misrepresented;
2475 you must not claim that you wrote the original software.
2476 If you use this software in a product, an acknowledgment
2477 in the product documentation would be appreciated but
2480 2. Altered source versions must be plainly marked as such,
2481 and must not be misrepresented as being the original software.
2483 3. This notice may not be removed or altered from any
2484 source distribution.
2486 ****************************************************************/
2493 #define TRexChar unsigned short
2494 #define MAX_CHAR 0xFFFF
2495 #define _TREXC(c) L##c
2496 #define trex_strlen wcslen
2497 #define trex_printf wprintf
2499 #define TRexChar char
2500 #define MAX_CHAR 0xFF
2501 #define _TREXC(c) (c)
2502 #define trex_strlen strlen
2503 #define trex_printf printf
2507 #define TREX_API extern
2511 #define TRex_False 0
2513 #define TREX_ICASE ARG_REX_ICASE
2515 typedef unsigned int TRexBool
;
2516 typedef struct TRex TRex
;
2519 const TRexChar
*begin
;
2523 TREX_API TRex
*trex_compile(const TRexChar
*pattern
, const TRexChar
**error
, int flags
);
2524 TREX_API
void trex_free(TRex
*exp
);
2525 TREX_API TRexBool
trex_match(TRex
*exp
, const TRexChar
*text
);
2526 TREX_API TRexBool
trex_search(TRex
*exp
, const TRexChar
*text
, const TRexChar
**out_begin
, const TRexChar
**out_end
);
2527 TREX_API TRexBool
trex_searchrange(TRex
*exp
, const TRexChar
*text_begin
, const TRexChar
*text_end
, const TRexChar
**out_begin
, const TRexChar
**out_end
);
2528 TREX_API
int trex_getsubexpcount(TRex
*exp
);
2529 TREX_API TRexBool
trex_getsubexp(TRex
*exp
, int n
, TRexMatch
*subexp
);
2540 const char *pattern
;
2545 static void arg_rex_resetfn(struct arg_rex
*parent
) {
2546 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2550 static int arg_rex_scanfn(struct arg_rex
*parent
, const char *argval
) {
2552 const TRexChar
*error
= NULL
;
2556 if (parent
->count
== parent
->hdr
.maxcount
) {
2557 /* maximum number of arguments exceeded */
2558 errorcode
= EMAXCOUNT
;
2559 } else if (!argval
) {
2560 /* a valid argument with no argument value was given. */
2561 /* This happens when an optional argument value was invoked. */
2562 /* leave parent argument value unaltered but still count the argument. */
2565 struct privhdr
*priv
= (struct privhdr
*)parent
->hdr
.priv
;
2567 /* test the current argument value for a match with the regular expression */
2568 /* if a match is detected, record the argument value in the arg_rex struct */
2570 rex
= trex_compile(priv
->pattern
, &error
, priv
->flags
);
2571 is_match
= trex_match(rex
, argval
);
2573 errorcode
= EREGNOMATCH
;
2575 parent
->sval
[parent
->count
++] = argval
;
2580 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
2584 static int arg_rex_checkfn(struct arg_rex
*parent
) {
2585 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2586 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2588 /* free the regex "program" we constructed in resetfn */
2589 //regfree(&(priv->regex));
2591 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2595 static void arg_rex_errorfn(struct arg_rex
*parent
,
2599 const char *progname
) {
2600 const char *shortopts
= parent
->hdr
.shortopts
;
2601 const char *longopts
= parent
->hdr
.longopts
;
2602 const char *datatype
= parent
->hdr
.datatype
;
2604 /* make argval NULL safe */
2605 argval
= argval
? argval
: "";
2607 fprintf(fp
, "%s: ", progname
);
2608 switch (errorcode
) {
2610 fputs("missing option ", fp
);
2611 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2615 fputs("excess option ", fp
);
2616 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2620 fputs("illegal value ", fp
);
2621 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2625 //char errbuff[256];
2626 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2627 //printf("%s\n", errbuff);
2634 struct arg_rex
*arg_rex0(const char *shortopts
,
2635 const char *longopts
,
2636 const char *pattern
,
2637 const char *datatype
,
2639 const char *glossary
) {
2640 return arg_rexn(shortopts
,
2650 struct arg_rex
*arg_rex1(const char *shortopts
,
2651 const char *longopts
,
2652 const char *pattern
,
2653 const char *datatype
,
2655 const char *glossary
) {
2656 return arg_rexn(shortopts
,
2667 struct arg_rex
*arg_rexn(const char *shortopts
,
2668 const char *longopts
,
2669 const char *pattern
,
2670 const char *datatype
,
2674 const char *glossary
) {
2676 struct arg_rex
*result
;
2677 struct privhdr
*priv
;
2679 const TRexChar
*error
= NULL
;
2684 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2685 printf("argtable: Bad argument table.\n");
2689 /* foolproof things by ensuring maxcount is not less than mincount */
2690 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2692 nbytes
= sizeof(struct arg_rex
) /* storage for struct arg_rex */
2693 + sizeof(struct privhdr
) /* storage for private arg_rex data */
2694 + maxcount
* sizeof(char *); /* storage for sval[maxcount] array */
2696 result
= (struct arg_rex
*)malloc(nbytes
);
2700 /* init the arg_hdr struct */
2701 result
->hdr
.flag
= ARG_HASVALUE
;
2702 result
->hdr
.shortopts
= shortopts
;
2703 result
->hdr
.longopts
= longopts
;
2704 result
->hdr
.datatype
= datatype
? datatype
: pattern
;
2705 result
->hdr
.glossary
= glossary
;
2706 result
->hdr
.mincount
= mincount
;
2707 result
->hdr
.maxcount
= maxcount
;
2708 result
->hdr
.parent
= result
;
2709 result
->hdr
.resetfn
= (arg_resetfn
*)arg_rex_resetfn
;
2710 result
->hdr
.scanfn
= (arg_scanfn
*)arg_rex_scanfn
;
2711 result
->hdr
.checkfn
= (arg_checkfn
*)arg_rex_checkfn
;
2712 result
->hdr
.errorfn
= (arg_errorfn
*)arg_rex_errorfn
;
2714 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2715 result
->hdr
.priv
= result
+ 1;
2716 priv
= (struct privhdr
*)(result
->hdr
.priv
);
2717 priv
->pattern
= pattern
;
2718 priv
->flags
= flags
;
2720 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2721 result
->sval
= (const char * *)(priv
+ 1);
2724 /* foolproof the string pointers by initializing them to reference empty strings */
2725 for (i
= 0; i
< maxcount
; i
++)
2726 result
->sval
[i
] = "";
2728 /* here we construct and destroy a regex representation of the regular
2729 * expression for no other reason than to force any regex errors to be
2730 * trapped now rather than later. If we don't, then errors may go undetected
2731 * until an argument is actually parsed.
2734 rex
= trex_compile(priv
->pattern
, &error
, priv
->flags
);
2736 ARG_LOG(("argtable: %s \"%s\"\n", error
? error
: _TREXC("undefined"), priv
->pattern
));
2737 ARG_LOG(("argtable: Bad argument table.\n"));
2742 ARG_TRACE(("arg_rexn() returns %p\n", result
));
2748 /* see copyright notice in trex.h */
2755 #define scisprint iswprint
2756 #define scstrlen wcslen
2757 #define scprintf wprintf
2760 #define scisprint isprint
2761 #define scstrlen strlen
2762 #define scprintf printf
2769 static const TRexChar
*g_nnames
[] = {
2770 _SC("NONE"), _SC("OP_GREEDY"), _SC("OP_OR"),
2771 _SC("OP_EXPR"), _SC("OP_NOCAPEXPR"), _SC("OP_DOT"), _SC("OP_CLASS"),
2772 _SC("OP_CCLASS"), _SC("OP_NCLASS"), _SC("OP_RANGE"), _SC("OP_CHAR"),
2773 _SC("OP_EOL"), _SC("OP_BOL"), _SC("OP_WB")
2777 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2778 #define OP_OR (MAX_CHAR+2)
2779 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2780 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2781 #define OP_DOT (MAX_CHAR+5)
2782 #define OP_CLASS (MAX_CHAR+6)
2783 #define OP_CCLASS (MAX_CHAR+7)
2784 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2785 #define OP_RANGE (MAX_CHAR+9)
2786 #define OP_CHAR (MAX_CHAR+10)
2787 #define OP_EOL (MAX_CHAR+11)
2788 #define OP_BOL (MAX_CHAR+12)
2789 #define OP_WB (MAX_CHAR+13)
2791 #define TREX_SYMBOL_ANY_CHAR ('.')
2792 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
2793 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
2794 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
2795 #define TREX_SYMBOL_BRANCH ('|')
2796 #define TREX_SYMBOL_END_OF_STRING ('$')
2797 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
2798 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
2801 typedef int TRexNodeType
;
2803 typedef struct tagTRexNode
{
2811 const TRexChar
*_eol
;
2812 const TRexChar
*_bol
;
2820 TRexMatch
*_matches
;
2823 const TRexChar
**_error
;
2827 static int trex_list(TRex
*exp
);
2829 static int trex_newnode(TRex
*exp
, TRexNodeType type
) {
2833 n
.next
= n
.right
= n
.left
= -1;
2834 if (type
== OP_EXPR
)
2835 n
.right
= exp
->_nsubexpr
++;
2836 if (exp
->_nallocated
< (exp
->_nsize
+ 1)) {
2837 exp
->_nallocated
*= 2;
2838 exp
->_nodes
= (TRexNode
*)realloc(exp
->_nodes
, exp
->_nallocated
* sizeof(TRexNode
));
2840 exp
->_nodes
[exp
->_nsize
++] = n
;
2841 newid
= exp
->_nsize
- 1;
2845 static void trex_error(TRex
*exp
, const TRexChar
*error
) {
2846 if (exp
->_error
) *exp
->_error
= error
;
2847 longjmp(*((jmp_buf *)exp
->_jmpbuf
), -1);
2850 static void trex_expect(TRex
*exp
, int n
) {
2851 if ((*exp
->_p
) != n
)
2852 trex_error(exp
, _SC("expected paren"));
2856 static TRexChar
trex_escapechar(TRex
*exp
) {
2857 if (*exp
->_p
== TREX_SYMBOL_ESCAPE_CHAR
) {
2876 return (*exp
->_p
++);
2878 } else if (!scisprint(*exp
->_p
)) trex_error(exp
, _SC("letter expected"));
2879 return (*exp
->_p
++);
2882 static int trex_charclass(TRex
*exp
, int classid
) {
2883 int n
= trex_newnode(exp
, OP_CCLASS
);
2884 exp
->_nodes
[n
].left
= classid
;
2888 static int trex_charnode(TRex
*exp
, TRexBool isclass
) {
2890 if (*exp
->_p
== TREX_SYMBOL_ESCAPE_CHAR
) {
2895 return trex_newnode(exp
, '\n');
2898 return trex_newnode(exp
, '\t');
2901 return trex_newnode(exp
, '\r');
2904 return trex_newnode(exp
, '\f');
2907 return trex_newnode(exp
, '\v');
2926 return trex_charclass(exp
, t
);
2931 int node
= trex_newnode(exp
, OP_WB
);
2932 exp
->_nodes
[node
].left
= *exp
->_p
;
2939 return trex_newnode(exp
, t
);
2941 } else if (!scisprint(*exp
->_p
)) {
2943 trex_error(exp
, _SC("letter expected"));
2947 return trex_newnode(exp
, t
);
2949 static int trex_class(TRex
*exp
) {
2951 int first
= -1, chain
;
2952 if (*exp
->_p
== TREX_SYMBOL_BEGINNING_OF_STRING
) {
2953 ret
= trex_newnode(exp
, OP_NCLASS
);
2955 } else ret
= trex_newnode(exp
, OP_CLASS
);
2957 if (*exp
->_p
== ']') trex_error(exp
, _SC("empty class"));
2959 while (*exp
->_p
!= ']' && exp
->_p
!= exp
->_eol
) {
2960 if (*exp
->_p
== '-' && first
!= -1) {
2962 if (*exp
->_p
++ == ']') {
2963 trex_error(exp
, _SC("unfinished range"));
2966 r
= trex_newnode(exp
, OP_RANGE
);
2967 if (first
> *exp
->_p
) {
2968 trex_error(exp
, _SC("invalid range"));
2971 if (exp
->_nodes
[first
].type
== OP_CCLASS
) {
2972 trex_error(exp
, _SC("cannot use character classes in ranges"));
2975 exp
->_nodes
[r
].left
= exp
->_nodes
[first
].type
;
2976 t
= trex_escapechar(exp
);
2977 exp
->_nodes
[r
].right
= t
;
2978 exp
->_nodes
[chain
].next
= r
;
2984 exp
->_nodes
[chain
].next
= c
;
2986 first
= trex_charnode(exp
, TRex_True
);
2988 first
= trex_charnode(exp
, TRex_True
);
2994 exp
->_nodes
[chain
].next
= c
;
2997 exp
->_nodes
[ret
].left
= exp
->_nodes
[ret
].next
;
2998 exp
->_nodes
[ret
].next
= -1;
3002 static int trex_parsenumber(TRex
*exp
) {
3003 int ret
= *exp
->_p
- '0';
3006 while (isdigit(*exp
->_p
)) {
3007 ret
= ret
* 10 + (*exp
->_p
++ -'0');
3008 if (positions
== 1000000000) trex_error(exp
, _SC("overflow in numeric constant"));
3014 static int trex_element(TRex
*exp
) {
3022 if (*exp
->_p
== '?') {
3024 trex_expect(exp
, ':');
3025 expr
= trex_newnode(exp
, OP_NOCAPEXPR
);
3027 expr
= trex_newnode(exp
, OP_EXPR
);
3028 newn
= trex_list(exp
);
3029 exp
->_nodes
[expr
].left
= newn
;
3031 trex_expect(exp
, ')');
3036 ret
= trex_class(exp
);
3037 trex_expect(exp
, ']');
3039 case TREX_SYMBOL_END_OF_STRING
:
3041 ret
= trex_newnode(exp
, OP_EOL
);
3043 case TREX_SYMBOL_ANY_CHAR
:
3045 ret
= trex_newnode(exp
, OP_DOT
);
3048 ret
= trex_charnode(exp
, TRex_False
);
3053 TRexBool isgreedy
= TRex_False
;
3054 unsigned short p0
= 0, p1
= 0;
3056 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE
:
3060 isgreedy
= TRex_True
;
3062 case TREX_SYMBOL_GREEDY_ONE_OR_MORE
:
3066 isgreedy
= TRex_True
;
3068 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE
:
3072 isgreedy
= TRex_True
;
3076 if (!isdigit(*exp
->_p
)) trex_error(exp
, _SC("number expected"));
3077 p0
= (unsigned short)trex_parsenumber(exp
);
3078 /*******************************/
3087 if (isdigit(*exp
->_p
)) {
3088 p1
= (unsigned short)trex_parsenumber(exp
);
3090 trex_expect(exp
, '}');
3093 trex_error(exp
, _SC(", or } expected"));
3095 /*******************************/
3096 isgreedy
= TRex_True
;
3101 int nnode
= trex_newnode(exp
, OP_GREEDY
);
3102 exp
->_nodes
[nnode
].left
= ret
;
3103 exp
->_nodes
[nnode
].right
= ((p0
) << 16) | p1
;
3107 if ((*exp
->_p
!= TREX_SYMBOL_BRANCH
) && (*exp
->_p
!= ')') && (*exp
->_p
!= TREX_SYMBOL_GREEDY_ZERO_OR_MORE
) && (*exp
->_p
!= TREX_SYMBOL_GREEDY_ONE_OR_MORE
) && (*exp
->_p
!= '\0')) {
3108 int nnode
= trex_element(exp
);
3109 exp
->_nodes
[ret
].next
= nnode
;
3115 static int trex_list(TRex
*exp
) {
3117 if (*exp
->_p
== TREX_SYMBOL_BEGINNING_OF_STRING
) {
3119 ret
= trex_newnode(exp
, OP_BOL
);
3121 e
= trex_element(exp
);
3123 exp
->_nodes
[ret
].next
= e
;
3126 if (*exp
->_p
== TREX_SYMBOL_BRANCH
) {
3129 temp
= trex_newnode(exp
, OP_OR
);
3130 exp
->_nodes
[temp
].left
= ret
;
3131 tright
= trex_list(exp
);
3132 exp
->_nodes
[temp
].right
= tright
;
3138 static TRexBool
trex_matchcclass(int cclass
, TRexChar c
) {
3141 return isalpha(c
) ? TRex_True
: TRex_False
;
3143 return !isalpha(c
) ? TRex_True
: TRex_False
;
3145 return (isalnum(c
) || c
== '_') ? TRex_True
: TRex_False
;
3147 return (!isalnum(c
) && c
!= '_') ? TRex_True
: TRex_False
;
3149 return ISSPACE(c
) ? TRex_True
: TRex_False
;
3151 return !ISSPACE(c
) ? TRex_True
: TRex_False
;
3153 return isdigit(c
) ? TRex_True
: TRex_False
;
3155 return !isdigit(c
) ? TRex_True
: TRex_False
;
3157 return isxdigit(c
) ? TRex_True
: TRex_False
;
3159 return !isxdigit(c
) ? TRex_True
: TRex_False
;
3161 return iscntrl(c
) ? TRex_True
: TRex_False
;
3163 return !iscntrl(c
) ? TRex_True
: TRex_False
;
3165 return ispunct(c
) ? TRex_True
: TRex_False
;
3167 return !ispunct(c
) ? TRex_True
: TRex_False
;
3169 return islower(c
) ? TRex_True
: TRex_False
;
3171 return isupper(c
) ? TRex_True
: TRex_False
;
3173 return TRex_False
; /*cannot happen*/
3176 static TRexBool
trex_matchclass(TRex
*exp
, TRexNode
*node
, TRexChar c
) {
3178 switch (node
->type
) {
3180 if (exp
->_flags
& TREX_ICASE
) {
3181 if (c
>= toupper(node
->left
) && c
<= toupper(node
->right
)) return TRex_True
;
3182 if (c
>= tolower(node
->left
) && c
<= tolower(node
->right
)) return TRex_True
;
3184 if (c
>= node
->left
&& c
<= node
->right
) return TRex_True
;
3188 if (trex_matchcclass(node
->left
, c
)) return TRex_True
;
3191 if (exp
->_flags
& TREX_ICASE
) {
3192 if (c
== tolower(node
->type
) || c
== toupper(node
->type
)) return TRex_True
;
3194 if (c
== node
->type
)return TRex_True
;
3198 } while ((node
->next
!= -1) && (node
= &exp
->_nodes
[node
->next
]));
3202 static const TRexChar
*trex_matchnode(TRex
*exp
, TRexNode
*node
, const TRexChar
*str
, TRexNode
*next
) {
3204 TRexNodeType type
= node
->type
;
3207 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3208 TRexNode
*greedystop
= NULL
;
3209 int p0
= (node
->right
>> 16) & 0x0000FFFF, p1
= node
->right
& 0x0000FFFF, nmaches
= 0;
3210 const TRexChar
*s
= str
, *good
= str
;
3212 if (node
->next
!= -1) {
3213 greedystop
= &exp
->_nodes
[node
->next
];
3218 while ((nmaches
== 0xFFFF || nmaches
< p1
)) {
3220 const TRexChar
*stop
;
3221 if (!(s
= trex_matchnode(exp
, &exp
->_nodes
[node
->left
], s
, greedystop
)))
3226 //checks that 0 matches satisfy the expression(if so skips)
3227 //if not would always stop(for instance if is a '?')
3228 if (greedystop
->type
!= OP_GREEDY
||
3229 (greedystop
->type
== OP_GREEDY
&& ((greedystop
->right
>> 16) & 0x0000FFFF) != 0)) {
3230 TRexNode
*gnext
= NULL
;
3231 if (greedystop
->next
!= -1) {
3232 gnext
= &exp
->_nodes
[greedystop
->next
];
3233 } else if (next
&& next
->next
!= -1) {
3234 gnext
= &exp
->_nodes
[next
->next
];
3236 stop
= trex_matchnode(exp
, greedystop
, s
, gnext
);
3238 //if satisfied stop it
3239 if (p0
== p1
&& p0
== nmaches
) break;
3240 else if (nmaches
>= p0
&& p1
== 0xFFFF) break;
3241 else if (nmaches
>= p0
&& nmaches
<= p1
) break;
3249 if (p0
== p1
&& p0
== nmaches
) return good
;
3250 else if (nmaches
>= p0
&& p1
== 0xFFFF) return good
;
3251 else if (nmaches
>= p0
&& nmaches
<= p1
) return good
;
3255 const TRexChar
*asd
= str
;
3256 TRexNode
*temp
= &exp
->_nodes
[node
->left
];
3257 while ((asd
= trex_matchnode(exp
, temp
, asd
, NULL
))) {
3258 if (temp
->next
!= -1)
3259 temp
= &exp
->_nodes
[temp
->next
];
3264 temp
= &exp
->_nodes
[node
->right
];
3265 while ((asd
= trex_matchnode(exp
, temp
, asd
, NULL
))) {
3266 if (temp
->next
!= -1)
3267 temp
= &exp
->_nodes
[temp
->next
];
3274 case OP_NOCAPEXPR
: {
3275 TRexNode
*n
= &exp
->_nodes
[node
->left
];
3276 const TRexChar
*cur
= str
;
3278 if (node
->type
!= OP_NOCAPEXPR
&& node
->right
== exp
->_currsubexp
) {
3279 capture
= exp
->_currsubexp
;
3280 exp
->_matches
[capture
].begin
= cur
;
3285 TRexNode
*subnext
= NULL
;
3286 if (n
->next
!= -1) {
3287 subnext
= &exp
->_nodes
[n
->next
];
3291 if (!(cur
= trex_matchnode(exp
, n
, cur
, subnext
))) {
3292 if (capture
!= -1) {
3293 exp
->_matches
[capture
].begin
= 0;
3294 exp
->_matches
[capture
].len
= 0;
3298 } while ((n
->next
!= -1) && (n
= &exp
->_nodes
[n
->next
]));
3301 exp
->_matches
[capture
].len
= (int)(cur
- exp
->_matches
[capture
].begin
);
3305 if ((str
== exp
->_bol
&& !ISSPACE(*str
))
3306 || ((str
== exp
->_eol
&& !ISSPACE(*(str
- 1))))
3307 || ((!ISSPACE(*str
) && ISSPACE(*(str
+ 1))))
3308 || ((ISSPACE(*str
) && !ISSPACE(*(str
+ 1))))) {
3309 return (node
->left
== 'b') ? str
: NULL
;
3311 return (node
->left
== 'b') ? NULL
: str
;
3313 if (str
== exp
->_bol
) return str
;
3316 if (str
== exp
->_eol
) return str
;
3323 if (trex_matchclass(exp
, &exp
->_nodes
[node
->left
], *str
) ? (type
== OP_CLASS
? TRex_True
: TRex_False
) : (type
== OP_NCLASS
? TRex_True
: TRex_False
)) {
3329 if (trex_matchcclass(node
->left
, *str
)) {
3335 if (exp
->_flags
& TREX_ICASE
) {
3336 if (*str
!= tolower(node
->type
) && *str
!= toupper(node
->type
)) return NULL
;
3338 if (*str
!= node
->type
) return NULL
;
3347 TRex
*trex_compile(const TRexChar
*pattern
, const TRexChar
**error
, int flags
) {
3348 TRex
*exp
= (TRex
*)malloc(sizeof(TRex
));
3349 exp
->_eol
= exp
->_bol
= NULL
;
3351 exp
->_nallocated
= (int)scstrlen(pattern
) * sizeof(TRexChar
);
3352 exp
->_nodes
= (TRexNode
*)malloc(exp
->_nallocated
* sizeof(TRexNode
));
3356 exp
->_first
= trex_newnode(exp
, OP_EXPR
);
3357 exp
->_error
= error
;
3358 exp
->_jmpbuf
= malloc(sizeof(jmp_buf));
3359 exp
->_flags
= flags
;
3360 if (setjmp(*((jmp_buf *)exp
->_jmpbuf
)) == 0) {
3361 int res
= trex_list(exp
);
3362 exp
->_nodes
[exp
->_first
].left
= res
;
3363 if (*exp
->_p
!= '\0')
3364 trex_error(exp
, _SC("unexpected character"));
3369 nsize
= exp
->_nsize
;
3370 t
= &exp
->_nodes
[0];
3371 scprintf(_SC("\n"));
3372 for (i
= 0; i
< nsize
; i
++) {
3373 if (exp
->_nodes
[i
].type
> MAX_CHAR
)
3374 scprintf(_SC("[%02d] %10s "), i
, g_nnames
[exp
->_nodes
[i
].type
- MAX_CHAR
]);
3376 scprintf(_SC("[%02d] %10c "), i
, exp
->_nodes
[i
].type
);
3377 scprintf(_SC("left %02d right %02d next %02d\n"), exp
->_nodes
[i
].left
, exp
->_nodes
[i
].right
, exp
->_nodes
[i
].next
);
3379 scprintf(_SC("\n"));
3382 exp
->_matches
= (TRexMatch
*) malloc(exp
->_nsubexpr
* sizeof(TRexMatch
));
3383 memset(exp
->_matches
, 0, exp
->_nsubexpr
* sizeof(TRexMatch
));
3391 void trex_free(TRex
*exp
) {
3393 if (exp
->_nodes
) free(exp
->_nodes
);
3394 if (exp
->_jmpbuf
) free(exp
->_jmpbuf
);
3395 if (exp
->_matches
) free(exp
->_matches
);
3400 TRexBool
trex_match(TRex
*exp
, const TRexChar
*text
) {
3401 const TRexChar
*res
= NULL
;
3403 exp
->_eol
= text
+ scstrlen(text
);
3404 exp
->_currsubexp
= 0;
3405 res
= trex_matchnode(exp
, exp
->_nodes
, text
, NULL
);
3406 if (res
== NULL
|| res
!= exp
->_eol
)
3411 TRexBool
trex_searchrange(TRex
*exp
, const TRexChar
*text_begin
, const TRexChar
*text_end
, const TRexChar
**out_begin
, const TRexChar
**out_end
) {
3412 const TRexChar
*cur
= NULL
;
3413 int node
= exp
->_first
;
3414 if (text_begin
>= text_end
) return TRex_False
;
3415 exp
->_bol
= text_begin
;
3416 exp
->_eol
= text_end
;
3419 while (node
!= -1) {
3420 exp
->_currsubexp
= 0;
3421 cur
= trex_matchnode(exp
, &exp
->_nodes
[node
], cur
, NULL
);
3424 node
= exp
->_nodes
[node
].next
;
3427 } while (cur
== NULL
&& text_begin
!= text_end
);
3434 if (out_begin
) *out_begin
= text_begin
;
3435 if (out_end
) *out_end
= cur
;
3439 TRexBool
trex_search(TRex
*exp
, const TRexChar
*text
, const TRexChar
**out_begin
, const TRexChar
**out_end
) {
3440 return trex_searchrange(exp
, text
, text
+ scstrlen(text
), out_begin
, out_end
);
3443 int trex_getsubexpcount(TRex
*exp
) {
3444 return exp
->_nsubexpr
;
3447 TRexBool
trex_getsubexp(TRex
*exp
, int n
, TRexMatch
*subexp
) {
3448 if (n
< 0 || n
>= exp
->_nsubexpr
) return TRex_False
;
3449 *subexp
= exp
->_matches
[n
];
3452 /*******************************************************************************
3453 * This file is part of the argtable3 library.
3455 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3456 * <sheitmann@users.sourceforge.net>
3457 * All rights reserved.
3459 * Redistribution and use in source and binary forms, with or without
3460 * modification, are permitted provided that the following conditions are met:
3461 * * Redistributions of source code must retain the above copyright
3462 * notice, this list of conditions and the following disclaimer.
3463 * * Redistributions in binary form must reproduce the above copyright
3464 * notice, this list of conditions and the following disclaimer in the
3465 * documentation and/or other materials provided with the distribution.
3466 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3467 * may be used to endorse or promote products derived from this software
3468 * without specific prior written permission.
3470 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3471 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3472 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3473 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3474 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3475 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3476 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3477 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3478 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3479 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3480 ******************************************************************************/
3484 #include "argtable3.h"
3487 static void arg_str_resetfn(struct arg_str
*parent
) {
3489 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
3491 for (i
= 0; i
< parent
->count
; i
++) {
3492 parent
->sval
[i
] = "";
3497 static int arg_str_scanfn(struct arg_str
*parent
, const char *argval
) {
3500 if (parent
->count
== parent
->hdr
.maxcount
) {
3501 /* maximum number of arguments exceeded */
3502 errorcode
= EMAXCOUNT
;
3503 } else if (!argval
) {
3504 /* a valid argument with no argument value was given. */
3505 /* This happens when an optional argument value was invoked. */
3506 /* leave parent arguiment value unaltered but still count the argument. */
3509 parent
->sval
[parent
->count
++] = argval
;
3512 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
3517 static int arg_str_checkfn(struct arg_str
*parent
) {
3518 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
3520 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
3525 static void arg_str_errorfn(
3526 struct arg_str
*parent
,
3530 const char *progname
) {
3531 const char *shortopts
= parent
->hdr
.shortopts
;
3532 const char *longopts
= parent
->hdr
.longopts
;
3533 const char *datatype
= parent
->hdr
.datatype
;
3535 /* make argval NULL safe */
3536 argval
= argval
? argval
: "";
3538 fprintf(fp
, "%s: ", progname
);
3539 switch (errorcode
) {
3541 fputs("missing option ", fp
);
3542 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
3546 fputs("excess option ", fp
);
3547 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
3553 struct arg_str
*arg_str0(
3554 const char *shortopts
,
3555 const char *longopts
,
3556 const char *datatype
,
3557 const char *glossary
) {
3558 return arg_strn(shortopts
, longopts
, datatype
, 0, 1, glossary
);
3562 struct arg_str
*arg_str1(
3563 const char *shortopts
,
3564 const char *longopts
,
3565 const char *datatype
,
3566 const char *glossary
) {
3567 return arg_strn(shortopts
, longopts
, datatype
, 1, 1, glossary
);
3571 struct arg_str
*arg_strn(
3572 const char *shortopts
,
3573 const char *longopts
,
3574 const char *datatype
,
3577 const char *glossary
) {
3579 struct arg_str
*result
;
3581 /* should not allow this stupid error */
3582 /* we should return an error code warning this logic error */
3583 /* foolproof things by ensuring maxcount is not less than mincount */
3584 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
3586 nbytes
= sizeof(struct arg_str
) /* storage for struct arg_str */
3587 + maxcount
* sizeof(char *); /* storage for sval[maxcount] array */
3589 result
= (struct arg_str
*)malloc(nbytes
);
3593 /* init the arg_hdr struct */
3594 result
->hdr
.flag
= ARG_HASVALUE
;
3595 result
->hdr
.shortopts
= shortopts
;
3596 result
->hdr
.longopts
= longopts
;
3597 result
->hdr
.datatype
= datatype
? datatype
: "<string>";
3598 result
->hdr
.glossary
= glossary
;
3599 result
->hdr
.mincount
= mincount
;
3600 result
->hdr
.maxcount
= maxcount
;
3601 result
->hdr
.parent
= result
;
3602 result
->hdr
.resetfn
= (arg_resetfn
*)arg_str_resetfn
;
3603 result
->hdr
.scanfn
= (arg_scanfn
*)arg_str_scanfn
;
3604 result
->hdr
.checkfn
= (arg_checkfn
*)arg_str_checkfn
;
3605 result
->hdr
.errorfn
= (arg_errorfn
*)arg_str_errorfn
;
3607 /* store the sval[maxcount] array immediately after the arg_str struct */
3608 result
->sval
= (const char * *)(result
+ 1);
3611 /* foolproof the string pointers by initialising them to reference empty strings */
3612 for (i
= 0; i
< maxcount
; i
++)
3613 result
->sval
[i
] = "";
3616 ARG_TRACE(("arg_strn() returns %p\n", result
));
3619 /*******************************************************************************
3620 * This file is part of the argtable3 library.
3622 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3623 * <sheitmann@users.sourceforge.net>
3624 * All rights reserved.
3626 * Redistribution and use in source and binary forms, with or without
3627 * modification, are permitted provided that the following conditions are met:
3628 * * Redistributions of source code must retain the above copyright
3629 * notice, this list of conditions and the following disclaimer.
3630 * * Redistributions in binary form must reproduce the above copyright
3631 * notice, this list of conditions and the following disclaimer in the
3632 * documentation and/or other materials provided with the distribution.
3633 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3634 * may be used to endorse or promote products derived from this software
3635 * without specific prior written permission.
3637 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3638 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3639 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3640 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3641 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3642 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3643 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3644 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3645 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3646 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3647 ******************************************************************************/
3654 #include "argtable3.h"
3657 void arg_register_error(struct arg_end
*end
,
3660 const char *argval
) {
3661 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3662 if (end
->count
< end
->hdr
.maxcount
) {
3663 end
->error
[end
->count
] = error
;
3664 end
->parent
[end
->count
] = parent
;
3665 end
->argval
[end
->count
] = argval
;
3668 end
->error
[end
->hdr
.maxcount
- 1] = ARG_ELIMIT
;
3669 end
->parent
[end
->hdr
.maxcount
- 1] = end
;
3670 end
->argval
[end
->hdr
.maxcount
- 1] = NULL
;
3676 * Return index of first table entry with a matching short option
3677 * or -1 if no match was found.
3679 static int find_shortoption(struct arg_hdr
**table
, char shortopt
) {
3681 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++) {
3682 if (table
[tabindex
]->shortopts
&&
3683 strchr(table
[tabindex
]->shortopts
, shortopt
))
3689 struct longoptions
{
3692 struct option
*options
;
3697 void dump_longoptions(struct longoptions
*longoptions
) {
3699 printf("getoptval = %d\n", longoptions
->getoptval
);
3700 printf("noptions = %d\n", longoptions
->noptions
);
3701 for (i
= 0; i
< longoptions
->noptions
; i
++) {
3702 printf("options[%d].name = \"%s\"\n",
3704 longoptions
->options
[i
].name
);
3705 printf("options[%d].has_arg = %d\n", i
, longoptions
->options
[i
].has_arg
);
3706 printf("options[%d].flag = %p\n", i
, longoptions
->options
[i
].flag
);
3707 printf("options[%d].val = %d\n", i
, longoptions
->options
[i
].val
);
3712 static struct longoptions
*alloc_longoptions(struct arg_hdr
**table
) {
3713 struct longoptions
*result
;
3716 size_t longoptlen
= 0;
3720 * Determine the total number of option structs required
3721 * by counting the number of comma separated long options
3722 * in all table entries and return the count in noptions.
3723 * note: noptions starts at 1 not 0 because we getoptlong
3724 * requires a NULL option entry to terminate the option array.
3725 * While we are at it, count the number of chars required
3726 * to store private copies of all the longoption strings
3727 * and return that count in logoptlen.
3731 const char *longopts
= table
[tabindex
]->longopts
;
3732 longoptlen
+= (longopts
? strlen(longopts
) : 0) + 1;
3735 longopts
= strchr(longopts
+ 1, ',');
3737 } while (!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
3738 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3741 /* allocate storage for return data structure as: */
3742 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3743 nbytes
= sizeof(struct longoptions
)
3744 + sizeof(struct option
) * noptions
3746 result
= (struct longoptions
*)malloc(nbytes
);
3748 int option_index
= 0;
3751 result
->getoptval
= 0;
3752 result
->noptions
= noptions
;
3753 result
->options
= (struct option
*)(result
+ 1);
3754 store
= (char *)(result
->options
+ noptions
);
3756 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++) {
3757 const char *longopts
= table
[tabindex
]->longopts
;
3759 while (longopts
&& *longopts
) {
3760 char *storestart
= store
;
3762 /* copy progressive longopt strings into the store */
3763 while (*longopts
!= 0 && *longopts
!= ',')
3764 *store
++ = *longopts
++;
3766 if (*longopts
== ',')
3768 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3770 result
->options
[option_index
].name
= storestart
;
3771 result
->options
[option_index
].flag
= &(result
->getoptval
);
3772 result
->options
[option_index
].val
= tabindex
;
3773 if (table
[tabindex
]->flag
& ARG_HASOPTVALUE
)
3774 result
->options
[option_index
].has_arg
= 2;
3775 else if (table
[tabindex
]->flag
& ARG_HASVALUE
)
3776 result
->options
[option_index
].has_arg
= 1;
3778 result
->options
[option_index
].has_arg
= 0;
3783 /* terminate the options array with a zero-filled entry */
3784 result
->options
[option_index
].name
= 0;
3785 result
->options
[option_index
].has_arg
= 0;
3786 result
->options
[option_index
].flag
= 0;
3787 result
->options
[option_index
].val
= 0;
3790 /*dump_longoptions(result);*/
3794 static char *alloc_shortoptions(struct arg_hdr
**table
) {
3799 /* determine the total number of option chars required */
3800 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++) {
3801 struct arg_hdr
*hdr
= table
[tabindex
];
3802 len
+= 3 * (hdr
->shortopts
? strlen(hdr
->shortopts
) : 0);
3805 result
= malloc(len
);
3809 /* add a leading ':' so getopt return codes distinguish */
3810 /* unrecognised option and options missing argument values */
3813 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++) {
3814 struct arg_hdr
*hdr
= table
[tabindex
];
3815 const char *shortopts
= hdr
->shortopts
;
3816 while (shortopts
&& *shortopts
) {
3817 *res
++ = *shortopts
++;
3818 if (hdr
->flag
& ARG_HASVALUE
)
3820 if (hdr
->flag
& ARG_HASOPTVALUE
)
3824 /* null terminate the string */
3828 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
3833 /* return index of the table terminator entry */
3834 static int arg_endindex(struct arg_hdr
**table
) {
3836 while (!(table
[tabindex
]->flag
& ARG_TERMINATOR
))
3842 static void arg_parse_tagged(int argc
,
3844 struct arg_hdr
**table
,
3845 struct arg_end
*endtable
) {
3846 struct longoptions
*longoptions
;
3850 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
3852 /* allocate short and long option arrays for the given opttable[]. */
3853 /* if the allocs fail then put an error msg in the last table entry. */
3854 longoptions
= alloc_longoptions(table
);
3855 shortoptions
= alloc_shortoptions(table
);
3856 if (!longoptions
|| !shortoptions
) {
3857 /* one or both memory allocs failed */
3858 arg_register_error(endtable
, endtable
, ARG_EMALLOC
, NULL
);
3859 /* free anything that was allocated (this is null safe) */
3865 /*dump_longoptions(longoptions);*/
3867 /* reset getopts internal option-index to zero, and disable error reporting */
3871 /* fetch and process args using getopt_long */
3873 getopt_long(argc
, argv
, shortoptions
, longoptions
->options
,
3876 printf("optarg='%s'\n",optarg);
3877 printf("optind=%d\n",optind);
3878 printf("copt=%c\n",(char)copt);
3879 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
3883 int tabindex
= longoptions
->getoptval
;
3884 void *parent
= table
[tabindex
]->parent
;
3885 /*printf("long option detected from argtable[%d]\n", tabindex);*/
3886 if (optarg
&& optarg
[0] == 0 &&
3887 (table
[tabindex
]->flag
& ARG_HASVALUE
)) {
3888 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
3889 arg_register_error(endtable
, endtable
, ARG_EMISSARG
,
3891 /* continue to scan the (empty) argument value to enforce argument count checking */
3893 if (table
[tabindex
]->scanfn
) {
3894 int errorcode
= table
[tabindex
]->scanfn(parent
, optarg
);
3896 arg_register_error(endtable
, parent
, errorcode
, optarg
);
3903 * getopt_long() found an unrecognised short option.
3904 * if it was a short option its value is in optopt
3905 * if it was a long option then optopt=0
3909 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
3910 arg_register_error(endtable
, endtable
, ARG_ELONGOPT
,
3914 /*printf("?* unrecognised short option '%c'\n",optopt);*/
3915 arg_register_error(endtable
, endtable
, optopt
, NULL
);
3922 * getopt_long() found an option with its argument missing.
3924 /*printf(": option %s requires an argument\n",argv[optind-1]); */
3925 arg_register_error(endtable
, endtable
, ARG_EMISSARG
,
3930 /* getopt_long() found a valid short option */
3931 int tabindex
= find_shortoption(table
, (char)copt
);
3932 /*printf("short option detected from argtable[%d]\n", tabindex);*/
3933 if (tabindex
== -1) {
3934 /* should never get here - but handle it just in case */
3935 /*printf("unrecognised short option %d\n",copt);*/
3936 arg_register_error(endtable
, endtable
, copt
, NULL
);
3938 if (table
[tabindex
]->scanfn
) {
3939 void *parent
= table
[tabindex
]->parent
;
3940 int errorcode
= table
[tabindex
]->scanfn(parent
, optarg
);
3942 arg_register_error(endtable
, parent
, errorcode
, optarg
);
3955 static void arg_parse_untagged(int argc
,
3957 struct arg_hdr
**table
,
3958 struct arg_end
*endtable
) {
3961 const char *optarglast
= NULL
;
3962 void *parentlast
= NULL
;
3964 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
3965 while (!(table
[tabindex
]->flag
& ARG_TERMINATOR
)) {
3969 /* if we have exhausted our argv[optind] entries then we have finished */
3970 if (optind
>= argc
) {
3971 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
3975 /* skip table entries with non-null long or short options (they are not untagged entries) */
3976 if (table
[tabindex
]->longopts
|| table
[tabindex
]->shortopts
) {
3977 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
3982 /* skip table entries with NULL scanfn */
3983 if (!(table
[tabindex
]->scanfn
)) {
3984 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
3989 /* attempt to scan the current argv[optind] with the current */
3990 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
3991 /* try again with the next table[] entry. */
3992 parent
= table
[tabindex
]->parent
;
3993 errorcode
= table
[tabindex
]->scanfn(parent
, argv
[optind
]);
3994 if (errorcode
== 0) {
3995 /* success, move onto next argv[optind] but stay with same table[tabindex] */
3996 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
3999 /* clear the last tentative error */
4002 /* failure, try same argv[optind] with next table[tabindex] entry */
4003 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4006 /* remember this as a tentative error we may wish to reinstate later */
4007 errorlast
= errorcode
;
4008 optarglast
= argv
[optind
];
4009 parentlast
= parent
;
4013 /* if a tenative error still remains at this point then register it as a proper error */
4015 arg_register_error(endtable
, parentlast
, errorlast
, optarglast
);
4019 /* only get here when not all argv[] entries were consumed */
4020 /* register an error for each unused argv[] entry */
4021 while (optind
< argc
) {
4022 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4023 arg_register_error(endtable
, endtable
, ARG_ENOMATCH
, argv
[optind
++]);
4030 static void arg_parse_check(struct arg_hdr
**table
, struct arg_end
*endtable
) {
4032 /* printf("arg_parse_check()\n"); */
4034 if (table
[tabindex
]->checkfn
) {
4035 void *parent
= table
[tabindex
]->parent
;
4036 int errorcode
= table
[tabindex
]->checkfn(parent
);
4038 arg_register_error(endtable
, parent
, errorcode
, NULL
);
4040 } while (!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4044 static void arg_reset(void **argtable
) {
4045 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4047 /*printf("arg_reset(%p)\n",argtable);*/
4049 if (table
[tabindex
]->resetfn
)
4050 table
[tabindex
]->resetfn(table
[tabindex
]->parent
);
4051 } while (!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4055 int arg_parse(int argc
, char * *argv
, void * *argtable
) {
4056 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4057 struct arg_end
*endtable
;
4059 char * *argvcopy
= NULL
;
4061 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4063 /* reset any argtable data from previous invocations */
4064 arg_reset(argtable
);
4066 /* locate the first end-of-table marker within the array */
4067 endindex
= arg_endindex(table
);
4068 endtable
= (struct arg_end
*)table
[endindex
];
4070 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4071 /* Failure to trap this case results in an unwanted NULL result from */
4072 /* the malloc for argvcopy (next code block). */
4074 /* We must still perform post-parse checks despite the absence of command line arguments */
4075 arg_parse_check(table
, endtable
);
4077 /* Now we are finished */
4078 return endtable
->count
;
4081 argvcopy
= (char **)malloc(sizeof(char *) * (argc
+ 1));
4086 Fill in the local copy of argv[]. We need a local copy
4087 because getopt rearranges argv[] which adversely affects
4088 susbsequent parsing attempts.
4090 for (i
= 0; i
< argc
; i
++)
4091 argvcopy
[i
] = argv
[i
];
4093 argvcopy
[argc
] = NULL
;
4095 /* parse the command line (local copy) for tagged options */
4096 arg_parse_tagged(argc
, argvcopy
, table
, endtable
);
4098 /* parse the command line (local copy) for untagged options */
4099 arg_parse_untagged(argc
, argvcopy
, table
, endtable
);
4101 /* if no errors so far then perform post-parse checks otherwise dont bother */
4102 if (endtable
->count
== 0)
4103 arg_parse_check(table
, endtable
);
4105 /* release the local copt of argv[] */
4108 /* memory alloc failed */
4109 arg_register_error(endtable
, endtable
, ARG_EMALLOC
, NULL
);
4112 return endtable
->count
;
4117 * Concatenate contents of src[] string onto *pdest[] string.
4118 * The *pdest pointer is altered to point to the end of the
4119 * target string and *pndest is decremented by the same number
4121 * Does not append more than *pndest chars into *pdest[]
4122 * so as to prevent buffer overruns.
4123 * Its something like strncat() but more efficient for repeated
4124 * calls on the same destination string.
4126 * char dest[30] = "good"
4127 * size_t ndest = sizeof(dest);
4128 * char *pdest = dest;
4129 * arg_char(&pdest,"bye ",&ndest);
4130 * arg_char(&pdest,"cruel ",&ndest);
4131 * arg_char(&pdest,"world!",&ndest);
4133 * dest[] == "goodbye cruel world!"
4136 static void arg_cat(char **pdest
, const char *src
, size_t *pndest
) {
4137 char *dest
= *pdest
;
4138 // PM3 fix: leave room for null terminate char
4139 char *end
= dest
+ *pndest
- 1;
4141 /*locate null terminator of dest string */
4142 while (dest
< end
&& *dest
!= 0)
4145 /* concat src string to dest string */
4146 while (dest
< end
&& *src
!= 0)
4149 /* null terminate dest string */
4152 /* update *pdest and *pndest */
4153 *pndest
= end
- dest
;
4158 static void arg_cat_option(char *dest
,
4160 const char *shortopts
,
4161 const char *longopts
,
4162 const char *datatype
,
4167 /* note: option array[] is initialiazed dynamically here to satisfy */
4168 /* a deficiency in the watcom compiler wrt static array initializers. */
4170 option
[1] = shortopts
[0];
4173 arg_cat(&dest
, option
, &ndest
);
4175 arg_cat(&dest
, " ", &ndest
);
4177 arg_cat(&dest
, "[", &ndest
);
4178 arg_cat(&dest
, datatype
, &ndest
);
4179 arg_cat(&dest
, "]", &ndest
);
4181 arg_cat(&dest
, datatype
, &ndest
);
4183 } else if (longopts
) {
4186 /* add "--" tag prefix */
4187 arg_cat(&dest
, "--", &ndest
);
4189 /* add comma separated option tag */
4190 ncspn
= strcspn(longopts
, ",");
4191 #ifdef __STDC_WANT_SECURE_LIB__
4192 strncat_s(dest
, ndest
, longopts
, (ncspn
< ndest
) ? ncspn
: ndest
);
4194 strncat(dest
, longopts
, (ncspn
< ndest
) ? ncspn
: ndest
);
4198 arg_cat(&dest
, "=", &ndest
);
4200 arg_cat(&dest
, "[", &ndest
);
4201 arg_cat(&dest
, datatype
, &ndest
);
4202 arg_cat(&dest
, "]", &ndest
);
4204 arg_cat(&dest
, datatype
, &ndest
);
4206 } else if (datatype
) {
4208 arg_cat(&dest
, "[", &ndest
);
4209 arg_cat(&dest
, datatype
, &ndest
);
4210 arg_cat(&dest
, "]", &ndest
);
4212 arg_cat(&dest
, datatype
, &ndest
);
4216 static void arg_cat_optionv(char *dest
,
4218 const char *shortopts
,
4219 const char *longopts
,
4220 const char *datatype
,
4222 const char *separator
) {
4223 separator
= separator
? separator
: "";
4226 const char *c
= shortopts
;
4231 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4232 /* a deficiency in the watcom compiler wrt static array initializers. */
4237 arg_cat(&dest
, shortopt
, &ndest
);
4239 arg_cat(&dest
, separator
, &ndest
);
4243 /* put separator between long opts and short opts */
4244 if (shortopts
&& longopts
)
4245 arg_cat(&dest
, separator
, &ndest
);
4248 const char *c
= longopts
;
4252 /* add "--" tag prefix */
4253 arg_cat(&dest
, "--", &ndest
);
4255 /* add comma separated option tag */
4256 ncspn
= strcspn(c
, ",");
4257 #ifdef __STDC_WANT_SECURE_LIB__
4258 strncat_s(dest
, ndest
, c
, (ncspn
< ndest
) ? ncspn
: ndest
);
4260 strncat(dest
, c
, (ncspn
< ndest
) ? ncspn
: ndest
);
4264 /* add given separator in place of comma */
4266 arg_cat(&dest
, separator
, &ndest
);
4274 arg_cat(&dest
, "=", &ndest
);
4276 arg_cat(&dest
, " ", &ndest
);
4279 arg_cat(&dest
, "[", &ndest
);
4280 arg_cat(&dest
, datatype
, &ndest
);
4281 arg_cat(&dest
, "]", &ndest
);
4283 arg_cat(&dest
, datatype
, &ndest
);
4288 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4289 void arg_print_option(FILE *fp
,
4290 const char *shortopts
,
4291 const char *longopts
,
4292 const char *datatype
,
4293 const char *suffix
) {
4294 char syntax
[200] = "";
4295 suffix
= suffix
? suffix
: "";
4297 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4298 arg_cat_optionv(syntax
,
4312 * Print a GNU style [OPTION] string in which all short options that
4313 * do not take argument values are presented in abbreviated form, as
4314 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4317 void arg_print_gnuswitch(FILE *fp
, struct arg_hdr
* *table
) {
4319 const char *format1
= " -%c";
4320 const char *format2
= " [-%c";
4321 const char *suffix
= "";
4323 /* print all mandatory switches that are without argument values */
4325 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4327 /* skip optional options */
4328 if (table
[tabindex
]->mincount
< 1)
4331 /* skip non-short options */
4332 if (table
[tabindex
]->shortopts
== NULL
)
4335 /* skip options that take argument values */
4336 if (table
[tabindex
]->flag
& ARG_HASVALUE
)
4339 /* print the short option (only the first short option char, ignore multiple choices)*/
4340 fprintf(fp
, format1
, table
[tabindex
]->shortopts
[0]);
4345 /* print all optional switches that are without argument values */
4347 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4349 /* skip mandatory args */
4350 if (table
[tabindex
]->mincount
> 0)
4353 /* skip args without short options */
4354 if (table
[tabindex
]->shortopts
== NULL
)
4357 /* skip args with values */
4358 if (table
[tabindex
]->flag
& ARG_HASVALUE
)
4361 /* print first short option */
4362 fprintf(fp
, format2
, table
[tabindex
]->shortopts
[0]);
4367 fprintf(fp
, "%s", suffix
);
4371 void arg_print_syntax(FILE *fp
, void * *argtable
, const char *suffix
) {
4372 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4375 /* print GNU style [OPTION] string */
4376 arg_print_gnuswitch(fp
, table
);
4378 /* print remaining options in abbreviated style */
4380 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4382 char syntax
[200] = "";
4383 const char *shortopts
, *longopts
, *datatype
;
4385 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4386 if (table
[tabindex
]->shortopts
&&
4387 !(table
[tabindex
]->flag
& ARG_HASVALUE
))
4390 shortopts
= table
[tabindex
]->shortopts
;
4391 longopts
= table
[tabindex
]->longopts
;
4392 datatype
= table
[tabindex
]->datatype
;
4393 arg_cat_option(syntax
,
4398 table
[tabindex
]->flag
& ARG_HASOPTVALUE
);
4400 if (strlen(syntax
) > 0) {
4401 /* print mandatory instances of this option */
4402 for (i
= 0; i
< table
[tabindex
]->mincount
; i
++)
4403 fprintf(fp
, " %s", syntax
);
4405 /* print optional instances enclosed in "[..]" */
4406 switch (table
[tabindex
]->maxcount
- table
[tabindex
]->mincount
) {
4410 fprintf(fp
, " [%s]", syntax
);
4413 fprintf(fp
, " [%s] [%s]", syntax
, syntax
);
4416 fprintf(fp
, " [%s]...", syntax
);
4423 fprintf(fp
, "%s", suffix
);
4427 void arg_print_syntaxv(FILE *fp
, void * *argtable
, const char *suffix
) {
4428 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4431 /* print remaining options in abbreviated style */
4433 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4435 char syntax
[200] = "";
4436 const char *shortopts
, *longopts
, *datatype
;
4438 shortopts
= table
[tabindex
]->shortopts
;
4439 longopts
= table
[tabindex
]->longopts
;
4440 datatype
= table
[tabindex
]->datatype
;
4441 arg_cat_optionv(syntax
,
4446 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4449 /* print mandatory options */
4450 for (i
= 0; i
< table
[tabindex
]->mincount
; i
++)
4451 fprintf(fp
, " %s", syntax
);
4453 /* print optional args enclosed in "[..]" */
4454 switch (table
[tabindex
]->maxcount
- table
[tabindex
]->mincount
) {
4458 fprintf(fp
, " [%s]", syntax
);
4461 fprintf(fp
, " [%s] [%s]", syntax
, syntax
);
4464 fprintf(fp
, " [%s]...", syntax
);
4470 fprintf(fp
, "%s", suffix
);
4474 void arg_print_glossary(FILE *fp
, void * *argtable
, const char *format
) {
4475 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4478 format
= format
? format
: " %-20s %s\n";
4479 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++) {
4480 if (table
[tabindex
]->glossary
) {
4481 char syntax
[200] = "";
4482 const char *shortopts
= table
[tabindex
]->shortopts
;
4483 const char *longopts
= table
[tabindex
]->longopts
;
4484 const char *datatype
= table
[tabindex
]->datatype
;
4485 const char *glossary
= table
[tabindex
]->glossary
;
4486 arg_cat_optionv(syntax
,
4491 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4493 fprintf(fp
, format
, syntax
, glossary
);
4500 * Print a piece of text formatted, which means in a column with a
4501 * left and a right margin. The lines are wrapped at whitspaces next
4502 * to right margin. The function does not indent the first line, but
4503 * only the following ones.
4506 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4507 * will result in the following output:
4515 * Too long lines will be wrapped in the middle of a word.
4517 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4518 * will result in the following output:
4526 * As you see, the first line is not indented. This enables output of
4527 * lines, which start in a line where output already happened.
4529 * Author: Uli Fouquet
4532 void arg_print_formatted(FILE *fp
,
4533 const unsigned lmargin
,
4534 const unsigned rmargin
,
4536 const unsigned textlen
= (unsigned)strlen(text
);
4537 unsigned line_start
= 0;
4538 unsigned line_end
= textlen
+ 1;
4539 const unsigned colwidth
= (rmargin
- lmargin
) + 1;
4541 /* Someone doesn't like us... */
4542 if (line_end
== line_start
) {
4543 fprintf(fp
, "%s\n", text
);
4546 while (line_end
- 1 > line_start
) {
4547 /* Eat leading whitespaces. This is essential because while
4548 wrapping lines, there will often be a whitespace at beginning
4550 while (ISSPACE(*(text
+ line_start
)))
4553 if ((line_end
- line_start
) > colwidth
)
4554 { line_end
= line_start
+ colwidth
; }
4556 /* Find last whitespace, that fits into line */
4557 while ((line_end
> line_start
)
4558 && (line_end
- line_start
> colwidth
)
4559 && !ISSPACE(*(text
+ line_end
)))
4562 /* Do not print trailing whitespace. If this text
4563 has got only one line, line_end now points to the
4564 last char due to initialization. */
4567 /* Output line of text */
4568 while (line_start
< line_end
) {
4569 fputc(*(text
+ line_start
), fp
);
4574 /* Initialize another line */
4575 if (line_end
+ 1 < textlen
) {
4578 for (i
= 0; i
< lmargin
; i
++)
4584 /* If we have to print another line, get also the last char. */
4587 } /* lines of text */
4591 * Prints the glossary in strict GNU format.
4592 * Differences to arg_print_glossary() are:
4593 * - wraps lines after 80 chars
4594 * - indents lines without shortops
4595 * - does not accept formatstrings
4597 * Contributed by Uli Fouquet
4599 void arg_print_glossary_gnu(FILE *fp
, void * *argtable
) {
4600 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4603 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++) {
4604 if (table
[tabindex
]->glossary
) {
4605 char syntax
[200] = "";
4606 const char *shortopts
= table
[tabindex
]->shortopts
;
4607 const char *longopts
= table
[tabindex
]->longopts
;
4608 const char *datatype
= table
[tabindex
]->datatype
;
4609 const char *glossary
= table
[tabindex
]->glossary
;
4611 if (!shortopts
&& longopts
) {
4612 /* Indent trailing line by 4 spaces... */
4613 memset(syntax
, ' ', 4);
4614 *(syntax
+ 4) = '\0';
4617 arg_cat_optionv(syntax
,
4622 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4625 /* If syntax fits not into column, print glossary in new line... */
4626 if (strlen(syntax
) > 25) {
4627 fprintf(fp
, " %-25s %s\n", syntax
, "");
4631 fprintf(fp
, " %-25s ", syntax
);
4632 arg_print_formatted(fp
, 28, 79, glossary
);
4634 } /* for each table entry */
4641 * Checks the argtable[] array for NULL entries and returns 1
4642 * if any are found, zero otherwise.
4644 int arg_nullcheck(void * *argtable
) {
4645 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4647 /*printf("arg_nullcheck(%p)\n",argtable);*/
4654 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4655 if (!table
[tabindex
])
4657 } while (!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4663 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4664 * The flaw results in memory leak in the (very rare) case that an intermediate
4665 * entry in the argtable array failed its memory allocation while others following
4666 * that entry were still allocated ok. Those subsequent allocations will not be
4667 * deallocated by arg_free().
4668 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4669 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4670 * with the newer arg_freetable() function.
4671 * We still keep arg_free() for backwards compatibility.
4673 void arg_free(void * *argtable
) {
4674 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4677 /*printf("arg_free(%p)\n",argtable);*/
4680 if we encounter a NULL entry then somewhat incorrectly we presume
4681 we have come to the end of the array. It isnt strictly true because
4682 an intermediate entry could be NULL with other non-NULL entries to follow.
4683 The subsequent argtable entries would then not be freed as they should.
4685 if (table
[tabindex
] == NULL
)
4688 flag
= table
[tabindex
]->flag
;
4689 free(table
[tabindex
]);
4690 table
[tabindex
++] = NULL
;
4692 } while (!(flag
& ARG_TERMINATOR
));
4695 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4696 void arg_freetable(void * *argtable
, size_t n
) {
4697 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4698 size_t tabindex
= 0;
4699 /*printf("arg_freetable(%p)\n",argtable);*/
4700 for (tabindex
= 0; tabindex
< n
; tabindex
++) {
4701 if (table
[tabindex
] == NULL
)
4704 free(table
[tabindex
]);
4705 table
[tabindex
] = NULL
;