Cleanup armsrc/string.c and string.h (#964)
[legacy-proxmark3.git] / client / cliparser / argtable3.c
blobc661d26f7b30d781976c6c91fe53819c7ce66360
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>
6 * All rights reserved.
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
35 #ifdef UNICODE
36 #include <tchar.h>
37 #define ISSPACE _istspace
38 #else
39 #define ISSPACE isspace
40 #endif
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 ******************************************************************************/
72 #ifndef ARG_UTILS_H
73 #define ARG_UTILS_H
75 #define ARG_ENABLE_TRACE 0
76 #define ARG_ENABLE_LOG 1
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
82 enum
84 EMINCOUNT = 1,
85 EMAXCOUNT,
86 EBADINT,
87 // The same name define EOVERFLOW in errno.h on windows platform
88 #ifdef __STDC_WANT_SECURE_LIB__
89 EOVERFLOW_,
90 #else
91 EOVERFLOW,
92 #endif
93 EBADDOUBLE,
94 EBADDATE,
95 EREGNOMATCH
99 #if defined(_MSC_VER)
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))
106 #define ARG_LOG(x) \
107 __pragma(warning(push)) \
108 __pragma(warning(disable:4127)) \
109 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
110 __pragma(warning(pop))
111 #else
112 #define ARG_TRACE(x) \
113 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
115 #define ARG_LOG(x) \
116 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
117 #endif
119 extern void dbg_printf(const char *fmt, ...);
121 #ifdef __cplusplus
123 #endif
125 #endif
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 ******************************************************************************/
157 #include <stdarg.h>
158 #include <stdio.h>
161 void dbg_printf(const char *fmt, ...)
163 va_list args;
164 va_start(args, fmt);
165 vfprintf(stderr, fmt, args);
166 va_end(args);
169 /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
170 /* $FreeBSD$ */
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
183 * are met:
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.
203 #ifndef _GETOPT_H_
204 #define _GETOPT_H_
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
216 struct option {
217 /* name of long option */
218 const char *name;
220 * one of no_argument, required_argument, and optional_argument:
221 * whether option takes an argument
223 int has_arg;
224 /* if not NULL, set *flag to val when option found */
225 int *flag;
226 /* if flag not NULL, value to set *flag to; else return value */
227 int val;
230 __BEGIN_DECLS
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;
241 #endif
242 #ifndef _OPTRESET_DECLARED
243 #define _OPTRESET_DECLARED
244 extern int optreset; /* getopt(3) external variable */
245 #endif
246 __END_DECLS
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
284 * are met:
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.
304 #if 0
305 #include <err.h>
306 #endif
307 #include <errno.h>
308 #include <stdlib.h>
309 #include <string.h>
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 */
320 #endif
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 */
328 /* return values */
329 #define BADCH (int)'?'
330 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
331 #define INORDER (int)1
333 #define EMSG ""
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) */
348 /* Error messages */
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";
358 #ifdef _WIN32
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.
367 #include <stdio.h>
368 #include <stdarg.h>
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, ...)
377 va_list ap;
378 va_start(ap, 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);
384 if (fmt != NULL)
385 #ifdef __STDC_WANT_SECURE_LIB__
386 _vsnprintf_s(opterrmsg, MAX_OPTER_MSG_SIZE, sizeof(opterrmsg) - 1, fmt, ap);
387 #else
388 _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
389 #endif
390 va_end(ap);
392 #if defined(_MSC_VER)
393 #pragma warning(suppress: 6053)
394 #endif
395 fprintf(stderr, "%s\n", opterrmsg);
398 #else
399 #include <err.h>
400 #endif /*_WIN32*/
404 * Compute the greatest common divisor of a and b.
406 static int
407 gcd(int a, int b)
409 int c;
411 c = a % b;
412 while (c != 0) {
413 a = b;
414 b = c;
415 c = a % b;
418 return (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
424 * in each block).
426 static void
427 permute_args(int panonopt_start, int panonopt_end, int opt_end,
428 char * const *nargv)
430 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
431 char *swap;
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;
443 pos = cstart;
444 for (j = 0; j < cyclelen; j++) {
445 if (pos >= panonopt_end)
446 pos -= nnonopts;
447 else
448 pos += nopts;
449 swap = nargv[pos];
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.
463 static int
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;
469 int i, match;
471 current_argv = place;
472 match = -1;
474 optind++;
476 if ((has_equal = strchr(current_argv, '=')) != NULL) {
477 /* argument found (--option=arg) */
478 current_argv_len = has_equal - current_argv;
479 has_equal++;
480 } else
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,
486 current_argv_len))
487 continue;
489 if (strlen(long_options[i].name) == current_argv_len) {
490 /* exact match */
491 match = i;
492 break;
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)
499 continue;
501 if (match == -1) /* partial match */
502 match = i;
503 else {
504 /* ambiguous abbreviation */
505 if (PRINT_ERROR)
506 warnx(ambig, (int)current_argv_len,
507 current_argv);
508 optopt = 0;
509 return (BADCH);
512 if (match != -1) { /* option found */
513 if (long_options[match].has_arg == no_argument
514 && has_equal) {
515 if (PRINT_ERROR)
516 warnx(noarg, (int)current_argv_len,
517 current_argv);
519 * XXX: GNU sets optopt to val regardless of flag
521 if (long_options[match].flag == NULL)
522 optopt = long_options[match].val;
523 else
524 optopt = 0;
525 return (BADARG);
527 if (long_options[match].has_arg == required_argument ||
528 long_options[match].has_arg == optional_argument) {
529 if (has_equal)
530 optarg = has_equal;
531 else if (long_options[match].has_arg ==
532 required_argument) {
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.
545 if (PRINT_ERROR)
546 warnx(recargstring,
547 current_argv);
549 * XXX: GNU sets optopt to val regardless of flag
551 if (long_options[match].flag == NULL)
552 optopt = long_options[match].val;
553 else
554 optopt = 0;
555 --optind;
556 return (BADARG);
558 } else { /* unknown option */
559 if (short_too) {
560 --optind;
561 return (-1);
563 if (PRINT_ERROR)
564 warnx(illoptstring, current_argv);
565 optopt = 0;
566 return (BADCH);
568 if (idx)
569 *idx = match;
570 if (long_options[match].flag) {
571 *long_options[match].flag = long_options[match].val;
572 return (0);
573 } else
574 return (long_options[match].val);
578 * getopt_internal --
579 * Parse argc/argv argument vector. Called by user level routines.
581 static int
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__
589 char* buffer = NULL;
590 size_t buffer_size = 0;
591 errno_t err = 0;
592 #endif
594 if (options == NULL)
595 return (-1);
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) {
607 free(buffer);
610 #else
611 if (posixly_correct == -1)
612 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
613 #endif
614 if (posixly_correct || *options == '+')
615 flags &= ~FLAG_PERMUTE;
616 else if (*options == '-')
617 flags |= FLAG_ALLARGS;
618 if (*options == '+' || *options == '-')
619 options++;
622 * XXX Some GNU programs (like cvs) set optind to 0 instead of
623 * XXX using optreset. Work around this braindamage.
625 if (optind == 0)
626 optind = optreset = 1;
628 optarg = NULL;
629 if (optreset)
630 nonopt_start = nonopt_end = -1;
631 start:
632 if (optreset || !*place) { /* update scanning pointer */
633 optreset = 0;
634 if (optind >= nargc) { /* end of argument vector */
635 place = EMSG;
636 if (nonopt_end != -1) {
637 /* do permutation, if we have to */
638 permute_args(nonopt_start, nonopt_end,
639 optind, nargv);
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;
650 return (-1);
652 if (*(place = nargv[optind]) != '-' ||
653 (place[1] == '\0' && strchr(options, '-') == NULL)) {
654 place = EMSG; /* found non-option */
655 if (flags & FLAG_ALLARGS) {
657 * GNU extension:
658 * return non-option as argument to option 1
660 optarg = nargv[optind++];
661 return (INORDER);
663 if (!(flags & FLAG_PERMUTE)) {
665 * If no permutation wanted, stop parsing
666 * at first non-option.
668 return (-1);
670 /* do permutation */
671 if (nonopt_start == -1)
672 nonopt_start = optind;
673 else if (nonopt_end != -1) {
674 permute_args(nonopt_start, nonopt_end,
675 optind, nargv);
676 nonopt_start = optind -
677 (nonopt_end - nonopt_start);
678 nonopt_end = -1;
680 optind++;
681 /* process next argument */
682 goto start;
684 if (nonopt_start != -1 && nonopt_end == -1)
685 nonopt_end = optind;
688 * If we have "-" do nothing, if "--" we are done.
690 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
691 optind++;
692 place = EMSG;
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,
699 optind, nargv);
700 optind -= nonopt_end - nonopt_start;
702 nonopt_start = nonopt_end = -1;
703 return (-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))) {
715 short_too = 0;
716 if (*place == '-')
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,
722 idx, short_too);
723 if (optchar != -1) {
724 place = EMSG;
725 return (optchar);
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')
738 return (-1);
739 if (!*place)
740 ++optind;
741 if (PRINT_ERROR)
742 warnx(illoptchar, optchar);
743 optopt = optchar;
744 return (BADCH);
746 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
747 /* -W long-option */
748 if (*place) /* no space */
749 /* NOTHING */;
750 else if (++optind >= nargc) { /* no arg */
751 place = EMSG;
752 if (PRINT_ERROR)
753 warnx(recargchar, optchar);
754 optopt = optchar;
755 return (BADARG);
756 } else /* white space */
757 place = nargv[optind];
758 optchar = parse_long_options(nargv, options, long_options,
759 idx, 0);
760 place = EMSG;
761 return (optchar);
763 if (*++oli != ':') { /* doesn't take argument */
764 if (!*place)
765 ++optind;
766 } else { /* takes (optional) argument */
767 optarg = NULL;
768 if (*place) /* no white space */
769 optarg = place;
770 else if (oli[1] != ':') { /* arg not optional */
771 if (++optind >= nargc) { /* no arg */
772 place = EMSG;
773 if (PRINT_ERROR)
774 warnx(recargchar, optchar);
775 optopt = optchar;
776 return (BADARG);
777 } else
778 optarg = nargv[optind];
780 place = EMSG;
781 ++optind;
783 /* dump back option letter */
784 return (optchar);
787 #ifdef REPLACE_GETOPT
789 * 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 */
811 * getopt_long --
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,
820 FLAG_PERMUTE));
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 ******************************************************************************/
865 #include <stdlib.h>
866 #include <string.h>
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));
877 parent->count = 0;
881 static int arg_date_scanfn(struct arg_date *parent, const char *argval)
883 int errorcode = 0;
885 if (parent->count == parent->hdr.maxcount)
887 errorcode = EMAXCOUNT;
889 else if (!argval)
891 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
892 parent->count++;
894 else
896 const char *pend;
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;
903 else
904 errorcode = EBADDATE;
907 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
908 return 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));
917 return errorcode;
921 static void arg_date_errorfn(
922 struct arg_date *parent,
923 FILE *fp,
924 int errorcode,
925 const char *argval,
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);
936 switch(errorcode)
938 case EMINCOUNT:
939 fputs("missing option ", fp);
940 arg_print_option(fp, shortopts, longopts, datatype, "\n");
941 break;
943 case EMAXCOUNT:
944 fputs("excess option ", fp);
945 arg_print_option(fp, shortopts, longopts, argval, "\n");
946 break;
948 case EBADDATE:
950 struct tm tm;
951 char buff[200];
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);
958 break;
964 struct arg_date * arg_date0(
965 const char * shortopts,
966 const char * longopts,
967 const char * format,
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,
978 const char * format,
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,
989 const char * format,
990 const char *datatype,
991 int mincount,
992 int maxcount,
993 const char *glossary)
995 size_t nbytes;
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 */
1002 if (!format)
1003 format = "%x";
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);
1011 if (result)
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 */
1031 result->count = 0;
1032 result->format = format;
1035 ARG_TRACE(("arg_daten() returns %p\n", result));
1036 return 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
1049 * are met:
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.
1069 #include <ctype.h>
1070 #include <string.h>
1071 #include <time.h>
1074 * We do not implement alternate representations. However, we always
1075 * check whether a given modifier is allowed for a certain conversion.
1077 #define ALT_E 0x01
1078 #define ALT_O 0x02
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] = {
1104 "AM", "PM"
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++))
1113 if (*us1++ == '\0')
1114 return 0;
1116 return tolower(*us1) - tolower(*--us2);
1120 static int arg_strncasecmp(const char *s1, const char *s2, size_t n)
1122 if (n != 0)
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);
1131 if (*us1++ == '\0')
1132 break;
1133 } while (--n != 0);
1136 return 0;
1140 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm)
1142 char c;
1143 const char *bp;
1144 size_t len = 0;
1145 int alt_format, i, split_year = 0;
1147 bp = buf;
1149 while ((c = *fmt) != '\0') {
1150 /* Clear `alternate' modifier prior to new conversion. */
1151 alt_format = 0;
1153 /* Eat up white-space. */
1154 if (ISSPACE(c)) {
1155 while (ISSPACE(*bp))
1156 bp++;
1158 fmt++;
1159 continue;
1162 if ((c = *fmt++) != '%')
1163 goto literal;
1166 again:
1167 switch (c = *fmt++)
1169 case '%': /* "%%" is converted to "%". */
1170 literal:
1171 if (c != *bp++)
1172 return (0);
1173 break;
1176 * "Alternative" modifiers. Just set the appropriate flag
1177 * and start over again.
1179 case 'E': /* "%E?" alternative conversion modifier. */
1180 LEGAL_ALT(0);
1181 alt_format |= ALT_E;
1182 goto again;
1184 case 'O': /* "%O?" alternative conversion modifier. */
1185 LEGAL_ALT(0);
1186 alt_format |= ALT_O;
1187 goto again;
1190 * "Complex" conversion rules, implemented through recursion.
1192 case 'c': /* Date and time, using the locale's format. */
1193 LEGAL_ALT(ALT_E);
1194 bp = arg_strptime(bp, "%x %X", tm);
1195 if (!bp)
1196 return (0);
1197 break;
1199 case 'D': /* The date as "%m/%d/%y". */
1200 LEGAL_ALT(0);
1201 bp = arg_strptime(bp, "%m/%d/%y", tm);
1202 if (!bp)
1203 return (0);
1204 break;
1206 case 'R': /* The time as "%H:%M". */
1207 LEGAL_ALT(0);
1208 bp = arg_strptime(bp, "%H:%M", tm);
1209 if (!bp)
1210 return (0);
1211 break;
1213 case 'r': /* The time in 12-hour clock representation. */
1214 LEGAL_ALT(0);
1215 bp = arg_strptime(bp, "%I:%M:%S %p", tm);
1216 if (!bp)
1217 return (0);
1218 break;
1220 case 'T': /* The time as "%H:%M:%S". */
1221 LEGAL_ALT(0);
1222 bp = arg_strptime(bp, "%H:%M:%S", tm);
1223 if (!bp)
1224 return (0);
1225 break;
1227 case 'X': /* The time, using the locale's format. */
1228 LEGAL_ALT(ALT_E);
1229 bp = arg_strptime(bp, "%H:%M:%S", tm);
1230 if (!bp)
1231 return (0);
1232 break;
1234 case 'x': /* The date, using the locale's format. */
1235 LEGAL_ALT(ALT_E);
1236 bp = arg_strptime(bp, "%m/%d/%y", tm);
1237 if (!bp)
1238 return (0);
1239 break;
1242 * "Elementary" conversion rules.
1244 case 'A': /* The day of week, using the locale's form. */
1245 case 'a':
1246 LEGAL_ALT(0);
1247 for (i = 0; i < 7; i++) {
1248 /* Full name. */
1249 len = strlen(day[i]);
1250 if (arg_strncasecmp(day[i], bp, len) == 0)
1251 break;
1253 /* Abbreviated name. */
1254 len = strlen(abday[i]);
1255 if (arg_strncasecmp(abday[i], bp, len) == 0)
1256 break;
1259 /* Nothing matched. */
1260 if (i == 7)
1261 return (0);
1263 tm->tm_wday = i;
1264 bp += len;
1265 break;
1267 case 'B': /* The month, using the locale's form. */
1268 case 'b':
1269 case 'h':
1270 LEGAL_ALT(0);
1271 for (i = 0; i < 12; i++) {
1272 /* Full name. */
1273 len = strlen(mon[i]);
1274 if (arg_strncasecmp(mon[i], bp, len) == 0)
1275 break;
1277 /* Abbreviated name. */
1278 len = strlen(abmon[i]);
1279 if (arg_strncasecmp(abmon[i], bp, len) == 0)
1280 break;
1283 /* Nothing matched. */
1284 if (i == 12)
1285 return (0);
1287 tm->tm_mon = i;
1288 bp += len;
1289 break;
1291 case 'C': /* The century number. */
1292 LEGAL_ALT(ALT_E);
1293 if (!(conv_num(&bp, &i, 0, 99)))
1294 return (0);
1296 if (split_year) {
1297 tm->tm_year = (tm->tm_year % 100) + (i * 100);
1298 } else {
1299 tm->tm_year = i * 100;
1300 split_year = 1;
1302 break;
1304 case 'd': /* The day of month. */
1305 case 'e':
1306 LEGAL_ALT(ALT_O);
1307 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
1308 return (0);
1309 break;
1311 case 'k': /* The hour (24-hour clock representation). */
1312 LEGAL_ALT(0);
1313 /* FALLTHROUGH */
1314 case 'H':
1315 LEGAL_ALT(ALT_O);
1316 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
1317 return (0);
1318 break;
1320 case 'l': /* The hour (12-hour clock representation). */
1321 LEGAL_ALT(0);
1322 /* FALLTHROUGH */
1323 case 'I':
1324 LEGAL_ALT(ALT_O);
1325 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
1326 return (0);
1327 if (tm->tm_hour == 12)
1328 tm->tm_hour = 0;
1329 break;
1331 case 'j': /* The day of year. */
1332 LEGAL_ALT(0);
1333 if (!(conv_num(&bp, &i, 1, 366)))
1334 return (0);
1335 tm->tm_yday = i - 1;
1336 break;
1338 case 'M': /* The minute. */
1339 LEGAL_ALT(ALT_O);
1340 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
1341 return (0);
1342 break;
1344 case 'm': /* The month. */
1345 LEGAL_ALT(ALT_O);
1346 if (!(conv_num(&bp, &i, 1, 12)))
1347 return (0);
1348 tm->tm_mon = i - 1;
1349 break;
1351 case 'p': /* The locale's equivalent of AM/PM. */
1352 LEGAL_ALT(0);
1353 /* AM? */
1354 if (arg_strcasecmp(am_pm[0], bp) == 0) {
1355 if (tm->tm_hour > 11)
1356 return (0);
1358 bp += strlen(am_pm[0]);
1359 break;
1361 /* PM? */
1362 else if (arg_strcasecmp(am_pm[1], bp) == 0) {
1363 if (tm->tm_hour > 11)
1364 return (0);
1366 tm->tm_hour += 12;
1367 bp += strlen(am_pm[1]);
1368 break;
1371 /* Nothing matched. */
1372 return (0);
1374 case 'S': /* The seconds. */
1375 LEGAL_ALT(ALT_O);
1376 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
1377 return (0);
1378 break;
1380 case 'U': /* The week of year, beginning on sunday. */
1381 case 'W': /* The week of year, beginning on monday. */
1382 LEGAL_ALT(ALT_O);
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
1387 * range for now.
1389 if (!(conv_num(&bp, &i, 0, 53)))
1390 return (0);
1391 break;
1393 case 'w': /* The day of week, beginning on sunday. */
1394 LEGAL_ALT(ALT_O);
1395 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
1396 return (0);
1397 break;
1399 case 'Y': /* The year. */
1400 LEGAL_ALT(ALT_E);
1401 if (!(conv_num(&bp, &i, 0, 9999)))
1402 return (0);
1404 tm->tm_year = i - TM_YEAR_BASE;
1405 break;
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)))
1410 return (0);
1412 if (split_year) {
1413 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
1414 break;
1416 split_year = 1;
1417 if (i <= 68)
1418 tm->tm_year = i + 2000 - TM_YEAR_BASE;
1419 else
1420 tm->tm_year = i + 1900 - TM_YEAR_BASE;
1421 break;
1424 * Miscellaneous conversions.
1426 case 'n': /* Any kind of white-space. */
1427 case 't':
1428 LEGAL_ALT(0);
1429 while (ISSPACE(*bp))
1430 bp++;
1431 break;
1434 default: /* Unknown/unsupported conversion. */
1435 return (0);
1441 /* LINTED functional specification */
1442 return ((char *)bp);
1446 static int conv_num(const char * *buf, int *dest, int llim, int ulim)
1448 int result = 0;
1450 /* The limit also determines the number of valid digits. */
1451 int rulim = ulim;
1453 if (**buf < '0' || **buf > '9')
1454 return (0);
1456 do {
1457 result *= 10;
1458 result += *(*buf)++ - '0';
1459 rulim /= 10;
1460 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
1462 if (result < llim || result > ulim)
1463 return (0);
1465 *dest = result;
1466 return (1);
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 ******************************************************************************/
1498 #include <stdlib.h>
1500 #include "argtable3.h"
1503 static void arg_dbl_resetfn(struct arg_dbl *parent)
1505 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1506 parent->count = 0;
1510 static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval)
1512 int errorcode = 0;
1514 if (parent->count == parent->hdr.maxcount)
1516 /* maximum number of arguments exceeded */
1517 errorcode = EMAXCOUNT;
1519 else if (!argval)
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. */
1524 parent->count++;
1526 else
1528 double val;
1529 char *end;
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*/
1535 if (*end == 0)
1536 parent->dval[parent->count++] = val;
1537 else
1538 errorcode = EBADDOUBLE;
1541 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1542 return 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));
1551 return errorcode;
1555 static void arg_dbl_errorfn(
1556 struct arg_dbl *parent,
1557 FILE *fp,
1558 int errorcode,
1559 const char *argval,
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);
1570 switch(errorcode)
1572 case EMINCOUNT:
1573 fputs("missing option ", fp);
1574 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1575 break;
1577 case EMAXCOUNT:
1578 fputs("excess option ", fp);
1579 arg_print_option(fp, shortopts, longopts, argval, "\n");
1580 break;
1582 case EBADDOUBLE:
1583 fprintf(fp, "invalid argument \"%s\" to option ", argval);
1584 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1585 break;
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,
1614 int mincount,
1615 int maxcount,
1616 const char *glossary)
1618 size_t nbytes;
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);
1628 if (result)
1630 size_t addr;
1631 size_t rem;
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));
1657 result->count = 0;
1660 ARG_TRACE(("arg_dbln() returns %p\n", result));
1661 return 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 ******************************************************************************/
1693 #include <stdlib.h>
1695 #include "argtable3.h"
1698 static void arg_end_resetfn(struct arg_end *parent)
1700 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1701 parent->count = 0;
1704 static void arg_end_errorfn(
1705 void *parent,
1706 FILE *fp,
1707 int error,
1708 const char *argval,
1709 const char *progname)
1711 /* suppress unreferenced formal parameter warning */
1712 (void)parent;
1714 progname = progname ? progname : "";
1715 argval = argval ? argval : "";
1717 fprintf(fp, "%s: ", progname);
1718 switch(error)
1720 case ARG_ELIMIT:
1721 fputs("too many errors to display", fp);
1722 break;
1723 case ARG_EMALLOC:
1724 fputs("insufficent memory", fp);
1725 break;
1726 case ARG_ENOMATCH:
1727 fprintf(fp, "unexpected argument \"%s\"", argval);
1728 break;
1729 case ARG_EMISSARG:
1730 fprintf(fp, "option \"%s\" requires an argument", argval);
1731 break;
1732 case ARG_ELONGOPT:
1733 fprintf(fp, "invalid option \"%s\"", argval);
1734 break;
1735 default:
1736 fprintf(fp, "invalid option \"-%c\"", error);
1737 break;
1740 fputc('\n', fp);
1744 struct arg_end * arg_end(int maxcount)
1746 size_t nbytes;
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);
1755 if (result)
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));
1782 return result;
1786 void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname)
1788 int i;
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],
1796 end->error[i],
1797 end->argval[i],
1798 progname);
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 ******************************************************************************/
1831 #include <string.h>
1832 #include <stdlib.h>
1834 #include "argtable3.h"
1836 #ifdef WIN32
1837 # define FILESEPARATOR1 '\\'
1838 # define FILESEPARATOR2 '/'
1839 #else
1840 # define FILESEPARATOR1 '/'
1841 # define FILESEPARATOR2 '/'
1842 #endif
1845 static void arg_file_resetfn(struct arg_file *parent)
1847 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1848 parent->count = 0;
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);
1863 if (result2)
1864 result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
1866 if (result1)
1867 result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
1869 if (!result)
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);
1876 return result;
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);
1898 return result;
1902 static int arg_file_scanfn(struct arg_file *parent, const char *argval)
1904 int errorcode = 0;
1906 if (parent->count == parent->hdr.maxcount)
1908 /* maximum number of arguments exceeded */
1909 errorcode = EMAXCOUNT;
1911 else if (!argval)
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. */
1916 parent->count++;
1918 else
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)*/
1924 parent->count++;
1927 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1928 return 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));
1937 return errorcode;
1941 static void arg_file_errorfn(
1942 struct arg_file *parent,
1943 FILE *fp,
1944 int errorcode,
1945 const char *argval,
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);
1956 switch(errorcode)
1958 case EMINCOUNT:
1959 fputs("missing option ", fp);
1960 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1961 break;
1963 case EMAXCOUNT:
1964 fputs("excess option ", fp);
1965 arg_print_option(fp, shortopts, longopts, argval, "\n");
1966 break;
1968 default:
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,
1998 int mincount,
1999 int maxcount,
2000 const char *glossary)
2002 size_t nbytes;
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);
2014 if (result)
2016 int i;
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;
2036 result->count = 0;
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));
2048 return 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 ******************************************************************************/
2080 #include <stdlib.h>
2081 #include <limits.h>
2082 #include <ctype.h>
2084 #include "argtable3.h"
2087 static void arg_int_resetfn(struct arg_int *parent)
2089 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2090 parent->count = 0;
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,
2106 char X,
2107 int base)
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))
2115 ptr++;
2116 /* printf("1) %s\n",ptr); */
2118 /* scan optional sign character */
2119 switch (*ptr)
2121 case '+':
2122 ptr++;
2123 s = 1;
2124 break;
2125 case '-':
2126 ptr++;
2127 s = -1;
2128 break;
2129 default:
2130 s = 1;
2131 break;
2133 /* printf("2) %s\n",ptr); */
2135 /* '0X' prefix */
2136 if ((*ptr++) != '0')
2138 /* printf("failed to detect '0'\n"); */
2139 *endptr = str;
2140 return 0;
2142 /* printf("3) %s\n",ptr); */
2143 if (toupper(*ptr++) != toupper(X))
2145 /* printf("failed to detect '%c'\n",X); */
2146 *endptr = str;
2147 return 0;
2149 /* printf("4) %s\n",ptr); */
2151 /* attempt conversion on remainder of string using strtol() */
2152 val = strtol(ptr, (char * *)endptr, base);
2153 if (*endptr == ptr)
2155 /* conversion failed */
2156 *endptr = str;
2157 return 0;
2160 /* success */
2161 return s * val;
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 */
2175 if (*str == '\0')
2176 return 1;
2178 /* next chars */
2179 str++;
2180 suffix++;
2182 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2184 /* return 0 (fail) if the matching did not consume the entire suffix */
2185 if (*suffix != 0)
2186 return 0; /* failed to consume entire suffix */
2188 /* skip any remaining whitespace in str */
2189 while (ISSPACE(*str))
2190 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)
2199 int errorcode = 0;
2201 if (parent->count == parent->hdr.maxcount)
2203 /* maximum number of arguments exceeded */
2204 errorcode = EMAXCOUNT;
2206 else if (!argval)
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. */
2211 parent->count++;
2213 else
2215 long int val;
2216 const char *end;
2218 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2219 val = strtol0X(argval, &end, 'X', 16);
2220 if (end == argval)
2222 /* hex failed, attempt octal conversion (eg +0o123) */
2223 val = strtol0X(argval, &end, 'O', 8);
2224 if (end == argval)
2226 /* octal failed, attempt binary conversion (eg +0B101) */
2227 val = strtol0X(argval, &end, 'B', 2);
2228 if (end == argval)
2230 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2231 val = strtol(argval, (char * *)&end, 10);
2232 if (end == argval)
2234 /* all supported number formats failed */
2235 return EBADINT;
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_;
2246 #else
2247 errorcode = EOVERFLOW;
2248 #endif
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 */
2257 #else
2258 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2259 #endif
2260 else
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 */
2268 #else
2269 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2270 #endif
2271 else
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 */
2279 #else
2280 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2281 #endif
2282 else
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 */
2289 if (errorcode == 0)
2290 parent->ival[parent->count++] = val;
2293 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2294 return 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);*/
2302 return errorcode;
2306 static void arg_int_errorfn(
2307 struct arg_int *parent,
2308 FILE *fp,
2309 int errorcode,
2310 const char *argval,
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);
2321 switch(errorcode)
2323 case EMINCOUNT:
2324 fputs("missing option ", fp);
2325 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2326 break;
2328 case EMAXCOUNT:
2329 fputs("excess option ", fp);
2330 arg_print_option(fp, shortopts, longopts, argval, "\n");
2331 break;
2333 case EBADINT:
2334 fprintf(fp, "invalid argument \"%s\" to option ", argval);
2335 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2336 break;
2338 #ifdef __STDC_WANT_SECURE_LIB__
2339 case EOVERFLOW_:
2340 #else
2341 case EOVERFLOW:
2342 #endif
2343 fputs("integer overflow at option ", fp);
2344 arg_print_option(fp, shortopts, longopts, datatype, " ");
2345 fprintf(fp, "(%s is too large)\n", argval);
2346 break;
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,
2375 int mincount,
2376 int maxcount,
2377 const char *glossary)
2379 size_t nbytes;
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);
2389 if (result)
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);
2407 result->count = 0;
2410 ARG_TRACE(("arg_intn() returns %p\n", result));
2411 return 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 ******************************************************************************/
2443 #include <stdlib.h>
2445 #include "argtable3.h"
2448 static void arg_lit_resetfn(struct arg_lit *parent)
2450 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2451 parent->count = 0;
2455 static int arg_lit_scanfn(struct arg_lit *parent, const char *argval)
2457 int errorcode = 0;
2458 if (parent->count < parent->hdr.maxcount )
2459 parent->count++;
2460 else
2461 errorcode = EMAXCOUNT;
2463 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,
2464 errorcode));
2465 return errorcode;
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));
2473 return errorcode;
2477 static void arg_lit_errorfn(
2478 struct arg_lit *parent,
2479 FILE *fp,
2480 int errorcode,
2481 const char *argval,
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;
2488 switch(errorcode)
2490 case EMINCOUNT:
2491 fprintf(fp, "%s: missing option ", progname);
2492 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2493 fprintf(fp, "\n");
2494 break;
2496 case EMAXCOUNT:
2497 fprintf(fp, "%s: extraneous option ", progname);
2498 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2499 break;
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,
2528 int mincount,
2529 int maxcount,
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));
2538 if (result)
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 */
2555 result->count = 0;
2558 ARG_TRACE(("arg_litn() returns %p\n", result));
2559 return 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 ******************************************************************************/
2591 #include <stdlib.h>
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));
2598 if (result)
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));
2615 return 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 ******************************************************************************/
2648 #include <stdlib.h>
2649 #include <string.h>
2651 #include "argtable3.h"
2654 #ifndef _TREX_H_
2655 #define _TREX_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
2673 is not required.
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 ****************************************************************/
2683 #ifdef __cplusplus
2684 extern "C" {
2685 #endif
2687 #ifdef _UNICODE
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
2693 #else
2694 #define TRexChar char
2695 #define MAX_CHAR 0xFF
2696 #define _TREXC(c) (c)
2697 #define trex_strlen strlen
2698 #define trex_printf printf
2699 #endif
2701 #ifndef TREX_API
2702 #define TREX_API extern
2703 #endif
2705 #define TRex_True 1
2706 #define TRex_False 0
2708 #define TREX_ICASE ARG_REX_ICASE
2710 typedef unsigned int TRexBool;
2711 typedef struct TRex TRex;
2713 typedef struct {
2714 const TRexChar *begin;
2715 int len;
2716 } TRexMatch;
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);
2726 #ifdef __cplusplus
2728 #endif
2730 #endif
2734 struct privhdr
2736 const char *pattern;
2737 int flags;
2741 static void arg_rex_resetfn(struct arg_rex *parent)
2743 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2744 parent->count = 0;
2747 static int arg_rex_scanfn(struct arg_rex *parent, const char *argval)
2749 int errorcode = 0;
2750 const TRexChar *error = NULL;
2751 TRex *rex = NULL;
2752 TRexBool is_match = TRex_False;
2754 if (parent->count == parent->hdr.maxcount )
2756 /* maximum number of arguments exceeded */
2757 errorcode = EMAXCOUNT;
2759 else if (!argval)
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. */
2764 parent->count++;
2766 else
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);
2775 if (!is_match)
2776 errorcode = EREGNOMATCH;
2777 else
2778 parent->sval[parent->count++] = argval;
2780 trex_free(rex);
2783 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode));
2784 return 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);*/
2796 return errorcode;
2799 static void arg_rex_errorfn(struct arg_rex *parent,
2800 FILE *fp,
2801 int errorcode,
2802 const char *argval,
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);
2813 switch(errorcode)
2815 case EMINCOUNT:
2816 fputs("missing option ", fp);
2817 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2818 break;
2820 case EMAXCOUNT:
2821 fputs("excess option ", fp);
2822 arg_print_option(fp, shortopts, longopts, argval, "\n");
2823 break;
2825 case EREGNOMATCH:
2826 fputs("illegal value ", fp);
2827 arg_print_option(fp, shortopts, longopts, argval, "\n");
2828 break;
2830 default:
2832 //char errbuff[256];
2833 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2834 //printf("%s\n", errbuff);
2836 break;
2841 struct arg_rex * arg_rex0(const char * shortopts,
2842 const char * longopts,
2843 const char * pattern,
2844 const char *datatype,
2845 int flags,
2846 const char *glossary)
2848 return arg_rexn(shortopts,
2849 longopts,
2850 pattern,
2851 datatype,
2854 flags,
2855 glossary);
2858 struct arg_rex * arg_rex1(const char * shortopts,
2859 const char * longopts,
2860 const char * pattern,
2861 const char *datatype,
2862 int flags,
2863 const char *glossary)
2865 return arg_rexn(shortopts,
2866 longopts,
2867 pattern,
2868 datatype,
2871 flags,
2872 glossary);
2876 struct arg_rex * arg_rexn(const char * shortopts,
2877 const char * longopts,
2878 const char * pattern,
2879 const char *datatype,
2880 int mincount,
2881 int maxcount,
2882 int flags,
2883 const char *glossary)
2885 size_t nbytes;
2886 struct arg_rex *result;
2887 struct privhdr *priv;
2888 int i;
2889 const TRexChar *error = NULL;
2890 TRex *rex = NULL;
2892 if (!pattern)
2894 printf(
2895 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2896 printf("argtable: Bad argument table.\n");
2897 return NULL;
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);
2908 if (result == NULL)
2909 return result;
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);
2933 result->count = 0;
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);
2946 if (rex == NULL)
2948 ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
2949 ARG_LOG(("argtable: Bad argument table.\n"));
2952 trex_free(rex);
2954 ARG_TRACE(("arg_rexn() returns %p\n", result));
2955 return result;
2960 /* see copyright notice in trex.h */
2961 #include <string.h>
2962 #include <stdlib.h>
2963 #include <ctype.h>
2964 #include <setjmp.h>
2966 #ifdef _UINCODE
2967 #define scisprint iswprint
2968 #define scstrlen wcslen
2969 #define scprintf wprintf
2970 #define _SC(x) L(x)
2971 #else
2972 #define scisprint isprint
2973 #define scstrlen strlen
2974 #define scprintf printf
2975 #define _SC(x) (x)
2976 #endif
2978 #ifdef _DEBUG
2979 #include <stdio.h>
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")
2989 #endif
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{
3017 TRexNodeType type;
3018 int left;
3019 int right;
3020 int next;
3021 }TRexNode;
3023 struct TRex{
3024 const TRexChar *_eol;
3025 const TRexChar *_bol;
3026 const TRexChar *_p;
3027 int _first;
3028 int _op;
3029 TRexNode *_nodes;
3030 int _nallocated;
3031 int _nsize;
3032 int _nsubexpr;
3033 TRexMatch *_matches;
3034 int _currsubexp;
3035 void *_jmpbuf;
3036 const TRexChar **_error;
3037 int _flags;
3040 static int trex_list(TRex *exp);
3042 static int trex_newnode(TRex *exp, TRexNodeType type)
3044 TRexNode n;
3045 int newid;
3046 n.type = type;
3047 n.next = n.right = n.left = -1;
3048 if(type == OP_EXPR)
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;
3056 return (int)newid;
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){
3066 if((*exp->_p) != n)
3067 trex_error(exp, _SC("expected paren"));
3068 exp->_p++;
3071 static TRexChar trex_escapechar(TRex *exp)
3073 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
3074 exp->_p++;
3075 switch(*exp->_p) {
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;
3091 return n;
3094 static int trex_charnode(TRex *exp,TRexBool isclass)
3096 TRexChar t;
3097 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
3098 exp->_p++;
3099 switch(*exp->_p) {
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);
3112 case 'b':
3113 case 'B':
3114 if(!isclass) {
3115 int node = trex_newnode(exp,OP_WB);
3116 exp->_nodes[node].left = *exp->_p;
3117 exp->_p++;
3118 return node;
3119 } //else default
3120 default:
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)
3134 int ret = -1;
3135 int first = -1,chain;
3136 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
3137 ret = trex_newnode(exp,OP_NCLASS);
3138 exp->_p++;
3139 }else ret = trex_newnode(exp,OP_CLASS);
3141 if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
3142 chain = ret;
3143 while(*exp->_p != ']' && exp->_p != exp->_eol) {
3144 if(*exp->_p == '-' && first != -1){
3145 int r,t;
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;
3154 chain = r;
3155 first = -1;
3157 else{
3158 if(first!=-1){
3159 int c = first;
3160 exp->_nodes[chain].next = c;
3161 chain = c;
3162 first = trex_charnode(exp,TRex_True);
3164 else{
3165 first = trex_charnode(exp,TRex_True);
3169 if(first!=-1){
3170 int c = first;
3171 exp->_nodes[chain].next = c;
3172 chain = c;
3173 first = -1;
3175 /* hack? */
3176 exp->_nodes[ret].left = exp->_nodes[ret].next;
3177 exp->_nodes[ret].next = -1;
3178 return ret;
3181 static int trex_parsenumber(TRex *exp)
3183 int ret = *exp->_p-'0';
3184 int positions = 10;
3185 exp->_p++;
3186 while(isdigit(*exp->_p)) {
3187 ret = ret*10+(*exp->_p++-'0');
3188 if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
3189 positions *= 10;
3191 return ret;
3194 static int trex_element(TRex *exp)
3196 int ret = -1;
3197 switch(*exp->_p)
3199 case '(': {
3200 int expr,newn;
3201 exp->_p++;
3204 if(*exp->_p =='?') {
3205 exp->_p++;
3206 trex_expect(exp,':');
3207 expr = trex_newnode(exp,OP_NOCAPEXPR);
3209 else
3210 expr = trex_newnode(exp,OP_EXPR);
3211 newn = trex_list(exp);
3212 exp->_nodes[expr].left = newn;
3213 ret = expr;
3214 trex_expect(exp,')');
3216 break;
3217 case '[':
3218 exp->_p++;
3219 ret = trex_class(exp);
3220 trex_expect(exp,']');
3221 break;
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;
3224 default:
3225 ret = trex_charnode(exp,TRex_False);
3226 break;
3230 TRexBool isgreedy = TRex_False;
3231 unsigned short p0 = 0, p1 = 0;
3232 switch(*exp->_p){
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;
3236 case '{':
3237 exp->_p++;
3238 if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
3239 p0 = (unsigned short)trex_parsenumber(exp);
3240 /*******************************/
3241 switch(*exp->_p) {
3242 case '}':
3243 p1 = p0; exp->_p++;
3244 break;
3245 case ',':
3246 exp->_p++;
3247 p1 = 0xFFFF;
3248 if(isdigit(*exp->_p)){
3249 p1 = (unsigned short)trex_parsenumber(exp);
3251 trex_expect(exp,'}');
3252 break;
3253 default:
3254 trex_error(exp,_SC(", or } expected"));
3256 /*******************************/
3257 isgreedy = TRex_True;
3258 break;
3261 if(isgreedy) {
3262 int nnode = trex_newnode(exp,OP_GREEDY);
3263 exp->_nodes[nnode].left = ret;
3264 exp->_nodes[nnode].right = ((p0)<<16)|p1;
3265 ret = nnode;
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;
3273 return ret;
3276 static int trex_list(TRex *exp)
3278 int ret=-1,e;
3279 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
3280 exp->_p++;
3281 ret = trex_newnode(exp,OP_BOL);
3283 e = trex_element(exp);
3284 if(ret != -1) {
3285 exp->_nodes[ret].next = e;
3287 else ret = e;
3289 if(*exp->_p == TREX_SYMBOL_BRANCH) {
3290 int temp,tright;
3291 exp->_p++;
3292 temp = trex_newnode(exp,OP_OR);
3293 exp->_nodes[temp].left = ret;
3294 tright = trex_list(exp);
3295 exp->_nodes[temp].right = tright;
3296 ret = temp;
3298 return ret;
3301 static TRexBool trex_matchcclass(int cclass,TRexChar c)
3303 switch(cclass) {
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)
3326 do {
3327 switch(node->type) {
3328 case OP_RANGE:
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;
3334 else
3336 if(c >= node->left && c <= node->right) return TRex_True;
3338 break;
3339 case OP_CCLASS:
3340 if(trex_matchcclass(node->left,c)) return TRex_True;
3341 break;
3342 default:
3343 if (exp->_flags & TREX_ICASE)
3345 if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;
3347 else
3349 if(c == node->type)return TRex_True;
3353 } while((node->next != -1) && (node = &exp->_nodes[node->next]));
3354 return TRex_False;
3357 static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
3360 TRexNodeType type = node->type;
3361 switch(type) {
3362 case OP_GREEDY: {
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];
3371 else {
3372 greedystop = next;
3375 while((nmaches == 0xFFFF || nmaches < p1)) {
3377 const TRexChar *stop;
3378 if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
3379 break;
3380 nmaches++;
3381 good=s;
3382 if(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);
3395 if(stop) {
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;
3404 if(s >= exp->_eol)
3405 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;
3410 return NULL;
3412 case OP_OR: {
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];
3418 else
3419 return asd;
3421 asd = str;
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];
3426 else
3427 return asd;
3429 return NULL;
3430 break;
3432 case OP_EXPR:
3433 case OP_NOCAPEXPR:{
3434 TRexNode *n = &exp->_nodes[node->left];
3435 const TRexChar *cur = str;
3436 int capture = -1;
3437 if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
3438 capture = exp->_currsubexp;
3439 exp->_matches[capture].begin = cur;
3440 exp->_currsubexp++;
3443 do {
3444 TRexNode *subnext = NULL;
3445 if(n->next != -1) {
3446 subnext = &exp->_nodes[n->next];
3447 }else {
3448 subnext = next;
3450 if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
3451 if(capture != -1){
3452 exp->_matches[capture].begin = 0;
3453 exp->_matches[capture].len = 0;
3455 return NULL;
3457 } while((n->next != -1) && (n = &exp->_nodes[n->next]));
3459 if(capture != -1)
3460 exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin);
3461 return cur;
3463 case OP_WB:
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;
3471 case OP_BOL:
3472 if(str == exp->_bol) return str;
3473 return NULL;
3474 case OP_EOL:
3475 if(str == exp->_eol) return str;
3476 return NULL;
3477 case OP_DOT:
3478 str++;
3479 return str;
3480 case OP_NCLASS:
3481 case OP_CLASS:
3482 if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
3483 str++;
3484 return str;
3486 return NULL;
3487 case OP_CCLASS:
3488 if(trex_matchcclass(node->left,*str)) {
3489 str++;
3490 return str;
3492 return NULL;
3493 default: /* char */
3494 if (exp->_flags & TREX_ICASE)
3496 if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL;
3498 else
3500 if (*str != node->type) return NULL;
3502 str++;
3503 return str;
3505 return NULL;
3508 /* public api */
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;
3513 exp->_p = pattern;
3514 exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
3515 exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
3516 exp->_nsize = 0;
3517 exp->_matches = 0;
3518 exp->_nsubexpr = 0;
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;
3526 if(*exp->_p!='\0')
3527 trex_error(exp,_SC("unexpected character"));
3528 #ifdef _DEBUG
3530 int nsize,i;
3531 TRexNode *t;
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]);
3538 else
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"));
3544 #endif
3545 exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
3546 memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
3548 else{
3549 trex_free(exp);
3550 return NULL;
3552 return exp;
3555 void trex_free(TRex *exp)
3557 if(exp) {
3558 if(exp->_nodes) free(exp->_nodes);
3559 if(exp->_jmpbuf) free(exp->_jmpbuf);
3560 if(exp->_matches) free(exp->_matches);
3561 free(exp);
3565 TRexBool trex_match(TRex* exp,const TRexChar* text)
3567 const TRexChar* res = NULL;
3568 exp->_bol = text;
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)
3573 return TRex_False;
3574 return TRex_True;
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;
3584 do {
3585 cur = text_begin;
3586 while(node != -1) {
3587 exp->_currsubexp = 0;
3588 cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
3589 if(!cur)
3590 break;
3591 node = exp->_nodes[node].next;
3593 text_begin++;
3594 } while(cur == NULL && text_begin != text_end);
3596 if(cur == NULL)
3597 return TRex_False;
3599 --text_begin;
3601 if(out_begin) *out_begin = text_begin;
3602 if(out_end) *out_end = cur;
3603 return TRex_True;
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];
3620 return TRex_True;
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 ******************************************************************************/
3652 #include <stdlib.h>
3654 #include "argtable3.h"
3657 static void arg_str_resetfn(struct arg_str *parent)
3659 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
3660 parent->count = 0;
3664 static int arg_str_scanfn(struct arg_str *parent, const char *argval)
3666 int errorcode = 0;
3668 if (parent->count == parent->hdr.maxcount)
3670 /* maximum number of arguments exceeded */
3671 errorcode = EMAXCOUNT;
3673 else if (!argval)
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. */
3678 parent->count++;
3680 else
3682 parent->sval[parent->count++] = argval;
3685 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
3686 return 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));
3695 return errorcode;
3699 static void arg_str_errorfn(
3700 struct arg_str *parent,
3701 FILE *fp,
3702 int errorcode,
3703 const char *argval,
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);
3714 switch(errorcode)
3716 case EMINCOUNT:
3717 fputs("missing option ", fp);
3718 arg_print_option(fp, shortopts, longopts, datatype, "\n");
3719 break;
3721 case EMAXCOUNT:
3722 fputs("excess option ", fp);
3723 arg_print_option(fp, shortopts, longopts, argval, "\n");
3724 break;
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,
3753 int mincount,
3754 int maxcount,
3755 const char *glossary)
3757 size_t nbytes;
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);
3769 if (result)
3771 int i;
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);
3789 result->count = 0;
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));
3797 return 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 ******************************************************************************/
3829 #include <stdlib.h>
3830 #include <string.h>
3831 #include <stdlib.h>
3832 #include <ctype.h>
3834 #include "argtable3.h"
3836 static
3837 void arg_register_error(struct arg_end *end,
3838 void *parent,
3839 int error,
3840 const char *argval)
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;
3848 end->count++;
3850 else
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.
3863 static
3864 int find_shortoption(struct arg_hdr * *table, char shortopt)
3866 int tabindex;
3867 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3869 if (table[tabindex]->shortopts &&
3870 strchr(table[tabindex]->shortopts, shortopt))
3871 return tabindex;
3873 return -1;
3877 struct longoptions
3879 int getoptval;
3880 int noptions;
3881 struct option *options;
3884 #if 0
3885 static
3886 void dump_longoptions(struct longoptions * longoptions)
3888 int i;
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);
3901 #endif
3903 static
3904 struct longoptions * alloc_longoptions(struct arg_hdr * *table)
3906 struct longoptions *result;
3907 size_t nbytes;
3908 int noptions = 1;
3909 size_t longoptlen = 0;
3910 int tabindex;
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.
3922 tabindex = 0;
3925 const char *longopts = table[tabindex]->longopts;
3926 longoptlen += (longopts ? strlen(longopts) : 0) + 1;
3927 while (longopts)
3929 noptions++;
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
3940 + longoptlen;
3941 result = (struct longoptions *)malloc(nbytes);
3942 if (result)
3944 int option_index = 0;
3945 char *store;
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++;
3963 *store++ = 0;
3964 if (*longopts == ',')
3965 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;
3975 else
3976 result->options[option_index].has_arg = 0;
3978 option_index++;
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);*/
3989 return result;
3992 static
3993 char * alloc_shortoptions(struct arg_hdr * *table)
3995 char *result;
3996 size_t len = 2;
3997 int tabindex;
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);
4007 if (result)
4009 char *res = result;
4011 /* add a leading ':' so getopt return codes distinguish */
4012 /* unrecognised option and options missing argument values */
4013 *res++ = ':';
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)
4023 *res++ = ':';
4024 if (hdr->flag & ARG_HASOPTVALUE)
4025 *res++ = ':';
4028 /* null terminate the string */
4029 *res = 0;
4032 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
4033 return result;
4037 /* return index of the table terminator entry */
4038 static
4039 int arg_endindex(struct arg_hdr * *table)
4041 int tabindex = 0;
4042 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4043 tabindex++;
4044 return tabindex;
4048 static
4049 void arg_parse_tagged(int argc,
4050 char * *argv,
4051 struct arg_hdr * *table,
4052 struct arg_end *endtable)
4054 struct longoptions *longoptions;
4055 char *shortoptions;
4056 int copt;
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) */
4069 free(shortoptions);
4070 free(longoptions);
4071 return;
4074 /*dump_longoptions(longoptions);*/
4076 /* reset getopts internal option-index to zero, and disable error reporting */
4077 optind = 0;
4078 opterr = 0;
4080 /* fetch and process args using getopt_long */
4081 while( (copt =
4082 getopt_long(argc, argv, shortoptions, longoptions->options,
4083 NULL)) != -1)
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));
4091 switch(copt)
4093 case 0:
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,
4103 argv[optind - 1]);
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);
4109 if (errorcode != 0)
4110 arg_register_error(endtable, parent, errorcode, optarg);
4113 break;
4115 case '?':
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
4121 switch (optopt)
4123 case 0:
4124 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4125 arg_register_error(endtable, endtable, ARG_ELONGOPT,
4126 argv[optind - 1]);
4127 break;
4128 default:
4129 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4130 arg_register_error(endtable, endtable, optopt, NULL);
4131 break;
4133 break;
4135 case ':':
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,
4141 argv[optind - 1]);
4142 break;
4144 default:
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);*/
4149 if (tabindex == -1)
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);
4155 else
4157 if (table[tabindex]->scanfn)
4159 void *parent = table[tabindex]->parent;
4160 int errorcode = table[tabindex]->scanfn(parent, optarg);
4161 if (errorcode != 0)
4162 arg_register_error(endtable, parent, errorcode, optarg);
4165 break;
4170 free(shortoptions);
4171 free(longoptions);
4175 static
4176 void arg_parse_untagged(int argc,
4177 char * *argv,
4178 struct arg_hdr * *table,
4179 struct arg_end *endtable)
4181 int tabindex = 0;
4182 int errorlast = 0;
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))
4189 void *parent;
4190 int errorcode;
4192 /* if we have exhausted our argv[optind] entries then we have finished */
4193 if (optind >= argc)
4195 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4196 return;
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);*/
4203 tabindex++;
4204 continue;
4207 /* skip table entries with NULL scanfn */
4208 if (!(table[tabindex]->scanfn))
4210 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4211 tabindex++;
4212 continue;
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]);
4220 if (errorcode == 0)
4222 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4223 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4224 optind++;
4226 /* clear the last tentative error */
4227 errorlast = 0;
4229 else
4231 /* failure, try same argv[optind] with next table[tabindex] entry */
4232 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4233 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 */
4244 if (errorlast)
4246 arg_register_error(endtable, parentlast, errorlast, optarglast);
4247 optind++;
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++]);
4258 return;
4262 static
4263 void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable)
4265 int tabindex = 0;
4266 /* printf("arg_parse_check()\n"); */
4269 if (table[tabindex]->checkfn)
4271 void *parent = table[tabindex]->parent;
4272 int errorcode = table[tabindex]->checkfn(parent);
4273 if (errorcode != 0)
4274 arg_register_error(endtable, parent, errorcode, NULL);
4276 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4280 static
4281 void arg_reset(void * *argtable)
4283 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4284 int tabindex = 0;
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;
4298 int endindex;
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). */
4313 if (argc == 0)
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));
4323 if (argvcopy)
4325 int i;
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[] */
4348 free(argvcopy);
4350 else
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
4364 * of chars.
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.
4369 * Example of use:
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);
4376 * Results in:
4377 * dest[] == "goodbye cruel world!"
4378 * ndest == 10
4380 static
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)
4388 dest++;
4390 /* concat src string to dest string */
4391 while(dest < end && *src != 0)
4392 *dest++ = *src++;
4394 /* null terminate dest string */
4395 *dest = 0;
4397 /* update *pdest and *pndest */
4398 *pndest = end - dest;
4399 *pdest = dest;
4403 static
4404 void arg_cat_option(char *dest,
4405 size_t ndest,
4406 const char *shortopts,
4407 const char *longopts,
4408 const char *datatype,
4409 int optvalue)
4411 if (shortopts)
4413 char option[3];
4415 /* note: option array[] is initialiazed dynamically here to satisfy */
4416 /* a deficiency in the watcom compiler wrt static array initializers. */
4417 option[0] = '-';
4418 option[1] = shortopts[0];
4419 option[2] = 0;
4421 arg_cat(&dest, option, &ndest);
4422 if (datatype)
4424 arg_cat(&dest, " ", &ndest);
4425 if (optvalue)
4427 arg_cat(&dest, "[", &ndest);
4428 arg_cat(&dest, datatype, &ndest);
4429 arg_cat(&dest, "]", &ndest);
4431 else
4432 arg_cat(&dest, datatype, &ndest);
4435 else if (longopts)
4437 size_t ncspn;
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);
4446 #else
4447 strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
4448 #endif
4450 if (datatype)
4452 arg_cat(&dest, "=", &ndest);
4453 if (optvalue)
4455 arg_cat(&dest, "[", &ndest);
4456 arg_cat(&dest, datatype, &ndest);
4457 arg_cat(&dest, "]", &ndest);
4459 else
4460 arg_cat(&dest, datatype, &ndest);
4463 else if (datatype)
4465 if (optvalue)
4467 arg_cat(&dest, "[", &ndest);
4468 arg_cat(&dest, datatype, &ndest);
4469 arg_cat(&dest, "]", &ndest);
4471 else
4472 arg_cat(&dest, datatype, &ndest);
4476 static
4477 void arg_cat_optionv(char *dest,
4478 size_t ndest,
4479 const char *shortopts,
4480 const char *longopts,
4481 const char *datatype,
4482 int optvalue,
4483 const char *separator)
4485 separator = separator ? separator : "";
4487 if (shortopts)
4489 const char *c = shortopts;
4490 while(*c)
4492 /* "-a|-b|-c" */
4493 char shortopt[3];
4495 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4496 /* a deficiency in the watcom compiler wrt static array initializers. */
4497 shortopt[0] = '-';
4498 shortopt[1] = *c;
4499 shortopt[2] = 0;
4501 arg_cat(&dest, shortopt, &ndest);
4502 if (*++c)
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);
4511 if (longopts)
4513 const char *c = longopts;
4514 while(*c)
4516 size_t ncspn;
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);
4525 #else
4526 strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
4527 #endif
4528 c += ncspn;
4530 /* add given separator in place of comma */
4531 if (*c == ',')
4533 arg_cat(&dest, separator, &ndest);
4534 c++;
4539 if (datatype)
4541 if (longopts)
4542 arg_cat(&dest, "=", &ndest);
4543 else if (shortopts)
4544 arg_cat(&dest, " ", &ndest);
4546 if (optvalue)
4548 arg_cat(&dest, "[", &ndest);
4549 arg_cat(&dest, datatype, &ndest);
4550 arg_cat(&dest, "]", &ndest);
4552 else
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,
4563 const char *suffix)
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,
4570 sizeof(syntax),
4571 shortopts,
4572 longopts,
4573 datatype,
4575 "|");
4577 fputs(syntax, fp);
4578 fputs(suffix, fp);
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]
4587 static
4588 void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table)
4590 int tabindex;
4591 char *format1 = " -%c";
4592 char *format2 = " [-%c";
4593 char *suffix = "";
4595 /* print all mandatory switches that are without argument values */
4596 for(tabindex = 0;
4597 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4598 tabindex++)
4600 /* skip optional options */
4601 if (table[tabindex]->mincount < 1)
4602 continue;
4604 /* skip non-short options */
4605 if (table[tabindex]->shortopts == NULL)
4606 continue;
4608 /* skip options that take argument values */
4609 if (table[tabindex]->flag & ARG_HASVALUE)
4610 continue;
4612 /* print the short option (only the first short option char, ignore multiple choices)*/
4613 fprintf(fp, format1, table[tabindex]->shortopts[0]);
4614 format1 = "%c";
4615 format2 = "[%c";
4618 /* print all optional switches that are without argument values */
4619 for(tabindex = 0;
4620 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4621 tabindex++)
4623 /* skip mandatory args */
4624 if (table[tabindex]->mincount > 0)
4625 continue;
4627 /* skip args without short options */
4628 if (table[tabindex]->shortopts == NULL)
4629 continue;
4631 /* skip args with values */
4632 if (table[tabindex]->flag & ARG_HASVALUE)
4633 continue;
4635 /* print first short option */
4636 fprintf(fp, format2, table[tabindex]->shortopts[0]);
4637 format2 = "%c";
4638 suffix = "]";
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;
4648 int i, tabindex;
4650 /* print GNU style [OPTION] string */
4651 arg_print_gnuswitch(fp, table);
4653 /* print remaining options in abbreviated style */
4654 for(tabindex = 0;
4655 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4656 tabindex++)
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))
4664 continue;
4666 shortopts = table[tabindex]->shortopts;
4667 longopts = table[tabindex]->longopts;
4668 datatype = table[tabindex]->datatype;
4669 arg_cat_option(syntax,
4670 sizeof(syntax),
4671 shortopts,
4672 longopts,
4673 datatype,
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 )
4685 case 0:
4686 break;
4687 case 1:
4688 fprintf(fp, " [%s]", syntax);
4689 break;
4690 case 2:
4691 fprintf(fp, " [%s] [%s]", syntax, syntax);
4692 break;
4693 default:
4694 fprintf(fp, " [%s]...", syntax);
4695 break;
4700 if (suffix)
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;
4708 int i, tabindex;
4710 /* print remaining options in abbreviated style */
4711 for(tabindex = 0;
4712 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4713 tabindex++)
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,
4722 sizeof(syntax),
4723 shortopts,
4724 longopts,
4725 datatype,
4726 table[tabindex]->flag & ARG_HASOPTVALUE,
4727 "|");
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 )
4736 case 0:
4737 break;
4738 case 1:
4739 fprintf(fp, " [%s]", syntax);
4740 break;
4741 case 2:
4742 fprintf(fp, " [%s] [%s]", syntax, syntax);
4743 break;
4744 default:
4745 fprintf(fp, " [%s]...", syntax);
4746 break;
4750 if (suffix)
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;
4758 int tabindex;
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,
4771 sizeof(syntax),
4772 shortopts,
4773 longopts,
4774 datatype,
4775 table[tabindex]->flag & ARG_HASOPTVALUE,
4776 ", ");
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.
4789 * Example:
4790 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4791 * will result in the following output:
4793 * Some
4794 * text
4795 * that
4796 * doesn'
4797 * t fit.
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:
4804 * Some
4805 * text
4806 * that
4807 * doesn'
4808 * t fit.
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
4815 static
4816 void arg_print_formatted( FILE *fp,
4817 const unsigned lmargin,
4818 const unsigned rmargin,
4819 const char *text )
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
4834 of line */
4835 while ( ISSPACE(*(text + line_start)) )
4836 { 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)))
4845 { 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. */
4850 line_end--;
4852 /* Output line of text */
4853 while ( line_start < line_end )
4855 fputc(*(text + line_start), fp );
4856 line_start++;
4858 fputc( '\n', fp );
4860 /* Initialize another line */
4861 if ( line_end + 1 < textlen )
4863 unsigned i;
4865 for (i = 0; i < lmargin; i++ )
4866 { fputc( ' ', fp ); }
4868 line_end = textlen;
4871 /* If we have to print another line, get also the last char. */
4872 line_end++;
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;
4889 int tabindex;
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,
4909 sizeof(syntax),
4910 shortopts,
4911 longopts,
4912 datatype,
4913 table[tabindex]->flag & ARG_HASOPTVALUE,
4914 ", ");
4916 /* If syntax fits not into column, print glossary in new line... */
4917 if ( strlen(syntax) > 25 )
4919 fprintf( fp, " %-25s %s\n", syntax, "" );
4920 *syntax = '\0';
4923 fprintf( fp, " %-25s ", syntax );
4924 arg_print_formatted( fp, 28, 79, glossary );
4926 } /* for each table entry */
4928 fputc( '\n', fp );
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;
4939 int tabindex;
4940 /*printf("arg_nullcheck(%p)\n",argtable);*/
4942 if (!table)
4943 return 1;
4945 tabindex = 0;
4948 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4949 if (!table[tabindex])
4950 return 1;
4951 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4953 return 0;
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;
4971 int tabindex = 0;
4972 int flag;
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)
4983 break;
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)
5001 continue;
5003 free(table[tabindex]);
5004 table[tabindex] = NULL;