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
88 #ifdef __STDC_WANT_SECURE_LIB__
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
, ...)
165 vfprintf(stderr
, fmt
, args
);
169 /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
173 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
175 * Copyright (c) 2000 The NetBSD Foundation, Inc.
176 * All rights reserved.
178 * This code is derived from software contributed to The NetBSD Foundation
179 * by Dieter Baron and Thomas Klausner.
181 * Redistribution and use in source and binary forms, with or without
182 * modification, are permitted provided that the following conditions
184 * 1. Redistributions of source code must retain the above copyright
185 * notice, this list of conditions and the following disclaimer.
186 * 2. Redistributions in binary form must reproduce the above copyright
187 * notice, this list of conditions and the following disclaimer in the
188 * documentation and/or other materials provided with the distribution.
190 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
191 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
194 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
195 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
196 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
197 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
198 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
199 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
200 * POSSIBILITY OF SUCH DAMAGE.
206 #include <sys/cdefs.h>
209 * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension.
210 * getopt() is declared here too for GNU programs.
212 #define no_argument 0
213 #define required_argument 1
214 #define optional_argument 2
217 /* name of long option */
220 * one of no_argument, required_argument, and optional_argument:
221 * whether option takes an argument
224 /* if not NULL, set *flag to val when option found */
226 /* if flag not NULL, value to set *flag to; else return value */
231 int getopt_long(int, char * const *, const char *,
232 const struct option
*, int *);
233 int getopt_long_only(int, char * const *, const char *,
234 const struct option
*, int *);
235 #ifndef _GETOPT_DECLARED
236 #define _GETOPT_DECLARED
237 int getopt(int, char * const [], const char *);
239 extern char *optarg
; /* getopt(3) external variables */
240 extern int optind
, opterr
, optopt
;
242 #ifndef _OPTRESET_DECLARED
243 #define _OPTRESET_DECLARED
244 extern int optreset
; /* getopt(3) external variable */
248 #endif /* !_GETOPT_H_ */
249 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
250 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
251 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
254 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
256 * Permission to use, copy, modify, and distribute this software for any
257 * purpose with or without fee is hereby granted, provided that the above
258 * copyright notice and this permission notice appear in all copies.
260 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
261 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
262 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
263 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
264 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
265 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
266 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
268 * Sponsored in part by the Defense Advanced Research Projects
269 * Agency (DARPA) and Air Force Research Laboratory, Air Force
270 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
273 // $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $"
276 * Copyright (c) 2000 The NetBSD Foundation, Inc.
277 * All rights reserved.
279 * This code is derived from software contributed to The NetBSD Foundation
280 * by Dieter Baron and Thomas Klausner.
282 * Redistribution and use in source and binary forms, with or without
283 * modification, are permitted provided that the following conditions
285 * 1. Redistributions of source code must retain the above copyright
286 * notice, this list of conditions and the following disclaimer.
287 * 2. Redistributions in binary form must reproduce the above copyright
288 * notice, this list of conditions and the following disclaimer in the
289 * documentation and/or other materials provided with the distribution.
291 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
292 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
293 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
294 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
295 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
296 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
297 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
298 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
299 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
301 * POSSIBILITY OF SUCH DAMAGE.
312 #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
314 #ifdef REPLACE_GETOPT
315 int opterr
= 1; /* if error message should be printed */
316 int optind
= 1; /* index into parent argv vector */
317 int optopt
= '?'; /* character checked for validity */
318 int optreset
; /* reset getopt */
319 char *optarg
; /* argument associated with option */
322 #define PRINT_ERROR ((opterr) && (*options != ':'))
324 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
325 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
326 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
329 #define BADCH (int)'?'
330 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
331 #define INORDER (int)1
335 static int getopt_internal(int, char * const *, const char *,
336 const struct option
*, int *, int);
337 static int parse_long_options(char * const *, const char *,
338 const struct option
*, int *, int);
339 static int gcd(int, int);
340 static void permute_args(int, int, int, char * const *);
342 static char *place
= EMSG
; /* option letter processing */
344 /* XXX: set optreset to 1 rather than these two */
345 static int nonopt_start
= -1; /* first non option argument (for permute) */
346 static int nonopt_end
= -1; /* first option after non options (for permute) */
349 static const char recargchar
[] = "option requires an argument -- %c";
350 static const char recargstring
[] = "option requires an argument -- %s";
351 static const char ambig
[] = "ambiguous option -- %.*s";
352 static const char noarg
[] = "option doesn't take an argument -- %.*s";
353 static const char illoptchar
[] = "unknown option -- %c";
354 static const char illoptstring
[] = "unknown option -- %s";
360 /* Windows needs warnx(). We change the definition though:
361 * 1. (another) global is defined, opterrmsg, which holds the error message
362 * 2. errors are always printed out on stderr w/o the program name
363 * Note that opterrmsg always gets set no matter what opterr is set to. The
364 * error message will not be printed if opterr is 0 as usual.
370 #define MAX_OPTER_MSG_SIZE 128
372 extern char opterrmsg
[MAX_OPTER_MSG_SIZE
];
373 char opterrmsg
[MAX_OPTER_MSG_SIZE
]; /* buffer for the last error message */
375 static void warnx(const char *fmt
, ...)
380 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
381 implementation specifics and manually suppress the warning.
383 memset(opterrmsg
, 0, sizeof opterrmsg
);
385 #ifdef __STDC_WANT_SECURE_LIB__
386 _vsnprintf_s(opterrmsg
, MAX_OPTER_MSG_SIZE
, sizeof(opterrmsg
) - 1, fmt
, ap
);
388 _vsnprintf(opterrmsg
, sizeof(opterrmsg
) - 1, fmt
, ap
);
392 #pragma warning(suppress: 6053)
393 fprintf(stderr
, "%s\n", opterrmsg
);
402 * Compute the greatest common divisor of a and b.
420 * Exchange the block from nonopt_start to nonopt_end with the block
421 * from nonopt_end to opt_end (keeping the same order of arguments
425 permute_args(int panonopt_start
, int panonopt_end
, int opt_end
,
428 int cstart
, cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
, pos
;
432 * compute lengths of blocks and number and size of cycles
434 nnonopts
= panonopt_end
- panonopt_start
;
435 nopts
= opt_end
- panonopt_end
;
436 ncycle
= gcd(nnonopts
, nopts
);
437 cyclelen
= (opt_end
- panonopt_start
) / ncycle
;
439 for (i
= 0; i
< ncycle
; i
++) {
440 cstart
= panonopt_end
+i
;
442 for (j
= 0; j
< cyclelen
; j
++) {
443 if (pos
>= panonopt_end
)
448 /* LINTED const cast */
449 ((char **) nargv
)[pos
] = nargv
[cstart
];
450 /* LINTED const cast */
451 ((char **)nargv
)[cstart
] = swap
;
457 * parse_long_options --
458 * Parse long options in argc/argv argument vector.
459 * Returns -1 if short_too is set and the option does not match long_options.
462 parse_long_options(char * const *nargv
, const char *options
,
463 const struct option
*long_options
, int *idx
, int short_too
)
465 char *current_argv
, *has_equal
;
466 size_t current_argv_len
;
469 current_argv
= place
;
474 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
475 /* argument found (--option=arg) */
476 current_argv_len
= has_equal
- current_argv
;
479 current_argv_len
= strlen(current_argv
);
481 for (i
= 0; long_options
[i
].name
; i
++) {
482 /* find matching long option */
483 if (strncmp(current_argv
, long_options
[i
].name
,
487 if (strlen(long_options
[i
].name
) == current_argv_len
) {
493 * If this is a known short option, don't allow
494 * a partial match of a single character.
496 if (short_too
&& current_argv_len
== 1)
499 if (match
== -1) /* partial match */
502 /* ambiguous abbreviation */
504 warnx(ambig
, (int)current_argv_len
,
510 if (match
!= -1) { /* option found */
511 if (long_options
[match
].has_arg
== no_argument
514 warnx(noarg
, (int)current_argv_len
,
517 * XXX: GNU sets optopt to val regardless of flag
519 if (long_options
[match
].flag
== NULL
)
520 optopt
= long_options
[match
].val
;
525 if (long_options
[match
].has_arg
== required_argument
||
526 long_options
[match
].has_arg
== optional_argument
) {
529 else if (long_options
[match
].has_arg
==
532 * optional argument doesn't use next nargv
534 optarg
= nargv
[optind
++];
537 if ((long_options
[match
].has_arg
== required_argument
)
538 && (optarg
== NULL
)) {
540 * Missing argument; leading ':' indicates no error
541 * should be generated.
547 * XXX: GNU sets optopt to val regardless of flag
549 if (long_options
[match
].flag
== NULL
)
550 optopt
= long_options
[match
].val
;
556 } else { /* unknown option */
562 warnx(illoptstring
, current_argv
);
568 if (long_options
[match
].flag
) {
569 *long_options
[match
].flag
= long_options
[match
].val
;
572 return (long_options
[match
].val
);
577 * Parse argc/argv argument vector. Called by user level routines.
580 getopt_internal(int nargc
, char * const *nargv
, const char *options
,
581 const struct option
*long_options
, int *idx
, int flags
)
583 char *oli
; /* option letter list index */
584 int optchar
, short_too
;
585 static int posixly_correct
= -1;
586 #ifdef __STDC_WANT_SECURE_LIB__
588 size_t buffer_size
= 0;
596 * Disable GNU extensions if POSIXLY_CORRECT is set or options
597 * string begins with a '+'.
600 #ifdef __STDC_WANT_SECURE_LIB__
601 if (posixly_correct
== -1) {
602 err
= _dupenv_s(&buffer
, &buffer_size
, "POSIXLY_CORRECT") == 0;
603 posixly_correct
= buffer
!= NULL
;
604 if(buffer
!= NULL
&& err
== 0) {
609 if (posixly_correct
== -1)
610 posixly_correct
= (getenv("POSIXLY_CORRECT") != NULL
);
612 if (posixly_correct
|| *options
== '+')
613 flags
&= ~FLAG_PERMUTE
;
614 else if (*options
== '-')
615 flags
|= FLAG_ALLARGS
;
616 if (*options
== '+' || *options
== '-')
620 * XXX Some GNU programs (like cvs) set optind to 0 instead of
621 * XXX using optreset. Work around this braindamage.
624 optind
= optreset
= 1;
628 nonopt_start
= nonopt_end
= -1;
630 if (optreset
|| !*place
) { /* update scanning pointer */
632 if (optind
>= nargc
) { /* end of argument vector */
634 if (nonopt_end
!= -1) {
635 /* do permutation, if we have to */
636 permute_args(nonopt_start
, nonopt_end
,
638 optind
-= nonopt_end
- nonopt_start
;
640 else if (nonopt_start
!= -1) {
642 * If we skipped non-options, set optind
643 * to the first of them.
645 optind
= nonopt_start
;
647 nonopt_start
= nonopt_end
= -1;
650 if (*(place
= nargv
[optind
]) != '-' ||
651 (place
[1] == '\0' && strchr(options
, '-') == NULL
)) {
652 place
= EMSG
; /* found non-option */
653 if (flags
& FLAG_ALLARGS
) {
656 * return non-option as argument to option 1
658 optarg
= nargv
[optind
++];
661 if (!(flags
& FLAG_PERMUTE
)) {
663 * If no permutation wanted, stop parsing
664 * at first non-option.
669 if (nonopt_start
== -1)
670 nonopt_start
= optind
;
671 else if (nonopt_end
!= -1) {
672 permute_args(nonopt_start
, nonopt_end
,
674 nonopt_start
= optind
-
675 (nonopt_end
- nonopt_start
);
679 /* process next argument */
682 if (nonopt_start
!= -1 && nonopt_end
== -1)
686 * If we have "-" do nothing, if "--" we are done.
688 if (place
[1] != '\0' && *++place
== '-' && place
[1] == '\0') {
692 * We found an option (--), so if we skipped
693 * non-options, we have to permute.
695 if (nonopt_end
!= -1) {
696 permute_args(nonopt_start
, nonopt_end
,
698 optind
-= nonopt_end
- nonopt_start
;
700 nonopt_start
= nonopt_end
= -1;
706 * Check long options if:
707 * 1) we were passed some
708 * 2) the arg is not just "-"
709 * 3) either the arg starts with -- we are getopt_long_only()
711 if (long_options
!= NULL
&& place
!= nargv
[optind
] &&
712 (*place
== '-' || (flags
& FLAG_LONGONLY
))) {
715 place
++; /* --foo long option */
716 else if (*place
!= ':' && strchr(options
, *place
) != NULL
)
717 short_too
= 1; /* could be short option too */
719 optchar
= parse_long_options(nargv
, options
, long_options
,
727 if ((optchar
= (int)*place
++) == (int)':' ||
728 (optchar
== (int)'-' && *place
!= '\0') ||
729 (oli
= strchr(options
, optchar
)) == NULL
) {
731 * If the user specified "-" and '-' isn't listed in
732 * options, return -1 (non-option) as per POSIX.
733 * Otherwise, it is an unknown option character (or ':').
735 if (optchar
== (int)'-' && *place
== '\0')
740 warnx(illoptchar
, optchar
);
744 if (long_options
!= NULL
&& optchar
== 'W' && oli
[1] == ';') {
746 if (*place
) /* no space */
748 else if (++optind
>= nargc
) { /* no arg */
751 warnx(recargchar
, optchar
);
754 } else /* white space */
755 place
= nargv
[optind
];
756 optchar
= parse_long_options(nargv
, options
, long_options
,
761 if (*++oli
!= ':') { /* doesn't take argument */
764 } else { /* takes (optional) argument */
766 if (*place
) /* no white space */
768 else if (oli
[1] != ':') { /* arg not optional */
769 if (++optind
>= nargc
) { /* no arg */
772 warnx(recargchar
, optchar
);
776 optarg
= nargv
[optind
];
781 /* dump back option letter */
785 #ifdef REPLACE_GETOPT
788 * Parse argc/argv argument vector.
790 * [eventually this will replace the BSD getopt]
793 getopt(int nargc
, char * const *nargv
, const char *options
)
797 * We don't pass FLAG_PERMUTE to getopt_internal() since
798 * the BSD getopt(3) (unlike GNU) has never done this.
800 * Furthermore, since many privileged programs call getopt()
801 * before dropping privileges it makes sense to keep things
802 * as simple (and bug-free) as possible.
804 return (getopt_internal(nargc
, nargv
, options
, NULL
, NULL
, 0));
806 #endif /* REPLACE_GETOPT */
810 * Parse argc/argv argument vector.
813 getopt_long(int nargc
, char * const *nargv
, const char *options
,
814 const struct option
*long_options
, int *idx
)
817 return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
,
822 * getopt_long_only --
823 * Parse argc/argv argument vector.
826 getopt_long_only(int nargc
, char * const *nargv
, const char *options
,
827 const struct option
*long_options
, int *idx
)
830 return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
,
831 FLAG_PERMUTE
|FLAG_LONGONLY
));
833 /*******************************************************************************
834 * This file is part of the argtable3 library.
836 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
837 * <sheitmann@users.sourceforge.net>
838 * All rights reserved.
840 * Redistribution and use in source and binary forms, with or without
841 * modification, are permitted provided that the following conditions are met:
842 * * Redistributions of source code must retain the above copyright
843 * notice, this list of conditions and the following disclaimer.
844 * * Redistributions in binary form must reproduce the above copyright
845 * notice, this list of conditions and the following disclaimer in the
846 * documentation and/or other materials provided with the distribution.
847 * * Neither the name of STEWART HEITMANN nor the names of its contributors
848 * may be used to endorse or promote products derived from this software
849 * without specific prior written permission.
851 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
852 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
853 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
854 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
855 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
856 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
857 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
858 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
859 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
860 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
861 ******************************************************************************/
866 #include "argtable3.h"
869 char * arg_strptime(const char *buf
, const char *fmt
, struct tm
*tm
);
872 static void arg_date_resetfn(struct arg_date
*parent
)
874 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
879 static int arg_date_scanfn(struct arg_date
*parent
, const char *argval
)
883 if (parent
->count
== parent
->hdr
.maxcount
)
885 errorcode
= EMAXCOUNT
;
889 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
895 struct tm tm
= parent
->tmval
[parent
->count
];
897 /* parse the given argument value, store result in parent->tmval[] */
898 pend
= arg_strptime(argval
, parent
->format
, &tm
);
899 if (pend
&& pend
[0] == '\0')
900 parent
->tmval
[parent
->count
++] = tm
;
902 errorcode
= EBADDATE
;
905 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
910 static int arg_date_checkfn(struct arg_date
*parent
)
912 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
914 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
919 static void arg_date_errorfn(
920 struct arg_date
*parent
,
924 const char *progname
)
926 const char *shortopts
= parent
->hdr
.shortopts
;
927 const char *longopts
= parent
->hdr
.longopts
;
928 const char *datatype
= parent
->hdr
.datatype
;
930 /* make argval NULL safe */
931 argval
= argval
? argval
: "";
933 fprintf(fp
, "%s: ", progname
);
937 fputs("missing option ", fp
);
938 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
942 fputs("excess option ", fp
);
943 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
951 fprintf(fp
, "illegal timestamp format \"%s\"\n", argval
);
952 memset(&tm
, 0, sizeof(tm
));
953 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm
);
954 strftime(buff
, sizeof(buff
), parent
->format
, &tm
);
955 printf("correct format is \"%s\"\n", buff
);
962 struct arg_date
* arg_date0(
963 const char * shortopts
,
964 const char * longopts
,
966 const char *datatype
,
967 const char *glossary
)
969 return arg_daten(shortopts
, longopts
, format
, datatype
, 0, 1, glossary
);
973 struct arg_date
* arg_date1(
974 const char * shortopts
,
975 const char * longopts
,
977 const char *datatype
,
978 const char *glossary
)
980 return arg_daten(shortopts
, longopts
, format
, datatype
, 1, 1, glossary
);
984 struct arg_date
* arg_daten(
985 const char * shortopts
,
986 const char * longopts
,
988 const char *datatype
,
991 const char *glossary
)
994 struct arg_date
*result
;
996 /* foolproof things by ensuring maxcount is not less than mincount */
997 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
999 /* default time format is the national date format for the locale */
1003 nbytes
= sizeof(struct arg_date
) /* storage for struct arg_date */
1004 + maxcount
* sizeof(struct tm
); /* storage for tmval[maxcount] array */
1006 /* allocate storage for the arg_date struct + tmval[] array. */
1007 /* we use calloc because we want the tmval[] array zero filled. */
1008 result
= (struct arg_date
*)calloc(1, nbytes
);
1011 /* init the arg_hdr struct */
1012 result
->hdr
.flag
= ARG_HASVALUE
;
1013 result
->hdr
.shortopts
= shortopts
;
1014 result
->hdr
.longopts
= longopts
;
1015 result
->hdr
.datatype
= datatype
? datatype
: format
;
1016 result
->hdr
.glossary
= glossary
;
1017 result
->hdr
.mincount
= mincount
;
1018 result
->hdr
.maxcount
= maxcount
;
1019 result
->hdr
.parent
= result
;
1020 result
->hdr
.resetfn
= (arg_resetfn
*)arg_date_resetfn
;
1021 result
->hdr
.scanfn
= (arg_scanfn
*)arg_date_scanfn
;
1022 result
->hdr
.checkfn
= (arg_checkfn
*)arg_date_checkfn
;
1023 result
->hdr
.errorfn
= (arg_errorfn
*)arg_date_errorfn
;
1025 /* store the tmval[maxcount] array immediately after the arg_date struct */
1026 result
->tmval
= (struct tm
*)(result
+ 1);
1028 /* init the remaining arg_date member variables */
1030 result
->format
= format
;
1033 ARG_TRACE(("arg_daten() returns %p\n", result
));
1039 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1040 * All rights reserved.
1042 * This code was contributed to The NetBSD Foundation by Klaus Klein.
1043 * Heavily optimised by David Laight
1045 * Redistribution and use in source and binary forms, with or without
1046 * modification, are permitted provided that the following conditions
1048 * 1. Redistributions of source code must retain the above copyright
1049 * notice, this list of conditions and the following disclaimer.
1050 * 2. Redistributions in binary form must reproduce the above copyright
1051 * notice, this list of conditions and the following disclaimer in the
1052 * documentation and/or other materials provided with the distribution.
1054 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1055 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1056 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1057 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1058 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1060 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1061 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1062 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1063 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1064 * POSSIBILITY OF SUCH DAMAGE.
1072 * We do not implement alternate representations. However, we always
1073 * check whether a given modifier is allowed for a certain conversion.
1077 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
1078 #define TM_YEAR_BASE (1900)
1080 static int conv_num(const char * *, int *, int, int);
1082 static const char *day
[7] = {
1083 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
1084 "Friday", "Saturday"
1087 static const char *abday
[7] = {
1088 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1091 static const char *mon
[12] = {
1092 "January", "February", "March", "April", "May", "June", "July",
1093 "August", "September", "October", "November", "December"
1096 static const char *abmon
[12] = {
1097 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1098 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1101 static const char *am_pm
[2] = {
1106 static int arg_strcasecmp(const char *s1
, const char *s2
)
1108 const unsigned char *us1
= (const unsigned char *)s1
;
1109 const unsigned char *us2
= (const unsigned char *)s2
;
1110 while (tolower(*us1
) == tolower(*us2
++))
1114 return tolower(*us1
) - tolower(*--us2
);
1118 static int arg_strncasecmp(const char *s1
, const char *s2
, size_t n
)
1122 const unsigned char *us1
= (const unsigned char *)s1
;
1123 const unsigned char *us2
= (const unsigned char *)s2
;
1126 if (tolower(*us1
) != tolower(*us2
++))
1127 return tolower(*us1
) - tolower(*--us2
);
1138 char * arg_strptime(const char *buf
, const char *fmt
, struct tm
*tm
)
1143 int alt_format
, i
, split_year
= 0;
1147 while ((c
= *fmt
) != '\0') {
1148 /* Clear `alternate' modifier prior to new conversion. */
1151 /* Eat up white-space. */
1153 while (ISSPACE(*bp
))
1160 if ((c
= *fmt
++) != '%')
1167 case '%': /* "%%" is converted to "%". */
1174 * "Alternative" modifiers. Just set the appropriate flag
1175 * and start over again.
1177 case 'E': /* "%E?" alternative conversion modifier. */
1179 alt_format
|= ALT_E
;
1182 case 'O': /* "%O?" alternative conversion modifier. */
1184 alt_format
|= ALT_O
;
1188 * "Complex" conversion rules, implemented through recursion.
1190 case 'c': /* Date and time, using the locale's format. */
1192 bp
= arg_strptime(bp
, "%x %X", tm
);
1197 case 'D': /* The date as "%m/%d/%y". */
1199 bp
= arg_strptime(bp
, "%m/%d/%y", tm
);
1204 case 'R': /* The time as "%H:%M". */
1206 bp
= arg_strptime(bp
, "%H:%M", tm
);
1211 case 'r': /* The time in 12-hour clock representation. */
1213 bp
= arg_strptime(bp
, "%I:%M:%S %p", tm
);
1218 case 'T': /* The time as "%H:%M:%S". */
1220 bp
= arg_strptime(bp
, "%H:%M:%S", tm
);
1225 case 'X': /* The time, using the locale's format. */
1227 bp
= arg_strptime(bp
, "%H:%M:%S", tm
);
1232 case 'x': /* The date, using the locale's format. */
1234 bp
= arg_strptime(bp
, "%m/%d/%y", tm
);
1240 * "Elementary" conversion rules.
1242 case 'A': /* The day of week, using the locale's form. */
1245 for (i
= 0; i
< 7; i
++) {
1247 len
= strlen(day
[i
]);
1248 if (arg_strncasecmp(day
[i
], bp
, len
) == 0)
1251 /* Abbreviated name. */
1252 len
= strlen(abday
[i
]);
1253 if (arg_strncasecmp(abday
[i
], bp
, len
) == 0)
1257 /* Nothing matched. */
1265 case 'B': /* The month, using the locale's form. */
1269 for (i
= 0; i
< 12; i
++) {
1271 len
= strlen(mon
[i
]);
1272 if (arg_strncasecmp(mon
[i
], bp
, len
) == 0)
1275 /* Abbreviated name. */
1276 len
= strlen(abmon
[i
]);
1277 if (arg_strncasecmp(abmon
[i
], bp
, len
) == 0)
1281 /* Nothing matched. */
1289 case 'C': /* The century number. */
1291 if (!(conv_num(&bp
, &i
, 0, 99)))
1295 tm
->tm_year
= (tm
->tm_year
% 100) + (i
* 100);
1297 tm
->tm_year
= i
* 100;
1302 case 'd': /* The day of month. */
1305 if (!(conv_num(&bp
, &tm
->tm_mday
, 1, 31)))
1309 case 'k': /* The hour (24-hour clock representation). */
1314 if (!(conv_num(&bp
, &tm
->tm_hour
, 0, 23)))
1318 case 'l': /* The hour (12-hour clock representation). */
1323 if (!(conv_num(&bp
, &tm
->tm_hour
, 1, 12)))
1325 if (tm
->tm_hour
== 12)
1329 case 'j': /* The day of year. */
1331 if (!(conv_num(&bp
, &i
, 1, 366)))
1333 tm
->tm_yday
= i
- 1;
1336 case 'M': /* The minute. */
1338 if (!(conv_num(&bp
, &tm
->tm_min
, 0, 59)))
1342 case 'm': /* The month. */
1344 if (!(conv_num(&bp
, &i
, 1, 12)))
1349 case 'p': /* The locale's equivalent of AM/PM. */
1352 if (arg_strcasecmp(am_pm
[0], bp
) == 0) {
1353 if (tm
->tm_hour
> 11)
1356 bp
+= strlen(am_pm
[0]);
1360 else if (arg_strcasecmp(am_pm
[1], bp
) == 0) {
1361 if (tm
->tm_hour
> 11)
1365 bp
+= strlen(am_pm
[1]);
1369 /* Nothing matched. */
1372 case 'S': /* The seconds. */
1374 if (!(conv_num(&bp
, &tm
->tm_sec
, 0, 61)))
1378 case 'U': /* The week of year, beginning on sunday. */
1379 case 'W': /* The week of year, beginning on monday. */
1382 * XXX This is bogus, as we can not assume any valid
1383 * information present in the tm structure at this
1384 * point to calculate a real value, so just check the
1387 if (!(conv_num(&bp
, &i
, 0, 53)))
1391 case 'w': /* The day of week, beginning on sunday. */
1393 if (!(conv_num(&bp
, &tm
->tm_wday
, 0, 6)))
1397 case 'Y': /* The year. */
1399 if (!(conv_num(&bp
, &i
, 0, 9999)))
1402 tm
->tm_year
= i
- TM_YEAR_BASE
;
1405 case 'y': /* The year within 100 years of the epoch. */
1406 LEGAL_ALT(ALT_E
| ALT_O
);
1407 if (!(conv_num(&bp
, &i
, 0, 99)))
1411 tm
->tm_year
= ((tm
->tm_year
/ 100) * 100) + i
;
1416 tm
->tm_year
= i
+ 2000 - TM_YEAR_BASE
;
1418 tm
->tm_year
= i
+ 1900 - TM_YEAR_BASE
;
1422 * Miscellaneous conversions.
1424 case 'n': /* Any kind of white-space. */
1427 while (ISSPACE(*bp
))
1432 default: /* Unknown/unsupported conversion. */
1439 /* LINTED functional specification */
1440 return ((char *)bp
);
1444 static int conv_num(const char * *buf
, int *dest
, int llim
, int ulim
)
1448 /* The limit also determines the number of valid digits. */
1451 if (**buf
< '0' || **buf
> '9')
1456 result
+= *(*buf
)++ - '0';
1458 } while ((result
* 10 <= ulim
) && rulim
&& **buf
>= '0' && **buf
<= '9');
1460 if (result
< llim
|| result
> ulim
)
1466 /*******************************************************************************
1467 * This file is part of the argtable3 library.
1469 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1470 * <sheitmann@users.sourceforge.net>
1471 * All rights reserved.
1473 * Redistribution and use in source and binary forms, with or without
1474 * modification, are permitted provided that the following conditions are met:
1475 * * Redistributions of source code must retain the above copyright
1476 * notice, this list of conditions and the following disclaimer.
1477 * * Redistributions in binary form must reproduce the above copyright
1478 * notice, this list of conditions and the following disclaimer in the
1479 * documentation and/or other materials provided with the distribution.
1480 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1481 * may be used to endorse or promote products derived from this software
1482 * without specific prior written permission.
1484 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1485 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1486 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1487 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1488 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1489 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1490 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1491 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1492 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1493 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1494 ******************************************************************************/
1498 #include "argtable3.h"
1501 static void arg_dbl_resetfn(struct arg_dbl
*parent
)
1503 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1508 static int arg_dbl_scanfn(struct arg_dbl
*parent
, const char *argval
)
1512 if (parent
->count
== parent
->hdr
.maxcount
)
1514 /* maximum number of arguments exceeded */
1515 errorcode
= EMAXCOUNT
;
1519 /* a valid argument with no argument value was given. */
1520 /* This happens when an optional argument value was invoked. */
1521 /* leave parent argument value unaltered but still count the argument. */
1529 /* extract double from argval into val */
1530 val
= strtod(argval
, &end
);
1532 /* if success then store result in parent->dval[] array otherwise return error*/
1534 parent
->dval
[parent
->count
++] = val
;
1536 errorcode
= EBADDOUBLE
;
1539 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1544 static int arg_dbl_checkfn(struct arg_dbl
*parent
)
1546 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
1548 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1553 static void arg_dbl_errorfn(
1554 struct arg_dbl
*parent
,
1558 const char *progname
)
1560 const char *shortopts
= parent
->hdr
.shortopts
;
1561 const char *longopts
= parent
->hdr
.longopts
;
1562 const char *datatype
= parent
->hdr
.datatype
;
1564 /* make argval NULL safe */
1565 argval
= argval
? argval
: "";
1567 fprintf(fp
, "%s: ", progname
);
1571 fputs("missing option ", fp
);
1572 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1576 fputs("excess option ", fp
);
1577 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
1581 fprintf(fp
, "invalid argument \"%s\" to option ", argval
);
1582 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1588 struct arg_dbl
* arg_dbl0(
1589 const char * shortopts
,
1590 const char * longopts
,
1591 const char *datatype
,
1592 const char *glossary
)
1594 return arg_dbln(shortopts
, longopts
, datatype
, 0, 1, glossary
);
1598 struct arg_dbl
* arg_dbl1(
1599 const char * shortopts
,
1600 const char * longopts
,
1601 const char *datatype
,
1602 const char *glossary
)
1604 return arg_dbln(shortopts
, longopts
, datatype
, 1, 1, glossary
);
1608 struct arg_dbl
* arg_dbln(
1609 const char * shortopts
,
1610 const char * longopts
,
1611 const char *datatype
,
1614 const char *glossary
)
1617 struct arg_dbl
*result
;
1619 /* foolproof things by ensuring maxcount is not less than mincount */
1620 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
1622 nbytes
= sizeof(struct arg_dbl
) /* storage for struct arg_dbl */
1623 + (maxcount
+ 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1625 result
= (struct arg_dbl
*)malloc(nbytes
);
1631 /* init the arg_hdr struct */
1632 result
->hdr
.flag
= ARG_HASVALUE
;
1633 result
->hdr
.shortopts
= shortopts
;
1634 result
->hdr
.longopts
= longopts
;
1635 result
->hdr
.datatype
= datatype
? datatype
: "<double>";
1636 result
->hdr
.glossary
= glossary
;
1637 result
->hdr
.mincount
= mincount
;
1638 result
->hdr
.maxcount
= maxcount
;
1639 result
->hdr
.parent
= result
;
1640 result
->hdr
.resetfn
= (arg_resetfn
*)arg_dbl_resetfn
;
1641 result
->hdr
.scanfn
= (arg_scanfn
*)arg_dbl_scanfn
;
1642 result
->hdr
.checkfn
= (arg_checkfn
*)arg_dbl_checkfn
;
1643 result
->hdr
.errorfn
= (arg_errorfn
*)arg_dbl_errorfn
;
1645 /* Store the dval[maxcount] array on the first double boundary that
1646 * immediately follows the arg_dbl struct. We do the memory alignment
1647 * purely for SPARC and Motorola systems. They require floats and
1648 * doubles to be aligned on natural boundaries.
1650 addr
= (size_t)(result
+ 1);
1651 rem
= addr
% sizeof(double);
1652 result
->dval
= (double *)(addr
+ sizeof(double) - rem
);
1653 ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr
, result
->dval
, (int)sizeof(double), (int)rem
));
1658 ARG_TRACE(("arg_dbln() returns %p\n", result
));
1661 /*******************************************************************************
1662 * This file is part of the argtable3 library.
1664 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1665 * <sheitmann@users.sourceforge.net>
1666 * All rights reserved.
1668 * Redistribution and use in source and binary forms, with or without
1669 * modification, are permitted provided that the following conditions are met:
1670 * * Redistributions of source code must retain the above copyright
1671 * notice, this list of conditions and the following disclaimer.
1672 * * Redistributions in binary form must reproduce the above copyright
1673 * notice, this list of conditions and the following disclaimer in the
1674 * documentation and/or other materials provided with the distribution.
1675 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1676 * may be used to endorse or promote products derived from this software
1677 * without specific prior written permission.
1679 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1680 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1681 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1682 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1683 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1684 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1685 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1686 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1687 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1688 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1689 ******************************************************************************/
1693 #include "argtable3.h"
1696 static void arg_end_resetfn(struct arg_end
*parent
)
1698 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1702 static void arg_end_errorfn(
1707 const char *progname
)
1709 /* suppress unreferenced formal parameter warning */
1712 progname
= progname
? progname
: "";
1713 argval
= argval
? argval
: "";
1715 fprintf(fp
, "%s: ", progname
);
1719 fputs("too many errors to display", fp
);
1722 fputs("insufficent memory", fp
);
1725 fprintf(fp
, "unexpected argument \"%s\"", argval
);
1728 fprintf(fp
, "option \"%s\" requires an argument", argval
);
1731 fprintf(fp
, "invalid option \"%s\"", argval
);
1734 fprintf(fp
, "invalid option \"-%c\"", error
);
1742 struct arg_end
* arg_end(int maxcount
)
1745 struct arg_end
*result
;
1747 nbytes
= sizeof(struct arg_end
)
1748 + maxcount
* sizeof(int) /* storage for int error[maxcount] array*/
1749 + maxcount
* sizeof(void *) /* storage for void* parent[maxcount] array */
1750 + maxcount
* sizeof(char *); /* storage for char* argval[maxcount] array */
1752 result
= (struct arg_end
*)malloc(nbytes
);
1755 /* init the arg_hdr struct */
1756 result
->hdr
.flag
= ARG_TERMINATOR
;
1757 result
->hdr
.shortopts
= NULL
;
1758 result
->hdr
.longopts
= NULL
;
1759 result
->hdr
.datatype
= NULL
;
1760 result
->hdr
.glossary
= NULL
;
1761 result
->hdr
.mincount
= 1;
1762 result
->hdr
.maxcount
= maxcount
;
1763 result
->hdr
.parent
= result
;
1764 result
->hdr
.resetfn
= (arg_resetfn
*)arg_end_resetfn
;
1765 result
->hdr
.scanfn
= NULL
;
1766 result
->hdr
.checkfn
= NULL
;
1767 result
->hdr
.errorfn
= (arg_errorfn
*)arg_end_errorfn
;
1769 /* store error[maxcount] array immediately after struct arg_end */
1770 result
->error
= (int *)(result
+ 1);
1772 /* store parent[maxcount] array immediately after error[] array */
1773 result
->parent
= (void * *)(result
->error
+ maxcount
);
1775 /* store argval[maxcount] array immediately after parent[] array */
1776 result
->argval
= (const char * *)(result
->parent
+ maxcount
);
1779 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount
, result
));
1784 void arg_print_errors(FILE * fp
, struct arg_end
* end
, const char * progname
)
1787 ARG_TRACE(("arg_errors()\n"));
1788 for (i
= 0; i
< end
->count
; i
++)
1790 struct arg_hdr
*errorparent
= (struct arg_hdr
*)(end
->parent
[i
]);
1791 if (errorparent
->errorfn
)
1792 errorparent
->errorfn(end
->parent
[i
],
1799 /*******************************************************************************
1800 * This file is part of the argtable3 library.
1802 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1803 * <sheitmann@users.sourceforge.net>
1804 * All rights reserved.
1806 * Redistribution and use in source and binary forms, with or without
1807 * modification, are permitted provided that the following conditions are met:
1808 * * Redistributions of source code must retain the above copyright
1809 * notice, this list of conditions and the following disclaimer.
1810 * * Redistributions in binary form must reproduce the above copyright
1811 * notice, this list of conditions and the following disclaimer in the
1812 * documentation and/or other materials provided with the distribution.
1813 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1814 * may be used to endorse or promote products derived from this software
1815 * without specific prior written permission.
1817 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1818 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1819 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1820 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1821 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1822 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1823 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1824 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1825 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1826 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1827 ******************************************************************************/
1832 #include "argtable3.h"
1835 # define FILESEPARATOR1 '\\'
1836 # define FILESEPARATOR2 '/'
1838 # define FILESEPARATOR1 '/'
1839 # define FILESEPARATOR2 '/'
1843 static void arg_file_resetfn(struct arg_file
*parent
)
1845 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1850 /* Returns ptr to the base filename within *filename */
1851 static const char * arg_basename(const char *filename
)
1853 const char *result
= NULL
, *result1
, *result2
;
1855 /* Find the last occurrence of eother file separator character. */
1856 /* Two alternative file separator chars are supported as legal */
1857 /* file separators but not both together in the same filename. */
1858 result1
= (filename
? strrchr(filename
, FILESEPARATOR1
) : NULL
);
1859 result2
= (filename
? strrchr(filename
, FILESEPARATOR2
) : NULL
);
1862 result
= result2
+ 1; /* using FILESEPARATOR2 (the alternative file separator) */
1865 result
= result1
+ 1; /* using FILESEPARATOR1 (the preferred file separator) */
1868 result
= filename
; /* neither file separator was found so basename is the whole filename */
1870 /* special cases of "." and ".." are not considered basenames */
1871 if (result
&& ( strcmp(".", result
) == 0 || strcmp("..", result
) == 0 ))
1872 result
= filename
+ strlen(filename
);
1878 /* Returns ptr to the file extension within *basename */
1879 static const char * arg_extension(const char *basename
)
1881 /* find the last occurrence of '.' in basename */
1882 const char *result
= (basename
? strrchr(basename
, '.') : NULL
);
1884 /* if no '.' was found then return pointer to end of basename */
1885 if (basename
&& !result
)
1886 result
= basename
+ strlen(basename
);
1888 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1889 if (basename
&& result
== basename
)
1890 result
= basename
+ strlen(basename
);
1892 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1893 if (basename
&& result
&& result
[1] == '\0')
1894 result
= basename
+ strlen(basename
);
1900 static int arg_file_scanfn(struct arg_file
*parent
, const char *argval
)
1904 if (parent
->count
== parent
->hdr
.maxcount
)
1906 /* maximum number of arguments exceeded */
1907 errorcode
= EMAXCOUNT
;
1911 /* a valid argument with no argument value was given. */
1912 /* This happens when an optional argument value was invoked. */
1913 /* leave parent arguiment value unaltered but still count the argument. */
1918 parent
->filename
[parent
->count
] = argval
;
1919 parent
->basename
[parent
->count
] = arg_basename(argval
);
1920 parent
->extension
[parent
->count
] =
1921 arg_extension(parent
->basename
[parent
->count
]); /* only seek extensions within the basename (not the file path)*/
1925 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1930 static int arg_file_checkfn(struct arg_file
*parent
)
1932 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
1934 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1939 static void arg_file_errorfn(
1940 struct arg_file
*parent
,
1944 const char *progname
)
1946 const char *shortopts
= parent
->hdr
.shortopts
;
1947 const char *longopts
= parent
->hdr
.longopts
;
1948 const char *datatype
= parent
->hdr
.datatype
;
1950 /* make argval NULL safe */
1951 argval
= argval
? argval
: "";
1953 fprintf(fp
, "%s: ", progname
);
1957 fputs("missing option ", fp
);
1958 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1962 fputs("excess option ", fp
);
1963 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
1967 fprintf(fp
, "unknown error at \"%s\"\n", argval
);
1972 struct arg_file
* arg_file0(
1973 const char * shortopts
,
1974 const char * longopts
,
1975 const char *datatype
,
1976 const char *glossary
)
1978 return arg_filen(shortopts
, longopts
, datatype
, 0, 1, glossary
);
1982 struct arg_file
* arg_file1(
1983 const char * shortopts
,
1984 const char * longopts
,
1985 const char *datatype
,
1986 const char *glossary
)
1988 return arg_filen(shortopts
, longopts
, datatype
, 1, 1, glossary
);
1992 struct arg_file
* arg_filen(
1993 const char * shortopts
,
1994 const char * longopts
,
1995 const char *datatype
,
1998 const char *glossary
)
2001 struct arg_file
*result
;
2003 /* foolproof things by ensuring maxcount is not less than mincount */
2004 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2006 nbytes
= sizeof(struct arg_file
) /* storage for struct arg_file */
2007 + sizeof(char *) * maxcount
/* storage for filename[maxcount] array */
2008 + sizeof(char *) * maxcount
/* storage for basename[maxcount] array */
2009 + sizeof(char *) * maxcount
; /* storage for extension[maxcount] array */
2011 result
= (struct arg_file
*)malloc(nbytes
);
2016 /* init the arg_hdr struct */
2017 result
->hdr
.flag
= ARG_HASVALUE
;
2018 result
->hdr
.shortopts
= shortopts
;
2019 result
->hdr
.longopts
= longopts
;
2020 result
->hdr
.glossary
= glossary
;
2021 result
->hdr
.datatype
= datatype
? datatype
: "<file>";
2022 result
->hdr
.mincount
= mincount
;
2023 result
->hdr
.maxcount
= maxcount
;
2024 result
->hdr
.parent
= result
;
2025 result
->hdr
.resetfn
= (arg_resetfn
*)arg_file_resetfn
;
2026 result
->hdr
.scanfn
= (arg_scanfn
*)arg_file_scanfn
;
2027 result
->hdr
.checkfn
= (arg_checkfn
*)arg_file_checkfn
;
2028 result
->hdr
.errorfn
= (arg_errorfn
*)arg_file_errorfn
;
2030 /* store the filename,basename,extension arrays immediately after the arg_file struct */
2031 result
->filename
= (const char * *)(result
+ 1);
2032 result
->basename
= result
->filename
+ maxcount
;
2033 result
->extension
= result
->basename
+ maxcount
;
2036 /* foolproof the string pointers by initialising them with empty strings */
2037 for (i
= 0; i
< maxcount
; i
++)
2039 result
->filename
[i
] = "";
2040 result
->basename
[i
] = "";
2041 result
->extension
[i
] = "";
2045 ARG_TRACE(("arg_filen() returns %p\n", result
));
2048 /*******************************************************************************
2049 * This file is part of the argtable3 library.
2051 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2052 * <sheitmann@users.sourceforge.net>
2053 * All rights reserved.
2055 * Redistribution and use in source and binary forms, with or without
2056 * modification, are permitted provided that the following conditions are met:
2057 * * Redistributions of source code must retain the above copyright
2058 * notice, this list of conditions and the following disclaimer.
2059 * * Redistributions in binary form must reproduce the above copyright
2060 * notice, this list of conditions and the following disclaimer in the
2061 * documentation and/or other materials provided with the distribution.
2062 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2063 * may be used to endorse or promote products derived from this software
2064 * without specific prior written permission.
2066 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2067 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2068 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2069 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2070 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2071 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2072 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2073 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2074 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2075 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2076 ******************************************************************************/
2082 #include "argtable3.h"
2085 static void arg_int_resetfn(struct arg_int
*parent
)
2087 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2092 /* strtol0x() is like strtol() except that the numeric string is */
2093 /* expected to be prefixed by "0X" where X is a user supplied char. */
2094 /* The string may optionally be prefixed by white space and + or - */
2095 /* as in +0X123 or -0X123. */
2096 /* Once the prefix has been scanned, the remainder of the numeric */
2097 /* string is converted using strtol() with the given base. */
2098 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
2099 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
2100 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
2101 /* Failure of conversion is indicated by result where *endptr==str. */
2102 static long int strtol0X(const char * str
,
2103 const char * *endptr
,
2107 long int val
; /* stores result */
2108 int s
= 1; /* sign is +1 or -1 */
2109 const char *ptr
= str
; /* ptr to current position in str */
2111 /* skip leading whitespace */
2112 while (ISSPACE(*ptr
))
2114 /* printf("1) %s\n",ptr); */
2116 /* scan optional sign character */
2131 /* printf("2) %s\n",ptr); */
2134 if ((*ptr
++) != '0')
2136 /* printf("failed to detect '0'\n"); */
2140 /* printf("3) %s\n",ptr); */
2141 if (toupper(*ptr
++) != toupper(X
))
2143 /* printf("failed to detect '%c'\n",X); */
2147 /* printf("4) %s\n",ptr); */
2149 /* attempt conversion on remainder of string using strtol() */
2150 val
= strtol(ptr
, (char * *)endptr
, base
);
2153 /* conversion failed */
2163 /* Returns 1 if str matches suffix (case insensitive). */
2164 /* Str may contain trailing whitespace, but nothing else. */
2165 static int detectsuffix(const char *str
, const char *suffix
)
2167 /* scan pairwise through strings until mismatch detected */
2168 while( toupper(*str
) == toupper(*suffix
) )
2170 /* printf("'%c' '%c'\n", *str, *suffix); */
2172 /* return 1 (success) if match persists until the string terminator */
2180 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2182 /* return 0 (fail) if the matching did not consume the entire suffix */
2184 return 0; /* failed to consume entire suffix */
2186 /* skip any remaining whitespace in str */
2187 while (ISSPACE(*str
))
2190 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2191 return (*str
== '\0') ? 1 : 0;
2195 static int arg_int_scanfn(struct arg_int
*parent
, const char *argval
)
2199 if (parent
->count
== parent
->hdr
.maxcount
)
2201 /* maximum number of arguments exceeded */
2202 errorcode
= EMAXCOUNT
;
2206 /* a valid argument with no argument value was given. */
2207 /* This happens when an optional argument value was invoked. */
2208 /* leave parent arguiment value unaltered but still count the argument. */
2216 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2217 val
= strtol0X(argval
, &end
, 'X', 16);
2220 /* hex failed, attempt octal conversion (eg +0o123) */
2221 val
= strtol0X(argval
, &end
, 'O', 8);
2224 /* octal failed, attempt binary conversion (eg +0B101) */
2225 val
= strtol0X(argval
, &end
, 'B', 2);
2228 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2229 val
= strtol(argval
, (char * *)&end
, 10);
2232 /* all supported number formats failed */
2239 /* Safety check for integer overflow. WARNING: this check */
2240 /* achieves nothing on machines where size(int)==size(long). */
2241 if ( val
> INT_MAX
|| val
< INT_MIN
)
2242 #ifdef __STDC_WANT_SECURE_LIB__
2243 errorcode
= EOVERFLOW_
;
2245 errorcode
= EOVERFLOW
;
2248 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2249 /* We need to be mindful of integer overflows when using such big numbers. */
2250 if (detectsuffix(end
, "KB")) /* kilobytes */
2252 if ( val
> (INT_MAX
/ 1024) || val
< (INT_MIN
/ 1024) )
2253 #ifdef __STDC_WANT_SECURE_LIB__
2254 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2256 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2259 val
*= 1024; /* 1KB = 1024 */
2261 else if (detectsuffix(end
, "MB")) /* megabytes */
2263 if ( val
> (INT_MAX
/ 1048576) || val
< (INT_MIN
/ 1048576) )
2264 #ifdef __STDC_WANT_SECURE_LIB__
2265 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2267 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2270 val
*= 1048576; /* 1MB = 1024*1024 */
2272 else if (detectsuffix(end
, "GB")) /* gigabytes */
2274 if ( val
> (INT_MAX
/ 1073741824) || val
< (INT_MIN
/ 1073741824) )
2275 #ifdef __STDC_WANT_SECURE_LIB__
2276 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2278 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2281 val
*= 1073741824; /* 1GB = 1024*1024*1024 */
2283 else if (!detectsuffix(end
, ""))
2284 errorcode
= EBADINT
; /* invalid suffix detected */
2286 /* if success then store result in parent->ival[] array */
2288 parent
->ival
[parent
->count
++] = val
;
2291 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2296 static int arg_int_checkfn(struct arg_int
*parent
)
2298 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2299 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2304 static void arg_int_errorfn(
2305 struct arg_int
*parent
,
2309 const char *progname
)
2311 const char *shortopts
= parent
->hdr
.shortopts
;
2312 const char *longopts
= parent
->hdr
.longopts
;
2313 const char *datatype
= parent
->hdr
.datatype
;
2315 /* make argval NULL safe */
2316 argval
= argval
? argval
: "";
2318 fprintf(fp
, "%s: ", progname
);
2322 fputs("missing option ", fp
);
2323 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2327 fputs("excess option ", fp
);
2328 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2332 fprintf(fp
, "invalid argument \"%s\" to option ", argval
);
2333 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2336 #ifdef __STDC_WANT_SECURE_LIB__
2341 fputs("integer overflow at option ", fp
);
2342 arg_print_option(fp
, shortopts
, longopts
, datatype
, " ");
2343 fprintf(fp
, "(%s is too large)\n", argval
);
2349 struct arg_int
* arg_int0(
2350 const char *shortopts
,
2351 const char *longopts
,
2352 const char *datatype
,
2353 const char *glossary
)
2355 return arg_intn(shortopts
, longopts
, datatype
, 0, 1, glossary
);
2359 struct arg_int
* arg_int1(
2360 const char *shortopts
,
2361 const char *longopts
,
2362 const char *datatype
,
2363 const char *glossary
)
2365 return arg_intn(shortopts
, longopts
, datatype
, 1, 1, glossary
);
2369 struct arg_int
* arg_intn(
2370 const char *shortopts
,
2371 const char *longopts
,
2372 const char *datatype
,
2375 const char *glossary
)
2378 struct arg_int
*result
;
2380 /* foolproof things by ensuring maxcount is not less than mincount */
2381 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2383 nbytes
= sizeof(struct arg_int
) /* storage for struct arg_int */
2384 + maxcount
* sizeof(int); /* storage for ival[maxcount] array */
2386 result
= (struct arg_int
*)malloc(nbytes
);
2389 /* init the arg_hdr struct */
2390 result
->hdr
.flag
= ARG_HASVALUE
;
2391 result
->hdr
.shortopts
= shortopts
;
2392 result
->hdr
.longopts
= longopts
;
2393 result
->hdr
.datatype
= datatype
? datatype
: "<int>";
2394 result
->hdr
.glossary
= glossary
;
2395 result
->hdr
.mincount
= mincount
;
2396 result
->hdr
.maxcount
= maxcount
;
2397 result
->hdr
.parent
= result
;
2398 result
->hdr
.resetfn
= (arg_resetfn
*)arg_int_resetfn
;
2399 result
->hdr
.scanfn
= (arg_scanfn
*)arg_int_scanfn
;
2400 result
->hdr
.checkfn
= (arg_checkfn
*)arg_int_checkfn
;
2401 result
->hdr
.errorfn
= (arg_errorfn
*)arg_int_errorfn
;
2403 /* store the ival[maxcount] array immediately after the arg_int struct */
2404 result
->ival
= (int *)(result
+ 1);
2408 ARG_TRACE(("arg_intn() returns %p\n", result
));
2411 /*******************************************************************************
2412 * This file is part of the argtable3 library.
2414 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2415 * <sheitmann@users.sourceforge.net>
2416 * All rights reserved.
2418 * Redistribution and use in source and binary forms, with or without
2419 * modification, are permitted provided that the following conditions are met:
2420 * * Redistributions of source code must retain the above copyright
2421 * notice, this list of conditions and the following disclaimer.
2422 * * Redistributions in binary form must reproduce the above copyright
2423 * notice, this list of conditions and the following disclaimer in the
2424 * documentation and/or other materials provided with the distribution.
2425 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2426 * may be used to endorse or promote products derived from this software
2427 * without specific prior written permission.
2429 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2430 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2431 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2432 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2433 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2434 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2435 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2436 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2437 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2438 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2439 ******************************************************************************/
2443 #include "argtable3.h"
2446 static void arg_lit_resetfn(struct arg_lit
*parent
)
2448 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2453 static int arg_lit_scanfn(struct arg_lit
*parent
, const char *argval
)
2456 if (parent
->count
< parent
->hdr
.maxcount
)
2459 errorcode
= EMAXCOUNT
;
2461 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__
, parent
, argval
,
2467 static int arg_lit_checkfn(struct arg_lit
*parent
)
2469 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2470 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
2475 static void arg_lit_errorfn(
2476 struct arg_lit
*parent
,
2480 const char *progname
)
2482 const char *shortopts
= parent
->hdr
.shortopts
;
2483 const char *longopts
= parent
->hdr
.longopts
;
2484 const char *datatype
= parent
->hdr
.datatype
;
2489 fprintf(fp
, "%s: missing option ", progname
);
2490 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2495 fprintf(fp
, "%s: extraneous option ", progname
);
2496 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2500 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__
, parent
, fp
,
2501 errorcode
, argval
, progname
));
2505 struct arg_lit
* arg_lit0(
2506 const char * shortopts
,
2507 const char * longopts
,
2508 const char * glossary
)
2510 return arg_litn(shortopts
, longopts
, 0, 1, glossary
);
2514 struct arg_lit
* arg_lit1(
2515 const char *shortopts
,
2516 const char *longopts
,
2517 const char *glossary
)
2519 return arg_litn(shortopts
, longopts
, 1, 1, glossary
);
2523 struct arg_lit
* arg_litn(
2524 const char *shortopts
,
2525 const char *longopts
,
2528 const char *glossary
)
2530 struct arg_lit
*result
;
2532 /* foolproof things by ensuring maxcount is not less than mincount */
2533 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2535 result
= (struct arg_lit
*)malloc(sizeof(struct arg_lit
));
2538 /* init the arg_hdr struct */
2539 result
->hdr
.flag
= 0;
2540 result
->hdr
.shortopts
= shortopts
;
2541 result
->hdr
.longopts
= longopts
;
2542 result
->hdr
.datatype
= NULL
;
2543 result
->hdr
.glossary
= glossary
;
2544 result
->hdr
.mincount
= mincount
;
2545 result
->hdr
.maxcount
= maxcount
;
2546 result
->hdr
.parent
= result
;
2547 result
->hdr
.resetfn
= (arg_resetfn
*)arg_lit_resetfn
;
2548 result
->hdr
.scanfn
= (arg_scanfn
*)arg_lit_scanfn
;
2549 result
->hdr
.checkfn
= (arg_checkfn
*)arg_lit_checkfn
;
2550 result
->hdr
.errorfn
= (arg_errorfn
*)arg_lit_errorfn
;
2552 /* init local variables */
2556 ARG_TRACE(("arg_litn() returns %p\n", result
));
2559 /*******************************************************************************
2560 * This file is part of the argtable3 library.
2562 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2563 * <sheitmann@users.sourceforge.net>
2564 * All rights reserved.
2566 * Redistribution and use in source and binary forms, with or without
2567 * modification, are permitted provided that the following conditions are met:
2568 * * Redistributions of source code must retain the above copyright
2569 * notice, this list of conditions and the following disclaimer.
2570 * * Redistributions in binary form must reproduce the above copyright
2571 * notice, this list of conditions and the following disclaimer in the
2572 * documentation and/or other materials provided with the distribution.
2573 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2574 * may be used to endorse or promote products derived from this software
2575 * without specific prior written permission.
2577 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2578 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2579 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2580 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2581 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2582 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2583 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2584 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2585 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2586 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2587 ******************************************************************************/
2591 #include "argtable3.h"
2593 struct arg_rem
*arg_rem(const char *datatype
, const char *glossary
)
2595 struct arg_rem
*result
= (struct arg_rem
*)malloc(sizeof(struct arg_rem
));
2598 result
->hdr
.flag
= 0;
2599 result
->hdr
.shortopts
= NULL
;
2600 result
->hdr
.longopts
= NULL
;
2601 result
->hdr
.datatype
= datatype
;
2602 result
->hdr
.glossary
= glossary
;
2603 result
->hdr
.mincount
= 1;
2604 result
->hdr
.maxcount
= 1;
2605 result
->hdr
.parent
= result
;
2606 result
->hdr
.resetfn
= NULL
;
2607 result
->hdr
.scanfn
= NULL
;
2608 result
->hdr
.checkfn
= NULL
;
2609 result
->hdr
.errorfn
= NULL
;
2612 ARG_TRACE(("arg_rem() returns %p\n", result
));
2616 /*******************************************************************************
2617 * This file is part of the argtable3 library.
2619 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2620 * <sheitmann@users.sourceforge.net>
2621 * All rights reserved.
2623 * Redistribution and use in source and binary forms, with or without
2624 * modification, are permitted provided that the following conditions are met:
2625 * * Redistributions of source code must retain the above copyright
2626 * notice, this list of conditions and the following disclaimer.
2627 * * Redistributions in binary form must reproduce the above copyright
2628 * notice, this list of conditions and the following disclaimer in the
2629 * documentation and/or other materials provided with the distribution.
2630 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2631 * may be used to endorse or promote products derived from this software
2632 * without specific prior written permission.
2634 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2635 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2636 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2637 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2638 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2639 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2640 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2641 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2642 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2643 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2644 ******************************************************************************/
2649 #include "argtable3.h"
2654 /***************************************************************
2655 T-Rex a tiny regular expression library
2657 Copyright (C) 2003-2006 Alberto Demichelis
2659 This software is provided 'as-is', without any express
2660 or implied warranty. In no event will the authors be held
2661 liable for any damages arising from the use of this software.
2663 Permission is granted to anyone to use this software for
2664 any purpose, including commercial applications, and to alter
2665 it and redistribute it freely, subject to the following restrictions:
2667 1. The origin of this software must not be misrepresented;
2668 you must not claim that you wrote the original software.
2669 If you use this software in a product, an acknowledgment
2670 in the product documentation would be appreciated but
2673 2. Altered source versions must be plainly marked as such,
2674 and must not be misrepresented as being the original software.
2676 3. This notice may not be removed or altered from any
2677 source distribution.
2679 ****************************************************************/
2686 #define TRexChar unsigned short
2687 #define MAX_CHAR 0xFFFF
2688 #define _TREXC(c) L##c
2689 #define trex_strlen wcslen
2690 #define trex_printf wprintf
2692 #define TRexChar char
2693 #define MAX_CHAR 0xFF
2694 #define _TREXC(c) (c)
2695 #define trex_strlen strlen
2696 #define trex_printf printf
2700 #define TREX_API extern
2704 #define TRex_False 0
2706 #define TREX_ICASE ARG_REX_ICASE
2708 typedef unsigned int TRexBool
;
2709 typedef struct TRex TRex
;
2712 const TRexChar
*begin
;
2716 TREX_API TRex
*trex_compile(const TRexChar
*pattern
, const TRexChar
**error
, int flags
);
2717 TREX_API
void trex_free(TRex
*exp
);
2718 TREX_API TRexBool
trex_match(TRex
* exp
, const TRexChar
* text
);
2719 TREX_API TRexBool
trex_search(TRex
* exp
, const TRexChar
* text
, const TRexChar
** out_begin
, const TRexChar
** out_end
);
2720 TREX_API TRexBool
trex_searchrange(TRex
* exp
, const TRexChar
* text_begin
, const TRexChar
* text_end
, const TRexChar
** out_begin
, const TRexChar
** out_end
);
2721 TREX_API
int trex_getsubexpcount(TRex
* exp
);
2722 TREX_API TRexBool
trex_getsubexp(TRex
* exp
, int n
, TRexMatch
*subexp
);
2734 const char *pattern
;
2739 static void arg_rex_resetfn(struct arg_rex
*parent
)
2741 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2745 static int arg_rex_scanfn(struct arg_rex
*parent
, const char *argval
)
2748 const TRexChar
*error
= NULL
;
2750 TRexBool is_match
= TRex_False
;
2752 if (parent
->count
== parent
->hdr
.maxcount
)
2754 /* maximum number of arguments exceeded */
2755 errorcode
= EMAXCOUNT
;
2759 /* a valid argument with no argument value was given. */
2760 /* This happens when an optional argument value was invoked. */
2761 /* leave parent argument value unaltered but still count the argument. */
2766 struct privhdr
*priv
= (struct privhdr
*)parent
->hdr
.priv
;
2768 /* test the current argument value for a match with the regular expression */
2769 /* if a match is detected, record the argument value in the arg_rex struct */
2771 rex
= trex_compile(priv
->pattern
, &error
, priv
->flags
);
2772 is_match
= trex_match(rex
, argval
);
2774 errorcode
= EREGNOMATCH
;
2776 parent
->sval
[parent
->count
++] = argval
;
2781 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__
,parent
,errorcode
));
2785 static int arg_rex_checkfn(struct arg_rex
*parent
)
2787 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2788 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2790 /* free the regex "program" we constructed in resetfn */
2791 //regfree(&(priv->regex));
2793 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2797 static void arg_rex_errorfn(struct arg_rex
*parent
,
2801 const char *progname
)
2803 const char *shortopts
= parent
->hdr
.shortopts
;
2804 const char *longopts
= parent
->hdr
.longopts
;
2805 const char *datatype
= parent
->hdr
.datatype
;
2807 /* make argval NULL safe */
2808 argval
= argval
? argval
: "";
2810 fprintf(fp
, "%s: ", progname
);
2814 fputs("missing option ", fp
);
2815 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2819 fputs("excess option ", fp
);
2820 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2824 fputs("illegal value ", fp
);
2825 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2830 //char errbuff[256];
2831 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2832 //printf("%s\n", errbuff);
2839 struct arg_rex
* arg_rex0(const char * shortopts
,
2840 const char * longopts
,
2841 const char * pattern
,
2842 const char *datatype
,
2844 const char *glossary
)
2846 return arg_rexn(shortopts
,
2856 struct arg_rex
* arg_rex1(const char * shortopts
,
2857 const char * longopts
,
2858 const char * pattern
,
2859 const char *datatype
,
2861 const char *glossary
)
2863 return arg_rexn(shortopts
,
2874 struct arg_rex
* arg_rexn(const char * shortopts
,
2875 const char * longopts
,
2876 const char * pattern
,
2877 const char *datatype
,
2881 const char *glossary
)
2884 struct arg_rex
*result
;
2885 struct privhdr
*priv
;
2887 const TRexChar
*error
= NULL
;
2893 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2894 printf("argtable: Bad argument table.\n");
2898 /* foolproof things by ensuring maxcount is not less than mincount */
2899 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2901 nbytes
= sizeof(struct arg_rex
) /* storage for struct arg_rex */
2902 + sizeof(struct privhdr
) /* storage for private arg_rex data */
2903 + maxcount
* sizeof(char *); /* storage for sval[maxcount] array */
2905 result
= (struct arg_rex
*)malloc(nbytes
);
2909 /* init the arg_hdr struct */
2910 result
->hdr
.flag
= ARG_HASVALUE
;
2911 result
->hdr
.shortopts
= shortopts
;
2912 result
->hdr
.longopts
= longopts
;
2913 result
->hdr
.datatype
= datatype
? datatype
: pattern
;
2914 result
->hdr
.glossary
= glossary
;
2915 result
->hdr
.mincount
= mincount
;
2916 result
->hdr
.maxcount
= maxcount
;
2917 result
->hdr
.parent
= result
;
2918 result
->hdr
.resetfn
= (arg_resetfn
*)arg_rex_resetfn
;
2919 result
->hdr
.scanfn
= (arg_scanfn
*)arg_rex_scanfn
;
2920 result
->hdr
.checkfn
= (arg_checkfn
*)arg_rex_checkfn
;
2921 result
->hdr
.errorfn
= (arg_errorfn
*)arg_rex_errorfn
;
2923 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2924 result
->hdr
.priv
= result
+ 1;
2925 priv
= (struct privhdr
*)(result
->hdr
.priv
);
2926 priv
->pattern
= pattern
;
2927 priv
->flags
= flags
;
2929 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2930 result
->sval
= (const char * *)(priv
+ 1);
2933 /* foolproof the string pointers by initializing them to reference empty strings */
2934 for (i
= 0; i
< maxcount
; i
++)
2935 result
->sval
[i
] = "";
2937 /* here we construct and destroy a regex representation of the regular
2938 * expression for no other reason than to force any regex errors to be
2939 * trapped now rather than later. If we don't, then errors may go undetected
2940 * until an argument is actually parsed.
2943 rex
= trex_compile(priv
->pattern
, &error
, priv
->flags
);
2946 ARG_LOG(("argtable: %s \"%s\"\n", error
? error
: _TREXC("undefined"), priv
->pattern
));
2947 ARG_LOG(("argtable: Bad argument table.\n"));
2952 ARG_TRACE(("arg_rexn() returns %p\n", result
));
2958 /* see copyright notice in trex.h */
2965 #define scisprint iswprint
2966 #define scstrlen wcslen
2967 #define scprintf wprintf
2970 #define scisprint isprint
2971 #define scstrlen strlen
2972 #define scprintf printf
2979 static const TRexChar
*g_nnames
[] =
2981 _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
2982 _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
2983 _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
2984 _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
2988 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2989 #define OP_OR (MAX_CHAR+2)
2990 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2991 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2992 #define OP_DOT (MAX_CHAR+5)
2993 #define OP_CLASS (MAX_CHAR+6)
2994 #define OP_CCLASS (MAX_CHAR+7)
2995 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2996 #define OP_RANGE (MAX_CHAR+9)
2997 #define OP_CHAR (MAX_CHAR+10)
2998 #define OP_EOL (MAX_CHAR+11)
2999 #define OP_BOL (MAX_CHAR+12)
3000 #define OP_WB (MAX_CHAR+13)
3002 #define TREX_SYMBOL_ANY_CHAR ('.')
3003 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
3004 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
3005 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
3006 #define TREX_SYMBOL_BRANCH ('|')
3007 #define TREX_SYMBOL_END_OF_STRING ('$')
3008 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
3009 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
3012 typedef int TRexNodeType
;
3014 typedef struct tagTRexNode
{
3022 const TRexChar
*_eol
;
3023 const TRexChar
*_bol
;
3031 TRexMatch
*_matches
;
3034 const TRexChar
**_error
;
3038 static int trex_list(TRex
*exp
);
3040 static int trex_newnode(TRex
*exp
, TRexNodeType type
)
3045 n
.next
= n
.right
= n
.left
= -1;
3047 n
.right
= exp
->_nsubexpr
++;
3048 if(exp
->_nallocated
< (exp
->_nsize
+ 1)) {
3049 exp
->_nallocated
*= 2;
3050 exp
->_nodes
= (TRexNode
*)realloc(exp
->_nodes
, exp
->_nallocated
* sizeof(TRexNode
));
3052 exp
->_nodes
[exp
->_nsize
++] = n
;
3053 newid
= exp
->_nsize
- 1;
3057 static void trex_error(TRex
*exp
,const TRexChar
*error
)
3059 if(exp
->_error
) *exp
->_error
= error
;
3060 longjmp(*((jmp_buf*)exp
->_jmpbuf
),-1);
3063 static void trex_expect(TRex
*exp
, int n
){
3065 trex_error(exp
, _SC("expected paren"));
3069 static TRexChar
trex_escapechar(TRex
*exp
)
3071 if(*exp
->_p
== TREX_SYMBOL_ESCAPE_CHAR
){
3074 case 'v': exp
->_p
++; return '\v';
3075 case 'n': exp
->_p
++; return '\n';
3076 case 't': exp
->_p
++; return '\t';
3077 case 'r': exp
->_p
++; return '\r';
3078 case 'f': exp
->_p
++; return '\f';
3079 default: return (*exp
->_p
++);
3081 } else if(!scisprint(*exp
->_p
)) trex_error(exp
,_SC("letter expected"));
3082 return (*exp
->_p
++);
3085 static int trex_charclass(TRex
*exp
,int classid
)
3087 int n
= trex_newnode(exp
,OP_CCLASS
);
3088 exp
->_nodes
[n
].left
= classid
;
3092 static int trex_charnode(TRex
*exp
,TRexBool isclass
)
3095 if(*exp
->_p
== TREX_SYMBOL_ESCAPE_CHAR
) {
3098 case 'n': exp
->_p
++; return trex_newnode(exp
,'\n');
3099 case 't': exp
->_p
++; return trex_newnode(exp
,'\t');
3100 case 'r': exp
->_p
++; return trex_newnode(exp
,'\r');
3101 case 'f': exp
->_p
++; return trex_newnode(exp
,'\f');
3102 case 'v': exp
->_p
++; return trex_newnode(exp
,'\v');
3103 case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
3104 case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
3105 case 'p': case 'P': case 'l': case 'u':
3107 t
= *exp
->_p
; exp
->_p
++;
3108 return trex_charclass(exp
,t
);
3113 int node
= trex_newnode(exp
,OP_WB
);
3114 exp
->_nodes
[node
].left
= *exp
->_p
;
3119 t
= *exp
->_p
; exp
->_p
++;
3120 return trex_newnode(exp
,t
);
3123 else if(!scisprint(*exp
->_p
)) {
3125 trex_error(exp
,_SC("letter expected"));
3127 t
= *exp
->_p
; exp
->_p
++;
3128 return trex_newnode(exp
,t
);
3130 static int trex_class(TRex
*exp
)
3133 int first
= -1,chain
;
3134 if(*exp
->_p
== TREX_SYMBOL_BEGINNING_OF_STRING
){
3135 ret
= trex_newnode(exp
,OP_NCLASS
);
3137 }else ret
= trex_newnode(exp
,OP_CLASS
);
3139 if(*exp
->_p
== ']') trex_error(exp
,_SC("empty class"));
3141 while(*exp
->_p
!= ']' && exp
->_p
!= exp
->_eol
) {
3142 if(*exp
->_p
== '-' && first
!= -1){
3144 if(*exp
->_p
++ == ']') trex_error(exp
,_SC("unfinished range"));
3145 r
= trex_newnode(exp
,OP_RANGE
);
3146 if(first
>*exp
->_p
) trex_error(exp
,_SC("invalid range"));
3147 if(exp
->_nodes
[first
].type
== OP_CCLASS
) trex_error(exp
,_SC("cannot use character classes in ranges"));
3148 exp
->_nodes
[r
].left
= exp
->_nodes
[first
].type
;
3149 t
= trex_escapechar(exp
);
3150 exp
->_nodes
[r
].right
= t
;
3151 exp
->_nodes
[chain
].next
= r
;
3158 exp
->_nodes
[chain
].next
= c
;
3160 first
= trex_charnode(exp
,TRex_True
);
3163 first
= trex_charnode(exp
,TRex_True
);
3169 exp
->_nodes
[chain
].next
= c
;
3174 exp
->_nodes
[ret
].left
= exp
->_nodes
[ret
].next
;
3175 exp
->_nodes
[ret
].next
= -1;
3179 static int trex_parsenumber(TRex
*exp
)
3181 int ret
= *exp
->_p
-'0';
3184 while(isdigit(*exp
->_p
)) {
3185 ret
= ret
*10+(*exp
->_p
++-'0');
3186 if(positions
==1000000000) trex_error(exp
,_SC("overflow in numeric constant"));
3192 static int trex_element(TRex
*exp
)
3202 if(*exp
->_p
=='?') {
3204 trex_expect(exp
,':');
3205 expr
= trex_newnode(exp
,OP_NOCAPEXPR
);
3208 expr
= trex_newnode(exp
,OP_EXPR
);
3209 newn
= trex_list(exp
);
3210 exp
->_nodes
[expr
].left
= newn
;
3212 trex_expect(exp
,')');
3217 ret
= trex_class(exp
);
3218 trex_expect(exp
,']');
3220 case TREX_SYMBOL_END_OF_STRING
: exp
->_p
++; ret
= trex_newnode(exp
,OP_EOL
);break;
3221 case TREX_SYMBOL_ANY_CHAR
: exp
->_p
++; ret
= trex_newnode(exp
,OP_DOT
);break;
3223 ret
= trex_charnode(exp
,TRex_False
);
3228 TRexBool isgreedy
= TRex_False
;
3229 unsigned short p0
= 0, p1
= 0;
3231 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE
: p0
= 0; p1
= 0xFFFF; exp
->_p
++; isgreedy
= TRex_True
; break;
3232 case TREX_SYMBOL_GREEDY_ONE_OR_MORE
: p0
= 1; p1
= 0xFFFF; exp
->_p
++; isgreedy
= TRex_True
; break;
3233 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE
: p0
= 0; p1
= 1; exp
->_p
++; isgreedy
= TRex_True
; break;
3236 if(!isdigit(*exp
->_p
)) trex_error(exp
,_SC("number expected"));
3237 p0
= (unsigned short)trex_parsenumber(exp
);
3238 /*******************************/
3246 if(isdigit(*exp
->_p
)){
3247 p1
= (unsigned short)trex_parsenumber(exp
);
3249 trex_expect(exp
,'}');
3252 trex_error(exp
,_SC(", or } expected"));
3254 /*******************************/
3255 isgreedy
= TRex_True
;
3260 int nnode
= trex_newnode(exp
,OP_GREEDY
);
3261 exp
->_nodes
[nnode
].left
= ret
;
3262 exp
->_nodes
[nnode
].right
= ((p0
)<<16)|p1
;
3266 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')) {
3267 int nnode
= trex_element(exp
);
3268 exp
->_nodes
[ret
].next
= nnode
;
3274 static int trex_list(TRex
*exp
)
3277 if(*exp
->_p
== TREX_SYMBOL_BEGINNING_OF_STRING
) {
3279 ret
= trex_newnode(exp
,OP_BOL
);
3281 e
= trex_element(exp
);
3283 exp
->_nodes
[ret
].next
= e
;
3287 if(*exp
->_p
== TREX_SYMBOL_BRANCH
) {
3290 temp
= trex_newnode(exp
,OP_OR
);
3291 exp
->_nodes
[temp
].left
= ret
;
3292 tright
= trex_list(exp
);
3293 exp
->_nodes
[temp
].right
= tright
;
3299 static TRexBool
trex_matchcclass(int cclass
,TRexChar c
)
3302 case 'a': return isalpha(c
)?TRex_True
:TRex_False
;
3303 case 'A': return !isalpha(c
)?TRex_True
:TRex_False
;
3304 case 'w': return (isalnum(c
) || c
== '_')?TRex_True
:TRex_False
;
3305 case 'W': return (!isalnum(c
) && c
!= '_')?TRex_True
:TRex_False
;
3306 case 's': return ISSPACE(c
)?TRex_True
:TRex_False
;
3307 case 'S': return !ISSPACE(c
)?TRex_True
:TRex_False
;
3308 case 'd': return isdigit(c
)?TRex_True
:TRex_False
;
3309 case 'D': return !isdigit(c
)?TRex_True
:TRex_False
;
3310 case 'x': return isxdigit(c
)?TRex_True
:TRex_False
;
3311 case 'X': return !isxdigit(c
)?TRex_True
:TRex_False
;
3312 case 'c': return iscntrl(c
)?TRex_True
:TRex_False
;
3313 case 'C': return !iscntrl(c
)?TRex_True
:TRex_False
;
3314 case 'p': return ispunct(c
)?TRex_True
:TRex_False
;
3315 case 'P': return !ispunct(c
)?TRex_True
:TRex_False
;
3316 case 'l': return islower(c
)?TRex_True
:TRex_False
;
3317 case 'u': return isupper(c
)?TRex_True
:TRex_False
;
3319 return TRex_False
; /*cannot happen*/
3322 static TRexBool
trex_matchclass(TRex
* exp
,TRexNode
*node
,TRexChar c
)
3325 switch(node
->type
) {
3327 if (exp
->_flags
& TREX_ICASE
)
3329 if(c
>= toupper(node
->left
) && c
<= toupper(node
->right
)) return TRex_True
;
3330 if(c
>= tolower(node
->left
) && c
<= tolower(node
->right
)) return TRex_True
;
3334 if(c
>= node
->left
&& c
<= node
->right
) return TRex_True
;
3338 if(trex_matchcclass(node
->left
,c
)) return TRex_True
;
3341 if (exp
->_flags
& TREX_ICASE
)
3343 if (c
== tolower(node
->type
) || c
== toupper(node
->type
)) return TRex_True
;
3347 if(c
== node
->type
)return TRex_True
;
3351 } while((node
->next
!= -1) && (node
= &exp
->_nodes
[node
->next
]));
3355 static const TRexChar
*trex_matchnode(TRex
* exp
,TRexNode
*node
,const TRexChar
*str
,TRexNode
*next
)
3358 TRexNodeType type
= node
->type
;
3361 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3362 TRexNode
*greedystop
= NULL
;
3363 int p0
= (node
->right
>> 16)&0x0000FFFF, p1
= node
->right
&0x0000FFFF, nmaches
= 0;
3364 const TRexChar
*s
=str
, *good
= str
;
3366 if(node
->next
!= -1) {
3367 greedystop
= &exp
->_nodes
[node
->next
];
3373 while((nmaches
== 0xFFFF || nmaches
< p1
)) {
3375 const TRexChar
*stop
;
3376 if(!(s
= trex_matchnode(exp
,&exp
->_nodes
[node
->left
],s
,greedystop
)))
3381 //checks that 0 matches satisfy the expression(if so skips)
3382 //if not would always stop(for instance if is a '?')
3383 if(greedystop
->type
!= OP_GREEDY
||
3384 (greedystop
->type
== OP_GREEDY
&& ((greedystop
->right
>> 16)&0x0000FFFF) != 0))
3386 TRexNode
*gnext
= NULL
;
3387 if(greedystop
->next
!= -1) {
3388 gnext
= &exp
->_nodes
[greedystop
->next
];
3389 }else if(next
&& next
->next
!= -1){
3390 gnext
= &exp
->_nodes
[next
->next
];
3392 stop
= trex_matchnode(exp
,greedystop
,s
,gnext
);
3394 //if satisfied stop it
3395 if(p0
== p1
&& p0
== nmaches
) break;
3396 else if(nmaches
>= p0
&& p1
== 0xFFFF) break;
3397 else if(nmaches
>= p0
&& nmaches
<= p1
) break;
3405 if(p0
== p1
&& p0
== nmaches
) return good
;
3406 else if(nmaches
>= p0
&& p1
== 0xFFFF) return good
;
3407 else if(nmaches
>= p0
&& nmaches
<= p1
) return good
;
3411 const TRexChar
*asd
= str
;
3412 TRexNode
*temp
=&exp
->_nodes
[node
->left
];
3413 while( (asd
= trex_matchnode(exp
,temp
,asd
,NULL
)) ) {
3414 if(temp
->next
!= -1)
3415 temp
= &exp
->_nodes
[temp
->next
];
3420 temp
= &exp
->_nodes
[node
->right
];
3421 while( (asd
= trex_matchnode(exp
,temp
,asd
,NULL
)) ) {
3422 if(temp
->next
!= -1)
3423 temp
= &exp
->_nodes
[temp
->next
];
3432 TRexNode
*n
= &exp
->_nodes
[node
->left
];
3433 const TRexChar
*cur
= str
;
3435 if(node
->type
!= OP_NOCAPEXPR
&& node
->right
== exp
->_currsubexp
) {
3436 capture
= exp
->_currsubexp
;
3437 exp
->_matches
[capture
].begin
= cur
;
3442 TRexNode
*subnext
= NULL
;
3444 subnext
= &exp
->_nodes
[n
->next
];
3448 if(!(cur
= trex_matchnode(exp
,n
,cur
,subnext
))) {
3450 exp
->_matches
[capture
].begin
= 0;
3451 exp
->_matches
[capture
].len
= 0;
3455 } while((n
->next
!= -1) && (n
= &exp
->_nodes
[n
->next
]));
3458 exp
->_matches
[capture
].len
= (int)(cur
- exp
->_matches
[capture
].begin
);
3462 if((str
== exp
->_bol
&& !ISSPACE(*str
))
3463 || ((str
== exp
->_eol
&& !ISSPACE(*(str
-1))))
3464 || ((!ISSPACE(*str
) && ISSPACE(*(str
+1))))
3465 || ((ISSPACE(*str
) && !ISSPACE(*(str
+1)))) ) {
3466 return (node
->left
== 'b')?str
:NULL
;
3468 return (node
->left
== 'b')?NULL
:str
;
3470 if(str
== exp
->_bol
) return str
;
3473 if(str
== exp
->_eol
) return str
;
3480 if(trex_matchclass(exp
,&exp
->_nodes
[node
->left
],*str
)?(type
== OP_CLASS
?TRex_True
:TRex_False
):(type
== OP_NCLASS
?TRex_True
:TRex_False
)) {
3486 if(trex_matchcclass(node
->left
,*str
)) {
3492 if (exp
->_flags
& TREX_ICASE
)
3494 if(*str
!= tolower(node
->type
) && *str
!= toupper(node
->type
)) return NULL
;
3498 if (*str
!= node
->type
) return NULL
;
3507 TRex
*trex_compile(const TRexChar
*pattern
,const TRexChar
**error
,int flags
)
3509 TRex
*exp
= (TRex
*)malloc(sizeof(TRex
));
3510 exp
->_eol
= exp
->_bol
= NULL
;
3512 exp
->_nallocated
= (int)scstrlen(pattern
) * sizeof(TRexChar
);
3513 exp
->_nodes
= (TRexNode
*)malloc(exp
->_nallocated
* sizeof(TRexNode
));
3517 exp
->_first
= trex_newnode(exp
,OP_EXPR
);
3518 exp
->_error
= error
;
3519 exp
->_jmpbuf
= malloc(sizeof(jmp_buf));
3520 exp
->_flags
= flags
;
3521 if(setjmp(*((jmp_buf*)exp
->_jmpbuf
)) == 0) {
3522 int res
= trex_list(exp
);
3523 exp
->_nodes
[exp
->_first
].left
= res
;
3525 trex_error(exp
,_SC("unexpected character"));
3530 nsize
= exp
->_nsize
;
3531 t
= &exp
->_nodes
[0];
3532 scprintf(_SC("\n"));
3533 for(i
= 0;i
< nsize
; i
++) {
3534 if(exp
->_nodes
[i
].type
>MAX_CHAR
)
3535 scprintf(_SC("[%02d] %10s "),i
,g_nnames
[exp
->_nodes
[i
].type
-MAX_CHAR
]);
3537 scprintf(_SC("[%02d] %10c "),i
,exp
->_nodes
[i
].type
);
3538 scprintf(_SC("left %02d right %02d next %02d\n"),exp
->_nodes
[i
].left
,exp
->_nodes
[i
].right
,exp
->_nodes
[i
].next
);
3540 scprintf(_SC("\n"));
3543 exp
->_matches
= (TRexMatch
*) malloc(exp
->_nsubexpr
* sizeof(TRexMatch
));
3544 memset(exp
->_matches
,0,exp
->_nsubexpr
* sizeof(TRexMatch
));
3553 void trex_free(TRex
*exp
)
3556 if(exp
->_nodes
) free(exp
->_nodes
);
3557 if(exp
->_jmpbuf
) free(exp
->_jmpbuf
);
3558 if(exp
->_matches
) free(exp
->_matches
);
3563 TRexBool
trex_match(TRex
* exp
,const TRexChar
* text
)
3565 const TRexChar
* res
= NULL
;
3567 exp
->_eol
= text
+ scstrlen(text
);
3568 exp
->_currsubexp
= 0;
3569 res
= trex_matchnode(exp
,exp
->_nodes
,text
,NULL
);
3570 if(res
== NULL
|| res
!= exp
->_eol
)
3575 TRexBool
trex_searchrange(TRex
* exp
,const TRexChar
* text_begin
,const TRexChar
* text_end
,const TRexChar
** out_begin
, const TRexChar
** out_end
)
3577 const TRexChar
*cur
= NULL
;
3578 int node
= exp
->_first
;
3579 if(text_begin
>= text_end
) return TRex_False
;
3580 exp
->_bol
= text_begin
;
3581 exp
->_eol
= text_end
;
3585 exp
->_currsubexp
= 0;
3586 cur
= trex_matchnode(exp
,&exp
->_nodes
[node
],cur
,NULL
);
3589 node
= exp
->_nodes
[node
].next
;
3592 } while(cur
== NULL
&& text_begin
!= text_end
);
3599 if(out_begin
) *out_begin
= text_begin
;
3600 if(out_end
) *out_end
= cur
;
3604 TRexBool
trex_search(TRex
* exp
,const TRexChar
* text
, const TRexChar
** out_begin
, const TRexChar
** out_end
)
3606 return trex_searchrange(exp
,text
,text
+ scstrlen(text
),out_begin
,out_end
);
3609 int trex_getsubexpcount(TRex
* exp
)
3611 return exp
->_nsubexpr
;
3614 TRexBool
trex_getsubexp(TRex
* exp
, int n
, TRexMatch
*subexp
)
3616 if( n
<0 || n
>= exp
->_nsubexpr
) return TRex_False
;
3617 *subexp
= exp
->_matches
[n
];
3620 /*******************************************************************************
3621 * This file is part of the argtable3 library.
3623 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3624 * <sheitmann@users.sourceforge.net>
3625 * All rights reserved.
3627 * Redistribution and use in source and binary forms, with or without
3628 * modification, are permitted provided that the following conditions are met:
3629 * * Redistributions of source code must retain the above copyright
3630 * notice, this list of conditions and the following disclaimer.
3631 * * Redistributions in binary form must reproduce the above copyright
3632 * notice, this list of conditions and the following disclaimer in the
3633 * documentation and/or other materials provided with the distribution.
3634 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3635 * may be used to endorse or promote products derived from this software
3636 * without specific prior written permission.
3638 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3639 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3640 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3641 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3642 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3643 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3644 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3645 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3646 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3647 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3648 ******************************************************************************/
3652 #include "argtable3.h"
3655 static void arg_str_resetfn(struct arg_str
*parent
)
3657 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
3662 static int arg_str_scanfn(struct arg_str
*parent
, const char *argval
)
3666 if (parent
->count
== parent
->hdr
.maxcount
)
3668 /* maximum number of arguments exceeded */
3669 errorcode
= EMAXCOUNT
;
3673 /* a valid argument with no argument value was given. */
3674 /* This happens when an optional argument value was invoked. */
3675 /* leave parent arguiment value unaltered but still count the argument. */
3680 parent
->sval
[parent
->count
++] = argval
;
3683 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
3688 static int arg_str_checkfn(struct arg_str
*parent
)
3690 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
3692 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
3697 static void arg_str_errorfn(
3698 struct arg_str
*parent
,
3702 const char *progname
)
3704 const char *shortopts
= parent
->hdr
.shortopts
;
3705 const char *longopts
= parent
->hdr
.longopts
;
3706 const char *datatype
= parent
->hdr
.datatype
;
3708 /* make argval NULL safe */
3709 argval
= argval
? argval
: "";
3711 fprintf(fp
, "%s: ", progname
);
3715 fputs("missing option ", fp
);
3716 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
3720 fputs("excess option ", fp
);
3721 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
3727 struct arg_str
* arg_str0(
3728 const char *shortopts
,
3729 const char *longopts
,
3730 const char *datatype
,
3731 const char *glossary
)
3733 return arg_strn(shortopts
, longopts
, datatype
, 0, 1, glossary
);
3737 struct arg_str
* arg_str1(
3738 const char *shortopts
,
3739 const char *longopts
,
3740 const char *datatype
,
3741 const char *glossary
)
3743 return arg_strn(shortopts
, longopts
, datatype
, 1, 1, glossary
);
3747 struct arg_str
* arg_strn(
3748 const char *shortopts
,
3749 const char *longopts
,
3750 const char *datatype
,
3753 const char *glossary
)
3756 struct arg_str
*result
;
3758 /* should not allow this stupid error */
3759 /* we should return an error code warning this logic error */
3760 /* foolproof things by ensuring maxcount is not less than mincount */
3761 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
3763 nbytes
= sizeof(struct arg_str
) /* storage for struct arg_str */
3764 + maxcount
* sizeof(char *); /* storage for sval[maxcount] array */
3766 result
= (struct arg_str
*)malloc(nbytes
);
3771 /* init the arg_hdr struct */
3772 result
->hdr
.flag
= ARG_HASVALUE
;
3773 result
->hdr
.shortopts
= shortopts
;
3774 result
->hdr
.longopts
= longopts
;
3775 result
->hdr
.datatype
= datatype
? datatype
: "<string>";
3776 result
->hdr
.glossary
= glossary
;
3777 result
->hdr
.mincount
= mincount
;
3778 result
->hdr
.maxcount
= maxcount
;
3779 result
->hdr
.parent
= result
;
3780 result
->hdr
.resetfn
= (arg_resetfn
*)arg_str_resetfn
;
3781 result
->hdr
.scanfn
= (arg_scanfn
*)arg_str_scanfn
;
3782 result
->hdr
.checkfn
= (arg_checkfn
*)arg_str_checkfn
;
3783 result
->hdr
.errorfn
= (arg_errorfn
*)arg_str_errorfn
;
3785 /* store the sval[maxcount] array immediately after the arg_str struct */
3786 result
->sval
= (const char * *)(result
+ 1);
3789 /* foolproof the string pointers by initialising them to reference empty strings */
3790 for (i
= 0; i
< maxcount
; i
++)
3791 result
->sval
[i
] = "";
3794 ARG_TRACE(("arg_strn() returns %p\n", result
));
3797 /*******************************************************************************
3798 * This file is part of the argtable3 library.
3800 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3801 * <sheitmann@users.sourceforge.net>
3802 * All rights reserved.
3804 * Redistribution and use in source and binary forms, with or without
3805 * modification, are permitted provided that the following conditions are met:
3806 * * Redistributions of source code must retain the above copyright
3807 * notice, this list of conditions and the following disclaimer.
3808 * * Redistributions in binary form must reproduce the above copyright
3809 * notice, this list of conditions and the following disclaimer in the
3810 * documentation and/or other materials provided with the distribution.
3811 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3812 * may be used to endorse or promote products derived from this software
3813 * without specific prior written permission.
3815 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3816 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3817 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3818 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3819 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3820 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3821 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3822 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3823 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3824 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3825 ******************************************************************************/
3832 #include "argtable3.h"
3835 void arg_register_error(struct arg_end
*end
,
3840 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3841 if (end
->count
< end
->hdr
.maxcount
)
3843 end
->error
[end
->count
] = error
;
3844 end
->parent
[end
->count
] = parent
;
3845 end
->argval
[end
->count
] = argval
;
3850 end
->error
[end
->hdr
.maxcount
- 1] = ARG_ELIMIT
;
3851 end
->parent
[end
->hdr
.maxcount
- 1] = end
;
3852 end
->argval
[end
->hdr
.maxcount
- 1] = NULL
;
3858 * Return index of first table entry with a matching short option
3859 * or -1 if no match was found.
3862 int find_shortoption(struct arg_hdr
* *table
, char shortopt
)
3865 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
3867 if (table
[tabindex
]->shortopts
&&
3868 strchr(table
[tabindex
]->shortopts
, shortopt
))
3879 struct option
*options
;
3884 void dump_longoptions(struct longoptions
* longoptions
)
3887 printf("getoptval = %d\n", longoptions
->getoptval
);
3888 printf("noptions = %d\n", longoptions
->noptions
);
3889 for (i
= 0; i
< longoptions
->noptions
; i
++)
3891 printf("options[%d].name = \"%s\"\n",
3893 longoptions
->options
[i
].name
);
3894 printf("options[%d].has_arg = %d\n", i
, longoptions
->options
[i
].has_arg
);
3895 printf("options[%d].flag = %p\n", i
, longoptions
->options
[i
].flag
);
3896 printf("options[%d].val = %d\n", i
, longoptions
->options
[i
].val
);
3902 struct longoptions
* alloc_longoptions(struct arg_hdr
* *table
)
3904 struct longoptions
*result
;
3907 size_t longoptlen
= 0;
3911 * Determine the total number of option structs required
3912 * by counting the number of comma separated long options
3913 * in all table entries and return the count in noptions.
3914 * note: noptions starts at 1 not 0 because we getoptlong
3915 * requires a NULL option entry to terminate the option array.
3916 * While we are at it, count the number of chars required
3917 * to store private copies of all the longoption strings
3918 * and return that count in logoptlen.
3923 const char *longopts
= table
[tabindex
]->longopts
;
3924 longoptlen
+= (longopts
? strlen(longopts
) : 0) + 1;
3928 longopts
= strchr(longopts
+ 1, ',');
3930 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
3931 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3934 /* allocate storage for return data structure as: */
3935 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3936 nbytes
= sizeof(struct longoptions
)
3937 + sizeof(struct option
) * noptions
3939 result
= (struct longoptions
*)malloc(nbytes
);
3942 int option_index
= 0;
3945 result
->getoptval
= 0;
3946 result
->noptions
= noptions
;
3947 result
->options
= (struct option
*)(result
+ 1);
3948 store
= (char *)(result
->options
+ noptions
);
3950 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
3952 const char *longopts
= table
[tabindex
]->longopts
;
3954 while(longopts
&& *longopts
)
3956 char *storestart
= store
;
3958 /* copy progressive longopt strings into the store */
3959 while (*longopts
!= 0 && *longopts
!= ',')
3960 *store
++ = *longopts
++;
3962 if (*longopts
== ',')
3964 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3966 result
->options
[option_index
].name
= storestart
;
3967 result
->options
[option_index
].flag
= &(result
->getoptval
);
3968 result
->options
[option_index
].val
= tabindex
;
3969 if (table
[tabindex
]->flag
& ARG_HASOPTVALUE
)
3970 result
->options
[option_index
].has_arg
= 2;
3971 else if (table
[tabindex
]->flag
& ARG_HASVALUE
)
3972 result
->options
[option_index
].has_arg
= 1;
3974 result
->options
[option_index
].has_arg
= 0;
3979 /* terminate the options array with a zero-filled entry */
3980 result
->options
[option_index
].name
= 0;
3981 result
->options
[option_index
].has_arg
= 0;
3982 result
->options
[option_index
].flag
= 0;
3983 result
->options
[option_index
].val
= 0;
3986 /*dump_longoptions(result);*/
3991 char * alloc_shortoptions(struct arg_hdr
* *table
)
3997 /* determine the total number of option chars required */
3998 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4000 struct arg_hdr
*hdr
= table
[tabindex
];
4001 len
+= 3 * (hdr
->shortopts
? strlen(hdr
->shortopts
) : 0);
4004 result
= malloc(len
);
4009 /* add a leading ':' so getopt return codes distinguish */
4010 /* unrecognised option and options missing argument values */
4013 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4015 struct arg_hdr
*hdr
= table
[tabindex
];
4016 const char *shortopts
= hdr
->shortopts
;
4017 while(shortopts
&& *shortopts
)
4019 *res
++ = *shortopts
++;
4020 if (hdr
->flag
& ARG_HASVALUE
)
4022 if (hdr
->flag
& ARG_HASOPTVALUE
)
4026 /* null terminate the string */
4030 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
4035 /* return index of the table terminator entry */
4037 int arg_endindex(struct arg_hdr
* *table
)
4040 while (!(table
[tabindex
]->flag
& ARG_TERMINATOR
))
4047 void arg_parse_tagged(int argc
,
4049 struct arg_hdr
* *table
,
4050 struct arg_end
*endtable
)
4052 struct longoptions
*longoptions
;
4056 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4058 /* allocate short and long option arrays for the given opttable[]. */
4059 /* if the allocs fail then put an error msg in the last table entry. */
4060 longoptions
= alloc_longoptions(table
);
4061 shortoptions
= alloc_shortoptions(table
);
4062 if (!longoptions
|| !shortoptions
)
4064 /* one or both memory allocs failed */
4065 arg_register_error(endtable
, endtable
, ARG_EMALLOC
, NULL
);
4066 /* free anything that was allocated (this is null safe) */
4072 /*dump_longoptions(longoptions);*/
4074 /* reset getopts internal option-index to zero, and disable error reporting */
4078 /* fetch and process args using getopt_long */
4080 getopt_long(argc
, argv
, shortoptions
, longoptions
->options
,
4084 printf("optarg='%s'\n",optarg);
4085 printf("optind=%d\n",optind);
4086 printf("copt=%c\n",(char)copt);
4087 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
4093 int tabindex
= longoptions
->getoptval
;
4094 void *parent
= table
[tabindex
]->parent
;
4095 /*printf("long option detected from argtable[%d]\n", tabindex);*/
4096 if (optarg
&& optarg
[0] == 0 &&
4097 (table
[tabindex
]->flag
& ARG_HASVALUE
))
4099 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
4100 arg_register_error(endtable
, endtable
, ARG_EMISSARG
,
4102 /* continue to scan the (empty) argument value to enforce argument count checking */
4104 if (table
[tabindex
]->scanfn
)
4106 int errorcode
= table
[tabindex
]->scanfn(parent
, optarg
);
4108 arg_register_error(endtable
, parent
, errorcode
, optarg
);
4115 * getopt_long() found an unrecognised short option.
4116 * if it was a short option its value is in optopt
4117 * if it was a long option then optopt=0
4122 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4123 arg_register_error(endtable
, endtable
, ARG_ELONGOPT
,
4127 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4128 arg_register_error(endtable
, endtable
, optopt
, NULL
);
4135 * getopt_long() found an option with its argument missing.
4137 /*printf(": option %s requires an argument\n",argv[optind-1]); */
4138 arg_register_error(endtable
, endtable
, ARG_EMISSARG
,
4144 /* getopt_long() found a valid short option */
4145 int tabindex
= find_shortoption(table
, (char)copt
);
4146 /*printf("short option detected from argtable[%d]\n", tabindex);*/
4149 /* should never get here - but handle it just in case */
4150 /*printf("unrecognised short option %d\n",copt);*/
4151 arg_register_error(endtable
, endtable
, copt
, NULL
);
4155 if (table
[tabindex
]->scanfn
)
4157 void *parent
= table
[tabindex
]->parent
;
4158 int errorcode
= table
[tabindex
]->scanfn(parent
, optarg
);
4160 arg_register_error(endtable
, parent
, errorcode
, optarg
);
4174 void arg_parse_untagged(int argc
,
4176 struct arg_hdr
* *table
,
4177 struct arg_end
*endtable
)
4181 const char *optarglast
= NULL
;
4182 void *parentlast
= NULL
;
4184 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4185 while (!(table
[tabindex
]->flag
& ARG_TERMINATOR
))
4190 /* if we have exhausted our argv[optind] entries then we have finished */
4193 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4197 /* skip table entries with non-null long or short options (they are not untagged entries) */
4198 if (table
[tabindex
]->longopts
|| table
[tabindex
]->shortopts
)
4200 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
4205 /* skip table entries with NULL scanfn */
4206 if (!(table
[tabindex
]->scanfn
))
4208 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4213 /* attempt to scan the current argv[optind] with the current */
4214 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
4215 /* try again with the next table[] entry. */
4216 parent
= table
[tabindex
]->parent
;
4217 errorcode
= table
[tabindex
]->scanfn(parent
, argv
[optind
]);
4220 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4221 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4224 /* clear the last tentative error */
4229 /* failure, try same argv[optind] with next table[tabindex] entry */
4230 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4233 /* remember this as a tentative error we may wish to reinstate later */
4234 errorlast
= errorcode
;
4235 optarglast
= argv
[optind
];
4236 parentlast
= parent
;
4241 /* if a tenative error still remains at this point then register it as a proper error */
4244 arg_register_error(endtable
, parentlast
, errorlast
, optarglast
);
4248 /* only get here when not all argv[] entries were consumed */
4249 /* register an error for each unused argv[] entry */
4250 while (optind
< argc
)
4252 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4253 arg_register_error(endtable
, endtable
, ARG_ENOMATCH
, argv
[optind
++]);
4261 void arg_parse_check(struct arg_hdr
* *table
, struct arg_end
*endtable
)
4264 /* printf("arg_parse_check()\n"); */
4267 if (table
[tabindex
]->checkfn
)
4269 void *parent
= table
[tabindex
]->parent
;
4270 int errorcode
= table
[tabindex
]->checkfn(parent
);
4272 arg_register_error(endtable
, parent
, errorcode
, NULL
);
4274 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4279 void arg_reset(void * *argtable
)
4281 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4283 /*printf("arg_reset(%p)\n",argtable);*/
4286 if (table
[tabindex
]->resetfn
)
4287 table
[tabindex
]->resetfn(table
[tabindex
]->parent
);
4288 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4292 int arg_parse(int argc
, char * *argv
, void * *argtable
)
4294 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4295 struct arg_end
*endtable
;
4297 char * *argvcopy
= NULL
;
4299 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4301 /* reset any argtable data from previous invocations */
4302 arg_reset(argtable
);
4304 /* locate the first end-of-table marker within the array */
4305 endindex
= arg_endindex(table
);
4306 endtable
= (struct arg_end
*)table
[endindex
];
4308 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4309 /* Failure to trap this case results in an unwanted NULL result from */
4310 /* the malloc for argvcopy (next code block). */
4313 /* We must still perform post-parse checks despite the absence of command line arguments */
4314 arg_parse_check(table
, endtable
);
4316 /* Now we are finished */
4317 return endtable
->count
;
4320 argvcopy
= (char **)malloc(sizeof(char *) * (argc
+ 1));
4326 Fill in the local copy of argv[]. We need a local copy
4327 because getopt rearranges argv[] which adversely affects
4328 susbsequent parsing attempts.
4330 for (i
= 0; i
< argc
; i
++)
4331 argvcopy
[i
] = argv
[i
];
4333 argvcopy
[argc
] = NULL
;
4335 /* parse the command line (local copy) for tagged options */
4336 arg_parse_tagged(argc
, argvcopy
, table
, endtable
);
4338 /* parse the command line (local copy) for untagged options */
4339 arg_parse_untagged(argc
, argvcopy
, table
, endtable
);
4341 /* if no errors so far then perform post-parse checks otherwise dont bother */
4342 if (endtable
->count
== 0)
4343 arg_parse_check(table
, endtable
);
4345 /* release the local copt of argv[] */
4350 /* memory alloc failed */
4351 arg_register_error(endtable
, endtable
, ARG_EMALLOC
, NULL
);
4354 return endtable
->count
;
4359 * Concatenate contents of src[] string onto *pdest[] string.
4360 * The *pdest pointer is altered to point to the end of the
4361 * target string and *pndest is decremented by the same number
4363 * Does not append more than *pndest chars into *pdest[]
4364 * so as to prevent buffer overruns.
4365 * Its something like strncat() but more efficient for repeated
4366 * calls on the same destination string.
4368 * char dest[30] = "good"
4369 * size_t ndest = sizeof(dest);
4370 * char *pdest = dest;
4371 * arg_char(&pdest,"bye ",&ndest);
4372 * arg_char(&pdest,"cruel ",&ndest);
4373 * arg_char(&pdest,"world!",&ndest);
4375 * dest[] == "goodbye cruel world!"
4379 void arg_cat(char * *pdest
, const char *src
, size_t *pndest
)
4381 char *dest
= *pdest
;
4382 char *end
= dest
+ *pndest
;
4384 /*locate null terminator of dest string */
4385 while(dest
< end
&& *dest
!= 0)
4388 /* concat src string to dest string */
4389 while(dest
< end
&& *src
!= 0)
4392 /* null terminate dest string */
4395 /* update *pdest and *pndest */
4396 *pndest
= end
- dest
;
4402 void arg_cat_option(char *dest
,
4404 const char *shortopts
,
4405 const char *longopts
,
4406 const char *datatype
,
4413 /* note: option array[] is initialiazed dynamically here to satisfy */
4414 /* a deficiency in the watcom compiler wrt static array initializers. */
4416 option
[1] = shortopts
[0];
4419 arg_cat(&dest
, option
, &ndest
);
4422 arg_cat(&dest
, " ", &ndest
);
4425 arg_cat(&dest
, "[", &ndest
);
4426 arg_cat(&dest
, datatype
, &ndest
);
4427 arg_cat(&dest
, "]", &ndest
);
4430 arg_cat(&dest
, datatype
, &ndest
);
4437 /* add "--" tag prefix */
4438 arg_cat(&dest
, "--", &ndest
);
4440 /* add comma separated option tag */
4441 ncspn
= strcspn(longopts
, ",");
4442 #ifdef __STDC_WANT_SECURE_LIB__
4443 strncat_s(dest
, ndest
, longopts
, (ncspn
< ndest
) ? ncspn
: ndest
);
4445 strncat(dest
, longopts
, (ncspn
< ndest
) ? ncspn
: ndest
);
4450 arg_cat(&dest
, "=", &ndest
);
4453 arg_cat(&dest
, "[", &ndest
);
4454 arg_cat(&dest
, datatype
, &ndest
);
4455 arg_cat(&dest
, "]", &ndest
);
4458 arg_cat(&dest
, datatype
, &ndest
);
4465 arg_cat(&dest
, "[", &ndest
);
4466 arg_cat(&dest
, datatype
, &ndest
);
4467 arg_cat(&dest
, "]", &ndest
);
4470 arg_cat(&dest
, datatype
, &ndest
);
4475 void arg_cat_optionv(char *dest
,
4477 const char *shortopts
,
4478 const char *longopts
,
4479 const char *datatype
,
4481 const char *separator
)
4483 separator
= separator
? separator
: "";
4487 const char *c
= shortopts
;
4493 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4494 /* a deficiency in the watcom compiler wrt static array initializers. */
4499 arg_cat(&dest
, shortopt
, &ndest
);
4501 arg_cat(&dest
, separator
, &ndest
);
4505 /* put separator between long opts and short opts */
4506 if (shortopts
&& longopts
)
4507 arg_cat(&dest
, separator
, &ndest
);
4511 const char *c
= longopts
;
4516 /* add "--" tag prefix */
4517 arg_cat(&dest
, "--", &ndest
);
4519 /* add comma separated option tag */
4520 ncspn
= strcspn(c
, ",");
4521 #ifdef __STDC_WANT_SECURE_LIB__
4522 strncat_s(dest
, ndest
, c
, (ncspn
< ndest
) ? ncspn
: ndest
);
4524 strncat(dest
, c
, (ncspn
< ndest
) ? ncspn
: ndest
);
4528 /* add given separator in place of comma */
4531 arg_cat(&dest
, separator
, &ndest
);
4540 arg_cat(&dest
, "=", &ndest
);
4542 arg_cat(&dest
, " ", &ndest
);
4546 arg_cat(&dest
, "[", &ndest
);
4547 arg_cat(&dest
, datatype
, &ndest
);
4548 arg_cat(&dest
, "]", &ndest
);
4551 arg_cat(&dest
, datatype
, &ndest
);
4556 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4557 void arg_print_option(FILE *fp
,
4558 const char *shortopts
,
4559 const char *longopts
,
4560 const char *datatype
,
4563 char syntax
[200] = "";
4564 suffix
= suffix
? suffix
: "";
4566 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4567 arg_cat_optionv(syntax
,
4581 * Print a GNU style [OPTION] string in which all short options that
4582 * do not take argument values are presented in abbreviated form, as
4583 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4586 void arg_print_gnuswitch(FILE *fp
, struct arg_hdr
* *table
)
4589 char *format1
= " -%c";
4590 char *format2
= " [-%c";
4593 /* print all mandatory switches that are without argument values */
4595 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4598 /* skip optional options */
4599 if (table
[tabindex
]->mincount
< 1)
4602 /* skip non-short options */
4603 if (table
[tabindex
]->shortopts
== NULL
)
4606 /* skip options that take argument values */
4607 if (table
[tabindex
]->flag
& ARG_HASVALUE
)
4610 /* print the short option (only the first short option char, ignore multiple choices)*/
4611 fprintf(fp
, format1
, table
[tabindex
]->shortopts
[0]);
4616 /* print all optional switches that are without argument values */
4618 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4621 /* skip mandatory args */
4622 if (table
[tabindex
]->mincount
> 0)
4625 /* skip args without short options */
4626 if (table
[tabindex
]->shortopts
== NULL
)
4629 /* skip args with values */
4630 if (table
[tabindex
]->flag
& ARG_HASVALUE
)
4633 /* print first short option */
4634 fprintf(fp
, format2
, table
[tabindex
]->shortopts
[0]);
4639 fprintf(fp
, "%s", suffix
);
4643 void arg_print_syntax(FILE *fp
, void * *argtable
, const char *suffix
)
4645 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4648 /* print GNU style [OPTION] string */
4649 arg_print_gnuswitch(fp
, table
);
4651 /* print remaining options in abbreviated style */
4653 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4656 char syntax
[200] = "";
4657 const char *shortopts
, *longopts
, *datatype
;
4659 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4660 if (table
[tabindex
]->shortopts
&&
4661 !(table
[tabindex
]->flag
& ARG_HASVALUE
))
4664 shortopts
= table
[tabindex
]->shortopts
;
4665 longopts
= table
[tabindex
]->longopts
;
4666 datatype
= table
[tabindex
]->datatype
;
4667 arg_cat_option(syntax
,
4672 table
[tabindex
]->flag
& ARG_HASOPTVALUE
);
4674 if (strlen(syntax
) > 0)
4676 /* print mandatory instances of this option */
4677 for (i
= 0; i
< table
[tabindex
]->mincount
; i
++)
4678 fprintf(fp
, " %s", syntax
);
4680 /* print optional instances enclosed in "[..]" */
4681 switch ( table
[tabindex
]->maxcount
- table
[tabindex
]->mincount
)
4686 fprintf(fp
, " [%s]", syntax
);
4689 fprintf(fp
, " [%s] [%s]", syntax
, syntax
);
4692 fprintf(fp
, " [%s]...", syntax
);
4699 fprintf(fp
, "%s", suffix
);
4703 void arg_print_syntaxv(FILE *fp
, void * *argtable
, const char *suffix
)
4705 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4708 /* print remaining options in abbreviated style */
4710 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4713 char syntax
[200] = "";
4714 const char *shortopts
, *longopts
, *datatype
;
4716 shortopts
= table
[tabindex
]->shortopts
;
4717 longopts
= table
[tabindex
]->longopts
;
4718 datatype
= table
[tabindex
]->datatype
;
4719 arg_cat_optionv(syntax
,
4724 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4727 /* print mandatory options */
4728 for (i
= 0; i
< table
[tabindex
]->mincount
; i
++)
4729 fprintf(fp
, " %s", syntax
);
4731 /* print optional args enclosed in "[..]" */
4732 switch ( table
[tabindex
]->maxcount
- table
[tabindex
]->mincount
)
4737 fprintf(fp
, " [%s]", syntax
);
4740 fprintf(fp
, " [%s] [%s]", syntax
, syntax
);
4743 fprintf(fp
, " [%s]...", syntax
);
4749 fprintf(fp
, "%s", suffix
);
4753 void arg_print_glossary(FILE *fp
, void * *argtable
, const char *format
)
4755 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4758 format
= format
? format
: " %-20s %s\n";
4759 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4761 if (table
[tabindex
]->glossary
)
4763 char syntax
[200] = "";
4764 const char *shortopts
= table
[tabindex
]->shortopts
;
4765 const char *longopts
= table
[tabindex
]->longopts
;
4766 const char *datatype
= table
[tabindex
]->datatype
;
4767 const char *glossary
= table
[tabindex
]->glossary
;
4768 arg_cat_optionv(syntax
,
4773 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4775 fprintf(fp
, format
, syntax
, glossary
);
4782 * Print a piece of text formatted, which means in a column with a
4783 * left and a right margin. The lines are wrapped at whitspaces next
4784 * to right margin. The function does not indent the first line, but
4785 * only the following ones.
4788 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4789 * will result in the following output:
4797 * Too long lines will be wrapped in the middle of a word.
4799 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4800 * will result in the following output:
4808 * As you see, the first line is not indented. This enables output of
4809 * lines, which start in a line where output already happened.
4811 * Author: Uli Fouquet
4814 void arg_print_formatted( FILE *fp
,
4815 const unsigned lmargin
,
4816 const unsigned rmargin
,
4819 const unsigned textlen
= (unsigned)strlen( text
);
4820 unsigned line_start
= 0;
4821 unsigned line_end
= textlen
+ 1;
4822 const unsigned colwidth
= (rmargin
- lmargin
) + 1;
4824 /* Someone doesn't like us... */
4825 if ( line_end
< line_start
)
4826 { fprintf( fp
, "%s\n", text
); }
4828 while (line_end
- 1 > line_start
)
4830 /* Eat leading whitespaces. This is essential because while
4831 wrapping lines, there will often be a whitespace at beginning
4833 while ( ISSPACE(*(text
+ line_start
)) )
4836 if ((line_end
- line_start
) > colwidth
)
4837 { line_end
= line_start
+ colwidth
; }
4839 /* Find last whitespace, that fits into line */
4840 while ( ( line_end
> line_start
)
4841 && ( line_end
- line_start
> colwidth
)
4842 && !ISSPACE(*(text
+ line_end
)))
4845 /* Do not print trailing whitespace. If this text
4846 has got only one line, line_end now points to the
4847 last char due to initialization. */
4850 /* Output line of text */
4851 while ( line_start
< line_end
)
4853 fputc(*(text
+ line_start
), fp
);
4858 /* Initialize another line */
4859 if ( line_end
+ 1 < textlen
)
4863 for (i
= 0; i
< lmargin
; i
++ )
4864 { fputc( ' ', fp
); }
4869 /* If we have to print another line, get also the last char. */
4872 } /* lines of text */
4876 * Prints the glossary in strict GNU format.
4877 * Differences to arg_print_glossary() are:
4878 * - wraps lines after 80 chars
4879 * - indents lines without shortops
4880 * - does not accept formatstrings
4882 * Contributed by Uli Fouquet
4884 void arg_print_glossary_gnu(FILE *fp
, void * *argtable
)
4886 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4889 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4891 if (table
[tabindex
]->glossary
)
4893 char syntax
[200] = "";
4894 const char *shortopts
= table
[tabindex
]->shortopts
;
4895 const char *longopts
= table
[tabindex
]->longopts
;
4896 const char *datatype
= table
[tabindex
]->datatype
;
4897 const char *glossary
= table
[tabindex
]->glossary
;
4899 if ( !shortopts
&& longopts
)
4901 /* Indent trailing line by 4 spaces... */
4902 memset( syntax
, ' ', 4 );
4903 *(syntax
+ 4) = '\0';
4906 arg_cat_optionv(syntax
,
4911 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4914 /* If syntax fits not into column, print glossary in new line... */
4915 if ( strlen(syntax
) > 25 )
4917 fprintf( fp
, " %-25s %s\n", syntax
, "" );
4921 fprintf( fp
, " %-25s ", syntax
);
4922 arg_print_formatted( fp
, 28, 79, glossary
);
4924 } /* for each table entry */
4931 * Checks the argtable[] array for NULL entries and returns 1
4932 * if any are found, zero otherwise.
4934 int arg_nullcheck(void * *argtable
)
4936 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4938 /*printf("arg_nullcheck(%p)\n",argtable);*/
4946 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4947 if (!table
[tabindex
])
4949 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4956 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4957 * The flaw results in memory leak in the (very rare) case that an intermediate
4958 * entry in the argtable array failed its memory allocation while others following
4959 * that entry were still allocated ok. Those subsequent allocations will not be
4960 * deallocated by arg_free().
4961 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4962 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4963 * with the newer arg_freetable() function.
4964 * We still keep arg_free() for backwards compatibility.
4966 void arg_free(void * *argtable
)
4968 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4971 /*printf("arg_free(%p)\n",argtable);*/
4975 if we encounter a NULL entry then somewhat incorrectly we presume
4976 we have come to the end of the array. It isnt strictly true because
4977 an intermediate entry could be NULL with other non-NULL entries to follow.
4978 The subsequent argtable entries would then not be freed as they should.
4980 if (table
[tabindex
] == NULL
)
4983 flag
= table
[tabindex
]->flag
;
4984 free(table
[tabindex
]);
4985 table
[tabindex
++] = NULL
;
4987 } while(!(flag
& ARG_TERMINATOR
));
4990 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4991 void arg_freetable(void * *argtable
, size_t n
)
4993 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4994 size_t tabindex
= 0;
4995 /*printf("arg_freetable(%p)\n",argtable);*/
4996 for (tabindex
= 0; tabindex
< n
; tabindex
++)
4998 if (table
[tabindex
] == NULL
)
5001 free(table
[tabindex
]);
5002 table
[tabindex
] = NULL
;