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 #if defined(_MSC_VER)
393 #pragma warning(suppress: 6053)
395 fprintf(stderr
, "%s\n", opterrmsg
);
404 * Compute the greatest common divisor of a and b.
422 * Exchange the block from nonopt_start to nonopt_end with the block
423 * from nonopt_end to opt_end (keeping the same order of arguments
427 permute_args(int panonopt_start
, int panonopt_end
, int opt_end
,
430 int cstart
, cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
, pos
;
434 * compute lengths of blocks and number and size of cycles
436 nnonopts
= panonopt_end
- panonopt_start
;
437 nopts
= opt_end
- panonopt_end
;
438 ncycle
= gcd(nnonopts
, nopts
);
439 cyclelen
= (opt_end
- panonopt_start
) / ncycle
;
441 for (i
= 0; i
< ncycle
; i
++) {
442 cstart
= panonopt_end
+i
;
444 for (j
= 0; j
< cyclelen
; j
++) {
445 if (pos
>= panonopt_end
)
450 /* LINTED const cast */
451 ((char **) nargv
)[pos
] = nargv
[cstart
];
452 /* LINTED const cast */
453 ((char **)nargv
)[cstart
] = swap
;
459 * parse_long_options --
460 * Parse long options in argc/argv argument vector.
461 * Returns -1 if short_too is set and the option does not match long_options.
464 parse_long_options(char * const *nargv
, const char *options
,
465 const struct option
*long_options
, int *idx
, int short_too
)
467 char *current_argv
, *has_equal
;
468 size_t current_argv_len
;
471 current_argv
= place
;
476 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
477 /* argument found (--option=arg) */
478 current_argv_len
= has_equal
- current_argv
;
481 current_argv_len
= strlen(current_argv
);
483 for (i
= 0; long_options
[i
].name
; i
++) {
484 /* find matching long option */
485 if (strncmp(current_argv
, long_options
[i
].name
,
489 if (strlen(long_options
[i
].name
) == current_argv_len
) {
495 * If this is a known short option, don't allow
496 * a partial match of a single character.
498 if (short_too
&& current_argv_len
== 1)
501 if (match
== -1) /* partial match */
504 /* ambiguous abbreviation */
506 warnx(ambig
, (int)current_argv_len
,
512 if (match
!= -1) { /* option found */
513 if (long_options
[match
].has_arg
== no_argument
516 warnx(noarg
, (int)current_argv_len
,
519 * XXX: GNU sets optopt to val regardless of flag
521 if (long_options
[match
].flag
== NULL
)
522 optopt
= long_options
[match
].val
;
527 if (long_options
[match
].has_arg
== required_argument
||
528 long_options
[match
].has_arg
== optional_argument
) {
531 else if (long_options
[match
].has_arg
==
534 * optional argument doesn't use next nargv
536 optarg
= nargv
[optind
++];
539 if ((long_options
[match
].has_arg
== required_argument
)
540 && (optarg
== NULL
)) {
542 * Missing argument; leading ':' indicates no error
543 * should be generated.
549 * XXX: GNU sets optopt to val regardless of flag
551 if (long_options
[match
].flag
== NULL
)
552 optopt
= long_options
[match
].val
;
558 } else { /* unknown option */
564 warnx(illoptstring
, current_argv
);
570 if (long_options
[match
].flag
) {
571 *long_options
[match
].flag
= long_options
[match
].val
;
574 return (long_options
[match
].val
);
579 * Parse argc/argv argument vector. Called by user level routines.
582 getopt_internal(int nargc
, char * const *nargv
, const char *options
,
583 const struct option
*long_options
, int *idx
, int flags
)
585 char *oli
; /* option letter list index */
586 int optchar
, short_too
;
587 static int posixly_correct
= -1;
588 #ifdef __STDC_WANT_SECURE_LIB__
590 size_t buffer_size
= 0;
598 * Disable GNU extensions if POSIXLY_CORRECT is set or options
599 * string begins with a '+'.
602 #ifdef __STDC_WANT_SECURE_LIB__
603 if (posixly_correct
== -1) {
604 err
= _dupenv_s(&buffer
, &buffer_size
, "POSIXLY_CORRECT") == 0;
605 posixly_correct
= buffer
!= NULL
;
606 if(buffer
!= NULL
&& err
== 0) {
611 if (posixly_correct
== -1)
612 posixly_correct
= (getenv("POSIXLY_CORRECT") != NULL
);
614 if (posixly_correct
|| *options
== '+')
615 flags
&= ~FLAG_PERMUTE
;
616 else if (*options
== '-')
617 flags
|= FLAG_ALLARGS
;
618 if (*options
== '+' || *options
== '-')
622 * XXX Some GNU programs (like cvs) set optind to 0 instead of
623 * XXX using optreset. Work around this braindamage.
626 optind
= optreset
= 1;
630 nonopt_start
= nonopt_end
= -1;
632 if (optreset
|| !*place
) { /* update scanning pointer */
634 if (optind
>= nargc
) { /* end of argument vector */
636 if (nonopt_end
!= -1) {
637 /* do permutation, if we have to */
638 permute_args(nonopt_start
, nonopt_end
,
640 optind
-= nonopt_end
- nonopt_start
;
642 else if (nonopt_start
!= -1) {
644 * If we skipped non-options, set optind
645 * to the first of them.
647 optind
= nonopt_start
;
649 nonopt_start
= nonopt_end
= -1;
652 if (*(place
= nargv
[optind
]) != '-' ||
653 (place
[1] == '\0' && strchr(options
, '-') == NULL
)) {
654 place
= EMSG
; /* found non-option */
655 if (flags
& FLAG_ALLARGS
) {
658 * return non-option as argument to option 1
660 optarg
= nargv
[optind
++];
663 if (!(flags
& FLAG_PERMUTE
)) {
665 * If no permutation wanted, stop parsing
666 * at first non-option.
671 if (nonopt_start
== -1)
672 nonopt_start
= optind
;
673 else if (nonopt_end
!= -1) {
674 permute_args(nonopt_start
, nonopt_end
,
676 nonopt_start
= optind
-
677 (nonopt_end
- nonopt_start
);
681 /* process next argument */
684 if (nonopt_start
!= -1 && nonopt_end
== -1)
688 * If we have "-" do nothing, if "--" we are done.
690 if (place
[1] != '\0' && *++place
== '-' && place
[1] == '\0') {
694 * We found an option (--), so if we skipped
695 * non-options, we have to permute.
697 if (nonopt_end
!= -1) {
698 permute_args(nonopt_start
, nonopt_end
,
700 optind
-= nonopt_end
- nonopt_start
;
702 nonopt_start
= nonopt_end
= -1;
708 * Check long options if:
709 * 1) we were passed some
710 * 2) the arg is not just "-"
711 * 3) either the arg starts with -- we are getopt_long_only()
713 if (long_options
!= NULL
&& place
!= nargv
[optind
] &&
714 (*place
== '-' || (flags
& FLAG_LONGONLY
))) {
717 place
++; /* --foo long option */
718 else if (*place
!= ':' && strchr(options
, *place
) != NULL
)
719 short_too
= 1; /* could be short option too */
721 optchar
= parse_long_options(nargv
, options
, long_options
,
729 if ((optchar
= (int)*place
++) == (int)':' ||
730 (optchar
== (int)'-' && *place
!= '\0') ||
731 (oli
= strchr(options
, optchar
)) == NULL
) {
733 * If the user specified "-" and '-' isn't listed in
734 * options, return -1 (non-option) as per POSIX.
735 * Otherwise, it is an unknown option character (or ':').
737 if (optchar
== (int)'-' && *place
== '\0')
742 warnx(illoptchar
, optchar
);
746 if (long_options
!= NULL
&& optchar
== 'W' && oli
[1] == ';') {
748 if (*place
) /* no space */
750 else if (++optind
>= nargc
) { /* no arg */
753 warnx(recargchar
, optchar
);
756 } else /* white space */
757 place
= nargv
[optind
];
758 optchar
= parse_long_options(nargv
, options
, long_options
,
763 if (*++oli
!= ':') { /* doesn't take argument */
766 } else { /* takes (optional) argument */
768 if (*place
) /* no white space */
770 else if (oli
[1] != ':') { /* arg not optional */
771 if (++optind
>= nargc
) { /* no arg */
774 warnx(recargchar
, optchar
);
778 optarg
= nargv
[optind
];
783 /* dump back option letter */
787 #ifdef REPLACE_GETOPT
790 * Parse argc/argv argument vector.
792 * [eventually this will replace the BSD getopt]
795 getopt(int nargc
, char * const *nargv
, const char *options
)
799 * We don't pass FLAG_PERMUTE to getopt_internal() since
800 * the BSD getopt(3) (unlike GNU) has never done this.
802 * Furthermore, since many privileged programs call getopt()
803 * before dropping privileges it makes sense to keep things
804 * as simple (and bug-free) as possible.
806 return (getopt_internal(nargc
, nargv
, options
, NULL
, NULL
, 0));
808 #endif /* REPLACE_GETOPT */
812 * Parse argc/argv argument vector.
815 getopt_long(int nargc
, char * const *nargv
, const char *options
,
816 const struct option
*long_options
, int *idx
)
819 return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
,
824 * getopt_long_only --
825 * Parse argc/argv argument vector.
828 getopt_long_only(int nargc
, char * const *nargv
, const char *options
,
829 const struct option
*long_options
, int *idx
)
832 return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
,
833 FLAG_PERMUTE
|FLAG_LONGONLY
));
835 /*******************************************************************************
836 * This file is part of the argtable3 library.
838 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
839 * <sheitmann@users.sourceforge.net>
840 * All rights reserved.
842 * Redistribution and use in source and binary forms, with or without
843 * modification, are permitted provided that the following conditions are met:
844 * * Redistributions of source code must retain the above copyright
845 * notice, this list of conditions and the following disclaimer.
846 * * Redistributions in binary form must reproduce the above copyright
847 * notice, this list of conditions and the following disclaimer in the
848 * documentation and/or other materials provided with the distribution.
849 * * Neither the name of STEWART HEITMANN nor the names of its contributors
850 * may be used to endorse or promote products derived from this software
851 * without specific prior written permission.
853 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
854 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
855 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
856 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
857 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
858 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
859 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
860 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
861 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
862 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
863 ******************************************************************************/
868 #include "argtable3.h"
871 char * arg_strptime(const char *buf
, const char *fmt
, struct tm
*tm
);
874 static void arg_date_resetfn(struct arg_date
*parent
)
876 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
881 static int arg_date_scanfn(struct arg_date
*parent
, const char *argval
)
885 if (parent
->count
== parent
->hdr
.maxcount
)
887 errorcode
= EMAXCOUNT
;
891 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
897 struct tm tm
= parent
->tmval
[parent
->count
];
899 /* parse the given argument value, store result in parent->tmval[] */
900 pend
= arg_strptime(argval
, parent
->format
, &tm
);
901 if (pend
&& pend
[0] == '\0')
902 parent
->tmval
[parent
->count
++] = tm
;
904 errorcode
= EBADDATE
;
907 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
912 static int arg_date_checkfn(struct arg_date
*parent
)
914 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
916 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
921 static void arg_date_errorfn(
922 struct arg_date
*parent
,
926 const char *progname
)
928 const char *shortopts
= parent
->hdr
.shortopts
;
929 const char *longopts
= parent
->hdr
.longopts
;
930 const char *datatype
= parent
->hdr
.datatype
;
932 /* make argval NULL safe */
933 argval
= argval
? argval
: "";
935 fprintf(fp
, "%s: ", progname
);
939 fputs("missing option ", fp
);
940 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
944 fputs("excess option ", fp
);
945 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
953 fprintf(fp
, "illegal timestamp format \"%s\"\n", argval
);
954 memset(&tm
, 0, sizeof(tm
));
955 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm
);
956 strftime(buff
, sizeof(buff
), parent
->format
, &tm
);
957 printf("correct format is \"%s\"\n", buff
);
964 struct arg_date
* arg_date0(
965 const char * shortopts
,
966 const char * longopts
,
968 const char *datatype
,
969 const char *glossary
)
971 return arg_daten(shortopts
, longopts
, format
, datatype
, 0, 1, glossary
);
975 struct arg_date
* arg_date1(
976 const char * shortopts
,
977 const char * longopts
,
979 const char *datatype
,
980 const char *glossary
)
982 return arg_daten(shortopts
, longopts
, format
, datatype
, 1, 1, glossary
);
986 struct arg_date
* arg_daten(
987 const char * shortopts
,
988 const char * longopts
,
990 const char *datatype
,
993 const char *glossary
)
996 struct arg_date
*result
;
998 /* foolproof things by ensuring maxcount is not less than mincount */
999 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
1001 /* default time format is the national date format for the locale */
1005 nbytes
= sizeof(struct arg_date
) /* storage for struct arg_date */
1006 + maxcount
* sizeof(struct tm
); /* storage for tmval[maxcount] array */
1008 /* allocate storage for the arg_date struct + tmval[] array. */
1009 /* we use calloc because we want the tmval[] array zero filled. */
1010 result
= (struct arg_date
*)calloc(1, nbytes
);
1013 /* init the arg_hdr struct */
1014 result
->hdr
.flag
= ARG_HASVALUE
;
1015 result
->hdr
.shortopts
= shortopts
;
1016 result
->hdr
.longopts
= longopts
;
1017 result
->hdr
.datatype
= datatype
? datatype
: format
;
1018 result
->hdr
.glossary
= glossary
;
1019 result
->hdr
.mincount
= mincount
;
1020 result
->hdr
.maxcount
= maxcount
;
1021 result
->hdr
.parent
= result
;
1022 result
->hdr
.resetfn
= (arg_resetfn
*)arg_date_resetfn
;
1023 result
->hdr
.scanfn
= (arg_scanfn
*)arg_date_scanfn
;
1024 result
->hdr
.checkfn
= (arg_checkfn
*)arg_date_checkfn
;
1025 result
->hdr
.errorfn
= (arg_errorfn
*)arg_date_errorfn
;
1027 /* store the tmval[maxcount] array immediately after the arg_date struct */
1028 result
->tmval
= (struct tm
*)(result
+ 1);
1030 /* init the remaining arg_date member variables */
1032 result
->format
= format
;
1035 ARG_TRACE(("arg_daten() returns %p\n", result
));
1041 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1042 * All rights reserved.
1044 * This code was contributed to The NetBSD Foundation by Klaus Klein.
1045 * Heavily optimised by David Laight
1047 * Redistribution and use in source and binary forms, with or without
1048 * modification, are permitted provided that the following conditions
1050 * 1. Redistributions of source code must retain the above copyright
1051 * notice, this list of conditions and the following disclaimer.
1052 * 2. Redistributions in binary form must reproduce the above copyright
1053 * notice, this list of conditions and the following disclaimer in the
1054 * documentation and/or other materials provided with the distribution.
1056 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1057 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1058 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1059 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1060 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1061 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1062 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1063 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1064 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1065 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1066 * POSSIBILITY OF SUCH DAMAGE.
1074 * We do not implement alternate representations. However, we always
1075 * check whether a given modifier is allowed for a certain conversion.
1079 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
1080 #define TM_YEAR_BASE (1900)
1082 static int conv_num(const char * *, int *, int, int);
1084 static const char *day
[7] = {
1085 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
1086 "Friday", "Saturday"
1089 static const char *abday
[7] = {
1090 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1093 static const char *mon
[12] = {
1094 "January", "February", "March", "April", "May", "June", "July",
1095 "August", "September", "October", "November", "December"
1098 static const char *abmon
[12] = {
1099 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1100 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1103 static const char *am_pm
[2] = {
1108 static int arg_strcasecmp(const char *s1
, const char *s2
)
1110 const unsigned char *us1
= (const unsigned char *)s1
;
1111 const unsigned char *us2
= (const unsigned char *)s2
;
1112 while (tolower(*us1
) == tolower(*us2
++))
1116 return tolower(*us1
) - tolower(*--us2
);
1120 static int arg_strncasecmp(const char *s1
, const char *s2
, size_t n
)
1124 const unsigned char *us1
= (const unsigned char *)s1
;
1125 const unsigned char *us2
= (const unsigned char *)s2
;
1128 if (tolower(*us1
) != tolower(*us2
++))
1129 return tolower(*us1
) - tolower(*--us2
);
1140 char * arg_strptime(const char *buf
, const char *fmt
, struct tm
*tm
)
1145 int alt_format
, i
, split_year
= 0;
1149 while ((c
= *fmt
) != '\0') {
1150 /* Clear `alternate' modifier prior to new conversion. */
1153 /* Eat up white-space. */
1155 while (ISSPACE(*bp
))
1162 if ((c
= *fmt
++) != '%')
1169 case '%': /* "%%" is converted to "%". */
1176 * "Alternative" modifiers. Just set the appropriate flag
1177 * and start over again.
1179 case 'E': /* "%E?" alternative conversion modifier. */
1181 alt_format
|= ALT_E
;
1184 case 'O': /* "%O?" alternative conversion modifier. */
1186 alt_format
|= ALT_O
;
1190 * "Complex" conversion rules, implemented through recursion.
1192 case 'c': /* Date and time, using the locale's format. */
1194 bp
= arg_strptime(bp
, "%x %X", tm
);
1199 case 'D': /* The date as "%m/%d/%y". */
1201 bp
= arg_strptime(bp
, "%m/%d/%y", tm
);
1206 case 'R': /* The time as "%H:%M". */
1208 bp
= arg_strptime(bp
, "%H:%M", tm
);
1213 case 'r': /* The time in 12-hour clock representation. */
1215 bp
= arg_strptime(bp
, "%I:%M:%S %p", tm
);
1220 case 'T': /* The time as "%H:%M:%S". */
1222 bp
= arg_strptime(bp
, "%H:%M:%S", tm
);
1227 case 'X': /* The time, using the locale's format. */
1229 bp
= arg_strptime(bp
, "%H:%M:%S", tm
);
1234 case 'x': /* The date, using the locale's format. */
1236 bp
= arg_strptime(bp
, "%m/%d/%y", tm
);
1242 * "Elementary" conversion rules.
1244 case 'A': /* The day of week, using the locale's form. */
1247 for (i
= 0; i
< 7; i
++) {
1249 len
= strlen(day
[i
]);
1250 if (arg_strncasecmp(day
[i
], bp
, len
) == 0)
1253 /* Abbreviated name. */
1254 len
= strlen(abday
[i
]);
1255 if (arg_strncasecmp(abday
[i
], bp
, len
) == 0)
1259 /* Nothing matched. */
1267 case 'B': /* The month, using the locale's form. */
1271 for (i
= 0; i
< 12; i
++) {
1273 len
= strlen(mon
[i
]);
1274 if (arg_strncasecmp(mon
[i
], bp
, len
) == 0)
1277 /* Abbreviated name. */
1278 len
= strlen(abmon
[i
]);
1279 if (arg_strncasecmp(abmon
[i
], bp
, len
) == 0)
1283 /* Nothing matched. */
1291 case 'C': /* The century number. */
1293 if (!(conv_num(&bp
, &i
, 0, 99)))
1297 tm
->tm_year
= (tm
->tm_year
% 100) + (i
* 100);
1299 tm
->tm_year
= i
* 100;
1304 case 'd': /* The day of month. */
1307 if (!(conv_num(&bp
, &tm
->tm_mday
, 1, 31)))
1311 case 'k': /* The hour (24-hour clock representation). */
1316 if (!(conv_num(&bp
, &tm
->tm_hour
, 0, 23)))
1320 case 'l': /* The hour (12-hour clock representation). */
1325 if (!(conv_num(&bp
, &tm
->tm_hour
, 1, 12)))
1327 if (tm
->tm_hour
== 12)
1331 case 'j': /* The day of year. */
1333 if (!(conv_num(&bp
, &i
, 1, 366)))
1335 tm
->tm_yday
= i
- 1;
1338 case 'M': /* The minute. */
1340 if (!(conv_num(&bp
, &tm
->tm_min
, 0, 59)))
1344 case 'm': /* The month. */
1346 if (!(conv_num(&bp
, &i
, 1, 12)))
1351 case 'p': /* The locale's equivalent of AM/PM. */
1354 if (arg_strcasecmp(am_pm
[0], bp
) == 0) {
1355 if (tm
->tm_hour
> 11)
1358 bp
+= strlen(am_pm
[0]);
1362 else if (arg_strcasecmp(am_pm
[1], bp
) == 0) {
1363 if (tm
->tm_hour
> 11)
1367 bp
+= strlen(am_pm
[1]);
1371 /* Nothing matched. */
1374 case 'S': /* The seconds. */
1376 if (!(conv_num(&bp
, &tm
->tm_sec
, 0, 61)))
1380 case 'U': /* The week of year, beginning on sunday. */
1381 case 'W': /* The week of year, beginning on monday. */
1384 * XXX This is bogus, as we can not assume any valid
1385 * information present in the tm structure at this
1386 * point to calculate a real value, so just check the
1389 if (!(conv_num(&bp
, &i
, 0, 53)))
1393 case 'w': /* The day of week, beginning on sunday. */
1395 if (!(conv_num(&bp
, &tm
->tm_wday
, 0, 6)))
1399 case 'Y': /* The year. */
1401 if (!(conv_num(&bp
, &i
, 0, 9999)))
1404 tm
->tm_year
= i
- TM_YEAR_BASE
;
1407 case 'y': /* The year within 100 years of the epoch. */
1408 LEGAL_ALT(ALT_E
| ALT_O
);
1409 if (!(conv_num(&bp
, &i
, 0, 99)))
1413 tm
->tm_year
= ((tm
->tm_year
/ 100) * 100) + i
;
1418 tm
->tm_year
= i
+ 2000 - TM_YEAR_BASE
;
1420 tm
->tm_year
= i
+ 1900 - TM_YEAR_BASE
;
1424 * Miscellaneous conversions.
1426 case 'n': /* Any kind of white-space. */
1429 while (ISSPACE(*bp
))
1434 default: /* Unknown/unsupported conversion. */
1441 /* LINTED functional specification */
1442 return ((char *)bp
);
1446 static int conv_num(const char * *buf
, int *dest
, int llim
, int ulim
)
1450 /* The limit also determines the number of valid digits. */
1453 if (**buf
< '0' || **buf
> '9')
1458 result
+= *(*buf
)++ - '0';
1460 } while ((result
* 10 <= ulim
) && rulim
&& **buf
>= '0' && **buf
<= '9');
1462 if (result
< llim
|| result
> ulim
)
1468 /*******************************************************************************
1469 * This file is part of the argtable3 library.
1471 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1472 * <sheitmann@users.sourceforge.net>
1473 * All rights reserved.
1475 * Redistribution and use in source and binary forms, with or without
1476 * modification, are permitted provided that the following conditions are met:
1477 * * Redistributions of source code must retain the above copyright
1478 * notice, this list of conditions and the following disclaimer.
1479 * * Redistributions in binary form must reproduce the above copyright
1480 * notice, this list of conditions and the following disclaimer in the
1481 * documentation and/or other materials provided with the distribution.
1482 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1483 * may be used to endorse or promote products derived from this software
1484 * without specific prior written permission.
1486 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1487 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1488 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1489 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1490 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1491 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1492 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1493 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1494 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1495 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1496 ******************************************************************************/
1500 #include "argtable3.h"
1503 static void arg_dbl_resetfn(struct arg_dbl
*parent
)
1505 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1510 static int arg_dbl_scanfn(struct arg_dbl
*parent
, const char *argval
)
1514 if (parent
->count
== parent
->hdr
.maxcount
)
1516 /* maximum number of arguments exceeded */
1517 errorcode
= EMAXCOUNT
;
1521 /* a valid argument with no argument value was given. */
1522 /* This happens when an optional argument value was invoked. */
1523 /* leave parent argument value unaltered but still count the argument. */
1531 /* extract double from argval into val */
1532 val
= strtod(argval
, &end
);
1534 /* if success then store result in parent->dval[] array otherwise return error*/
1536 parent
->dval
[parent
->count
++] = val
;
1538 errorcode
= EBADDOUBLE
;
1541 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1546 static int arg_dbl_checkfn(struct arg_dbl
*parent
)
1548 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
1550 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1555 static void arg_dbl_errorfn(
1556 struct arg_dbl
*parent
,
1560 const char *progname
)
1562 const char *shortopts
= parent
->hdr
.shortopts
;
1563 const char *longopts
= parent
->hdr
.longopts
;
1564 const char *datatype
= parent
->hdr
.datatype
;
1566 /* make argval NULL safe */
1567 argval
= argval
? argval
: "";
1569 fprintf(fp
, "%s: ", progname
);
1573 fputs("missing option ", fp
);
1574 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1578 fputs("excess option ", fp
);
1579 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
1583 fprintf(fp
, "invalid argument \"%s\" to option ", argval
);
1584 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1590 struct arg_dbl
* arg_dbl0(
1591 const char * shortopts
,
1592 const char * longopts
,
1593 const char *datatype
,
1594 const char *glossary
)
1596 return arg_dbln(shortopts
, longopts
, datatype
, 0, 1, glossary
);
1600 struct arg_dbl
* arg_dbl1(
1601 const char * shortopts
,
1602 const char * longopts
,
1603 const char *datatype
,
1604 const char *glossary
)
1606 return arg_dbln(shortopts
, longopts
, datatype
, 1, 1, glossary
);
1610 struct arg_dbl
* arg_dbln(
1611 const char * shortopts
,
1612 const char * longopts
,
1613 const char *datatype
,
1616 const char *glossary
)
1619 struct arg_dbl
*result
;
1621 /* foolproof things by ensuring maxcount is not less than mincount */
1622 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
1624 nbytes
= sizeof(struct arg_dbl
) /* storage for struct arg_dbl */
1625 + (maxcount
+ 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1627 result
= (struct arg_dbl
*)malloc(nbytes
);
1633 /* init the arg_hdr struct */
1634 result
->hdr
.flag
= ARG_HASVALUE
;
1635 result
->hdr
.shortopts
= shortopts
;
1636 result
->hdr
.longopts
= longopts
;
1637 result
->hdr
.datatype
= datatype
? datatype
: "<double>";
1638 result
->hdr
.glossary
= glossary
;
1639 result
->hdr
.mincount
= mincount
;
1640 result
->hdr
.maxcount
= maxcount
;
1641 result
->hdr
.parent
= result
;
1642 result
->hdr
.resetfn
= (arg_resetfn
*)arg_dbl_resetfn
;
1643 result
->hdr
.scanfn
= (arg_scanfn
*)arg_dbl_scanfn
;
1644 result
->hdr
.checkfn
= (arg_checkfn
*)arg_dbl_checkfn
;
1645 result
->hdr
.errorfn
= (arg_errorfn
*)arg_dbl_errorfn
;
1647 /* Store the dval[maxcount] array on the first double boundary that
1648 * immediately follows the arg_dbl struct. We do the memory alignment
1649 * purely for SPARC and Motorola systems. They require floats and
1650 * doubles to be aligned on natural boundaries.
1652 addr
= (size_t)(result
+ 1);
1653 rem
= addr
% sizeof(double);
1654 result
->dval
= (double *)(addr
+ sizeof(double) - rem
);
1655 ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr
, result
->dval
, (int)sizeof(double), (int)rem
));
1660 ARG_TRACE(("arg_dbln() returns %p\n", result
));
1663 /*******************************************************************************
1664 * This file is part of the argtable3 library.
1666 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1667 * <sheitmann@users.sourceforge.net>
1668 * All rights reserved.
1670 * Redistribution and use in source and binary forms, with or without
1671 * modification, are permitted provided that the following conditions are met:
1672 * * Redistributions of source code must retain the above copyright
1673 * notice, this list of conditions and the following disclaimer.
1674 * * Redistributions in binary form must reproduce the above copyright
1675 * notice, this list of conditions and the following disclaimer in the
1676 * documentation and/or other materials provided with the distribution.
1677 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1678 * may be used to endorse or promote products derived from this software
1679 * without specific prior written permission.
1681 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1682 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1683 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1684 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1685 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1686 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1687 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1688 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1689 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1690 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1691 ******************************************************************************/
1695 #include "argtable3.h"
1698 static void arg_end_resetfn(struct arg_end
*parent
)
1700 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1704 static void arg_end_errorfn(
1709 const char *progname
)
1711 /* suppress unreferenced formal parameter warning */
1714 progname
= progname
? progname
: "";
1715 argval
= argval
? argval
: "";
1717 fprintf(fp
, "%s: ", progname
);
1721 fputs("too many errors to display", fp
);
1724 fputs("insufficent memory", fp
);
1727 fprintf(fp
, "unexpected argument \"%s\"", argval
);
1730 fprintf(fp
, "option \"%s\" requires an argument", argval
);
1733 fprintf(fp
, "invalid option \"%s\"", argval
);
1736 fprintf(fp
, "invalid option \"-%c\"", error
);
1744 struct arg_end
* arg_end(int maxcount
)
1747 struct arg_end
*result
;
1749 nbytes
= sizeof(struct arg_end
)
1750 + maxcount
* sizeof(int) /* storage for int error[maxcount] array*/
1751 + maxcount
* sizeof(void *) /* storage for void* parent[maxcount] array */
1752 + maxcount
* sizeof(char *); /* storage for char* argval[maxcount] array */
1754 result
= (struct arg_end
*)malloc(nbytes
);
1757 /* init the arg_hdr struct */
1758 result
->hdr
.flag
= ARG_TERMINATOR
;
1759 result
->hdr
.shortopts
= NULL
;
1760 result
->hdr
.longopts
= NULL
;
1761 result
->hdr
.datatype
= NULL
;
1762 result
->hdr
.glossary
= NULL
;
1763 result
->hdr
.mincount
= 1;
1764 result
->hdr
.maxcount
= maxcount
;
1765 result
->hdr
.parent
= result
;
1766 result
->hdr
.resetfn
= (arg_resetfn
*)arg_end_resetfn
;
1767 result
->hdr
.scanfn
= NULL
;
1768 result
->hdr
.checkfn
= NULL
;
1769 result
->hdr
.errorfn
= (arg_errorfn
*)arg_end_errorfn
;
1771 /* store error[maxcount] array immediately after struct arg_end */
1772 result
->error
= (int *)(result
+ 1);
1774 /* store parent[maxcount] array immediately after error[] array */
1775 result
->parent
= (void * *)(result
->error
+ maxcount
);
1777 /* store argval[maxcount] array immediately after parent[] array */
1778 result
->argval
= (const char * *)(result
->parent
+ maxcount
);
1781 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount
, result
));
1786 void arg_print_errors(FILE * fp
, struct arg_end
* end
, const char * progname
)
1789 ARG_TRACE(("arg_errors()\n"));
1790 for (i
= 0; i
< end
->count
; i
++)
1792 struct arg_hdr
*errorparent
= (struct arg_hdr
*)(end
->parent
[i
]);
1793 if (errorparent
->errorfn
)
1794 errorparent
->errorfn(end
->parent
[i
],
1801 /*******************************************************************************
1802 * This file is part of the argtable3 library.
1804 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1805 * <sheitmann@users.sourceforge.net>
1806 * All rights reserved.
1808 * Redistribution and use in source and binary forms, with or without
1809 * modification, are permitted provided that the following conditions are met:
1810 * * Redistributions of source code must retain the above copyright
1811 * notice, this list of conditions and the following disclaimer.
1812 * * Redistributions in binary form must reproduce the above copyright
1813 * notice, this list of conditions and the following disclaimer in the
1814 * documentation and/or other materials provided with the distribution.
1815 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1816 * may be used to endorse or promote products derived from this software
1817 * without specific prior written permission.
1819 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1820 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1821 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1822 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1823 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1824 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1825 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1826 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1827 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1828 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1829 ******************************************************************************/
1834 #include "argtable3.h"
1837 # define FILESEPARATOR1 '\\'
1838 # define FILESEPARATOR2 '/'
1840 # define FILESEPARATOR1 '/'
1841 # define FILESEPARATOR2 '/'
1845 static void arg_file_resetfn(struct arg_file
*parent
)
1847 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
1852 /* Returns ptr to the base filename within *filename */
1853 static const char * arg_basename(const char *filename
)
1855 const char *result
= NULL
, *result1
, *result2
;
1857 /* Find the last occurrence of eother file separator character. */
1858 /* Two alternative file separator chars are supported as legal */
1859 /* file separators but not both together in the same filename. */
1860 result1
= (filename
? strrchr(filename
, FILESEPARATOR1
) : NULL
);
1861 result2
= (filename
? strrchr(filename
, FILESEPARATOR2
) : NULL
);
1864 result
= result2
+ 1; /* using FILESEPARATOR2 (the alternative file separator) */
1867 result
= result1
+ 1; /* using FILESEPARATOR1 (the preferred file separator) */
1870 result
= filename
; /* neither file separator was found so basename is the whole filename */
1872 /* special cases of "." and ".." are not considered basenames */
1873 if (result
&& ( strcmp(".", result
) == 0 || strcmp("..", result
) == 0 ))
1874 result
= filename
+ strlen(filename
);
1880 /* Returns ptr to the file extension within *basename */
1881 static const char * arg_extension(const char *basename
)
1883 /* find the last occurrence of '.' in basename */
1884 const char *result
= (basename
? strrchr(basename
, '.') : NULL
);
1886 /* if no '.' was found then return pointer to end of basename */
1887 if (basename
&& !result
)
1888 result
= basename
+ strlen(basename
);
1890 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1891 if (basename
&& result
== basename
)
1892 result
= basename
+ strlen(basename
);
1894 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1895 if (basename
&& result
&& result
[1] == '\0')
1896 result
= basename
+ strlen(basename
);
1902 static int arg_file_scanfn(struct arg_file
*parent
, const char *argval
)
1906 if (parent
->count
== parent
->hdr
.maxcount
)
1908 /* maximum number of arguments exceeded */
1909 errorcode
= EMAXCOUNT
;
1913 /* a valid argument with no argument value was given. */
1914 /* This happens when an optional argument value was invoked. */
1915 /* leave parent arguiment value unaltered but still count the argument. */
1920 parent
->filename
[parent
->count
] = argval
;
1921 parent
->basename
[parent
->count
] = arg_basename(argval
);
1922 parent
->extension
[parent
->count
] =
1923 arg_extension(parent
->basename
[parent
->count
]); /* only seek extensions within the basename (not the file path)*/
1927 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1932 static int arg_file_checkfn(struct arg_file
*parent
)
1934 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
1936 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
1941 static void arg_file_errorfn(
1942 struct arg_file
*parent
,
1946 const char *progname
)
1948 const char *shortopts
= parent
->hdr
.shortopts
;
1949 const char *longopts
= parent
->hdr
.longopts
;
1950 const char *datatype
= parent
->hdr
.datatype
;
1952 /* make argval NULL safe */
1953 argval
= argval
? argval
: "";
1955 fprintf(fp
, "%s: ", progname
);
1959 fputs("missing option ", fp
);
1960 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
1964 fputs("excess option ", fp
);
1965 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
1969 fprintf(fp
, "unknown error at \"%s\"\n", argval
);
1974 struct arg_file
* arg_file0(
1975 const char * shortopts
,
1976 const char * longopts
,
1977 const char *datatype
,
1978 const char *glossary
)
1980 return arg_filen(shortopts
, longopts
, datatype
, 0, 1, glossary
);
1984 struct arg_file
* arg_file1(
1985 const char * shortopts
,
1986 const char * longopts
,
1987 const char *datatype
,
1988 const char *glossary
)
1990 return arg_filen(shortopts
, longopts
, datatype
, 1, 1, glossary
);
1994 struct arg_file
* arg_filen(
1995 const char * shortopts
,
1996 const char * longopts
,
1997 const char *datatype
,
2000 const char *glossary
)
2003 struct arg_file
*result
;
2005 /* foolproof things by ensuring maxcount is not less than mincount */
2006 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2008 nbytes
= sizeof(struct arg_file
) /* storage for struct arg_file */
2009 + sizeof(char *) * maxcount
/* storage for filename[maxcount] array */
2010 + sizeof(char *) * maxcount
/* storage for basename[maxcount] array */
2011 + sizeof(char *) * maxcount
; /* storage for extension[maxcount] array */
2013 result
= (struct arg_file
*)malloc(nbytes
);
2018 /* init the arg_hdr struct */
2019 result
->hdr
.flag
= ARG_HASVALUE
;
2020 result
->hdr
.shortopts
= shortopts
;
2021 result
->hdr
.longopts
= longopts
;
2022 result
->hdr
.glossary
= glossary
;
2023 result
->hdr
.datatype
= datatype
? datatype
: "<file>";
2024 result
->hdr
.mincount
= mincount
;
2025 result
->hdr
.maxcount
= maxcount
;
2026 result
->hdr
.parent
= result
;
2027 result
->hdr
.resetfn
= (arg_resetfn
*)arg_file_resetfn
;
2028 result
->hdr
.scanfn
= (arg_scanfn
*)arg_file_scanfn
;
2029 result
->hdr
.checkfn
= (arg_checkfn
*)arg_file_checkfn
;
2030 result
->hdr
.errorfn
= (arg_errorfn
*)arg_file_errorfn
;
2032 /* store the filename,basename,extension arrays immediately after the arg_file struct */
2033 result
->filename
= (const char * *)(result
+ 1);
2034 result
->basename
= result
->filename
+ maxcount
;
2035 result
->extension
= result
->basename
+ maxcount
;
2038 /* foolproof the string pointers by initialising them with empty strings */
2039 for (i
= 0; i
< maxcount
; i
++)
2041 result
->filename
[i
] = "";
2042 result
->basename
[i
] = "";
2043 result
->extension
[i
] = "";
2047 ARG_TRACE(("arg_filen() returns %p\n", result
));
2050 /*******************************************************************************
2051 * This file is part of the argtable3 library.
2053 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2054 * <sheitmann@users.sourceforge.net>
2055 * All rights reserved.
2057 * Redistribution and use in source and binary forms, with or without
2058 * modification, are permitted provided that the following conditions are met:
2059 * * Redistributions of source code must retain the above copyright
2060 * notice, this list of conditions and the following disclaimer.
2061 * * Redistributions in binary form must reproduce the above copyright
2062 * notice, this list of conditions and the following disclaimer in the
2063 * documentation and/or other materials provided with the distribution.
2064 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2065 * may be used to endorse or promote products derived from this software
2066 * without specific prior written permission.
2068 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2069 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2070 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2071 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2072 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2073 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2074 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2075 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2076 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2077 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2078 ******************************************************************************/
2084 #include "argtable3.h"
2087 static void arg_int_resetfn(struct arg_int
*parent
)
2089 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2094 /* strtol0x() is like strtol() except that the numeric string is */
2095 /* expected to be prefixed by "0X" where X is a user supplied char. */
2096 /* The string may optionally be prefixed by white space and + or - */
2097 /* as in +0X123 or -0X123. */
2098 /* Once the prefix has been scanned, the remainder of the numeric */
2099 /* string is converted using strtol() with the given base. */
2100 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
2101 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
2102 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
2103 /* Failure of conversion is indicated by result where *endptr==str. */
2104 static long int strtol0X(const char * str
,
2105 const char * *endptr
,
2109 long int val
; /* stores result */
2110 int s
= 1; /* sign is +1 or -1 */
2111 const char *ptr
= str
; /* ptr to current position in str */
2113 /* skip leading whitespace */
2114 while (ISSPACE(*ptr
))
2116 /* printf("1) %s\n",ptr); */
2118 /* scan optional sign character */
2133 /* printf("2) %s\n",ptr); */
2136 if ((*ptr
++) != '0')
2138 /* printf("failed to detect '0'\n"); */
2142 /* printf("3) %s\n",ptr); */
2143 if (toupper(*ptr
++) != toupper(X
))
2145 /* printf("failed to detect '%c'\n",X); */
2149 /* printf("4) %s\n",ptr); */
2151 /* attempt conversion on remainder of string using strtol() */
2152 val
= strtol(ptr
, (char * *)endptr
, base
);
2155 /* conversion failed */
2165 /* Returns 1 if str matches suffix (case insensitive). */
2166 /* Str may contain trailing whitespace, but nothing else. */
2167 static int detectsuffix(const char *str
, const char *suffix
)
2169 /* scan pairwise through strings until mismatch detected */
2170 while( toupper(*str
) == toupper(*suffix
) )
2172 /* printf("'%c' '%c'\n", *str, *suffix); */
2174 /* return 1 (success) if match persists until the string terminator */
2182 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2184 /* return 0 (fail) if the matching did not consume the entire suffix */
2186 return 0; /* failed to consume entire suffix */
2188 /* skip any remaining whitespace in str */
2189 while (ISSPACE(*str
))
2192 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2193 return (*str
== '\0') ? 1 : 0;
2197 static int arg_int_scanfn(struct arg_int
*parent
, const char *argval
)
2201 if (parent
->count
== parent
->hdr
.maxcount
)
2203 /* maximum number of arguments exceeded */
2204 errorcode
= EMAXCOUNT
;
2208 /* a valid argument with no argument value was given. */
2209 /* This happens when an optional argument value was invoked. */
2210 /* leave parent arguiment value unaltered but still count the argument. */
2218 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2219 val
= strtol0X(argval
, &end
, 'X', 16);
2222 /* hex failed, attempt octal conversion (eg +0o123) */
2223 val
= strtol0X(argval
, &end
, 'O', 8);
2226 /* octal failed, attempt binary conversion (eg +0B101) */
2227 val
= strtol0X(argval
, &end
, 'B', 2);
2230 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2231 val
= strtol(argval
, (char * *)&end
, 10);
2234 /* all supported number formats failed */
2241 /* Safety check for integer overflow. WARNING: this check */
2242 /* achieves nothing on machines where size(int)==size(long). */
2243 if ( val
> INT_MAX
|| val
< INT_MIN
)
2244 #ifdef __STDC_WANT_SECURE_LIB__
2245 errorcode
= EOVERFLOW_
;
2247 errorcode
= EOVERFLOW
;
2250 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2251 /* We need to be mindful of integer overflows when using such big numbers. */
2252 if (detectsuffix(end
, "KB")) /* kilobytes */
2254 if ( val
> (INT_MAX
/ 1024) || val
< (INT_MIN
/ 1024) )
2255 #ifdef __STDC_WANT_SECURE_LIB__
2256 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2258 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2261 val
*= 1024; /* 1KB = 1024 */
2263 else if (detectsuffix(end
, "MB")) /* megabytes */
2265 if ( val
> (INT_MAX
/ 1048576) || val
< (INT_MIN
/ 1048576) )
2266 #ifdef __STDC_WANT_SECURE_LIB__
2267 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2269 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2272 val
*= 1048576; /* 1MB = 1024*1024 */
2274 else if (detectsuffix(end
, "GB")) /* gigabytes */
2276 if ( val
> (INT_MAX
/ 1073741824) || val
< (INT_MIN
/ 1073741824) )
2277 #ifdef __STDC_WANT_SECURE_LIB__
2278 errorcode
= EOVERFLOW_
; /* Overflow would occur if we proceed */
2280 errorcode
= EOVERFLOW
; /* Overflow would occur if we proceed */
2283 val
*= 1073741824; /* 1GB = 1024*1024*1024 */
2285 else if (!detectsuffix(end
, ""))
2286 errorcode
= EBADINT
; /* invalid suffix detected */
2288 /* if success then store result in parent->ival[] array */
2290 parent
->ival
[parent
->count
++] = val
;
2293 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2298 static int arg_int_checkfn(struct arg_int
*parent
)
2300 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2301 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2306 static void arg_int_errorfn(
2307 struct arg_int
*parent
,
2311 const char *progname
)
2313 const char *shortopts
= parent
->hdr
.shortopts
;
2314 const char *longopts
= parent
->hdr
.longopts
;
2315 const char *datatype
= parent
->hdr
.datatype
;
2317 /* make argval NULL safe */
2318 argval
= argval
? argval
: "";
2320 fprintf(fp
, "%s: ", progname
);
2324 fputs("missing option ", fp
);
2325 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2329 fputs("excess option ", fp
);
2330 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2334 fprintf(fp
, "invalid argument \"%s\" to option ", argval
);
2335 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2338 #ifdef __STDC_WANT_SECURE_LIB__
2343 fputs("integer overflow at option ", fp
);
2344 arg_print_option(fp
, shortopts
, longopts
, datatype
, " ");
2345 fprintf(fp
, "(%s is too large)\n", argval
);
2351 struct arg_int
* arg_int0(
2352 const char *shortopts
,
2353 const char *longopts
,
2354 const char *datatype
,
2355 const char *glossary
)
2357 return arg_intn(shortopts
, longopts
, datatype
, 0, 1, glossary
);
2361 struct arg_int
* arg_int1(
2362 const char *shortopts
,
2363 const char *longopts
,
2364 const char *datatype
,
2365 const char *glossary
)
2367 return arg_intn(shortopts
, longopts
, datatype
, 1, 1, glossary
);
2371 struct arg_int
* arg_intn(
2372 const char *shortopts
,
2373 const char *longopts
,
2374 const char *datatype
,
2377 const char *glossary
)
2380 struct arg_int
*result
;
2382 /* foolproof things by ensuring maxcount is not less than mincount */
2383 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2385 nbytes
= sizeof(struct arg_int
) /* storage for struct arg_int */
2386 + maxcount
* sizeof(int); /* storage for ival[maxcount] array */
2388 result
= (struct arg_int
*)malloc(nbytes
);
2391 /* init the arg_hdr struct */
2392 result
->hdr
.flag
= ARG_HASVALUE
;
2393 result
->hdr
.shortopts
= shortopts
;
2394 result
->hdr
.longopts
= longopts
;
2395 result
->hdr
.datatype
= datatype
? datatype
: "<int>";
2396 result
->hdr
.glossary
= glossary
;
2397 result
->hdr
.mincount
= mincount
;
2398 result
->hdr
.maxcount
= maxcount
;
2399 result
->hdr
.parent
= result
;
2400 result
->hdr
.resetfn
= (arg_resetfn
*)arg_int_resetfn
;
2401 result
->hdr
.scanfn
= (arg_scanfn
*)arg_int_scanfn
;
2402 result
->hdr
.checkfn
= (arg_checkfn
*)arg_int_checkfn
;
2403 result
->hdr
.errorfn
= (arg_errorfn
*)arg_int_errorfn
;
2405 /* store the ival[maxcount] array immediately after the arg_int struct */
2406 result
->ival
= (int *)(result
+ 1);
2410 ARG_TRACE(("arg_intn() returns %p\n", result
));
2413 /*******************************************************************************
2414 * This file is part of the argtable3 library.
2416 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2417 * <sheitmann@users.sourceforge.net>
2418 * All rights reserved.
2420 * Redistribution and use in source and binary forms, with or without
2421 * modification, are permitted provided that the following conditions are met:
2422 * * Redistributions of source code must retain the above copyright
2423 * notice, this list of conditions and the following disclaimer.
2424 * * Redistributions in binary form must reproduce the above copyright
2425 * notice, this list of conditions and the following disclaimer in the
2426 * documentation and/or other materials provided with the distribution.
2427 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2428 * may be used to endorse or promote products derived from this software
2429 * without specific prior written permission.
2431 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2432 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2433 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2434 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2435 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2436 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2437 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2438 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2439 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2440 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2441 ******************************************************************************/
2445 #include "argtable3.h"
2448 static void arg_lit_resetfn(struct arg_lit
*parent
)
2450 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2455 static int arg_lit_scanfn(struct arg_lit
*parent
, const char *argval
)
2458 if (parent
->count
< parent
->hdr
.maxcount
)
2461 errorcode
= EMAXCOUNT
;
2463 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__
, parent
, argval
,
2469 static int arg_lit_checkfn(struct arg_lit
*parent
)
2471 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2472 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
2477 static void arg_lit_errorfn(
2478 struct arg_lit
*parent
,
2482 const char *progname
)
2484 const char *shortopts
= parent
->hdr
.shortopts
;
2485 const char *longopts
= parent
->hdr
.longopts
;
2486 const char *datatype
= parent
->hdr
.datatype
;
2491 fprintf(fp
, "%s: missing option ", progname
);
2492 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2497 fprintf(fp
, "%s: extraneous option ", progname
);
2498 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2502 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__
, parent
, fp
,
2503 errorcode
, argval
, progname
));
2507 struct arg_lit
* arg_lit0(
2508 const char * shortopts
,
2509 const char * longopts
,
2510 const char * glossary
)
2512 return arg_litn(shortopts
, longopts
, 0, 1, glossary
);
2516 struct arg_lit
* arg_lit1(
2517 const char *shortopts
,
2518 const char *longopts
,
2519 const char *glossary
)
2521 return arg_litn(shortopts
, longopts
, 1, 1, glossary
);
2525 struct arg_lit
* arg_litn(
2526 const char *shortopts
,
2527 const char *longopts
,
2530 const char *glossary
)
2532 struct arg_lit
*result
;
2534 /* foolproof things by ensuring maxcount is not less than mincount */
2535 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2537 result
= (struct arg_lit
*)malloc(sizeof(struct arg_lit
));
2540 /* init the arg_hdr struct */
2541 result
->hdr
.flag
= 0;
2542 result
->hdr
.shortopts
= shortopts
;
2543 result
->hdr
.longopts
= longopts
;
2544 result
->hdr
.datatype
= NULL
;
2545 result
->hdr
.glossary
= glossary
;
2546 result
->hdr
.mincount
= mincount
;
2547 result
->hdr
.maxcount
= maxcount
;
2548 result
->hdr
.parent
= result
;
2549 result
->hdr
.resetfn
= (arg_resetfn
*)arg_lit_resetfn
;
2550 result
->hdr
.scanfn
= (arg_scanfn
*)arg_lit_scanfn
;
2551 result
->hdr
.checkfn
= (arg_checkfn
*)arg_lit_checkfn
;
2552 result
->hdr
.errorfn
= (arg_errorfn
*)arg_lit_errorfn
;
2554 /* init local variables */
2558 ARG_TRACE(("arg_litn() returns %p\n", result
));
2561 /*******************************************************************************
2562 * This file is part of the argtable3 library.
2564 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2565 * <sheitmann@users.sourceforge.net>
2566 * All rights reserved.
2568 * Redistribution and use in source and binary forms, with or without
2569 * modification, are permitted provided that the following conditions are met:
2570 * * Redistributions of source code must retain the above copyright
2571 * notice, this list of conditions and the following disclaimer.
2572 * * Redistributions in binary form must reproduce the above copyright
2573 * notice, this list of conditions and the following disclaimer in the
2574 * documentation and/or other materials provided with the distribution.
2575 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2576 * may be used to endorse or promote products derived from this software
2577 * without specific prior written permission.
2579 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2580 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2581 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2582 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2583 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2584 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2585 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2586 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2587 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2588 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2589 ******************************************************************************/
2593 #include "argtable3.h"
2595 struct arg_rem
*arg_rem(const char *datatype
, const char *glossary
)
2597 struct arg_rem
*result
= (struct arg_rem
*)malloc(sizeof(struct arg_rem
));
2600 result
->hdr
.flag
= 0;
2601 result
->hdr
.shortopts
= NULL
;
2602 result
->hdr
.longopts
= NULL
;
2603 result
->hdr
.datatype
= datatype
;
2604 result
->hdr
.glossary
= glossary
;
2605 result
->hdr
.mincount
= 1;
2606 result
->hdr
.maxcount
= 1;
2607 result
->hdr
.parent
= result
;
2608 result
->hdr
.resetfn
= NULL
;
2609 result
->hdr
.scanfn
= NULL
;
2610 result
->hdr
.checkfn
= NULL
;
2611 result
->hdr
.errorfn
= NULL
;
2614 ARG_TRACE(("arg_rem() returns %p\n", result
));
2618 /*******************************************************************************
2619 * This file is part of the argtable3 library.
2621 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2622 * <sheitmann@users.sourceforge.net>
2623 * All rights reserved.
2625 * Redistribution and use in source and binary forms, with or without
2626 * modification, are permitted provided that the following conditions are met:
2627 * * Redistributions of source code must retain the above copyright
2628 * notice, this list of conditions and the following disclaimer.
2629 * * Redistributions in binary form must reproduce the above copyright
2630 * notice, this list of conditions and the following disclaimer in the
2631 * documentation and/or other materials provided with the distribution.
2632 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2633 * may be used to endorse or promote products derived from this software
2634 * without specific prior written permission.
2636 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2637 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2638 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2639 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2640 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2641 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2642 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2643 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2644 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2645 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2646 ******************************************************************************/
2651 #include "argtable3.h"
2656 /***************************************************************
2657 T-Rex a tiny regular expression library
2659 Copyright (C) 2003-2006 Alberto Demichelis
2661 This software is provided 'as-is', without any express
2662 or implied warranty. In no event will the authors be held
2663 liable for any damages arising from the use of this software.
2665 Permission is granted to anyone to use this software for
2666 any purpose, including commercial applications, and to alter
2667 it and redistribute it freely, subject to the following restrictions:
2669 1. The origin of this software must not be misrepresented;
2670 you must not claim that you wrote the original software.
2671 If you use this software in a product, an acknowledgment
2672 in the product documentation would be appreciated but
2675 2. Altered source versions must be plainly marked as such,
2676 and must not be misrepresented as being the original software.
2678 3. This notice may not be removed or altered from any
2679 source distribution.
2681 ****************************************************************/
2688 #define TRexChar unsigned short
2689 #define MAX_CHAR 0xFFFF
2690 #define _TREXC(c) L##c
2691 #define trex_strlen wcslen
2692 #define trex_printf wprintf
2694 #define TRexChar char
2695 #define MAX_CHAR 0xFF
2696 #define _TREXC(c) (c)
2697 #define trex_strlen strlen
2698 #define trex_printf printf
2702 #define TREX_API extern
2706 #define TRex_False 0
2708 #define TREX_ICASE ARG_REX_ICASE
2710 typedef unsigned int TRexBool
;
2711 typedef struct TRex TRex
;
2714 const TRexChar
*begin
;
2718 TREX_API TRex
*trex_compile(const TRexChar
*pattern
, const TRexChar
**error
, int flags
);
2719 TREX_API
void trex_free(TRex
*exp
);
2720 TREX_API TRexBool
trex_match(TRex
* exp
, const TRexChar
* text
);
2721 TREX_API TRexBool
trex_search(TRex
* exp
, const TRexChar
* text
, const TRexChar
** out_begin
, const TRexChar
** out_end
);
2722 TREX_API TRexBool
trex_searchrange(TRex
* exp
, const TRexChar
* text_begin
, const TRexChar
* text_end
, const TRexChar
** out_begin
, const TRexChar
** out_end
);
2723 TREX_API
int trex_getsubexpcount(TRex
* exp
);
2724 TREX_API TRexBool
trex_getsubexp(TRex
* exp
, int n
, TRexMatch
*subexp
);
2736 const char *pattern
;
2741 static void arg_rex_resetfn(struct arg_rex
*parent
)
2743 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
2747 static int arg_rex_scanfn(struct arg_rex
*parent
, const char *argval
)
2750 const TRexChar
*error
= NULL
;
2752 TRexBool is_match
= TRex_False
;
2754 if (parent
->count
== parent
->hdr
.maxcount
)
2756 /* maximum number of arguments exceeded */
2757 errorcode
= EMAXCOUNT
;
2761 /* a valid argument with no argument value was given. */
2762 /* This happens when an optional argument value was invoked. */
2763 /* leave parent argument value unaltered but still count the argument. */
2768 struct privhdr
*priv
= (struct privhdr
*)parent
->hdr
.priv
;
2770 /* test the current argument value for a match with the regular expression */
2771 /* if a match is detected, record the argument value in the arg_rex struct */
2773 rex
= trex_compile(priv
->pattern
, &error
, priv
->flags
);
2774 is_match
= trex_match(rex
, argval
);
2776 errorcode
= EREGNOMATCH
;
2778 parent
->sval
[parent
->count
++] = argval
;
2783 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__
,parent
,errorcode
));
2787 static int arg_rex_checkfn(struct arg_rex
*parent
)
2789 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
2790 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2792 /* free the regex "program" we constructed in resetfn */
2793 //regfree(&(priv->regex));
2795 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2799 static void arg_rex_errorfn(struct arg_rex
*parent
,
2803 const char *progname
)
2805 const char *shortopts
= parent
->hdr
.shortopts
;
2806 const char *longopts
= parent
->hdr
.longopts
;
2807 const char *datatype
= parent
->hdr
.datatype
;
2809 /* make argval NULL safe */
2810 argval
= argval
? argval
: "";
2812 fprintf(fp
, "%s: ", progname
);
2816 fputs("missing option ", fp
);
2817 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
2821 fputs("excess option ", fp
);
2822 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2826 fputs("illegal value ", fp
);
2827 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
2832 //char errbuff[256];
2833 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2834 //printf("%s\n", errbuff);
2841 struct arg_rex
* arg_rex0(const char * shortopts
,
2842 const char * longopts
,
2843 const char * pattern
,
2844 const char *datatype
,
2846 const char *glossary
)
2848 return arg_rexn(shortopts
,
2858 struct arg_rex
* arg_rex1(const char * shortopts
,
2859 const char * longopts
,
2860 const char * pattern
,
2861 const char *datatype
,
2863 const char *glossary
)
2865 return arg_rexn(shortopts
,
2876 struct arg_rex
* arg_rexn(const char * shortopts
,
2877 const char * longopts
,
2878 const char * pattern
,
2879 const char *datatype
,
2883 const char *glossary
)
2886 struct arg_rex
*result
;
2887 struct privhdr
*priv
;
2889 const TRexChar
*error
= NULL
;
2895 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2896 printf("argtable: Bad argument table.\n");
2900 /* foolproof things by ensuring maxcount is not less than mincount */
2901 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
2903 nbytes
= sizeof(struct arg_rex
) /* storage for struct arg_rex */
2904 + sizeof(struct privhdr
) /* storage for private arg_rex data */
2905 + maxcount
* sizeof(char *); /* storage for sval[maxcount] array */
2907 result
= (struct arg_rex
*)malloc(nbytes
);
2911 /* init the arg_hdr struct */
2912 result
->hdr
.flag
= ARG_HASVALUE
;
2913 result
->hdr
.shortopts
= shortopts
;
2914 result
->hdr
.longopts
= longopts
;
2915 result
->hdr
.datatype
= datatype
? datatype
: pattern
;
2916 result
->hdr
.glossary
= glossary
;
2917 result
->hdr
.mincount
= mincount
;
2918 result
->hdr
.maxcount
= maxcount
;
2919 result
->hdr
.parent
= result
;
2920 result
->hdr
.resetfn
= (arg_resetfn
*)arg_rex_resetfn
;
2921 result
->hdr
.scanfn
= (arg_scanfn
*)arg_rex_scanfn
;
2922 result
->hdr
.checkfn
= (arg_checkfn
*)arg_rex_checkfn
;
2923 result
->hdr
.errorfn
= (arg_errorfn
*)arg_rex_errorfn
;
2925 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2926 result
->hdr
.priv
= result
+ 1;
2927 priv
= (struct privhdr
*)(result
->hdr
.priv
);
2928 priv
->pattern
= pattern
;
2929 priv
->flags
= flags
;
2931 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2932 result
->sval
= (const char * *)(priv
+ 1);
2935 /* foolproof the string pointers by initializing them to reference empty strings */
2936 for (i
= 0; i
< maxcount
; i
++)
2937 result
->sval
[i
] = "";
2939 /* here we construct and destroy a regex representation of the regular
2940 * expression for no other reason than to force any regex errors to be
2941 * trapped now rather than later. If we don't, then errors may go undetected
2942 * until an argument is actually parsed.
2945 rex
= trex_compile(priv
->pattern
, &error
, priv
->flags
);
2948 ARG_LOG(("argtable: %s \"%s\"\n", error
? error
: _TREXC("undefined"), priv
->pattern
));
2949 ARG_LOG(("argtable: Bad argument table.\n"));
2954 ARG_TRACE(("arg_rexn() returns %p\n", result
));
2960 /* see copyright notice in trex.h */
2967 #define scisprint iswprint
2968 #define scstrlen wcslen
2969 #define scprintf wprintf
2972 #define scisprint isprint
2973 #define scstrlen strlen
2974 #define scprintf printf
2981 static const TRexChar
*g_nnames
[] =
2983 _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
2984 _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
2985 _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
2986 _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
2990 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2991 #define OP_OR (MAX_CHAR+2)
2992 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2993 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2994 #define OP_DOT (MAX_CHAR+5)
2995 #define OP_CLASS (MAX_CHAR+6)
2996 #define OP_CCLASS (MAX_CHAR+7)
2997 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2998 #define OP_RANGE (MAX_CHAR+9)
2999 #define OP_CHAR (MAX_CHAR+10)
3000 #define OP_EOL (MAX_CHAR+11)
3001 #define OP_BOL (MAX_CHAR+12)
3002 #define OP_WB (MAX_CHAR+13)
3004 #define TREX_SYMBOL_ANY_CHAR ('.')
3005 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
3006 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
3007 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
3008 #define TREX_SYMBOL_BRANCH ('|')
3009 #define TREX_SYMBOL_END_OF_STRING ('$')
3010 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
3011 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
3014 typedef int TRexNodeType
;
3016 typedef struct tagTRexNode
{
3024 const TRexChar
*_eol
;
3025 const TRexChar
*_bol
;
3033 TRexMatch
*_matches
;
3036 const TRexChar
**_error
;
3040 static int trex_list(TRex
*exp
);
3042 static int trex_newnode(TRex
*exp
, TRexNodeType type
)
3047 n
.next
= n
.right
= n
.left
= -1;
3049 n
.right
= exp
->_nsubexpr
++;
3050 if(exp
->_nallocated
< (exp
->_nsize
+ 1)) {
3051 exp
->_nallocated
*= 2;
3052 exp
->_nodes
= (TRexNode
*)realloc(exp
->_nodes
, exp
->_nallocated
* sizeof(TRexNode
));
3054 exp
->_nodes
[exp
->_nsize
++] = n
;
3055 newid
= exp
->_nsize
- 1;
3059 static void trex_error(TRex
*exp
,const TRexChar
*error
)
3061 if(exp
->_error
) *exp
->_error
= error
;
3062 longjmp(*((jmp_buf*)exp
->_jmpbuf
),-1);
3065 static void trex_expect(TRex
*exp
, int n
){
3067 trex_error(exp
, _SC("expected paren"));
3071 static TRexChar
trex_escapechar(TRex
*exp
)
3073 if(*exp
->_p
== TREX_SYMBOL_ESCAPE_CHAR
){
3076 case 'v': exp
->_p
++; return '\v';
3077 case 'n': exp
->_p
++; return '\n';
3078 case 't': exp
->_p
++; return '\t';
3079 case 'r': exp
->_p
++; return '\r';
3080 case 'f': exp
->_p
++; return '\f';
3081 default: return (*exp
->_p
++);
3083 } else if(!scisprint(*exp
->_p
)) trex_error(exp
,_SC("letter expected"));
3084 return (*exp
->_p
++);
3087 static int trex_charclass(TRex
*exp
,int classid
)
3089 int n
= trex_newnode(exp
,OP_CCLASS
);
3090 exp
->_nodes
[n
].left
= classid
;
3094 static int trex_charnode(TRex
*exp
,TRexBool isclass
)
3097 if(*exp
->_p
== TREX_SYMBOL_ESCAPE_CHAR
) {
3100 case 'n': exp
->_p
++; return trex_newnode(exp
,'\n');
3101 case 't': exp
->_p
++; return trex_newnode(exp
,'\t');
3102 case 'r': exp
->_p
++; return trex_newnode(exp
,'\r');
3103 case 'f': exp
->_p
++; return trex_newnode(exp
,'\f');
3104 case 'v': exp
->_p
++; return trex_newnode(exp
,'\v');
3105 case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
3106 case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
3107 case 'p': case 'P': case 'l': case 'u':
3109 t
= *exp
->_p
; exp
->_p
++;
3110 return trex_charclass(exp
,t
);
3115 int node
= trex_newnode(exp
,OP_WB
);
3116 exp
->_nodes
[node
].left
= *exp
->_p
;
3121 t
= *exp
->_p
; exp
->_p
++;
3122 return trex_newnode(exp
,t
);
3125 else if(!scisprint(*exp
->_p
)) {
3127 trex_error(exp
,_SC("letter expected"));
3129 t
= *exp
->_p
; exp
->_p
++;
3130 return trex_newnode(exp
,t
);
3132 static int trex_class(TRex
*exp
)
3135 int first
= -1,chain
;
3136 if(*exp
->_p
== TREX_SYMBOL_BEGINNING_OF_STRING
){
3137 ret
= trex_newnode(exp
,OP_NCLASS
);
3139 }else ret
= trex_newnode(exp
,OP_CLASS
);
3141 if(*exp
->_p
== ']') trex_error(exp
,_SC("empty class"));
3143 while(*exp
->_p
!= ']' && exp
->_p
!= exp
->_eol
) {
3144 if(*exp
->_p
== '-' && first
!= -1){
3146 if(*exp
->_p
++ == ']') trex_error(exp
,_SC("unfinished range"));
3147 r
= trex_newnode(exp
,OP_RANGE
);
3148 if(first
>*exp
->_p
) trex_error(exp
,_SC("invalid range"));
3149 if(exp
->_nodes
[first
].type
== OP_CCLASS
) trex_error(exp
,_SC("cannot use character classes in ranges"));
3150 exp
->_nodes
[r
].left
= exp
->_nodes
[first
].type
;
3151 t
= trex_escapechar(exp
);
3152 exp
->_nodes
[r
].right
= t
;
3153 exp
->_nodes
[chain
].next
= r
;
3160 exp
->_nodes
[chain
].next
= c
;
3162 first
= trex_charnode(exp
,TRex_True
);
3165 first
= trex_charnode(exp
,TRex_True
);
3171 exp
->_nodes
[chain
].next
= c
;
3176 exp
->_nodes
[ret
].left
= exp
->_nodes
[ret
].next
;
3177 exp
->_nodes
[ret
].next
= -1;
3181 static int trex_parsenumber(TRex
*exp
)
3183 int ret
= *exp
->_p
-'0';
3186 while(isdigit(*exp
->_p
)) {
3187 ret
= ret
*10+(*exp
->_p
++-'0');
3188 if(positions
==1000000000) trex_error(exp
,_SC("overflow in numeric constant"));
3194 static int trex_element(TRex
*exp
)
3204 if(*exp
->_p
=='?') {
3206 trex_expect(exp
,':');
3207 expr
= trex_newnode(exp
,OP_NOCAPEXPR
);
3210 expr
= trex_newnode(exp
,OP_EXPR
);
3211 newn
= trex_list(exp
);
3212 exp
->_nodes
[expr
].left
= newn
;
3214 trex_expect(exp
,')');
3219 ret
= trex_class(exp
);
3220 trex_expect(exp
,']');
3222 case TREX_SYMBOL_END_OF_STRING
: exp
->_p
++; ret
= trex_newnode(exp
,OP_EOL
);break;
3223 case TREX_SYMBOL_ANY_CHAR
: exp
->_p
++; ret
= trex_newnode(exp
,OP_DOT
);break;
3225 ret
= trex_charnode(exp
,TRex_False
);
3230 TRexBool isgreedy
= TRex_False
;
3231 unsigned short p0
= 0, p1
= 0;
3233 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE
: p0
= 0; p1
= 0xFFFF; exp
->_p
++; isgreedy
= TRex_True
; break;
3234 case TREX_SYMBOL_GREEDY_ONE_OR_MORE
: p0
= 1; p1
= 0xFFFF; exp
->_p
++; isgreedy
= TRex_True
; break;
3235 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE
: p0
= 0; p1
= 1; exp
->_p
++; isgreedy
= TRex_True
; break;
3238 if(!isdigit(*exp
->_p
)) trex_error(exp
,_SC("number expected"));
3239 p0
= (unsigned short)trex_parsenumber(exp
);
3240 /*******************************/
3248 if(isdigit(*exp
->_p
)){
3249 p1
= (unsigned short)trex_parsenumber(exp
);
3251 trex_expect(exp
,'}');
3254 trex_error(exp
,_SC(", or } expected"));
3256 /*******************************/
3257 isgreedy
= TRex_True
;
3262 int nnode
= trex_newnode(exp
,OP_GREEDY
);
3263 exp
->_nodes
[nnode
].left
= ret
;
3264 exp
->_nodes
[nnode
].right
= ((p0
)<<16)|p1
;
3268 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')) {
3269 int nnode
= trex_element(exp
);
3270 exp
->_nodes
[ret
].next
= nnode
;
3276 static int trex_list(TRex
*exp
)
3279 if(*exp
->_p
== TREX_SYMBOL_BEGINNING_OF_STRING
) {
3281 ret
= trex_newnode(exp
,OP_BOL
);
3283 e
= trex_element(exp
);
3285 exp
->_nodes
[ret
].next
= e
;
3289 if(*exp
->_p
== TREX_SYMBOL_BRANCH
) {
3292 temp
= trex_newnode(exp
,OP_OR
);
3293 exp
->_nodes
[temp
].left
= ret
;
3294 tright
= trex_list(exp
);
3295 exp
->_nodes
[temp
].right
= tright
;
3301 static TRexBool
trex_matchcclass(int cclass
,TRexChar c
)
3304 case 'a': return isalpha(c
)?TRex_True
:TRex_False
;
3305 case 'A': return !isalpha(c
)?TRex_True
:TRex_False
;
3306 case 'w': return (isalnum(c
) || c
== '_')?TRex_True
:TRex_False
;
3307 case 'W': return (!isalnum(c
) && c
!= '_')?TRex_True
:TRex_False
;
3308 case 's': return ISSPACE(c
)?TRex_True
:TRex_False
;
3309 case 'S': return !ISSPACE(c
)?TRex_True
:TRex_False
;
3310 case 'd': return isdigit(c
)?TRex_True
:TRex_False
;
3311 case 'D': return !isdigit(c
)?TRex_True
:TRex_False
;
3312 case 'x': return isxdigit(c
)?TRex_True
:TRex_False
;
3313 case 'X': return !isxdigit(c
)?TRex_True
:TRex_False
;
3314 case 'c': return iscntrl(c
)?TRex_True
:TRex_False
;
3315 case 'C': return !iscntrl(c
)?TRex_True
:TRex_False
;
3316 case 'p': return ispunct(c
)?TRex_True
:TRex_False
;
3317 case 'P': return !ispunct(c
)?TRex_True
:TRex_False
;
3318 case 'l': return islower(c
)?TRex_True
:TRex_False
;
3319 case 'u': return isupper(c
)?TRex_True
:TRex_False
;
3321 return TRex_False
; /*cannot happen*/
3324 static TRexBool
trex_matchclass(TRex
* exp
,TRexNode
*node
,TRexChar c
)
3327 switch(node
->type
) {
3329 if (exp
->_flags
& TREX_ICASE
)
3331 if(c
>= toupper(node
->left
) && c
<= toupper(node
->right
)) return TRex_True
;
3332 if(c
>= tolower(node
->left
) && c
<= tolower(node
->right
)) return TRex_True
;
3336 if(c
>= node
->left
&& c
<= node
->right
) return TRex_True
;
3340 if(trex_matchcclass(node
->left
,c
)) return TRex_True
;
3343 if (exp
->_flags
& TREX_ICASE
)
3345 if (c
== tolower(node
->type
) || c
== toupper(node
->type
)) return TRex_True
;
3349 if(c
== node
->type
)return TRex_True
;
3353 } while((node
->next
!= -1) && (node
= &exp
->_nodes
[node
->next
]));
3357 static const TRexChar
*trex_matchnode(TRex
* exp
,TRexNode
*node
,const TRexChar
*str
,TRexNode
*next
)
3360 TRexNodeType type
= node
->type
;
3363 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3364 TRexNode
*greedystop
= NULL
;
3365 int p0
= (node
->right
>> 16)&0x0000FFFF, p1
= node
->right
&0x0000FFFF, nmaches
= 0;
3366 const TRexChar
*s
=str
, *good
= str
;
3368 if(node
->next
!= -1) {
3369 greedystop
= &exp
->_nodes
[node
->next
];
3375 while((nmaches
== 0xFFFF || nmaches
< p1
)) {
3377 const TRexChar
*stop
;
3378 if(!(s
= trex_matchnode(exp
,&exp
->_nodes
[node
->left
],s
,greedystop
)))
3383 //checks that 0 matches satisfy the expression(if so skips)
3384 //if not would always stop(for instance if is a '?')
3385 if(greedystop
->type
!= OP_GREEDY
||
3386 (greedystop
->type
== OP_GREEDY
&& ((greedystop
->right
>> 16)&0x0000FFFF) != 0))
3388 TRexNode
*gnext
= NULL
;
3389 if(greedystop
->next
!= -1) {
3390 gnext
= &exp
->_nodes
[greedystop
->next
];
3391 }else if(next
&& next
->next
!= -1){
3392 gnext
= &exp
->_nodes
[next
->next
];
3394 stop
= trex_matchnode(exp
,greedystop
,s
,gnext
);
3396 //if satisfied stop it
3397 if(p0
== p1
&& p0
== nmaches
) break;
3398 else if(nmaches
>= p0
&& p1
== 0xFFFF) break;
3399 else if(nmaches
>= p0
&& nmaches
<= p1
) break;
3407 if(p0
== p1
&& p0
== nmaches
) return good
;
3408 else if(nmaches
>= p0
&& p1
== 0xFFFF) return good
;
3409 else if(nmaches
>= p0
&& nmaches
<= p1
) return good
;
3413 const TRexChar
*asd
= str
;
3414 TRexNode
*temp
=&exp
->_nodes
[node
->left
];
3415 while( (asd
= trex_matchnode(exp
,temp
,asd
,NULL
)) ) {
3416 if(temp
->next
!= -1)
3417 temp
= &exp
->_nodes
[temp
->next
];
3422 temp
= &exp
->_nodes
[node
->right
];
3423 while( (asd
= trex_matchnode(exp
,temp
,asd
,NULL
)) ) {
3424 if(temp
->next
!= -1)
3425 temp
= &exp
->_nodes
[temp
->next
];
3434 TRexNode
*n
= &exp
->_nodes
[node
->left
];
3435 const TRexChar
*cur
= str
;
3437 if(node
->type
!= OP_NOCAPEXPR
&& node
->right
== exp
->_currsubexp
) {
3438 capture
= exp
->_currsubexp
;
3439 exp
->_matches
[capture
].begin
= cur
;
3444 TRexNode
*subnext
= NULL
;
3446 subnext
= &exp
->_nodes
[n
->next
];
3450 if(!(cur
= trex_matchnode(exp
,n
,cur
,subnext
))) {
3452 exp
->_matches
[capture
].begin
= 0;
3453 exp
->_matches
[capture
].len
= 0;
3457 } while((n
->next
!= -1) && (n
= &exp
->_nodes
[n
->next
]));
3460 exp
->_matches
[capture
].len
= (int)(cur
- exp
->_matches
[capture
].begin
);
3464 if((str
== exp
->_bol
&& !ISSPACE(*str
))
3465 || ((str
== exp
->_eol
&& !ISSPACE(*(str
-1))))
3466 || ((!ISSPACE(*str
) && ISSPACE(*(str
+1))))
3467 || ((ISSPACE(*str
) && !ISSPACE(*(str
+1)))) ) {
3468 return (node
->left
== 'b')?str
:NULL
;
3470 return (node
->left
== 'b')?NULL
:str
;
3472 if(str
== exp
->_bol
) return str
;
3475 if(str
== exp
->_eol
) return str
;
3482 if(trex_matchclass(exp
,&exp
->_nodes
[node
->left
],*str
)?(type
== OP_CLASS
?TRex_True
:TRex_False
):(type
== OP_NCLASS
?TRex_True
:TRex_False
)) {
3488 if(trex_matchcclass(node
->left
,*str
)) {
3494 if (exp
->_flags
& TREX_ICASE
)
3496 if(*str
!= tolower(node
->type
) && *str
!= toupper(node
->type
)) return NULL
;
3500 if (*str
!= node
->type
) return NULL
;
3509 TRex
*trex_compile(const TRexChar
*pattern
,const TRexChar
**error
,int flags
)
3511 TRex
*exp
= (TRex
*)malloc(sizeof(TRex
));
3512 exp
->_eol
= exp
->_bol
= NULL
;
3514 exp
->_nallocated
= (int)scstrlen(pattern
) * sizeof(TRexChar
);
3515 exp
->_nodes
= (TRexNode
*)malloc(exp
->_nallocated
* sizeof(TRexNode
));
3519 exp
->_first
= trex_newnode(exp
,OP_EXPR
);
3520 exp
->_error
= error
;
3521 exp
->_jmpbuf
= malloc(sizeof(jmp_buf));
3522 exp
->_flags
= flags
;
3523 if(setjmp(*((jmp_buf*)exp
->_jmpbuf
)) == 0) {
3524 int res
= trex_list(exp
);
3525 exp
->_nodes
[exp
->_first
].left
= res
;
3527 trex_error(exp
,_SC("unexpected character"));
3532 nsize
= exp
->_nsize
;
3533 t
= &exp
->_nodes
[0];
3534 scprintf(_SC("\n"));
3535 for(i
= 0;i
< nsize
; i
++) {
3536 if(exp
->_nodes
[i
].type
>MAX_CHAR
)
3537 scprintf(_SC("[%02d] %10s "),i
,g_nnames
[exp
->_nodes
[i
].type
-MAX_CHAR
]);
3539 scprintf(_SC("[%02d] %10c "),i
,exp
->_nodes
[i
].type
);
3540 scprintf(_SC("left %02d right %02d next %02d\n"),exp
->_nodes
[i
].left
,exp
->_nodes
[i
].right
,exp
->_nodes
[i
].next
);
3542 scprintf(_SC("\n"));
3545 exp
->_matches
= (TRexMatch
*) malloc(exp
->_nsubexpr
* sizeof(TRexMatch
));
3546 memset(exp
->_matches
,0,exp
->_nsubexpr
* sizeof(TRexMatch
));
3555 void trex_free(TRex
*exp
)
3558 if(exp
->_nodes
) free(exp
->_nodes
);
3559 if(exp
->_jmpbuf
) free(exp
->_jmpbuf
);
3560 if(exp
->_matches
) free(exp
->_matches
);
3565 TRexBool
trex_match(TRex
* exp
,const TRexChar
* text
)
3567 const TRexChar
* res
= NULL
;
3569 exp
->_eol
= text
+ scstrlen(text
);
3570 exp
->_currsubexp
= 0;
3571 res
= trex_matchnode(exp
,exp
->_nodes
,text
,NULL
);
3572 if(res
== NULL
|| res
!= exp
->_eol
)
3577 TRexBool
trex_searchrange(TRex
* exp
,const TRexChar
* text_begin
,const TRexChar
* text_end
,const TRexChar
** out_begin
, const TRexChar
** out_end
)
3579 const TRexChar
*cur
= NULL
;
3580 int node
= exp
->_first
;
3581 if(text_begin
>= text_end
) return TRex_False
;
3582 exp
->_bol
= text_begin
;
3583 exp
->_eol
= text_end
;
3587 exp
->_currsubexp
= 0;
3588 cur
= trex_matchnode(exp
,&exp
->_nodes
[node
],cur
,NULL
);
3591 node
= exp
->_nodes
[node
].next
;
3594 } while(cur
== NULL
&& text_begin
!= text_end
);
3601 if(out_begin
) *out_begin
= text_begin
;
3602 if(out_end
) *out_end
= cur
;
3606 TRexBool
trex_search(TRex
* exp
,const TRexChar
* text
, const TRexChar
** out_begin
, const TRexChar
** out_end
)
3608 return trex_searchrange(exp
,text
,text
+ scstrlen(text
),out_begin
,out_end
);
3611 int trex_getsubexpcount(TRex
* exp
)
3613 return exp
->_nsubexpr
;
3616 TRexBool
trex_getsubexp(TRex
* exp
, int n
, TRexMatch
*subexp
)
3618 if( n
<0 || n
>= exp
->_nsubexpr
) return TRex_False
;
3619 *subexp
= exp
->_matches
[n
];
3622 /*******************************************************************************
3623 * This file is part of the argtable3 library.
3625 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3626 * <sheitmann@users.sourceforge.net>
3627 * All rights reserved.
3629 * Redistribution and use in source and binary forms, with or without
3630 * modification, are permitted provided that the following conditions are met:
3631 * * Redistributions of source code must retain the above copyright
3632 * notice, this list of conditions and the following disclaimer.
3633 * * Redistributions in binary form must reproduce the above copyright
3634 * notice, this list of conditions and the following disclaimer in the
3635 * documentation and/or other materials provided with the distribution.
3636 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3637 * may be used to endorse or promote products derived from this software
3638 * without specific prior written permission.
3640 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3641 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3642 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3643 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3644 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3645 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3646 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3647 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3648 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3649 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3650 ******************************************************************************/
3654 #include "argtable3.h"
3657 static void arg_str_resetfn(struct arg_str
*parent
)
3659 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
));
3664 static int arg_str_scanfn(struct arg_str
*parent
, const char *argval
)
3668 if (parent
->count
== parent
->hdr
.maxcount
)
3670 /* maximum number of arguments exceeded */
3671 errorcode
= EMAXCOUNT
;
3675 /* a valid argument with no argument value was given. */
3676 /* This happens when an optional argument value was invoked. */
3677 /* leave parent arguiment value unaltered but still count the argument. */
3682 parent
->sval
[parent
->count
++] = argval
;
3685 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
3690 static int arg_str_checkfn(struct arg_str
*parent
)
3692 int errorcode
= (parent
->count
< parent
->hdr
.mincount
) ? EMINCOUNT
: 0;
3694 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
));
3699 static void arg_str_errorfn(
3700 struct arg_str
*parent
,
3704 const char *progname
)
3706 const char *shortopts
= parent
->hdr
.shortopts
;
3707 const char *longopts
= parent
->hdr
.longopts
;
3708 const char *datatype
= parent
->hdr
.datatype
;
3710 /* make argval NULL safe */
3711 argval
= argval
? argval
: "";
3713 fprintf(fp
, "%s: ", progname
);
3717 fputs("missing option ", fp
);
3718 arg_print_option(fp
, shortopts
, longopts
, datatype
, "\n");
3722 fputs("excess option ", fp
);
3723 arg_print_option(fp
, shortopts
, longopts
, argval
, "\n");
3729 struct arg_str
* arg_str0(
3730 const char *shortopts
,
3731 const char *longopts
,
3732 const char *datatype
,
3733 const char *glossary
)
3735 return arg_strn(shortopts
, longopts
, datatype
, 0, 1, glossary
);
3739 struct arg_str
* arg_str1(
3740 const char *shortopts
,
3741 const char *longopts
,
3742 const char *datatype
,
3743 const char *glossary
)
3745 return arg_strn(shortopts
, longopts
, datatype
, 1, 1, glossary
);
3749 struct arg_str
* arg_strn(
3750 const char *shortopts
,
3751 const char *longopts
,
3752 const char *datatype
,
3755 const char *glossary
)
3758 struct arg_str
*result
;
3760 /* should not allow this stupid error */
3761 /* we should return an error code warning this logic error */
3762 /* foolproof things by ensuring maxcount is not less than mincount */
3763 maxcount
= (maxcount
< mincount
) ? mincount
: maxcount
;
3765 nbytes
= sizeof(struct arg_str
) /* storage for struct arg_str */
3766 + maxcount
* sizeof(char *); /* storage for sval[maxcount] array */
3768 result
= (struct arg_str
*)malloc(nbytes
);
3773 /* init the arg_hdr struct */
3774 result
->hdr
.flag
= ARG_HASVALUE
;
3775 result
->hdr
.shortopts
= shortopts
;
3776 result
->hdr
.longopts
= longopts
;
3777 result
->hdr
.datatype
= datatype
? datatype
: "<string>";
3778 result
->hdr
.glossary
= glossary
;
3779 result
->hdr
.mincount
= mincount
;
3780 result
->hdr
.maxcount
= maxcount
;
3781 result
->hdr
.parent
= result
;
3782 result
->hdr
.resetfn
= (arg_resetfn
*)arg_str_resetfn
;
3783 result
->hdr
.scanfn
= (arg_scanfn
*)arg_str_scanfn
;
3784 result
->hdr
.checkfn
= (arg_checkfn
*)arg_str_checkfn
;
3785 result
->hdr
.errorfn
= (arg_errorfn
*)arg_str_errorfn
;
3787 /* store the sval[maxcount] array immediately after the arg_str struct */
3788 result
->sval
= (const char * *)(result
+ 1);
3791 /* foolproof the string pointers by initialising them to reference empty strings */
3792 for (i
= 0; i
< maxcount
; i
++)
3793 result
->sval
[i
] = "";
3796 ARG_TRACE(("arg_strn() returns %p\n", result
));
3799 /*******************************************************************************
3800 * This file is part of the argtable3 library.
3802 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3803 * <sheitmann@users.sourceforge.net>
3804 * All rights reserved.
3806 * Redistribution and use in source and binary forms, with or without
3807 * modification, are permitted provided that the following conditions are met:
3808 * * Redistributions of source code must retain the above copyright
3809 * notice, this list of conditions and the following disclaimer.
3810 * * Redistributions in binary form must reproduce the above copyright
3811 * notice, this list of conditions and the following disclaimer in the
3812 * documentation and/or other materials provided with the distribution.
3813 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3814 * may be used to endorse or promote products derived from this software
3815 * without specific prior written permission.
3817 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3818 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3819 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3820 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3821 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3822 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3823 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3824 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3825 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3826 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3827 ******************************************************************************/
3834 #include "argtable3.h"
3837 void arg_register_error(struct arg_end
*end
,
3842 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3843 if (end
->count
< end
->hdr
.maxcount
)
3845 end
->error
[end
->count
] = error
;
3846 end
->parent
[end
->count
] = parent
;
3847 end
->argval
[end
->count
] = argval
;
3852 end
->error
[end
->hdr
.maxcount
- 1] = ARG_ELIMIT
;
3853 end
->parent
[end
->hdr
.maxcount
- 1] = end
;
3854 end
->argval
[end
->hdr
.maxcount
- 1] = NULL
;
3860 * Return index of first table entry with a matching short option
3861 * or -1 if no match was found.
3864 int find_shortoption(struct arg_hdr
* *table
, char shortopt
)
3867 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
3869 if (table
[tabindex
]->shortopts
&&
3870 strchr(table
[tabindex
]->shortopts
, shortopt
))
3881 struct option
*options
;
3886 void dump_longoptions(struct longoptions
* longoptions
)
3889 printf("getoptval = %d\n", longoptions
->getoptval
);
3890 printf("noptions = %d\n", longoptions
->noptions
);
3891 for (i
= 0; i
< longoptions
->noptions
; i
++)
3893 printf("options[%d].name = \"%s\"\n",
3895 longoptions
->options
[i
].name
);
3896 printf("options[%d].has_arg = %d\n", i
, longoptions
->options
[i
].has_arg
);
3897 printf("options[%d].flag = %p\n", i
, longoptions
->options
[i
].flag
);
3898 printf("options[%d].val = %d\n", i
, longoptions
->options
[i
].val
);
3904 struct longoptions
* alloc_longoptions(struct arg_hdr
* *table
)
3906 struct longoptions
*result
;
3909 size_t longoptlen
= 0;
3913 * Determine the total number of option structs required
3914 * by counting the number of comma separated long options
3915 * in all table entries and return the count in noptions.
3916 * note: noptions starts at 1 not 0 because we getoptlong
3917 * requires a NULL option entry to terminate the option array.
3918 * While we are at it, count the number of chars required
3919 * to store private copies of all the longoption strings
3920 * and return that count in logoptlen.
3925 const char *longopts
= table
[tabindex
]->longopts
;
3926 longoptlen
+= (longopts
? strlen(longopts
) : 0) + 1;
3930 longopts
= strchr(longopts
+ 1, ',');
3932 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
3933 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3936 /* allocate storage for return data structure as: */
3937 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3938 nbytes
= sizeof(struct longoptions
)
3939 + sizeof(struct option
) * noptions
3941 result
= (struct longoptions
*)malloc(nbytes
);
3944 int option_index
= 0;
3947 result
->getoptval
= 0;
3948 result
->noptions
= noptions
;
3949 result
->options
= (struct option
*)(result
+ 1);
3950 store
= (char *)(result
->options
+ noptions
);
3952 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
3954 const char *longopts
= table
[tabindex
]->longopts
;
3956 while(longopts
&& *longopts
)
3958 char *storestart
= store
;
3960 /* copy progressive longopt strings into the store */
3961 while (*longopts
!= 0 && *longopts
!= ',')
3962 *store
++ = *longopts
++;
3964 if (*longopts
== ',')
3966 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3968 result
->options
[option_index
].name
= storestart
;
3969 result
->options
[option_index
].flag
= &(result
->getoptval
);
3970 result
->options
[option_index
].val
= tabindex
;
3971 if (table
[tabindex
]->flag
& ARG_HASOPTVALUE
)
3972 result
->options
[option_index
].has_arg
= 2;
3973 else if (table
[tabindex
]->flag
& ARG_HASVALUE
)
3974 result
->options
[option_index
].has_arg
= 1;
3976 result
->options
[option_index
].has_arg
= 0;
3981 /* terminate the options array with a zero-filled entry */
3982 result
->options
[option_index
].name
= 0;
3983 result
->options
[option_index
].has_arg
= 0;
3984 result
->options
[option_index
].flag
= 0;
3985 result
->options
[option_index
].val
= 0;
3988 /*dump_longoptions(result);*/
3993 char * alloc_shortoptions(struct arg_hdr
* *table
)
3999 /* determine the total number of option chars required */
4000 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4002 struct arg_hdr
*hdr
= table
[tabindex
];
4003 len
+= 3 * (hdr
->shortopts
? strlen(hdr
->shortopts
) : 0);
4006 result
= malloc(len
);
4011 /* add a leading ':' so getopt return codes distinguish */
4012 /* unrecognised option and options missing argument values */
4015 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4017 struct arg_hdr
*hdr
= table
[tabindex
];
4018 const char *shortopts
= hdr
->shortopts
;
4019 while(shortopts
&& *shortopts
)
4021 *res
++ = *shortopts
++;
4022 if (hdr
->flag
& ARG_HASVALUE
)
4024 if (hdr
->flag
& ARG_HASOPTVALUE
)
4028 /* null terminate the string */
4032 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
4037 /* return index of the table terminator entry */
4039 int arg_endindex(struct arg_hdr
* *table
)
4042 while (!(table
[tabindex
]->flag
& ARG_TERMINATOR
))
4049 void arg_parse_tagged(int argc
,
4051 struct arg_hdr
* *table
,
4052 struct arg_end
*endtable
)
4054 struct longoptions
*longoptions
;
4058 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4060 /* allocate short and long option arrays for the given opttable[]. */
4061 /* if the allocs fail then put an error msg in the last table entry. */
4062 longoptions
= alloc_longoptions(table
);
4063 shortoptions
= alloc_shortoptions(table
);
4064 if (!longoptions
|| !shortoptions
)
4066 /* one or both memory allocs failed */
4067 arg_register_error(endtable
, endtable
, ARG_EMALLOC
, NULL
);
4068 /* free anything that was allocated (this is null safe) */
4074 /*dump_longoptions(longoptions);*/
4076 /* reset getopts internal option-index to zero, and disable error reporting */
4080 /* fetch and process args using getopt_long */
4082 getopt_long(argc
, argv
, shortoptions
, longoptions
->options
,
4086 printf("optarg='%s'\n",optarg);
4087 printf("optind=%d\n",optind);
4088 printf("copt=%c\n",(char)copt);
4089 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
4095 int tabindex
= longoptions
->getoptval
;
4096 void *parent
= table
[tabindex
]->parent
;
4097 /*printf("long option detected from argtable[%d]\n", tabindex);*/
4098 if (optarg
&& optarg
[0] == 0 &&
4099 (table
[tabindex
]->flag
& ARG_HASVALUE
))
4101 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
4102 arg_register_error(endtable
, endtable
, ARG_EMISSARG
,
4104 /* continue to scan the (empty) argument value to enforce argument count checking */
4106 if (table
[tabindex
]->scanfn
)
4108 int errorcode
= table
[tabindex
]->scanfn(parent
, optarg
);
4110 arg_register_error(endtable
, parent
, errorcode
, optarg
);
4117 * getopt_long() found an unrecognised short option.
4118 * if it was a short option its value is in optopt
4119 * if it was a long option then optopt=0
4124 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4125 arg_register_error(endtable
, endtable
, ARG_ELONGOPT
,
4129 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4130 arg_register_error(endtable
, endtable
, optopt
, NULL
);
4137 * getopt_long() found an option with its argument missing.
4139 /*printf(": option %s requires an argument\n",argv[optind-1]); */
4140 arg_register_error(endtable
, endtable
, ARG_EMISSARG
,
4146 /* getopt_long() found a valid short option */
4147 int tabindex
= find_shortoption(table
, (char)copt
);
4148 /*printf("short option detected from argtable[%d]\n", tabindex);*/
4151 /* should never get here - but handle it just in case */
4152 /*printf("unrecognised short option %d\n",copt);*/
4153 arg_register_error(endtable
, endtable
, copt
, NULL
);
4157 if (table
[tabindex
]->scanfn
)
4159 void *parent
= table
[tabindex
]->parent
;
4160 int errorcode
= table
[tabindex
]->scanfn(parent
, optarg
);
4162 arg_register_error(endtable
, parent
, errorcode
, optarg
);
4176 void arg_parse_untagged(int argc
,
4178 struct arg_hdr
* *table
,
4179 struct arg_end
*endtable
)
4183 const char *optarglast
= NULL
;
4184 void *parentlast
= NULL
;
4186 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4187 while (!(table
[tabindex
]->flag
& ARG_TERMINATOR
))
4192 /* if we have exhausted our argv[optind] entries then we have finished */
4195 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4199 /* skip table entries with non-null long or short options (they are not untagged entries) */
4200 if (table
[tabindex
]->longopts
|| table
[tabindex
]->shortopts
)
4202 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
4207 /* skip table entries with NULL scanfn */
4208 if (!(table
[tabindex
]->scanfn
))
4210 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4215 /* attempt to scan the current argv[optind] with the current */
4216 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
4217 /* try again with the next table[] entry. */
4218 parent
= table
[tabindex
]->parent
;
4219 errorcode
= table
[tabindex
]->scanfn(parent
, argv
[optind
]);
4222 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4223 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4226 /* clear the last tentative error */
4231 /* failure, try same argv[optind] with next table[tabindex] entry */
4232 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4235 /* remember this as a tentative error we may wish to reinstate later */
4236 errorlast
= errorcode
;
4237 optarglast
= argv
[optind
];
4238 parentlast
= parent
;
4243 /* if a tenative error still remains at this point then register it as a proper error */
4246 arg_register_error(endtable
, parentlast
, errorlast
, optarglast
);
4250 /* only get here when not all argv[] entries were consumed */
4251 /* register an error for each unused argv[] entry */
4252 while (optind
< argc
)
4254 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4255 arg_register_error(endtable
, endtable
, ARG_ENOMATCH
, argv
[optind
++]);
4263 void arg_parse_check(struct arg_hdr
* *table
, struct arg_end
*endtable
)
4266 /* printf("arg_parse_check()\n"); */
4269 if (table
[tabindex
]->checkfn
)
4271 void *parent
= table
[tabindex
]->parent
;
4272 int errorcode
= table
[tabindex
]->checkfn(parent
);
4274 arg_register_error(endtable
, parent
, errorcode
, NULL
);
4276 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4281 void arg_reset(void * *argtable
)
4283 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4285 /*printf("arg_reset(%p)\n",argtable);*/
4288 if (table
[tabindex
]->resetfn
)
4289 table
[tabindex
]->resetfn(table
[tabindex
]->parent
);
4290 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4294 int arg_parse(int argc
, char * *argv
, void * *argtable
)
4296 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4297 struct arg_end
*endtable
;
4299 char * *argvcopy
= NULL
;
4301 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4303 /* reset any argtable data from previous invocations */
4304 arg_reset(argtable
);
4306 /* locate the first end-of-table marker within the array */
4307 endindex
= arg_endindex(table
);
4308 endtable
= (struct arg_end
*)table
[endindex
];
4310 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4311 /* Failure to trap this case results in an unwanted NULL result from */
4312 /* the malloc for argvcopy (next code block). */
4315 /* We must still perform post-parse checks despite the absence of command line arguments */
4316 arg_parse_check(table
, endtable
);
4318 /* Now we are finished */
4319 return endtable
->count
;
4322 argvcopy
= (char **)malloc(sizeof(char *) * (argc
+ 1));
4328 Fill in the local copy of argv[]. We need a local copy
4329 because getopt rearranges argv[] which adversely affects
4330 susbsequent parsing attempts.
4332 for (i
= 0; i
< argc
; i
++)
4333 argvcopy
[i
] = argv
[i
];
4335 argvcopy
[argc
] = NULL
;
4337 /* parse the command line (local copy) for tagged options */
4338 arg_parse_tagged(argc
, argvcopy
, table
, endtable
);
4340 /* parse the command line (local copy) for untagged options */
4341 arg_parse_untagged(argc
, argvcopy
, table
, endtable
);
4343 /* if no errors so far then perform post-parse checks otherwise dont bother */
4344 if (endtable
->count
== 0)
4345 arg_parse_check(table
, endtable
);
4347 /* release the local copt of argv[] */
4352 /* memory alloc failed */
4353 arg_register_error(endtable
, endtable
, ARG_EMALLOC
, NULL
);
4356 return endtable
->count
;
4361 * Concatenate contents of src[] string onto *pdest[] string.
4362 * The *pdest pointer is altered to point to the end of the
4363 * target string and *pndest is decremented by the same number
4365 * Does not append more than *pndest chars into *pdest[]
4366 * so as to prevent buffer overruns.
4367 * Its something like strncat() but more efficient for repeated
4368 * calls on the same destination string.
4370 * char dest[30] = "good"
4371 * size_t ndest = sizeof(dest);
4372 * char *pdest = dest;
4373 * arg_char(&pdest,"bye ",&ndest);
4374 * arg_char(&pdest,"cruel ",&ndest);
4375 * arg_char(&pdest,"world!",&ndest);
4377 * dest[] == "goodbye cruel world!"
4381 void arg_cat(char * *pdest
, const char *src
, size_t *pndest
)
4383 char *dest
= *pdest
;
4384 char *end
= dest
+ *pndest
;
4386 /*locate null terminator of dest string */
4387 while(dest
< end
&& *dest
!= 0)
4390 /* concat src string to dest string */
4391 while(dest
< end
&& *src
!= 0)
4394 /* null terminate dest string */
4397 /* update *pdest and *pndest */
4398 *pndest
= end
- dest
;
4404 void arg_cat_option(char *dest
,
4406 const char *shortopts
,
4407 const char *longopts
,
4408 const char *datatype
,
4415 /* note: option array[] is initialiazed dynamically here to satisfy */
4416 /* a deficiency in the watcom compiler wrt static array initializers. */
4418 option
[1] = shortopts
[0];
4421 arg_cat(&dest
, option
, &ndest
);
4424 arg_cat(&dest
, " ", &ndest
);
4427 arg_cat(&dest
, "[", &ndest
);
4428 arg_cat(&dest
, datatype
, &ndest
);
4429 arg_cat(&dest
, "]", &ndest
);
4432 arg_cat(&dest
, datatype
, &ndest
);
4439 /* add "--" tag prefix */
4440 arg_cat(&dest
, "--", &ndest
);
4442 /* add comma separated option tag */
4443 ncspn
= strcspn(longopts
, ",");
4444 #ifdef __STDC_WANT_SECURE_LIB__
4445 strncat_s(dest
, ndest
, longopts
, (ncspn
< ndest
) ? ncspn
: ndest
);
4447 strncat(dest
, longopts
, (ncspn
< ndest
) ? ncspn
: ndest
);
4452 arg_cat(&dest
, "=", &ndest
);
4455 arg_cat(&dest
, "[", &ndest
);
4456 arg_cat(&dest
, datatype
, &ndest
);
4457 arg_cat(&dest
, "]", &ndest
);
4460 arg_cat(&dest
, datatype
, &ndest
);
4467 arg_cat(&dest
, "[", &ndest
);
4468 arg_cat(&dest
, datatype
, &ndest
);
4469 arg_cat(&dest
, "]", &ndest
);
4472 arg_cat(&dest
, datatype
, &ndest
);
4477 void arg_cat_optionv(char *dest
,
4479 const char *shortopts
,
4480 const char *longopts
,
4481 const char *datatype
,
4483 const char *separator
)
4485 separator
= separator
? separator
: "";
4489 const char *c
= shortopts
;
4495 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4496 /* a deficiency in the watcom compiler wrt static array initializers. */
4501 arg_cat(&dest
, shortopt
, &ndest
);
4503 arg_cat(&dest
, separator
, &ndest
);
4507 /* put separator between long opts and short opts */
4508 if (shortopts
&& longopts
)
4509 arg_cat(&dest
, separator
, &ndest
);
4513 const char *c
= longopts
;
4518 /* add "--" tag prefix */
4519 arg_cat(&dest
, "--", &ndest
);
4521 /* add comma separated option tag */
4522 ncspn
= strcspn(c
, ",");
4523 #ifdef __STDC_WANT_SECURE_LIB__
4524 strncat_s(dest
, ndest
, c
, (ncspn
< ndest
) ? ncspn
: ndest
);
4526 strncat(dest
, c
, (ncspn
< ndest
) ? ncspn
: ndest
);
4530 /* add given separator in place of comma */
4533 arg_cat(&dest
, separator
, &ndest
);
4542 arg_cat(&dest
, "=", &ndest
);
4544 arg_cat(&dest
, " ", &ndest
);
4548 arg_cat(&dest
, "[", &ndest
);
4549 arg_cat(&dest
, datatype
, &ndest
);
4550 arg_cat(&dest
, "]", &ndest
);
4553 arg_cat(&dest
, datatype
, &ndest
);
4558 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4559 void arg_print_option(FILE *fp
,
4560 const char *shortopts
,
4561 const char *longopts
,
4562 const char *datatype
,
4565 char syntax
[200] = "";
4566 suffix
= suffix
? suffix
: "";
4568 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4569 arg_cat_optionv(syntax
,
4583 * Print a GNU style [OPTION] string in which all short options that
4584 * do not take argument values are presented in abbreviated form, as
4585 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4588 void arg_print_gnuswitch(FILE *fp
, struct arg_hdr
* *table
)
4591 char *format1
= " -%c";
4592 char *format2
= " [-%c";
4595 /* print all mandatory switches that are without argument values */
4597 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4600 /* skip optional options */
4601 if (table
[tabindex
]->mincount
< 1)
4604 /* skip non-short options */
4605 if (table
[tabindex
]->shortopts
== NULL
)
4608 /* skip options that take argument values */
4609 if (table
[tabindex
]->flag
& ARG_HASVALUE
)
4612 /* print the short option (only the first short option char, ignore multiple choices)*/
4613 fprintf(fp
, format1
, table
[tabindex
]->shortopts
[0]);
4618 /* print all optional switches that are without argument values */
4620 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4623 /* skip mandatory args */
4624 if (table
[tabindex
]->mincount
> 0)
4627 /* skip args without short options */
4628 if (table
[tabindex
]->shortopts
== NULL
)
4631 /* skip args with values */
4632 if (table
[tabindex
]->flag
& ARG_HASVALUE
)
4635 /* print first short option */
4636 fprintf(fp
, format2
, table
[tabindex
]->shortopts
[0]);
4641 fprintf(fp
, "%s", suffix
);
4645 void arg_print_syntax(FILE *fp
, void * *argtable
, const char *suffix
)
4647 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4650 /* print GNU style [OPTION] string */
4651 arg_print_gnuswitch(fp
, table
);
4653 /* print remaining options in abbreviated style */
4655 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4658 char syntax
[200] = "";
4659 const char *shortopts
, *longopts
, *datatype
;
4661 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4662 if (table
[tabindex
]->shortopts
&&
4663 !(table
[tabindex
]->flag
& ARG_HASVALUE
))
4666 shortopts
= table
[tabindex
]->shortopts
;
4667 longopts
= table
[tabindex
]->longopts
;
4668 datatype
= table
[tabindex
]->datatype
;
4669 arg_cat_option(syntax
,
4674 table
[tabindex
]->flag
& ARG_HASOPTVALUE
);
4676 if (strlen(syntax
) > 0)
4678 /* print mandatory instances of this option */
4679 for (i
= 0; i
< table
[tabindex
]->mincount
; i
++)
4680 fprintf(fp
, " %s", syntax
);
4682 /* print optional instances enclosed in "[..]" */
4683 switch ( table
[tabindex
]->maxcount
- table
[tabindex
]->mincount
)
4688 fprintf(fp
, " [%s]", syntax
);
4691 fprintf(fp
, " [%s] [%s]", syntax
, syntax
);
4694 fprintf(fp
, " [%s]...", syntax
);
4701 fprintf(fp
, "%s", suffix
);
4705 void arg_print_syntaxv(FILE *fp
, void * *argtable
, const char *suffix
)
4707 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4710 /* print remaining options in abbreviated style */
4712 table
[tabindex
] && !(table
[tabindex
]->flag
& ARG_TERMINATOR
);
4715 char syntax
[200] = "";
4716 const char *shortopts
, *longopts
, *datatype
;
4718 shortopts
= table
[tabindex
]->shortopts
;
4719 longopts
= table
[tabindex
]->longopts
;
4720 datatype
= table
[tabindex
]->datatype
;
4721 arg_cat_optionv(syntax
,
4726 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4729 /* print mandatory options */
4730 for (i
= 0; i
< table
[tabindex
]->mincount
; i
++)
4731 fprintf(fp
, " %s", syntax
);
4733 /* print optional args enclosed in "[..]" */
4734 switch ( table
[tabindex
]->maxcount
- table
[tabindex
]->mincount
)
4739 fprintf(fp
, " [%s]", syntax
);
4742 fprintf(fp
, " [%s] [%s]", syntax
, syntax
);
4745 fprintf(fp
, " [%s]...", syntax
);
4751 fprintf(fp
, "%s", suffix
);
4755 void arg_print_glossary(FILE *fp
, void * *argtable
, const char *format
)
4757 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4760 format
= format
? format
: " %-20s %s\n";
4761 for (tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4763 if (table
[tabindex
]->glossary
)
4765 char syntax
[200] = "";
4766 const char *shortopts
= table
[tabindex
]->shortopts
;
4767 const char *longopts
= table
[tabindex
]->longopts
;
4768 const char *datatype
= table
[tabindex
]->datatype
;
4769 const char *glossary
= table
[tabindex
]->glossary
;
4770 arg_cat_optionv(syntax
,
4775 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4777 fprintf(fp
, format
, syntax
, glossary
);
4784 * Print a piece of text formatted, which means in a column with a
4785 * left and a right margin. The lines are wrapped at whitspaces next
4786 * to right margin. The function does not indent the first line, but
4787 * only the following ones.
4790 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4791 * will result in the following output:
4799 * Too long lines will be wrapped in the middle of a word.
4801 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4802 * will result in the following output:
4810 * As you see, the first line is not indented. This enables output of
4811 * lines, which start in a line where output already happened.
4813 * Author: Uli Fouquet
4816 void arg_print_formatted( FILE *fp
,
4817 const unsigned lmargin
,
4818 const unsigned rmargin
,
4821 const unsigned textlen
= (unsigned)strlen( text
);
4822 unsigned line_start
= 0;
4823 unsigned line_end
= textlen
+ 1;
4824 const unsigned colwidth
= (rmargin
- lmargin
) + 1;
4826 /* Someone doesn't like us... */
4827 if ( line_end
< line_start
)
4828 { fprintf( fp
, "%s\n", text
); }
4830 while (line_end
- 1 > line_start
)
4832 /* Eat leading whitespaces. This is essential because while
4833 wrapping lines, there will often be a whitespace at beginning
4835 while ( ISSPACE(*(text
+ line_start
)) )
4838 if ((line_end
- line_start
) > colwidth
)
4839 { line_end
= line_start
+ colwidth
; }
4841 /* Find last whitespace, that fits into line */
4842 while ( ( line_end
> line_start
)
4843 && ( line_end
- line_start
> colwidth
)
4844 && !ISSPACE(*(text
+ line_end
)))
4847 /* Do not print trailing whitespace. If this text
4848 has got only one line, line_end now points to the
4849 last char due to initialization. */
4852 /* Output line of text */
4853 while ( line_start
< line_end
)
4855 fputc(*(text
+ line_start
), fp
);
4860 /* Initialize another line */
4861 if ( line_end
+ 1 < textlen
)
4865 for (i
= 0; i
< lmargin
; i
++ )
4866 { fputc( ' ', fp
); }
4871 /* If we have to print another line, get also the last char. */
4874 } /* lines of text */
4878 * Prints the glossary in strict GNU format.
4879 * Differences to arg_print_glossary() are:
4880 * - wraps lines after 80 chars
4881 * - indents lines without shortops
4882 * - does not accept formatstrings
4884 * Contributed by Uli Fouquet
4886 void arg_print_glossary_gnu(FILE *fp
, void * *argtable
)
4888 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4891 for(tabindex
= 0; !(table
[tabindex
]->flag
& ARG_TERMINATOR
); tabindex
++)
4893 if (table
[tabindex
]->glossary
)
4895 char syntax
[200] = "";
4896 const char *shortopts
= table
[tabindex
]->shortopts
;
4897 const char *longopts
= table
[tabindex
]->longopts
;
4898 const char *datatype
= table
[tabindex
]->datatype
;
4899 const char *glossary
= table
[tabindex
]->glossary
;
4901 if ( !shortopts
&& longopts
)
4903 /* Indent trailing line by 4 spaces... */
4904 memset( syntax
, ' ', 4 );
4905 *(syntax
+ 4) = '\0';
4908 arg_cat_optionv(syntax
,
4913 table
[tabindex
]->flag
& ARG_HASOPTVALUE
,
4916 /* If syntax fits not into column, print glossary in new line... */
4917 if ( strlen(syntax
) > 25 )
4919 fprintf( fp
, " %-25s %s\n", syntax
, "" );
4923 fprintf( fp
, " %-25s ", syntax
);
4924 arg_print_formatted( fp
, 28, 79, glossary
);
4926 } /* for each table entry */
4933 * Checks the argtable[] array for NULL entries and returns 1
4934 * if any are found, zero otherwise.
4936 int arg_nullcheck(void * *argtable
)
4938 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4940 /*printf("arg_nullcheck(%p)\n",argtable);*/
4948 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4949 if (!table
[tabindex
])
4951 } while(!(table
[tabindex
++]->flag
& ARG_TERMINATOR
));
4958 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4959 * The flaw results in memory leak in the (very rare) case that an intermediate
4960 * entry in the argtable array failed its memory allocation while others following
4961 * that entry were still allocated ok. Those subsequent allocations will not be
4962 * deallocated by arg_free().
4963 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4964 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4965 * with the newer arg_freetable() function.
4966 * We still keep arg_free() for backwards compatibility.
4968 void arg_free(void * *argtable
)
4970 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4973 /*printf("arg_free(%p)\n",argtable);*/
4977 if we encounter a NULL entry then somewhat incorrectly we presume
4978 we have come to the end of the array. It isnt strictly true because
4979 an intermediate entry could be NULL with other non-NULL entries to follow.
4980 The subsequent argtable entries would then not be freed as they should.
4982 if (table
[tabindex
] == NULL
)
4985 flag
= table
[tabindex
]->flag
;
4986 free(table
[tabindex
]);
4987 table
[tabindex
++] = NULL
;
4989 } while(!(flag
& ARG_TERMINATOR
));
4992 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4993 void arg_freetable(void * *argtable
, size_t n
)
4995 struct arg_hdr
* *table
= (struct arg_hdr
* *)argtable
;
4996 size_t tabindex
= 0;
4997 /*printf("arg_freetable(%p)\n",argtable);*/
4998 for (tabindex
= 0; tabindex
< n
; tabindex
++)
5000 if (table
[tabindex
] == NULL
)
5003 free(table
[tabindex
]);
5004 table
[tabindex
] = NULL
;