1 /*******************************************************************************
2 * This file is part of the argtable3 library.
3 *
4 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
5 * <sheitmann@users.sourceforge.net>
6 * All rights reserved.
7 *
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.
18 *
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 ******************************************************************************/
30 // THIS FILE HAS BEEN ALTERED from original version to:
31 // * fix warnings
32 // * fix issues found by static code analisys:
33 // - Null pointer dereference in trex_compile
34
35 #include "argtable3.h"
36
37 // On Windows isspace crashes app in case of using Unicode character set and string to be above ASCII
38 // so you have to use _istspace instead of space
39 #ifdef UNICODE
40 #include <tchar.h>
41 #define ISSPACE _istspace
42 #else
43 #define ISSPACE isspace
44 #endif
45
46 /*******************************************************************************
47 * This file is part of the argtable3 library.
48 *
49 * Copyright (C) 2013 Tom G. Huang
50 * <tomghuang@gmail.com>
51 * All rights reserved.
52 *
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions are met:
55 * * Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
57 * * Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in the
59 * documentation and/or other materials provided with the distribution.
60 * * Neither the name of STEWART HEITMANN nor the names of its contributors
61 * may be used to endorse or promote products derived from this software
62 * without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
65 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
68 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
69 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
70 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
71 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
73 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 ******************************************************************************/
75
76 #ifndef ARG_UTILS_H
77 #define ARG_UTILS_H
78
79 #define ARG_ENABLE_TRACE 0
80 #define ARG_ENABLE_LOG 1
81
82 #ifdef __cplusplus
83 extern "C" {
84 #endif
85
86 enum
87 {
88 EMINCOUNT = 1,
89 EMAXCOUNT,
90 EBADINT,
91 // The same name define EOVERFLOW in errno.h on windows platform
92 #ifdef __STDC_WANT_SECURE_LIB__
93 EOVERFLOW_,
94 #else
95 EOVERFLOW_,
96 #endif
97 EBADDOUBLE,
98 EBADDATE,
99 EREGNOMATCH
100 };
101
102
103 #if defined(_MSC_VER)
104 #define ARG_TRACE(x) \
105 __pragma(warning(push)) \
106 __pragma(warning(disable:4127)) \
107 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \
108 __pragma(warning(pop))
109
110 #define ARG_LOG(x) \
111 __pragma(warning(push)) \
112 __pragma(warning(disable:4127)) \
113 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
114 __pragma(warning(pop))
115 #else
116 #define ARG_TRACE(x) \
117 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
118
119 #define ARG_LOG(x) \
120 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
121 #endif
122
123 extern void dbg_printf(const char *fmt, ...);
124
125 #ifdef __cplusplus
126 }
127 #endif
128
129 #endif
130
131 /*******************************************************************************
132 * This file is part of the argtable3 library.
133 *
134 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
135 * <sheitmann@users.sourceforge.net>
136 * All rights reserved.
137 *
138 * Redistribution and use in source and binary forms, with or without
139 * modification, are permitted provided that the following conditions are met:
140 * * Redistributions of source code must retain the above copyright
141 * notice, this list of conditions and the following disclaimer.
142 * * Redistributions in binary form must reproduce the above copyright
143 * notice, this list of conditions and the following disclaimer in the
144 * documentation and/or other materials provided with the distribution.
145 * * Neither the name of STEWART HEITMANN nor the names of its contributors
146 * may be used to endorse or promote products derived from this software
147 * without specific prior written permission.
148 *
149 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
150 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
152 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
153 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
154 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
155 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
156 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
157 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
158 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
159 ******************************************************************************/
160
161 #include <stdarg.h>
162 #include <stdio.h>
163
164
dbg_printf(const char * fmt,...)165 void dbg_printf(const char *fmt, ...)
166 {
167 va_list args;
168 va_start(args, fmt);
169 vfprintf(stderr, fmt, args);
170 va_end(args);
171 }
172
173 /* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
174 /* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */
175 /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
176
177 /*-
178 * Copyright (c) 2000 The NetBSD Foundation, Inc.
179 * All rights reserved.
180 *
181 * This code is derived from software contributed to The NetBSD Foundation
182 * by Dieter Baron and Thomas Klausner.
183 *
184 * Redistribution and use in source and binary forms, with or without
185 * modification, are permitted provided that the following conditions
186 * are met:
187 * 1. Redistributions of source code must retain the above copyright
188 * notice, this list of conditions and the following disclaimer.
189 * 2. Redistributions in binary form must reproduce the above copyright
190 * notice, this list of conditions and the following disclaimer in the
191 * documentation and/or other materials provided with the distribution.
192 * 3. All advertising materials mentioning features or use of this software
193 * must display the following acknowledgement:
194 * This product includes software developed by the NetBSD
195 * Foundation, Inc. and its contributors.
196 * 4. Neither the name of The NetBSD Foundation nor the names of its
197 * contributors may be used to endorse or promote products derived
198 * from this software without specific prior written permission.
199 *
200 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
202 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
203 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
204 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
205 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
206 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
207 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
208 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
209 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
210 * POSSIBILITY OF SUCH DAMAGE.
211 */
212
213 #ifndef _GETOPT_H_
214 #define _GETOPT_H_
215
216 #if 0
217 #include <sys/cdefs.h>
218 #endif
219
220 /*
221 * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
222 */
223 #define no_argument 0
224 #define required_argument 1
225 #define optional_argument 2
226
227 struct option {
228 /* name of long option */
229 const char *name;
230 /*
231 * one of no_argument, required_argument, and optional_argument:
232 * whether option takes an argument
233 */
234 int has_arg;
235 /* if not NULL, set *flag to val when option found */
236 int *flag;
237 /* if flag not NULL, value to set *flag to; else return value */
238 int val;
239 };
240
241 #ifdef __cplusplus
242 extern "C" {
243 #endif
244
245 int getopt_long(int, char * const *, const char *,
246 const struct option *, int *);
247 int getopt_long_only(int, char * const *, const char *,
248 const struct option *, int *);
249 #ifndef _GETOPT_DEFINED
250 #define _GETOPT_DEFINED
251 int getopt(int, char * const *, const char *);
252 int getsubopt(char **, char * const *, char **);
253
254 extern char *optarg; /* getopt(3) external variables */
255 extern int opterr;
256 extern int optind;
257 extern int optopt;
258 extern int optreset;
259 extern char *suboptarg; /* getsubopt(3) external variable */
260 #endif /* _GETOPT_DEFINED */
261
262 #ifdef __cplusplus
263 }
264 #endif
265 #endif /* !_GETOPT_H_ */
266 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
267 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
268 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
269
270 /*
271 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
272 *
273 * Permission to use, copy, modify, and distribute this software for any
274 * purpose with or without fee is hereby granted, provided that the above
275 * copyright notice and this permission notice appear in all copies.
276 *
277 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
278 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
279 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
280 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
281 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
282 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
283 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
284 *
285 * Sponsored in part by the Defense Advanced Research Projects
286 * Agency (DARPA) and Air Force Research Laboratory, Air Force
287 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
288 */
289
290 /*-
291 * Copyright (c) 2000 The NetBSD Foundation, Inc.
292 * All rights reserved.
293 *
294 * This code is derived from software contributed to The NetBSD Foundation
295 * by Dieter Baron and Thomas Klausner.
296 *
297 * Redistribution and use in source and binary forms, with or without
298 * modification, are permitted provided that the following conditions
299 * are met:
300 * 1. Redistributions of source code must retain the above copyright
301 * notice, this list of conditions and the following disclaimer.
302 * 2. Redistributions in binary form must reproduce the above copyright
303 * notice, this list of conditions and the following disclaimer in the
304 * documentation and/or other materials provided with the distribution.
305 *
306 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
307 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
308 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
309 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
310 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
311 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
312 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
313 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
314 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
315 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
316 * POSSIBILITY OF SUCH DAMAGE.
317 */
318
319 #if 0
320 #include <err.h>
321 #endif
322 #include <errno.h>
323 #include <stdlib.h>
324 #include <string.h>
325
326
327 #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
328
329 #ifdef REPLACE_GETOPT
330 int opterr = 1; /* if error message should be printed */
331 int optind = 1; /* index into parent argv vector */
332 int optopt = '?'; /* character checked for validity */
333 int optreset; /* reset getopt */
334 char *optarg; /* argument associated with option */
335 #endif
336
337 #define PRINT_ERROR ((opterr) && (*options != ':'))
338
339 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
340 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
341 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
342
343 /* return values */
344 #define BADCH (int)'?'
345 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
346 #define INORDER (int)1
347
348 #define EMSG ""
349
350 static int getopt_internal(int, char * const *, const char *,
351 const struct option *, int *, int);
352 static int parse_long_options(char * const *, const char *,
353 const struct option *, int *, int);
354 static int gcd(int, int);
355 static void permute_args(int, int, int, char * const *);
356
357 static char *place = EMSG; /* option letter processing */
358
359 /* XXX: set optreset to 1 rather than these two */
360 static int nonopt_start = -1; /* first non option argument (for permute) */
361 static int nonopt_end = -1; /* first option after non options (for permute) */
362
363 /* Error messages */
364 static const char recargchar[] = "option requires an argument -- %c";
365 static const char recargstring[] = "option requires an argument -- %s";
366 static const char ambig[] = "ambiguous option -- %.*s";
367 static const char noarg[] = "option doesn't take an argument -- %.*s";
368 static const char illoptchar[] = "unknown option -- %c";
369 static const char illoptstring[] = "unknown option -- %s";
370
371
372
373 #ifdef _WIN32
374
375 /* Windows needs warnx(). We change the definition though:
376 * 1. (another) global is defined, opterrmsg, which holds the error message
377 * 2. errors are always printed out on stderr w/o the program name
378 * Note that opterrmsg always gets set no matter what opterr is set to. The
379 * error message will not be printed if opterr is 0 as usual.
380 */
381
382 #include <stdio.h>
383 #include <stdarg.h>
384
385 #define MAX_OPTER_MSG_SIZE 128
386
387 extern char opterrmsg[MAX_OPTER_MSG_SIZE];
388 char opterrmsg[MAX_OPTER_MSG_SIZE]; /* buffer for the last error message */
389
warnx(const char * fmt,...)390 static void warnx(const char *fmt, ...)
391 {
392 va_list ap;
393 va_start(ap, fmt);
394 /*
395 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
396 implementation specifics and manually suppress the warning.
397 */
398 memset(opterrmsg, 0, sizeof opterrmsg);
399 if (fmt != NULL)
400 #ifdef __STDC_WANT_SECURE_LIB__
401 _vsnprintf_s(opterrmsg, MAX_OPTER_MSG_SIZE, sizeof(opterrmsg) - 1, fmt, ap);
402 #else
403 _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
404 #endif
405 va_end(ap);
406
407 #ifndef __ICL
408 #pragma warning(suppress: 6053)
409 #endif
410 fprintf(stderr, "%s\n", opterrmsg);
411 }
412
413 #else
414 #include <err.h>
415 #endif /*_WIN32*/
416
417
418 /*
419 * Compute the greatest common divisor of a and b.
420 */
421 static int
gcd(int a,int b)422 gcd(int a, int b)
423 {
424 int c;
425
426 c = a % b;
427 while (c != 0) {
428 a = b;
429 b = c;
430 c = a % b;
431 }
432
433 return (b);
434 }
435
436 /*
437 * Exchange the block from nonopt_start to nonopt_end with the block
438 * from nonopt_end to opt_end (keeping the same order of arguments
439 * in each block).
440 */
441 static void
permute_args(int panonopt_start,int panonopt_end,int opt_end,char * const * nargv)442 permute_args(int panonopt_start, int panonopt_end, int opt_end,
443 char * const *nargv)
444 {
445 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
446 char *swap;
447
448 /*
449 * compute lengths of blocks and number and size of cycles
450 */
451 nnonopts = panonopt_end - panonopt_start;
452 nopts = opt_end - panonopt_end;
453 ncycle = gcd(nnonopts, nopts);
454 cyclelen = (opt_end - panonopt_start) / ncycle;
455
456 for (i = 0; i < ncycle; i++) {
457 cstart = panonopt_end+i;
458 pos = cstart;
459 for (j = 0; j < cyclelen; j++) {
460 if (pos >= panonopt_end)
461 pos -= nnonopts;
462 else
463 pos += nopts;
464 swap = nargv[pos];
465 /* LINTED const cast */
466 ((char **) nargv)[pos] = nargv[cstart];
467 /* LINTED const cast */
468 ((char **)nargv)[cstart] = swap;
469 }
470 }
471 }
472
473 /*
474 * parse_long_options --
475 * Parse long options in argc/argv argument vector.
476 * Returns -1 if short_too is set and the option does not match long_options.
477 */
478 static int
parse_long_options(char * const * nargv,const char * options,const struct option * long_options,int * idx,int short_too)479 parse_long_options(char * const *nargv, const char *options,
480 const struct option *long_options, int *idx, int short_too)
481 {
482 char *current_argv, *has_equal;
483 size_t current_argv_len;
484 int i, match;
485
486 current_argv = place;
487 match = -1;
488
489 optind++;
490
491 if ((has_equal = strchr(current_argv, '=')) != NULL) {
492 /* argument found (--option=arg) */
493 current_argv_len = has_equal - current_argv;
494 has_equal++;
495 } else
496 current_argv_len = strlen(current_argv);
497
498 for (i = 0; long_options[i].name; i++) {
499 /* find matching long option */
500 if (strncmp(current_argv, long_options[i].name,
501 current_argv_len))
502 continue;
503
504 if (strlen(long_options[i].name) == current_argv_len) {
505 /* exact match */
506 match = i;
507 break;
508 }
509 /*
510 * If this is a known short option, don't allow
511 * a partial match of a single character.
512 */
513 if (short_too && current_argv_len == 1)
514 continue;
515
516 if (match == -1) /* partial match */
517 match = i;
518 else {
519 /* ambiguous abbreviation */
520 if (PRINT_ERROR)
521 warnx(ambig, (int)current_argv_len,
522 current_argv);
523 optopt = 0;
524 return (BADCH);
525 }
526 }
527 if (match != -1) { /* option found */
528 if (long_options[match].has_arg == no_argument
529 && has_equal) {
530 if (PRINT_ERROR)
531 warnx(noarg, (int)current_argv_len,
532 current_argv);
533 /*
534 * XXX: GNU sets optopt to val regardless of flag
535 */
536 if (long_options[match].flag == NULL)
537 optopt = long_options[match].val;
538 else
539 optopt = 0;
540 return (BADARG);
541 }
542 if (long_options[match].has_arg == required_argument ||
543 long_options[match].has_arg == optional_argument) {
544 if (has_equal)
545 optarg = has_equal;
546 else if (long_options[match].has_arg ==
547 required_argument) {
548 /*
549 * optional argument doesn't use next nargv
550 */
551 optarg = nargv[optind++];
552 }
553 }
554 if ((long_options[match].has_arg == required_argument)
555 && (optarg == NULL)) {
556 /*
557 * Missing argument; leading ':' indicates no error
558 * should be generated.
559 */
560 if (PRINT_ERROR)
561 warnx(recargstring,
562 current_argv);
563 /*
564 * XXX: GNU sets optopt to val regardless of flag
565 */
566 if (long_options[match].flag == NULL)
567 optopt = long_options[match].val;
568 else
569 optopt = 0;
570 --optind;
571 return (BADARG);
572 }
573 } else { /* unknown option */
574 if (short_too) {
575 --optind;
576 return (-1);
577 }
578 if (PRINT_ERROR)
579 warnx(illoptstring, current_argv);
580 optopt = 0;
581 return (BADCH);
582 }
583 if (idx)
584 *idx = match;
585 if (long_options[match].flag) {
586 *long_options[match].flag = long_options[match].val;
587 return (0);
588 } else
589 return (long_options[match].val);
590 }
591
592 /*
593 * getopt_internal --
594 * Parse argc/argv argument vector. Called by user level routines.
595 */
596 static int
getopt_internal(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx,int flags)597 getopt_internal(int nargc, char * const *nargv, const char *options,
598 const struct option *long_options, int *idx, int flags)
599 {
600 char *oli; /* option letter list index */
601 int optchar, short_too;
602 static int posixly_correct = -1;
603 #ifdef __STDC_WANT_SECURE_LIB__
604 char* buffer = NULL;
605 size_t buffer_size = 0;
606 errno_t err = 0;
607 #endif
608
609 if (options == NULL)
610 return (-1);
611
612 /*
613 * Disable GNU extensions if POSIXLY_CORRECT is set or options
614 * string begins with a '+'.
615 */
616
617 #ifdef __STDC_WANT_SECURE_LIB__
618 if (posixly_correct == -1) {
619 err = _dupenv_s(&buffer, &buffer_size, "POSIXLY_CORRECT") == 0;
620 posixly_correct = buffer != NULL;
621 if(buffer != NULL && err == 0) {
622 free(buffer);
623 }
624 }
625 #else
626 if (posixly_correct == -1)
627 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
628 #endif
629 if (posixly_correct || *options == '+')
630 flags &= ~FLAG_PERMUTE;
631 else if (*options == '-')
632 flags |= FLAG_ALLARGS;
633 if (*options == '+' || *options == '-')
634 options++;
635
636 /*
637 * XXX Some GNU programs (like cvs) set optind to 0 instead of
638 * XXX using optreset. Work around this braindamage.
639 */
640 if (optind == 0)
641 optind = optreset = 1;
642
643 optarg = NULL;
644 if (optreset)
645 nonopt_start = nonopt_end = -1;
646 start:
647 if (optreset || !*place) { /* update scanning pointer */
648 optreset = 0;
649 if (optind >= nargc) { /* end of argument vector */
650 place = EMSG;
651 if (nonopt_end != -1) {
652 /* do permutation, if we have to */
653 permute_args(nonopt_start, nonopt_end,
654 optind, nargv);
655 optind -= nonopt_end - nonopt_start;
656 }
657 else if (nonopt_start != -1) {
658 /*
659 * If we skipped non-options, set optind
660 * to the first of them.
661 */
662 optind = nonopt_start;
663 }
664 nonopt_start = nonopt_end = -1;
665 return (-1);
666 }
667 if (*(place = nargv[optind]) != '-' ||
668 (place[1] == '\0' && strchr(options, '-') == NULL)) {
669 place = EMSG; /* found non-option */
670 if (flags & FLAG_ALLARGS) {
671 /*
672 * GNU extension:
673 * return non-option as argument to option 1
674 */
675 optarg = nargv[optind++];
676 return (INORDER);
677 }
678 if (!(flags & FLAG_PERMUTE)) {
679 /*
680 * If no permutation wanted, stop parsing
681 * at first non-option.
682 */
683 return (-1);
684 }
685 /* do permutation */
686 if (nonopt_start == -1)
687 nonopt_start = optind;
688 else if (nonopt_end != -1) {
689 permute_args(nonopt_start, nonopt_end,
690 optind, nargv);
691 nonopt_start = optind -
692 (nonopt_end - nonopt_start);
693 nonopt_end = -1;
694 }
695 optind++;
696 /* process next argument */
697 goto start;
698 }
699 if (nonopt_start != -1 && nonopt_end == -1)
700 nonopt_end = optind;
701
702 /*
703 * If we have "-" do nothing, if "--" we are done.
704 */
705 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
706 optind++;
707 place = EMSG;
708 /*
709 * We found an option (--), so if we skipped
710 * non-options, we have to permute.
711 */
712 if (nonopt_end != -1) {
713 permute_args(nonopt_start, nonopt_end,
714 optind, nargv);
715 optind -= nonopt_end - nonopt_start;
716 }
717 nonopt_start = nonopt_end = -1;
718 return (-1);
719 }
720 }
721
722 /*
723 * Check long options if:
724 * 1) we were passed some
725 * 2) the arg is not just "-"
726 * 3) either the arg starts with -- we are getopt_long_only()
727 */
728 if (long_options != NULL && place != nargv[optind] &&
729 (*place == '-' || (flags & FLAG_LONGONLY))) {
730 short_too = 0;
731 if (*place == '-')
732 place++; /* --foo long option */
733 else if (*place != ':' && strchr(options, *place) != NULL)
734 short_too = 1; /* could be short option too */
735
736 optchar = parse_long_options(nargv, options, long_options,
737 idx, short_too);
738 if (optchar != -1) {
739 place = EMSG;
740 return (optchar);
741 }
742 }
743
744 if ((optchar = (int)*place++) == (int)':' ||
745 (optchar == (int)'-' && *place != '\0') ||
746 (oli = strchr(options, optchar)) == NULL) {
747 /*
748 * If the user specified "-" and '-' isn't listed in
749 * options, return -1 (non-option) as per POSIX.
750 * Otherwise, it is an unknown option character (or ':').
751 */
752 if (optchar == (int)'-' && *place == '\0')
753 return (-1);
754 if (!*place)
755 ++optind;
756 if (PRINT_ERROR)
757 warnx(illoptchar, optchar);
758 optopt = optchar;
759 return (BADCH);
760 }
761 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
762 /* -W long-option */
763 if (*place) /* no space */
764 /* NOTHING */;
765 else if (++optind >= nargc) { /* no arg */
766 place = EMSG;
767 if (PRINT_ERROR)
768 warnx(recargchar, optchar);
769 optopt = optchar;
770 return (BADARG);
771 } else /* white space */
772 place = nargv[optind];
773 optchar = parse_long_options(nargv, options, long_options,
774 idx, 0);
775 place = EMSG;
776 return (optchar);
777 }
778 if (*++oli != ':') { /* doesn't take argument */
779 if (!*place)
780 ++optind;
781 } else { /* takes (optional) argument */
782 optarg = NULL;
783 if (*place) /* no white space */
784 optarg = place;
785 else if (oli[1] != ':') { /* arg not optional */
786 if (++optind >= nargc) { /* no arg */
787 place = EMSG;
788 if (PRINT_ERROR)
789 warnx(recargchar, optchar);
790 optopt = optchar;
791 return (BADARG);
792 } else
793 optarg = nargv[optind];
794 }
795 place = EMSG;
796 ++optind;
797 }
798 /* dump back option letter */
799 return (optchar);
800 }
801
802 #ifdef REPLACE_GETOPT
803 /*
804 * getopt --
805 * Parse argc/argv argument vector.
806 *
807 * [eventually this will replace the BSD getopt]
808 */
809 int
getopt(int nargc,char * const * nargv,const char * options)810 getopt(int nargc, char * const *nargv, const char *options)
811 {
812
813 /*
814 * We don't pass FLAG_PERMUTE to getopt_internal() since
815 * the BSD getopt(3) (unlike GNU) has never done this.
816 *
817 * Furthermore, since many privileged programs call getopt()
818 * before dropping privileges it makes sense to keep things
819 * as simple (and bug-free) as possible.
820 */
821 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
822 }
823 #endif /* REPLACE_GETOPT */
824
825 /*
826 * getopt_long --
827 * Parse argc/argv argument vector.
828 */
829 int
getopt_long(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)830 getopt_long(int nargc, char * const *nargv, const char *options,
831 const struct option *long_options, int *idx)
832 {
833
834 return (getopt_internal(nargc, nargv, options, long_options, idx,
835 FLAG_PERMUTE));
836 }
837
838 /*
839 * getopt_long_only --
840 * Parse argc/argv argument vector.
841 */
842 int
getopt_long_only(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)843 getopt_long_only(int nargc, char * const *nargv, const char *options,
844 const struct option *long_options, int *idx)
845 {
846
847 return (getopt_internal(nargc, nargv, options, long_options, idx,
848 FLAG_PERMUTE|FLAG_LONGONLY));
849 }
850 /*******************************************************************************
851 * This file is part of the argtable3 library.
852 *
853 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
854 * <sheitmann@users.sourceforge.net>
855 * All rights reserved.
856 *
857 * Redistribution and use in source and binary forms, with or without
858 * modification, are permitted provided that the following conditions are met:
859 * * Redistributions of source code must retain the above copyright
860 * notice, this list of conditions and the following disclaimer.
861 * * Redistributions in binary form must reproduce the above copyright
862 * notice, this list of conditions and the following disclaimer in the
863 * documentation and/or other materials provided with the distribution.
864 * * Neither the name of STEWART HEITMANN nor the names of its contributors
865 * may be used to endorse or promote products derived from this software
866 * without specific prior written permission.
867 *
868 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
869 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
870 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
871 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
872 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
873 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
874 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
875 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
876 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
877 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
878 ******************************************************************************/
879
880 #include <stdlib.h>
881 #include <string.h>
882
883 #include "argtable3.h"
884
885
886 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm);
887
888
arg_date_resetfn(struct arg_date * parent)889 static void arg_date_resetfn(struct arg_date *parent)
890 {
891 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
892 parent->count = 0;
893 }
894
895
arg_date_scanfn(struct arg_date * parent,const char * argval)896 static int arg_date_scanfn(struct arg_date *parent, const char *argval)
897 {
898 int errorcode = 0;
899
900 if (parent->count == parent->hdr.maxcount)
901 {
902 errorcode = EMAXCOUNT;
903 }
904 else if (!argval)
905 {
906 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
907 parent->count++;
908 }
909 else
910 {
911 const char *pend;
912 struct tm tm = parent->tmval[parent->count];
913
914 /* parse the given argument value, store result in parent->tmval[] */
915 pend = arg_strptime(argval, parent->format, &tm);
916 if (pend && pend[0] == '\0')
917 parent->tmval[parent->count++] = tm;
918 else
919 errorcode = EBADDATE;
920 }
921
922 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
923 return errorcode;
924 }
925
926
arg_date_checkfn(struct arg_date * parent)927 static int arg_date_checkfn(struct arg_date *parent)
928 {
929 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
930
931 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
932 return errorcode;
933 }
934
935
arg_date_errorfn(struct arg_date * parent,FILE * fp,int errorcode,const char * argval,const char * progname)936 static void arg_date_errorfn(
937 struct arg_date *parent,
938 FILE *fp,
939 int errorcode,
940 const char *argval,
941 const char *progname)
942 {
943 const char *shortopts = parent->hdr.shortopts;
944 const char *longopts = parent->hdr.longopts;
945 const char *datatype = parent->hdr.datatype;
946
947 /* make argval NULL safe */
948 argval = argval ? argval : "";
949
950 fprintf(fp, "%s: ", progname);
951 switch(errorcode)
952 {
953 case EMINCOUNT:
954 fputs("missing option ", fp);
955 arg_print_option(fp, shortopts, longopts, datatype, "\n");
956 break;
957
958 case EMAXCOUNT:
959 fputs("excess option ", fp);
960 arg_print_option(fp, shortopts, longopts, argval, "\n");
961 break;
962
963 case EBADDATE:
964 {
965 struct tm tm;
966 char buff[200];
967
968 fprintf(fp, "illegal timestamp format \"%s\"\n", argval);
969 memset(&tm, 0, sizeof(tm));
970 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
971 strftime(buff, sizeof(buff), parent->format, &tm);
972 printf("correct format is \"%s\"\n", buff);
973 break;
974 }
975 }
976 }
977
978
arg_date0(const char * shortopts,const char * longopts,const char * format,const char * datatype,const char * glossary)979 struct arg_date * arg_date0(
980 const char * shortopts,
981 const char * longopts,
982 const char * format,
983 const char *datatype,
984 const char *glossary)
985 {
986 return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
987 }
988
989
arg_date1(const char * shortopts,const char * longopts,const char * format,const char * datatype,const char * glossary)990 struct arg_date * arg_date1(
991 const char * shortopts,
992 const char * longopts,
993 const char * format,
994 const char *datatype,
995 const char *glossary)
996 {
997 return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
998 }
999
1000
arg_daten(const char * shortopts,const char * longopts,const char * format,const char * datatype,int mincount,int maxcount,const char * glossary)1001 struct arg_date * arg_daten(
1002 const char * shortopts,
1003 const char * longopts,
1004 const char * format,
1005 const char *datatype,
1006 int mincount,
1007 int maxcount,
1008 const char *glossary)
1009 {
1010 size_t nbytes;
1011 struct arg_date *result;
1012
1013 /* foolproof things by ensuring maxcount is not less than mincount */
1014 maxcount = (maxcount < mincount) ? mincount : maxcount;
1015
1016 /* default time format is the national date format for the locale */
1017 if (!format)
1018 format = "%x";
1019
1020 nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
1021 + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
1022
1023 /* allocate storage for the arg_date struct + tmval[] array. */
1024 /* we use calloc because we want the tmval[] array zero filled. */
1025 result = (struct arg_date *)calloc(1, nbytes);
1026 if (result)
1027 {
1028 /* init the arg_hdr struct */
1029 result->hdr.flag = ARG_HASVALUE;
1030 result->hdr.shortopts = shortopts;
1031 result->hdr.longopts = longopts;
1032 result->hdr.datatype = datatype ? datatype : format;
1033 result->hdr.glossary = glossary;
1034 result->hdr.mincount = mincount;
1035 result->hdr.maxcount = maxcount;
1036 result->hdr.parent = result;
1037 result->hdr.resetfn = (arg_resetfn *)arg_date_resetfn;
1038 result->hdr.scanfn = (arg_scanfn *)arg_date_scanfn;
1039 result->hdr.checkfn = (arg_checkfn *)arg_date_checkfn;
1040 result->hdr.errorfn = (arg_errorfn *)arg_date_errorfn;
1041
1042 /* store the tmval[maxcount] array immediately after the arg_date struct */
1043 result->tmval = (struct tm *)(result + 1);
1044
1045 /* init the remaining arg_date member variables */
1046 result->count = 0;
1047 result->format = format;
1048 }
1049
1050 ARG_TRACE(("arg_daten() returns %p\n", result));
1051 return result;
1052 }
1053
1054
1055 /*-
1056 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1057 * All rights reserved.
1058 *
1059 * This code was contributed to The NetBSD Foundation by Klaus Klein.
1060 * Heavily optimised by David Laight
1061 *
1062 * Redistribution and use in source and binary forms, with or without
1063 * modification, are permitted provided that the following conditions
1064 * are met:
1065 * 1. Redistributions of source code must retain the above copyright
1066 * notice, this list of conditions and the following disclaimer.
1067 * 2. Redistributions in binary form must reproduce the above copyright
1068 * notice, this list of conditions and the following disclaimer in the
1069 * documentation and/or other materials provided with the distribution.
1070 *
1071 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1072 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1073 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1074 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1075 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1076 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1077 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1078 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1079 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1080 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1081 * POSSIBILITY OF SUCH DAMAGE.
1082 */
1083
1084 #include <ctype.h>
1085 #include <string.h>
1086 #include <time.h>
1087
1088 /*
1089 * We do not implement alternate representations. However, we always
1090 * check whether a given modifier is allowed for a certain conversion.
1091 */
1092 #define ALT_E 0x01
1093 #define ALT_O 0x02
1094 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
1095 #define TM_YEAR_BASE (1900)
1096
1097 static int conv_num(const char * *, int *, int, int);
1098
1099 static const char *day[7] = {
1100 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
1101 "Friday", "Saturday"
1102 };
1103
1104 static const char *abday[7] = {
1105 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1106 };
1107
1108 static const char *mon[12] = {
1109 "January", "February", "March", "April", "May", "June", "July",
1110 "August", "September", "October", "November", "December"
1111 };
1112
1113 static const char *abmon[12] = {
1114 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1115 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1116 };
1117
1118 static const char *am_pm[2] = {
1119 "AM", "PM"
1120 };
1121
1122
arg_strcasecmp(const char * s1,const char * s2)1123 static int arg_strcasecmp(const char *s1, const char *s2)
1124 {
1125 const unsigned char *us1 = (const unsigned char *)s1;
1126 const unsigned char *us2 = (const unsigned char *)s2;
1127 while (tolower(*us1) == tolower(*us2++))
1128 if (*us1++ == '\0')
1129 return 0;
1130
1131 return tolower(*us1) - tolower(*--us2);
1132 }
1133
1134
arg_strncasecmp(const char * s1,const char * s2,size_t n)1135 static int arg_strncasecmp(const char *s1, const char *s2, size_t n)
1136 {
1137 if (n != 0)
1138 {
1139 const unsigned char *us1 = (const unsigned char *)s1;
1140 const unsigned char *us2 = (const unsigned char *)s2;
1141 do
1142 {
1143 if (tolower(*us1) != tolower(*us2++))
1144 return tolower(*us1) - tolower(*--us2);
1145
1146 if (*us1++ == '\0')
1147 break;
1148 } while (--n != 0);
1149 }
1150
1151 return 0;
1152 }
1153
1154
arg_strptime(const char * buf,const char * fmt,struct tm * tm)1155 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm)
1156 {
1157 char c;
1158 const char *bp;
1159 size_t len = 0;
1160 int alt_format, i, split_year = 0;
1161
1162 bp = buf;
1163
1164 while ((c = *fmt) != '\0') {
1165 /* Clear `alternate' modifier prior to new conversion. */
1166 alt_format = 0;
1167
1168 /* Eat up white-space. */
1169 if (ISSPACE(c)) {
1170 while (ISSPACE(*bp))
1171 bp++;
1172
1173 fmt++;
1174 continue;
1175 }
1176
1177 if ((c = *fmt++) != '%')
1178 goto literal;
1179
1180
1181 again:
1182 switch (c = *fmt++)
1183 {
1184 case '%': /* "%%" is converted to "%". */
1185 literal:
1186 if (c != *bp++)
1187 return (0);
1188 break;
1189
1190 /*
1191 * "Alternative" modifiers. Just set the appropriate flag
1192 * and start over again.
1193 */
1194 case 'E': /* "%E?" alternative conversion modifier. */
1195 LEGAL_ALT(0);
1196 alt_format |= ALT_E;
1197 goto again;
1198
1199 case 'O': /* "%O?" alternative conversion modifier. */
1200 LEGAL_ALT(0);
1201 alt_format |= ALT_O;
1202 goto again;
1203
1204 /*
1205 * "Complex" conversion rules, implemented through recursion.
1206 */
1207 case 'c': /* Date and time, using the locale's format. */
1208 LEGAL_ALT(ALT_E);
1209 bp = arg_strptime(bp, "%x %X", tm);
1210 if (!bp)
1211 return (0);
1212 break;
1213
1214 case 'D': /* The date as "%m/%d/%y". */
1215 LEGAL_ALT(0);
1216 bp = arg_strptime(bp, "%m/%d/%y", tm);
1217 if (!bp)
1218 return (0);
1219 break;
1220
1221 case 'R': /* The time as "%H:%M". */
1222 LEGAL_ALT(0);
1223 bp = arg_strptime(bp, "%H:%M", tm);
1224 if (!bp)
1225 return (0);
1226 break;
1227
1228 case 'r': /* The time in 12-hour clock representation. */
1229 LEGAL_ALT(0);
1230 bp = arg_strptime(bp, "%I:%M:%S %p", tm);
1231 if (!bp)
1232 return (0);
1233 break;
1234
1235 case 'T': /* The time as "%H:%M:%S". */
1236 LEGAL_ALT(0);
1237 bp = arg_strptime(bp, "%H:%M:%S", tm);
1238 if (!bp)
1239 return (0);
1240 break;
1241
1242 case 'X': /* The time, using the locale's format. */
1243 LEGAL_ALT(ALT_E);
1244 bp = arg_strptime(bp, "%H:%M:%S", tm);
1245 if (!bp)
1246 return (0);
1247 break;
1248
1249 case 'x': /* The date, using the locale's format. */
1250 LEGAL_ALT(ALT_E);
1251 bp = arg_strptime(bp, "%m/%d/%y", tm);
1252 if (!bp)
1253 return (0);
1254 break;
1255
1256 /*
1257 * "Elementary" conversion rules.
1258 */
1259 case 'A': /* The day of week, using the locale's form. */
1260 case 'a':
1261 LEGAL_ALT(0);
1262 for (i = 0; i < 7; i++) {
1263 /* Full name. */
1264 len = strlen(day[i]);
1265 if (arg_strncasecmp(day[i], bp, len) == 0)
1266 break;
1267
1268 /* Abbreviated name. */
1269 len = strlen(abday[i]);
1270 if (arg_strncasecmp(abday[i], bp, len) == 0)
1271 break;
1272 }
1273
1274 /* Nothing matched. */
1275 if (i == 7)
1276 return (0);
1277
1278 tm->tm_wday = i;
1279 bp += len;
1280 break;
1281
1282 case 'B': /* The month, using the locale's form. */
1283 case 'b':
1284 case 'h':
1285 LEGAL_ALT(0);
1286 for (i = 0; i < 12; i++) {
1287 /* Full name. */
1288 len = strlen(mon[i]);
1289 if (arg_strncasecmp(mon[i], bp, len) == 0)
1290 break;
1291
1292 /* Abbreviated name. */
1293 len = strlen(abmon[i]);
1294 if (arg_strncasecmp(abmon[i], bp, len) == 0)
1295 break;
1296 }
1297
1298 /* Nothing matched. */
1299 if (i == 12)
1300 return (0);
1301
1302 tm->tm_mon = i;
1303 bp += len;
1304 break;
1305
1306 case 'C': /* The century number. */
1307 LEGAL_ALT(ALT_E);
1308 if (!(conv_num(&bp, &i, 0, 99)))
1309 return (0);
1310
1311 if (split_year) {
1312 tm->tm_year = (tm->tm_year % 100) + (i * 100);
1313 } else {
1314 tm->tm_year = i * 100;
1315 split_year = 1;
1316 }
1317 break;
1318
1319 case 'd': /* The day of month. */
1320 case 'e':
1321 LEGAL_ALT(ALT_O);
1322 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
1323 return (0);
1324 break;
1325
1326 case 'k': /* The hour (24-hour clock representation). */
1327 LEGAL_ALT(0);
1328 /* FALLTHROUGH */
1329 case 'H':
1330 LEGAL_ALT(ALT_O);
1331 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
1332 return (0);
1333 break;
1334
1335 case 'l': /* The hour (12-hour clock representation). */
1336 LEGAL_ALT(0);
1337 /* FALLTHROUGH */
1338 case 'I':
1339 LEGAL_ALT(ALT_O);
1340 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
1341 return (0);
1342 if (tm->tm_hour == 12)
1343 tm->tm_hour = 0;
1344 break;
1345
1346 case 'j': /* The day of year. */
1347 LEGAL_ALT(0);
1348 if (!(conv_num(&bp, &i, 1, 366)))
1349 return (0);
1350 tm->tm_yday = i - 1;
1351 break;
1352
1353 case 'M': /* The minute. */
1354 LEGAL_ALT(ALT_O);
1355 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
1356 return (0);
1357 break;
1358
1359 case 'm': /* The month. */
1360 LEGAL_ALT(ALT_O);
1361 if (!(conv_num(&bp, &i, 1, 12)))
1362 return (0);
1363 tm->tm_mon = i - 1;
1364 break;
1365
1366 case 'p': /* The locale's equivalent of AM/PM. */
1367 LEGAL_ALT(0);
1368 /* AM? */
1369 if (arg_strcasecmp(am_pm[0], bp) == 0) {
1370 if (tm->tm_hour > 11)
1371 return (0);
1372
1373 bp += strlen(am_pm[0]);
1374 break;
1375 }
1376 /* PM? */
1377 else if (arg_strcasecmp(am_pm[1], bp) == 0) {
1378 if (tm->tm_hour > 11)
1379 return (0);
1380
1381 tm->tm_hour += 12;
1382 bp += strlen(am_pm[1]);
1383 break;
1384 }
1385
1386 /* Nothing matched. */
1387 return (0);
1388
1389 case 'S': /* The seconds. */
1390 LEGAL_ALT(ALT_O);
1391 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
1392 return (0);
1393 break;
1394
1395 case 'U': /* The week of year, beginning on sunday. */
1396 case 'W': /* The week of year, beginning on monday. */
1397 LEGAL_ALT(ALT_O);
1398 /*
1399 * XXX This is bogus, as we can not assume any valid
1400 * information present in the tm structure at this
1401 * point to calculate a real value, so just check the
1402 * range for now.
1403 */
1404 if (!(conv_num(&bp, &i, 0, 53)))
1405 return (0);
1406 break;
1407
1408 case 'w': /* The day of week, beginning on sunday. */
1409 LEGAL_ALT(ALT_O);
1410 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
1411 return (0);
1412 break;
1413
1414 case 'Y': /* The year. */
1415 LEGAL_ALT(ALT_E);
1416 if (!(conv_num(&bp, &i, 0, 9999)))
1417 return (0);
1418
1419 tm->tm_year = i - TM_YEAR_BASE;
1420 break;
1421
1422 case 'y': /* The year within 100 years of the epoch. */
1423 LEGAL_ALT(ALT_E | ALT_O);
1424 if (!(conv_num(&bp, &i, 0, 99)))
1425 return (0);
1426
1427 if (split_year) {
1428 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
1429 break;
1430 }
1431 split_year = 1;
1432 if (i <= 68)
1433 tm->tm_year = i + 2000 - TM_YEAR_BASE;
1434 else
1435 tm->tm_year = i + 1900 - TM_YEAR_BASE;
1436 break;
1437
1438 /*
1439 * Miscellaneous conversions.
1440 */
1441 case 'n': /* Any kind of white-space. */
1442 case 't':
1443 LEGAL_ALT(0);
1444 while (ISSPACE(*bp))
1445 bp++;
1446 break;
1447
1448
1449 default: /* Unknown/unsupported conversion. */
1450 return (0);
1451 }
1452
1453
1454 }
1455
1456 /* LINTED functional specification */
1457 return ((char *)bp);
1458 }
1459
1460
conv_num(const char ** buf,int * dest,int llim,int ulim)1461 static int conv_num(const char * *buf, int *dest, int llim, int ulim)
1462 {
1463 int result = 0;
1464
1465 /* The limit also determines the number of valid digits. */
1466 int rulim = ulim;
1467
1468 if (**buf < '0' || **buf > '9')
1469 return (0);
1470
1471 do {
1472 result *= 10;
1473 result += *(*buf)++ - '0';
1474 rulim /= 10;
1475 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
1476
1477 if (result < llim || result > ulim)
1478 return (0);
1479
1480 *dest = result;
1481 return (1);
1482 }
1483 /*******************************************************************************
1484 * This file is part of the argtable3 library.
1485 *
1486 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1487 * <sheitmann@users.sourceforge.net>
1488 * All rights reserved.
1489 *
1490 * Redistribution and use in source and binary forms, with or without
1491 * modification, are permitted provided that the following conditions are met:
1492 * * Redistributions of source code must retain the above copyright
1493 * notice, this list of conditions and the following disclaimer.
1494 * * Redistributions in binary form must reproduce the above copyright
1495 * notice, this list of conditions and the following disclaimer in the
1496 * documentation and/or other materials provided with the distribution.
1497 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1498 * may be used to endorse or promote products derived from this software
1499 * without specific prior written permission.
1500 *
1501 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1502 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1503 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1504 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1505 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1506 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1507 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1508 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1509 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1510 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1511 ******************************************************************************/
1512
1513 #include <stdlib.h>
1514
1515 #include "argtable3.h"
1516
1517
arg_dbl_resetfn(struct arg_dbl * parent)1518 static void arg_dbl_resetfn(struct arg_dbl *parent)
1519 {
1520 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1521 parent->count = 0;
1522 }
1523
1524
arg_dbl_scanfn(struct arg_dbl * parent,const char * argval)1525 static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval)
1526 {
1527 int errorcode = 0;
1528
1529 if (parent->count == parent->hdr.maxcount)
1530 {
1531 /* maximum number of arguments exceeded */
1532 errorcode = EMAXCOUNT;
1533 }
1534 else if (!argval)
1535 {
1536 /* a valid argument with no argument value was given. */
1537 /* This happens when an optional argument value was invoked. */
1538 /* leave parent argument value unaltered but still count the argument. */
1539 parent->count++;
1540 }
1541 else
1542 {
1543 double val;
1544 char *end;
1545
1546 /* extract double from argval into val */
1547 val = strtod(argval, &end);
1548
1549 /* if success then store result in parent->dval[] array otherwise return error*/
1550 if (*end == 0)
1551 parent->dval[parent->count++] = val;
1552 else
1553 errorcode = EBADDOUBLE;
1554 }
1555
1556 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1557 return errorcode;
1558 }
1559
1560
arg_dbl_checkfn(struct arg_dbl * parent)1561 static int arg_dbl_checkfn(struct arg_dbl *parent)
1562 {
1563 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1564
1565 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1566 return errorcode;
1567 }
1568
1569
arg_dbl_errorfn(struct arg_dbl * parent,FILE * fp,int errorcode,const char * argval,const char * progname)1570 static void arg_dbl_errorfn(
1571 struct arg_dbl *parent,
1572 FILE *fp,
1573 int errorcode,
1574 const char *argval,
1575 const char *progname)
1576 {
1577 const char *shortopts = parent->hdr.shortopts;
1578 const char *longopts = parent->hdr.longopts;
1579 const char *datatype = parent->hdr.datatype;
1580
1581 /* make argval NULL safe */
1582 argval = argval ? argval : "";
1583
1584 fprintf(fp, "%s: ", progname);
1585 switch(errorcode)
1586 {
1587 case EMINCOUNT:
1588 fputs("missing option ", fp);
1589 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1590 break;
1591
1592 case EMAXCOUNT:
1593 fputs("excess option ", fp);
1594 arg_print_option(fp, shortopts, longopts, argval, "\n");
1595 break;
1596
1597 case EBADDOUBLE:
1598 fprintf(fp, "invalid argument \"%s\" to option ", argval);
1599 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1600 break;
1601 }
1602 }
1603
1604
arg_dbl0(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)1605 struct arg_dbl * arg_dbl0(
1606 const char * shortopts,
1607 const char * longopts,
1608 const char *datatype,
1609 const char *glossary)
1610 {
1611 return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
1612 }
1613
1614
arg_dbl1(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)1615 struct arg_dbl * arg_dbl1(
1616 const char * shortopts,
1617 const char * longopts,
1618 const char *datatype,
1619 const char *glossary)
1620 {
1621 return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
1622 }
1623
1624
arg_dbln(const char * shortopts,const char * longopts,const char * datatype,int mincount,int maxcount,const char * glossary)1625 struct arg_dbl * arg_dbln(
1626 const char * shortopts,
1627 const char * longopts,
1628 const char *datatype,
1629 int mincount,
1630 int maxcount,
1631 const char *glossary)
1632 {
1633 size_t nbytes;
1634 struct arg_dbl *result;
1635
1636 /* foolproof things by ensuring maxcount is not less than mincount */
1637 maxcount = (maxcount < mincount) ? mincount : maxcount;
1638
1639 nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
1640 + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1641
1642 result = (struct arg_dbl *)malloc(nbytes);
1643 if (result)
1644 {
1645 size_t addr;
1646 size_t rem;
1647
1648 /* init the arg_hdr struct */
1649 result->hdr.flag = ARG_HASVALUE;
1650 result->hdr.shortopts = shortopts;
1651 result->hdr.longopts = longopts;
1652 result->hdr.datatype = datatype ? datatype : "<double>";
1653 result->hdr.glossary = glossary;
1654 result->hdr.mincount = mincount;
1655 result->hdr.maxcount = maxcount;
1656 result->hdr.parent = result;
1657 result->hdr.resetfn = (arg_resetfn *)arg_dbl_resetfn;
1658 result->hdr.scanfn = (arg_scanfn *)arg_dbl_scanfn;
1659 result->hdr.checkfn = (arg_checkfn *)arg_dbl_checkfn;
1660 result->hdr.errorfn = (arg_errorfn *)arg_dbl_errorfn;
1661
1662 /* Store the dval[maxcount] array on the first double boundary that
1663 * immediately follows the arg_dbl struct. We do the memory alignment
1664 * purely for SPARC and Motorola systems. They require floats and
1665 * doubles to be aligned on natural boundaries.
1666 */
1667 addr = (size_t)(result + 1);
1668 rem = addr % sizeof(double);
1669 result->dval = (double *)(addr + sizeof(double) - rem);
1670 ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
1671
1672 result->count = 0;
1673 }
1674
1675 ARG_TRACE(("arg_dbln() returns %p\n", result));
1676 return result;
1677 }
1678 /*******************************************************************************
1679 * This file is part of the argtable3 library.
1680 *
1681 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1682 * <sheitmann@users.sourceforge.net>
1683 * All rights reserved.
1684 *
1685 * Redistribution and use in source and binary forms, with or without
1686 * modification, are permitted provided that the following conditions are met:
1687 * * Redistributions of source code must retain the above copyright
1688 * notice, this list of conditions and the following disclaimer.
1689 * * Redistributions in binary form must reproduce the above copyright
1690 * notice, this list of conditions and the following disclaimer in the
1691 * documentation and/or other materials provided with the distribution.
1692 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1693 * may be used to endorse or promote products derived from this software
1694 * without specific prior written permission.
1695 *
1696 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1697 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1698 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1699 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1700 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1701 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1702 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1703 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1704 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1705 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1706 ******************************************************************************/
1707
1708 #include <stdlib.h>
1709
1710 #include "argtable3.h"
1711
1712
arg_end_resetfn(struct arg_end * parent)1713 static void arg_end_resetfn(struct arg_end *parent)
1714 {
1715 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1716 parent->count = 0;
1717 }
1718
arg_end_errorfn(void * parent,FILE * fp,int error,const char * argval,const char * progname)1719 static void arg_end_errorfn(
1720 void *parent,
1721 FILE *fp,
1722 int error,
1723 const char *argval,
1724 const char *progname)
1725 {
1726 /* suppress unreferenced formal parameter warning */
1727 (void)parent;
1728
1729 progname = progname ? progname : "";
1730 argval = argval ? argval : "";
1731
1732 fprintf(fp, "%s: ", progname);
1733 switch(error)
1734 {
1735 case ARG_ELIMIT:
1736 fputs("too many errors to display", fp);
1737 break;
1738 case ARG_EMALLOC:
1739 fputs("insufficent memory", fp);
1740 break;
1741 case ARG_ENOMATCH:
1742 fprintf(fp, "unexpected argument \"%s\"", argval);
1743 break;
1744 case ARG_EMISSARG:
1745 fprintf(fp, "option \"%s\" requires an argument", argval);
1746 break;
1747 case ARG_ELONGOPT:
1748 fprintf(fp, "invalid option \"%s\"", argval);
1749 break;
1750 default:
1751 fprintf(fp, "invalid option \"-%c\"", error);
1752 break;
1753 }
1754
1755 fputc('\n', fp);
1756 }
1757
1758
arg_end(int maxcount)1759 struct arg_end * arg_end(int maxcount)
1760 {
1761 size_t nbytes;
1762 struct arg_end *result;
1763
1764 nbytes = sizeof(struct arg_end)
1765 + maxcount * sizeof(int) /* storage for int error[maxcount] array*/
1766 + maxcount * sizeof(void *) /* storage for void* parent[maxcount] array */
1767 + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */
1768
1769 result = (struct arg_end *)malloc(nbytes);
1770 if (result)
1771 {
1772 /* init the arg_hdr struct */
1773 result->hdr.flag = ARG_TERMINATOR;
1774 result->hdr.shortopts = NULL;
1775 result->hdr.longopts = NULL;
1776 result->hdr.datatype = NULL;
1777 result->hdr.glossary = NULL;
1778 result->hdr.mincount = 1;
1779 result->hdr.maxcount = maxcount;
1780 result->hdr.parent = result;
1781 result->hdr.resetfn = (arg_resetfn *)arg_end_resetfn;
1782 result->hdr.scanfn = NULL;
1783 result->hdr.checkfn = NULL;
1784 result->hdr.errorfn = (arg_errorfn *)arg_end_errorfn;
1785
1786 /* store error[maxcount] array immediately after struct arg_end */
1787 result->error = (int *)(result + 1);
1788
1789 /* store parent[maxcount] array immediately after error[] array */
1790 result->parent = (void * *)(result->error + maxcount );
1791
1792 /* store argval[maxcount] array immediately after parent[] array */
1793 result->argval = (const char * *)(result->parent + maxcount );
1794 }
1795
1796 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
1797 return result;
1798 }
1799
1800
arg_print_errors(FILE * fp,struct arg_end * end,const char * progname)1801 void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname)
1802 {
1803 int i;
1804 ARG_TRACE(("arg_errors()\n"));
1805 for (i = 0; i < end->count; i++)
1806 {
1807 struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]);
1808 if (errorparent->errorfn)
1809 errorparent->errorfn(end->parent[i],
1810 fp,
1811 end->error[i],
1812 end->argval[i],
1813 progname);
1814 }
1815 }
1816 /*******************************************************************************
1817 * This file is part of the argtable3 library.
1818 *
1819 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1820 * <sheitmann@users.sourceforge.net>
1821 * All rights reserved.
1822 *
1823 * Redistribution and use in source and binary forms, with or without
1824 * modification, are permitted provided that the following conditions are met:
1825 * * Redistributions of source code must retain the above copyright
1826 * notice, this list of conditions and the following disclaimer.
1827 * * Redistributions in binary form must reproduce the above copyright
1828 * notice, this list of conditions and the following disclaimer in the
1829 * documentation and/or other materials provided with the distribution.
1830 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1831 * may be used to endorse or promote products derived from this software
1832 * without specific prior written permission.
1833 *
1834 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1835 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1836 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1837 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1838 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1839 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1840 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1841 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1842 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1843 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1844 ******************************************************************************/
1845 // THIS FILE HAS BEEN ALTERED from original version to:
1846 // * fix issues found by static code analisys:
1847 // - Possible null pointer dereference at arg_basename
1848
1849 #include <string.h>
1850 #include <stdlib.h>
1851
1852 #include "argtable3.h"
1853
1854 #ifdef WIN32
1855 # define FILESEPARATOR1 '\\'
1856 # define FILESEPARATOR2 '/'
1857 #else
1858 # define FILESEPARATOR1 '/'
1859 # define FILESEPARATOR2 '/'
1860 #endif
1861
1862
arg_file_resetfn(struct arg_file * parent)1863 static void arg_file_resetfn(struct arg_file *parent)
1864 {
1865 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1866 parent->count = 0;
1867 }
1868
1869
1870 /* Returns ptr to the base filename within *filename */
arg_basename(const char * filename)1871 static const char * arg_basename(const char *filename)
1872 {
1873 const char *result = NULL, *result1, *result2;
1874
1875 /* Find the last occurrence of eother file separator character. */
1876 /* Two alternative file separator chars are supported as legal */
1877 /* file separators but not both together in the same filename. */
1878 result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
1879 result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
1880
1881 if (result2)
1882 result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
1883
1884 if (result1)
1885 result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
1886
1887 if (!result)
1888 result = filename; /* neither file separator was found so basename is the whole filename */
1889
1890 /* special cases of "." and ".." are not considered basenames */
1891 if (filename && result &&
1892 (strcmp(".", result) == 0 || strcmp("..", result) == 0))
1893 result = filename + strlen(filename);
1894
1895 return result;
1896 }
1897
1898
1899 /* Returns ptr to the file extension within *basename */
arg_extension(const char * basename)1900 static const char * arg_extension(const char *basename)
1901 {
1902 /* find the last occurrence of '.' in basename */
1903 const char *result = (basename ? strrchr(basename, '.') : NULL);
1904
1905 /* if no '.' was found then return pointer to end of basename */
1906 if (basename && !result)
1907 result = basename + strlen(basename);
1908
1909 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1910 if (basename && result == basename)
1911 result = basename + strlen(basename);
1912
1913 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1914 if (basename && result && result[1] == '\0')
1915 result = basename + strlen(basename);
1916
1917 return result;
1918 }
1919
1920
arg_file_scanfn(struct arg_file * parent,const char * argval)1921 static int arg_file_scanfn(struct arg_file *parent, const char *argval)
1922 {
1923 int errorcode = 0;
1924
1925 if (parent->count == parent->hdr.maxcount)
1926 {
1927 /* maximum number of arguments exceeded */
1928 errorcode = EMAXCOUNT;
1929 }
1930 else if (!argval)
1931 {
1932 /* a valid argument with no argument value was given. */
1933 /* This happens when an optional argument value was invoked. */
1934 /* leave parent arguiment value unaltered but still count the argument. */
1935 parent->count++;
1936 }
1937 else
1938 {
1939 parent->filename[parent->count] = argval;
1940 parent->basename[parent->count] = arg_basename(argval);
1941 parent->extension[parent->count] =
1942 arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
1943 parent->count++;
1944 }
1945
1946 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1947 return errorcode;
1948 }
1949
1950
arg_file_checkfn(struct arg_file * parent)1951 static int arg_file_checkfn(struct arg_file *parent)
1952 {
1953 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1954
1955 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1956 return errorcode;
1957 }
1958
1959
arg_file_errorfn(struct arg_file * parent,FILE * fp,int errorcode,const char * argval,const char * progname)1960 static void arg_file_errorfn(
1961 struct arg_file *parent,
1962 FILE *fp,
1963 int errorcode,
1964 const char *argval,
1965 const char *progname)
1966 {
1967 const char *shortopts = parent->hdr.shortopts;
1968 const char *longopts = parent->hdr.longopts;
1969 const char *datatype = parent->hdr.datatype;
1970
1971 /* make argval NULL safe */
1972 argval = argval ? argval : "";
1973
1974 fprintf(fp, "%s: ", progname);
1975 switch(errorcode)
1976 {
1977 case EMINCOUNT:
1978 fputs("missing option ", fp);
1979 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1980 break;
1981
1982 case EMAXCOUNT:
1983 fputs("excess option ", fp);
1984 arg_print_option(fp, shortopts, longopts, argval, "\n");
1985 break;
1986
1987 default:
1988 fprintf(fp, "unknown error at \"%s\"\n", argval);
1989 }
1990 }
1991
1992
arg_file0(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)1993 struct arg_file * arg_file0(
1994 const char * shortopts,
1995 const char * longopts,
1996 const char *datatype,
1997 const char *glossary)
1998 {
1999 return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
2000 }
2001
2002
arg_file1(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)2003 struct arg_file * arg_file1(
2004 const char * shortopts,
2005 const char * longopts,
2006 const char *datatype,
2007 const char *glossary)
2008 {
2009 return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
2010 }
2011
2012
arg_filen(const char * shortopts,const char * longopts,const char * datatype,int mincount,int maxcount,const char * glossary)2013 struct arg_file * arg_filen(
2014 const char * shortopts,
2015 const char * longopts,
2016 const char *datatype,
2017 int mincount,
2018 int maxcount,
2019 const char *glossary)
2020 {
2021 size_t nbytes;
2022 struct arg_file *result;
2023
2024 /* foolproof things by ensuring maxcount is not less than mincount */
2025 maxcount = (maxcount < mincount) ? mincount : maxcount;
2026
2027 nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
2028 + sizeof(char *) * maxcount /* storage for filename[maxcount] array */
2029 + sizeof(char *) * maxcount /* storage for basename[maxcount] array */
2030 + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */
2031
2032 result = (struct arg_file *)malloc(nbytes);
2033 if (result)
2034 {
2035 int i;
2036
2037 /* init the arg_hdr struct */
2038 result->hdr.flag = ARG_HASVALUE;
2039 result->hdr.shortopts = shortopts;
2040 result->hdr.longopts = longopts;
2041 result->hdr.glossary = glossary;
2042 result->hdr.datatype = datatype ? datatype : "<file>";
2043 result->hdr.mincount = mincount;
2044 result->hdr.maxcount = maxcount;
2045 result->hdr.parent = result;
2046 result->hdr.resetfn = (arg_resetfn *)arg_file_resetfn;
2047 result->hdr.scanfn = (arg_scanfn *)arg_file_scanfn;
2048 result->hdr.checkfn = (arg_checkfn *)arg_file_checkfn;
2049 result->hdr.errorfn = (arg_errorfn *)arg_file_errorfn;
2050
2051 /* store the filename,basename,extension arrays immediately after the arg_file struct */
2052 result->filename = (const char * *)(result + 1);
2053 result->basename = result->filename + maxcount;
2054 result->extension = result->basename + maxcount;
2055 result->count = 0;
2056
2057 /* foolproof the string pointers by initialising them with empty strings */
2058 for (i = 0; i < maxcount; i++)
2059 {
2060 result->filename[i] = "";
2061 result->basename[i] = "";
2062 result->extension[i] = "";
2063 }
2064 }
2065
2066 ARG_TRACE(("arg_filen() returns %p\n", result));
2067 return result;
2068 }
2069 /*******************************************************************************
2070 * This file is part of the argtable3 library.
2071 *
2072 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2073 * <sheitmann@users.sourceforge.net>
2074 * All rights reserved.
2075 *
2076 * Redistribution and use in source and binary forms, with or without
2077 * modification, are permitted provided that the following conditions are met:
2078 * * Redistributions of source code must retain the above copyright
2079 * notice, this list of conditions and the following disclaimer.
2080 * * Redistributions in binary form must reproduce the above copyright
2081 * notice, this list of conditions and the following disclaimer in the
2082 * documentation and/or other materials provided with the distribution.
2083 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2084 * may be used to endorse or promote products derived from this software
2085 * without specific prior written permission.
2086 *
2087 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2088 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2089 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2090 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2091 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2092 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2093 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2094 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2095 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2096 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2097 ******************************************************************************/
2098
2099 #include <stdlib.h>
2100 #include <limits.h>
2101 #include <ctype.h>
2102
2103 #include "argtable3.h"
2104
2105
arg_int_resetfn(struct arg_int * parent)2106 static void arg_int_resetfn(struct arg_int *parent)
2107 {
2108 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2109 parent->count = 0;
2110 }
2111
2112
2113 /* strtol0x() is like strtol() except that the numeric string is */
2114 /* expected to be prefixed by "0X" where X is a user supplied char. */
2115 /* The string may optionally be prefixed by white space and + or - */
2116 /* as in +0X123 or -0X123. */
2117 /* Once the prefix has been scanned, the remainder of the numeric */
2118 /* string is converted using strtol() with the given base. */
2119 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
2120 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
2121 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
2122 /* Failure of conversion is indicated by result where *endptr==str. */
strtol0X(const char * str,const char ** endptr,char X,int base)2123 static long int strtol0X(const char * str,
2124 const char * *endptr,
2125 char X,
2126 int base)
2127 {
2128 long int val; /* stores result */
2129 int s = 1; /* sign is +1 or -1 */
2130 const char *ptr = str; /* ptr to current position in str */
2131
2132 /* skip leading whitespace */
2133 while (ISSPACE(*ptr))
2134 ptr++;
2135 /* printf("1) %s\n",ptr); */
2136
2137 /* scan optional sign character */
2138 switch (*ptr)
2139 {
2140 case '+':
2141 ptr++;
2142 s = 1;
2143 break;
2144 case '-':
2145 ptr++;
2146 s = -1;
2147 break;
2148 default:
2149 s = 1;
2150 break;
2151 }
2152 /* printf("2) %s\n",ptr); */
2153
2154 /* '0X' prefix */
2155 if ((*ptr++) != '0')
2156 {
2157 /* printf("failed to detect '0'\n"); */
2158 *endptr = str;
2159 return 0;
2160 }
2161 /* printf("3) %s\n",ptr); */
2162 if (toupper(*ptr++) != toupper(X))
2163 {
2164 /* printf("failed to detect '%c'\n",X); */
2165 *endptr = str;
2166 return 0;
2167 }
2168 /* printf("4) %s\n",ptr); */
2169
2170 /* attempt conversion on remainder of string using strtol() */
2171 val = strtol(ptr, (char * *)endptr, base);
2172 if (*endptr == ptr)
2173 {
2174 /* conversion failed */
2175 *endptr = str;
2176 return 0;
2177 }
2178
2179 /* success */
2180 return s * val;
2181 }
2182
2183
2184 /* Returns 1 if str matches suffix (case insensitive). */
2185 /* Str may contain trailing whitespace, but nothing else. */
detectsuffix(const char * str,const char * suffix)2186 static int detectsuffix(const char *str, const char *suffix)
2187 {
2188 /* scan pairwise through strings until mismatch detected */
2189 while( toupper(*str) == toupper(*suffix) )
2190 {
2191 /* printf("'%c' '%c'\n", *str, *suffix); */
2192
2193 /* return 1 (success) if match persists until the string terminator */
2194 if (*str == '\0')
2195 return 1;
2196
2197 /* next chars */
2198 str++;
2199 suffix++;
2200 }
2201 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2202
2203 /* return 0 (fail) if the matching did not consume the entire suffix */
2204 if (*suffix != 0)
2205 return 0; /* failed to consume entire suffix */
2206
2207 /* skip any remaining whitespace in str */
2208 while (ISSPACE(*str))
2209 str++;
2210
2211 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2212 return (*str == '\0') ? 1 : 0;
2213 }
2214
2215
arg_int_scanfn(struct arg_int * parent,const char * argval)2216 static int arg_int_scanfn(struct arg_int *parent, const char *argval)
2217 {
2218 int errorcode = 0;
2219
2220 if (parent->count == parent->hdr.maxcount)
2221 {
2222 /* maximum number of arguments exceeded */
2223 errorcode = EMAXCOUNT;
2224 }
2225 else if (!argval)
2226 {
2227 /* a valid argument with no argument value was given. */
2228 /* This happens when an optional argument value was invoked. */
2229 /* leave parent arguiment value unaltered but still count the argument. */
2230 parent->count++;
2231 }
2232 else
2233 {
2234 long int val;
2235 const char *end;
2236
2237 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2238 val = strtol0X(argval, &end, 'X', 16);
2239 if (end == argval)
2240 {
2241 /* hex failed, attempt octal conversion (eg +0o123) */
2242 val = strtol0X(argval, &end, 'O', 8);
2243 if (end == argval)
2244 {
2245 /* octal failed, attempt binary conversion (eg +0B101) */
2246 val = strtol0X(argval, &end, 'B', 2);
2247 if (end == argval)
2248 {
2249 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2250 val = strtol(argval, (char * *)&end, 10);
2251 if (end == argval)
2252 {
2253 /* all supported number formats failed */
2254 return EBADINT;
2255 }
2256 }
2257 }
2258 }
2259
2260 /* Safety check for integer overflow. WARNING: this check */
2261 /* achieves nothing on machines where size(int)==size(long). */
2262 if ( val > INT_MAX || val < INT_MIN )
2263 #ifdef __STDC_WANT_SECURE_LIB__
2264 errorcode = EOVERFLOW_;
2265 #else
2266 errorcode = EOVERFLOW_;
2267 #endif
2268
2269 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2270 /* We need to be mindful of integer overflows when using such big numbers. */
2271 if (detectsuffix(end, "KB")) /* kilobytes */
2272 {
2273 if ( val > (INT_MAX / 1024) || val < (INT_MIN / 1024) )
2274 #ifdef __STDC_WANT_SECURE_LIB__
2275 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2276 #else
2277 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2278 #endif
2279 else
2280 val *= 1024; /* 1KB = 1024 */
2281 }
2282 else if (detectsuffix(end, "MB")) /* megabytes */
2283 {
2284 if ( val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576) )
2285 #ifdef __STDC_WANT_SECURE_LIB__
2286 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2287 #else
2288 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2289 #endif
2290 else
2291 val *= 1048576; /* 1MB = 1024*1024 */
2292 }
2293 else if (detectsuffix(end, "GB")) /* gigabytes */
2294 {
2295 if ( val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824) )
2296 #ifdef __STDC_WANT_SECURE_LIB__
2297 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2298 #else
2299 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2300 #endif
2301 else
2302 val *= 1073741824; /* 1GB = 1024*1024*1024 */
2303 }
2304 else if (!detectsuffix(end, ""))
2305 errorcode = EBADINT; /* invalid suffix detected */
2306
2307 /* if success then store result in parent->ival[] array */
2308 if (errorcode == 0)
2309 parent->ival[parent->count++] = val;
2310 }
2311
2312 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2313 return errorcode;
2314 }
2315
2316
arg_int_checkfn(struct arg_int * parent)2317 static int arg_int_checkfn(struct arg_int *parent)
2318 {
2319 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2320 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2321 return errorcode;
2322 }
2323
2324
arg_int_errorfn(struct arg_int * parent,FILE * fp,int errorcode,const char * argval,const char * progname)2325 static void arg_int_errorfn(
2326 struct arg_int *parent,
2327 FILE *fp,
2328 int errorcode,
2329 const char *argval,
2330 const char *progname)
2331 {
2332 const char *shortopts = parent->hdr.shortopts;
2333 const char *longopts = parent->hdr.longopts;
2334 const char *datatype = parent->hdr.datatype;
2335
2336 /* make argval NULL safe */
2337 argval = argval ? argval : "";
2338
2339 fprintf(fp, "%s: ", progname);
2340 switch(errorcode)
2341 {
2342 case EMINCOUNT:
2343 fputs("missing option ", fp);
2344 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2345 break;
2346
2347 case EMAXCOUNT:
2348 fputs("excess option ", fp);
2349 arg_print_option(fp, shortopts, longopts, argval, "\n");
2350 break;
2351
2352 case EBADINT:
2353 fprintf(fp, "invalid argument \"%s\" to option ", argval);
2354 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2355 break;
2356
2357 #ifdef __STDC_WANT_SECURE_LIB__
2358 case EOVERFLOW_:
2359 #else
2360 case EOVERFLOW_:
2361 #endif
2362 fputs("integer overflow at option ", fp);
2363 arg_print_option(fp, shortopts, longopts, datatype, " ");
2364 fprintf(fp, "(%s is too large)\n", argval);
2365 break;
2366 }
2367 }
2368
2369
arg_int0(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)2370 struct arg_int * arg_int0(
2371 const char *shortopts,
2372 const char *longopts,
2373 const char *datatype,
2374 const char *glossary)
2375 {
2376 return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
2377 }
2378
2379
arg_int1(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)2380 struct arg_int * arg_int1(
2381 const char *shortopts,
2382 const char *longopts,
2383 const char *datatype,
2384 const char *glossary)
2385 {
2386 return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
2387 }
2388
2389
arg_intn(const char * shortopts,const char * longopts,const char * datatype,int mincount,int maxcount,const char * glossary)2390 struct arg_int * arg_intn(
2391 const char *shortopts,
2392 const char *longopts,
2393 const char *datatype,
2394 int mincount,
2395 int maxcount,
2396 const char *glossary)
2397 {
2398 size_t nbytes;
2399 struct arg_int *result;
2400
2401 /* foolproof things by ensuring maxcount is not less than mincount */
2402 maxcount = (maxcount < mincount) ? mincount : maxcount;
2403
2404 nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
2405 + maxcount * sizeof(int); /* storage for ival[maxcount] array */
2406
2407 result = (struct arg_int *)malloc(nbytes);
2408 if (result)
2409 {
2410 /* init the arg_hdr struct */
2411 result->hdr.flag = ARG_HASVALUE;
2412 result->hdr.shortopts = shortopts;
2413 result->hdr.longopts = longopts;
2414 result->hdr.datatype = datatype ? datatype : "<int>";
2415 result->hdr.glossary = glossary;
2416 result->hdr.mincount = mincount;
2417 result->hdr.maxcount = maxcount;
2418 result->hdr.parent = result;
2419 result->hdr.resetfn = (arg_resetfn *)arg_int_resetfn;
2420 result->hdr.scanfn = (arg_scanfn *)arg_int_scanfn;
2421 result->hdr.checkfn = (arg_checkfn *)arg_int_checkfn;
2422 result->hdr.errorfn = (arg_errorfn *)arg_int_errorfn;
2423
2424 /* store the ival[maxcount] array immediately after the arg_int struct */
2425 result->ival = (int *)(result + 1);
2426 result->count = 0;
2427 }
2428
2429 ARG_TRACE(("arg_intn() returns %p\n", result));
2430 return result;
2431 }
2432 /*******************************************************************************
2433 * This file is part of the argtable3 library.
2434 *
2435 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2436 * <sheitmann@users.sourceforge.net>
2437 * All rights reserved.
2438 *
2439 * Redistribution and use in source and binary forms, with or without
2440 * modification, are permitted provided that the following conditions are met:
2441 * * Redistributions of source code must retain the above copyright
2442 * notice, this list of conditions and the following disclaimer.
2443 * * Redistributions in binary form must reproduce the above copyright
2444 * notice, this list of conditions and the following disclaimer in the
2445 * documentation and/or other materials provided with the distribution.
2446 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2447 * may be used to endorse or promote products derived from this software
2448 * without specific prior written permission.
2449 *
2450 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2451 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2452 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2453 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2454 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2455 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2456 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2457 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2458 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2459 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2460 ******************************************************************************/
2461
2462 #include <stdlib.h>
2463
2464 #include "argtable3.h"
2465
2466
arg_lit_resetfn(struct arg_lit * parent)2467 static void arg_lit_resetfn(struct arg_lit *parent)
2468 {
2469 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2470 parent->count = 0;
2471 }
2472
2473
arg_lit_scanfn(struct arg_lit * parent,const char * argval)2474 static int arg_lit_scanfn(struct arg_lit *parent, const char *argval)
2475 {
2476 int errorcode = 0;
2477 if (parent->count < parent->hdr.maxcount )
2478 parent->count++;
2479 else
2480 errorcode = EMAXCOUNT;
2481
2482 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,
2483 errorcode));
2484 return errorcode;
2485 }
2486
2487
arg_lit_checkfn(struct arg_lit * parent)2488 static int arg_lit_checkfn(struct arg_lit *parent)
2489 {
2490 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2491 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
2492 return errorcode;
2493 }
2494
2495
arg_lit_errorfn(struct arg_lit * parent,FILE * fp,int errorcode,const char * argval,const char * progname)2496 static void arg_lit_errorfn(
2497 struct arg_lit *parent,
2498 FILE *fp,
2499 int errorcode,
2500 const char *argval,
2501 const char *progname)
2502 {
2503 const char *shortopts = parent->hdr.shortopts;
2504 const char *longopts = parent->hdr.longopts;
2505 const char *datatype = parent->hdr.datatype;
2506
2507 switch(errorcode)
2508 {
2509 case EMINCOUNT:
2510 fprintf(fp, "%s: missing option ", progname);
2511 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2512 fprintf(fp, "\n");
2513 break;
2514
2515 case EMAXCOUNT:
2516 fprintf(fp, "%s: extraneous option ", progname);
2517 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2518 break;
2519 }
2520
2521 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
2522 errorcode, argval, progname));
2523 }
2524
2525
arg_lit0(const char * shortopts,const char * longopts,const char * glossary)2526 struct arg_lit * arg_lit0(
2527 const char * shortopts,
2528 const char * longopts,
2529 const char * glossary)
2530 {
2531 return arg_litn(shortopts, longopts, 0, 1, glossary);
2532 }
2533
2534
arg_lit1(const char * shortopts,const char * longopts,const char * glossary)2535 struct arg_lit * arg_lit1(
2536 const char *shortopts,
2537 const char *longopts,
2538 const char *glossary)
2539 {
2540 return arg_litn(shortopts, longopts, 1, 1, glossary);
2541 }
2542
2543
arg_litn(const char * shortopts,const char * longopts,int mincount,int maxcount,const char * glossary)2544 struct arg_lit * arg_litn(
2545 const char *shortopts,
2546 const char *longopts,
2547 int mincount,
2548 int maxcount,
2549 const char *glossary)
2550 {
2551 struct arg_lit *result;
2552
2553 /* foolproof things by ensuring maxcount is not less than mincount */
2554 maxcount = (maxcount < mincount) ? mincount : maxcount;
2555
2556 result = (struct arg_lit *)malloc(sizeof(struct arg_lit));
2557 if (result)
2558 {
2559 /* init the arg_hdr struct */
2560 result->hdr.flag = 0;
2561 result->hdr.shortopts = shortopts;
2562 result->hdr.longopts = longopts;
2563 result->hdr.datatype = NULL;
2564 result->hdr.glossary = glossary;
2565 result->hdr.mincount = mincount;
2566 result->hdr.maxcount = maxcount;
2567 result->hdr.parent = result;
2568 result->hdr.resetfn = (arg_resetfn *)arg_lit_resetfn;
2569 result->hdr.scanfn = (arg_scanfn *)arg_lit_scanfn;
2570 result->hdr.checkfn = (arg_checkfn *)arg_lit_checkfn;
2571 result->hdr.errorfn = (arg_errorfn *)arg_lit_errorfn;
2572
2573 /* init local variables */
2574 result->count = 0;
2575 }
2576
2577 ARG_TRACE(("arg_litn() returns %p\n", result));
2578 return result;
2579 }
2580 /*******************************************************************************
2581 * This file is part of the argtable3 library.
2582 *
2583 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2584 * <sheitmann@users.sourceforge.net>
2585 * All rights reserved.
2586 *
2587 * Redistribution and use in source and binary forms, with or without
2588 * modification, are permitted provided that the following conditions are met:
2589 * * Redistributions of source code must retain the above copyright
2590 * notice, this list of conditions and the following disclaimer.
2591 * * Redistributions in binary form must reproduce the above copyright
2592 * notice, this list of conditions and the following disclaimer in the
2593 * documentation and/or other materials provided with the distribution.
2594 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2595 * may be used to endorse or promote products derived from this software
2596 * without specific prior written permission.
2597 *
2598 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2599 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2600 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2601 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2602 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2603 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2604 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2605 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2606 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2607 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2608 ******************************************************************************/
2609
2610 #include <stdlib.h>
2611
2612 #include "argtable3.h"
2613
arg_rem(const char * datatype,const char * glossary)2614 struct arg_rem *arg_rem(const char *datatype, const char *glossary)
2615 {
2616 struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem));
2617 if (result)
2618 {
2619 result->hdr.flag = 0;
2620 result->hdr.shortopts = NULL;
2621 result->hdr.longopts = NULL;
2622 result->hdr.datatype = datatype;
2623 result->hdr.glossary = glossary;
2624 result->hdr.mincount = 1;
2625 result->hdr.maxcount = 1;
2626 result->hdr.parent = result;
2627 result->hdr.resetfn = NULL;
2628 result->hdr.scanfn = NULL;
2629 result->hdr.checkfn = NULL;
2630 result->hdr.errorfn = NULL;
2631 }
2632
2633 ARG_TRACE(("arg_rem() returns %p\n", result));
2634 return result;
2635 }
2636
2637 /*******************************************************************************
2638 * This file is part of the argtable3 library.
2639 *
2640 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2641 * <sheitmann@users.sourceforge.net>
2642 * All rights reserved.
2643 *
2644 * Redistribution and use in source and binary forms, with or without
2645 * modification, are permitted provided that the following conditions are met:
2646 * * Redistributions of source code must retain the above copyright
2647 * notice, this list of conditions and the following disclaimer.
2648 * * Redistributions in binary form must reproduce the above copyright
2649 * notice, this list of conditions and the following disclaimer in the
2650 * documentation and/or other materials provided with the distribution.
2651 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2652 * may be used to endorse or promote products derived from this software
2653 * without specific prior written permission.
2654 *
2655 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2656 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2657 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2658 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2659 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2660 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2661 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2662 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2663 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2664 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2665 ******************************************************************************/
2666
2667 #include <stdlib.h>
2668 #include <string.h>
2669
2670 #include "argtable3.h"
2671
2672
2673 #ifndef _TREX_H_
2674 #define _TREX_H_
2675 /***************************************************************
2676 T-Rex a tiny regular expression library
2677
2678 Copyright (C) 2003-2006 Alberto Demichelis
2679
2680 This software is provided 'as-is', without any express
2681 or implied warranty. In no event will the authors be held
2682 liable for any damages arising from the use of this software.
2683
2684 Permission is granted to anyone to use this software for
2685 any purpose, including commercial applications, and to alter
2686 it and redistribute it freely, subject to the following restrictions:
2687
2688 1. The origin of this software must not be misrepresented;
2689 you must not claim that you wrote the original software.
2690 If you use this software in a product, an acknowledgment
2691 in the product documentation would be appreciated but
2692 is not required.
2693
2694 2. Altered source versions must be plainly marked as such,
2695 and must not be misrepresented as being the original software.
2696
2697 3. This notice may not be removed or altered from any
2698 source distribution.
2699
2700 ****************************************************************/
2701 // THIS FILE HAS BEEN ALTERED from original version to:
2702 // * fix issues found by static code analisys:
2703 // - Null pointer dereference in trex_newnode, arg_rex_scanfn and trex_compile
2704 // * Fix implicit-fallthrough GCC error in trex_charnode
2705 // * Fix clobbered GCC error in trex_compile
2706
2707 #ifdef __cplusplus
2708 extern "C" {
2709 #endif
2710
2711 #ifdef _UNICODE
2712 #define TRexChar unsigned short
2713 #define MAX_CHAR 0xFFFF
2714 #define _TREXC(c) L##c
2715 #define trex_strlen wcslen
2716 #define trex_printf wprintf
2717 #else
2718 #define TRexChar char
2719 #define MAX_CHAR 0xFF
2720 #define _TREXC(c) (c)
2721 #define trex_strlen strlen
2722 #define trex_printf printf
2723 #endif
2724
2725 #ifndef TREX_API
2726 #define TREX_API extern
2727 #endif
2728
2729 #define TRex_True 1
2730 #define TRex_False 0
2731
2732 #define TREX_ICASE ARG_REX_ICASE
2733
2734 typedef unsigned int TRexBool;
2735 typedef struct TRex TRex;
2736
2737 typedef struct {
2738 const TRexChar *begin;
2739 int len;
2740 } TRexMatch;
2741
2742 TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags);
2743 TREX_API void trex_free(TRex *exp);
2744 TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);
2745 TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
2746 TREX_API TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);
2747 TREX_API int trex_getsubexpcount(TRex* exp);
2748 TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
2749
2750 #ifdef __cplusplus
2751 }
2752 #endif
2753
2754 #endif
2755
2756
2757
2758 struct privhdr
2759 {
2760 const char *pattern;
2761 int flags;
2762 };
2763
2764
arg_rex_resetfn(struct arg_rex * parent)2765 static void arg_rex_resetfn(struct arg_rex *parent)
2766 {
2767 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2768 parent->count = 0;
2769 }
2770
arg_rex_scanfn(struct arg_rex * parent,const char * argval)2771 static int arg_rex_scanfn(struct arg_rex *parent, const char *argval)
2772 {
2773 int errorcode = 0;
2774 const TRexChar *error = NULL;
2775 TRex *rex = NULL;
2776 TRexBool is_match = TRex_False;
2777
2778 if (parent->count == parent->hdr.maxcount )
2779 {
2780 /* maximum number of arguments exceeded */
2781 errorcode = EMAXCOUNT;
2782 }
2783 else if (!argval)
2784 {
2785 /* a valid argument with no argument value was given. */
2786 /* This happens when an optional argument value was invoked. */
2787 /* leave parent argument value unaltered but still count the argument. */
2788 parent->count++;
2789 }
2790 else
2791 {
2792 struct privhdr *priv = (struct privhdr *)parent->hdr.priv;
2793
2794 /* test the current argument value for a match with the regular expression */
2795 /* if a match is detected, record the argument value in the arg_rex struct */
2796
2797 rex = trex_compile(priv->pattern, &error, priv->flags);
2798 if (!rex)
2799 {
2800 errorcode = EREGNOMATCH;
2801 }
2802 else
2803 {
2804 is_match = trex_match(rex, argval);
2805 if (!is_match)
2806 errorcode = EREGNOMATCH;
2807 else
2808 parent->sval[parent->count++] = argval;
2809
2810 trex_free(rex);
2811 }
2812 }
2813
2814 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode));
2815 return errorcode;
2816 }
2817
arg_rex_checkfn(struct arg_rex * parent)2818 static int arg_rex_checkfn(struct arg_rex *parent)
2819 {
2820 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2821 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2822
2823 /* free the regex "program" we constructed in resetfn */
2824 //regfree(&(priv->regex));
2825
2826 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2827 return errorcode;
2828 }
2829
arg_rex_errorfn(struct arg_rex * parent,FILE * fp,int errorcode,const char * argval,const char * progname)2830 static void arg_rex_errorfn(struct arg_rex *parent,
2831 FILE *fp,
2832 int errorcode,
2833 const char *argval,
2834 const char *progname)
2835 {
2836 const char *shortopts = parent->hdr.shortopts;
2837 const char *longopts = parent->hdr.longopts;
2838 const char *datatype = parent->hdr.datatype;
2839
2840 /* make argval NULL safe */
2841 argval = argval ? argval : "";
2842
2843 fprintf(fp, "%s: ", progname);
2844 switch(errorcode)
2845 {
2846 case EMINCOUNT:
2847 fputs("missing option ", fp);
2848 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2849 break;
2850
2851 case EMAXCOUNT:
2852 fputs("excess option ", fp);
2853 arg_print_option(fp, shortopts, longopts, argval, "\n");
2854 break;
2855
2856 case EREGNOMATCH:
2857 fputs("illegal value ", fp);
2858 arg_print_option(fp, shortopts, longopts, argval, "\n");
2859 break;
2860
2861 default:
2862 {
2863 //char errbuff[256];
2864 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2865 //printf("%s\n", errbuff);
2866 }
2867 break;
2868 }
2869 }
2870
2871
arg_rex0(const char * shortopts,const char * longopts,const char * pattern,const char * datatype,int flags,const char * glossary)2872 struct arg_rex * arg_rex0(const char * shortopts,
2873 const char * longopts,
2874 const char * pattern,
2875 const char *datatype,
2876 int flags,
2877 const char *glossary)
2878 {
2879 return arg_rexn(shortopts,
2880 longopts,
2881 pattern,
2882 datatype,
2883 0,
2884 1,
2885 flags,
2886 glossary);
2887 }
2888
arg_rex1(const char * shortopts,const char * longopts,const char * pattern,const char * datatype,int flags,const char * glossary)2889 struct arg_rex * arg_rex1(const char * shortopts,
2890 const char * longopts,
2891 const char * pattern,
2892 const char *datatype,
2893 int flags,
2894 const char *glossary)
2895 {
2896 return arg_rexn(shortopts,
2897 longopts,
2898 pattern,
2899 datatype,
2900 1,
2901 1,
2902 flags,
2903 glossary);
2904 }
2905
2906
arg_rexn(const char * shortopts,const char * longopts,const char * pattern,const char * datatype,int mincount,int maxcount,int flags,const char * glossary)2907 struct arg_rex * arg_rexn(const char * shortopts,
2908 const char * longopts,
2909 const char * pattern,
2910 const char *datatype,
2911 int mincount,
2912 int maxcount,
2913 int flags,
2914 const char *glossary)
2915 {
2916 size_t nbytes;
2917 struct arg_rex *result;
2918 struct privhdr *priv;
2919 int i;
2920 const TRexChar *error = NULL;
2921 TRex *rex = NULL;
2922
2923 if (!pattern)
2924 {
2925 printf(
2926 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2927 printf("argtable: Bad argument table.\n");
2928 return NULL;
2929 }
2930
2931 /* foolproof things by ensuring maxcount is not less than mincount */
2932 maxcount = (maxcount < mincount) ? mincount : maxcount;
2933
2934 nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */
2935 + sizeof(struct privhdr) /* storage for private arg_rex data */
2936 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
2937
2938 result = (struct arg_rex *)malloc(nbytes);
2939 if (result == NULL)
2940 return result;
2941
2942 /* init the arg_hdr struct */
2943 result->hdr.flag = ARG_HASVALUE;
2944 result->hdr.shortopts = shortopts;
2945 result->hdr.longopts = longopts;
2946 result->hdr.datatype = datatype ? datatype : pattern;
2947 result->hdr.glossary = glossary;
2948 result->hdr.mincount = mincount;
2949 result->hdr.maxcount = maxcount;
2950 result->hdr.parent = result;
2951 result->hdr.resetfn = (arg_resetfn *)arg_rex_resetfn;
2952 result->hdr.scanfn = (arg_scanfn *)arg_rex_scanfn;
2953 result->hdr.checkfn = (arg_checkfn *)arg_rex_checkfn;
2954 result->hdr.errorfn = (arg_errorfn *)arg_rex_errorfn;
2955
2956 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2957 result->hdr.priv = result + 1;
2958 priv = (struct privhdr *)(result->hdr.priv);
2959 priv->pattern = pattern;
2960 priv->flags = flags;
2961
2962 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2963 result->sval = (const char * *)(priv + 1);
2964 result->count = 0;
2965
2966 /* foolproof the string pointers by initializing them to reference empty strings */
2967 for (i = 0; i < maxcount; i++)
2968 result->sval[i] = "";
2969
2970 /* here we construct and destroy a regex representation of the regular
2971 * expression for no other reason than to force any regex errors to be
2972 * trapped now rather than later. If we don't, then errors may go undetected
2973 * until an argument is actually parsed.
2974 */
2975
2976 rex = trex_compile(priv->pattern, &error, priv->flags);
2977 if (rex == NULL)
2978 {
2979 ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
2980 ARG_LOG(("argtable: Bad argument table.\n"));
2981 }
2982
2983 trex_free(rex);
2984
2985 ARG_TRACE(("arg_rexn() returns %p\n", result));
2986 return result;
2987 }
2988
2989
2990
2991 /* see copyright notice in trex.h */
2992 #include <string.h>
2993 #include <stdlib.h>
2994 #include <ctype.h>
2995 #include <setjmp.h>
2996
2997 #ifdef _UINCODE
2998 #define scisprint iswprint
2999 #define scstrlen wcslen
3000 #define scprintf wprintf
3001 #define _SC(x) L(x)
3002 #else
3003 #define scisprint isprint
3004 #define scstrlen strlen
3005 #define scprintf printf
3006 #define _SC(x) (x)
3007 #endif
3008
3009 #ifdef _DEBUG
3010 #include <stdio.h>
3011
3012 static const TRexChar *g_nnames[] =
3013 {
3014 _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
3015 _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
3016 _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
3017 _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
3018 };
3019
3020 #endif
3021 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
3022 #define OP_OR (MAX_CHAR+2)
3023 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
3024 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
3025 #define OP_DOT (MAX_CHAR+5)
3026 #define OP_CLASS (MAX_CHAR+6)
3027 #define OP_CCLASS (MAX_CHAR+7)
3028 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
3029 #define OP_RANGE (MAX_CHAR+9)
3030 #define OP_CHAR (MAX_CHAR+10)
3031 #define OP_EOL (MAX_CHAR+11)
3032 #define OP_BOL (MAX_CHAR+12)
3033 #define OP_WB (MAX_CHAR+13)
3034
3035 #define TREX_SYMBOL_ANY_CHAR ('.')
3036 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
3037 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
3038 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
3039 #define TREX_SYMBOL_BRANCH ('|')
3040 #define TREX_SYMBOL_END_OF_STRING ('$')
3041 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
3042 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
3043
3044
3045 typedef int TRexNodeType;
3046
3047 typedef struct tagTRexNode{
3048 TRexNodeType type;
3049 int left;
3050 int right;
3051 int next;
3052 }TRexNode;
3053
3054 struct TRex{
3055 const TRexChar *_eol;
3056 const TRexChar *_bol;
3057 const TRexChar *_p;
3058 int _first;
3059 int _op;
3060 TRexNode *_nodes;
3061 int _nallocated;
3062 int _nsize;
3063 int _nsubexpr;
3064 TRexMatch *_matches;
3065 int _currsubexp;
3066 void *_jmpbuf;
3067 const TRexChar **_error;
3068 int _flags;
3069 };
3070
3071 static int trex_list(TRex *exp);
3072
trex_newnode(TRex * exp,TRexNodeType type)3073 static int trex_newnode(TRex *exp, TRexNodeType type)
3074 {
3075 TRexNode n;
3076 int newid;
3077 n.type = type;
3078 n.next = n.right = n.left = -1;
3079 if(type == OP_EXPR)
3080 n.right = exp->_nsubexpr++;
3081 if(exp->_nallocated < (exp->_nsize + 1)) {
3082 TRexNode *new_nodes = NULL;
3083 exp->_nallocated *= 2;
3084 new_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
3085 if (!new_nodes)
3086 return 0; // return id of _nodes[0] in case of re-allocation failure
3087 exp->_nodes = new_nodes;
3088 }
3089 exp->_nodes[exp->_nsize++] = n;
3090 newid = exp->_nsize - 1;
3091 return (int)newid;
3092 }
3093
trex_error(TRex * exp,const TRexChar * error)3094 static void trex_error(TRex *exp,const TRexChar *error)
3095 {
3096 if(exp->_error) *exp->_error = error;
3097 longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
3098 }
3099
trex_expect(TRex * exp,int n)3100 static void trex_expect(TRex *exp, int n){
3101 if((*exp->_p) != n)
3102 trex_error(exp, _SC("expected paren"));
3103 exp->_p++;
3104 }
3105
trex_escapechar(TRex * exp)3106 static TRexChar trex_escapechar(TRex *exp)
3107 {
3108 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
3109 exp->_p++;
3110 switch(*exp->_p) {
3111 case 'v': exp->_p++; return '\v';
3112 case 'n': exp->_p++; return '\n';
3113 case 't': exp->_p++; return '\t';
3114 case 'r': exp->_p++; return '\r';
3115 case 'f': exp->_p++; return '\f';
3116 default: return (*exp->_p++);
3117 }
3118 } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
3119 return (*exp->_p++);
3120 }
3121
trex_charclass(TRex * exp,int classid)3122 static int trex_charclass(TRex *exp,int classid)
3123 {
3124 int n = trex_newnode(exp,OP_CCLASS);
3125 exp->_nodes[n].left = classid;
3126 return n;
3127 }
3128
trex_charnode(TRex * exp,TRexBool isclass)3129 static int trex_charnode(TRex *exp,TRexBool isclass)
3130 {
3131 TRexChar t;
3132 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
3133 exp->_p++;
3134 switch(*exp->_p) {
3135 case 'n': exp->_p++; return trex_newnode(exp,'\n');
3136 case 't': exp->_p++; return trex_newnode(exp,'\t');
3137 case 'r': exp->_p++; return trex_newnode(exp,'\r');
3138 case 'f': exp->_p++; return trex_newnode(exp,'\f');
3139 case 'v': exp->_p++; return trex_newnode(exp,'\v');
3140 case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
3141 case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
3142 case 'p': case 'P': case 'l': case 'u':
3143 {
3144 t = *exp->_p; exp->_p++;
3145 return trex_charclass(exp,t);
3146 }
3147 case 'b':
3148 case 'B':
3149 if(!isclass) {
3150 int node = trex_newnode(exp,OP_WB);
3151 exp->_nodes[node].left = *exp->_p;
3152 exp->_p++;
3153 return node;
3154 } // fallthrough
3155 //else default
3156 default:
3157 t = *exp->_p; exp->_p++;
3158 return trex_newnode(exp,t);
3159 }
3160 }
3161 else if(!scisprint(*exp->_p)) {
3162
3163 trex_error(exp,_SC("letter expected"));
3164 }
3165 t = *exp->_p; exp->_p++;
3166 return trex_newnode(exp,t);
3167 }
trex_class(TRex * exp)3168 static int trex_class(TRex *exp)
3169 {
3170 int ret = -1;
3171 int first = -1,chain;
3172 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
3173 ret = trex_newnode(exp,OP_NCLASS);
3174 exp->_p++;
3175 }else ret = trex_newnode(exp,OP_CLASS);
3176
3177 if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
3178 chain = ret;
3179 while(*exp->_p != ']' && exp->_p != exp->_eol) {
3180 if(*exp->_p == '-' && first != -1){
3181 int r,t;
3182 if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
3183 r = trex_newnode(exp,OP_RANGE);
3184 if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
3185 if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
3186 exp->_nodes[r].left = exp->_nodes[first].type;
3187 t = trex_escapechar(exp);
3188 exp->_nodes[r].right = t;
3189 exp->_nodes[chain].next = r;
3190 chain = r;
3191 first = -1;
3192 }
3193 else{
3194 if(first!=-1){
3195 int c = first;
3196 exp->_nodes[chain].next = c;
3197 chain = c;
3198 first = trex_charnode(exp,TRex_True);
3199 }
3200 else{
3201 first = trex_charnode(exp,TRex_True);
3202 }
3203 }
3204 }
3205 if(first!=-1){
3206 int c = first;
3207 exp->_nodes[chain].next = c;
3208 chain = c;
3209 first = -1;
3210 }
3211 /* hack? */
3212 exp->_nodes[ret].left = exp->_nodes[ret].next;
3213 exp->_nodes[ret].next = -1;
3214 return ret;
3215 }
3216
trex_parsenumber(TRex * exp)3217 static int trex_parsenumber(TRex *exp)
3218 {
3219 int ret = *exp->_p-'0';
3220 int positions = 10;
3221 exp->_p++;
3222 while(isdigit(*exp->_p)) {
3223 ret = ret*10+(*exp->_p++-'0');
3224 if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
3225 positions *= 10;
3226 };
3227 return ret;
3228 }
3229
trex_element(TRex * exp)3230 static int trex_element(TRex *exp)
3231 {
3232 int ret = -1;
3233 switch(*exp->_p)
3234 {
3235 case '(': {
3236 int expr,newn;
3237 exp->_p++;
3238
3239
3240 if(*exp->_p =='?') {
3241 exp->_p++;
3242 trex_expect(exp,':');
3243 expr = trex_newnode(exp,OP_NOCAPEXPR);
3244 }
3245 else
3246 expr = trex_newnode(exp,OP_EXPR);
3247 newn = trex_list(exp);
3248 exp->_nodes[expr].left = newn;
3249 ret = expr;
3250 trex_expect(exp,')');
3251 }
3252 break;
3253 case '[':
3254 exp->_p++;
3255 ret = trex_class(exp);
3256 trex_expect(exp,']');
3257 break;
3258 case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
3259 case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
3260 default:
3261 ret = trex_charnode(exp,TRex_False);
3262 break;
3263 }
3264
3265 {
3266 TRexBool isgreedy = TRex_False;
3267 unsigned short p0 = 0, p1 = 0;
3268 switch(*exp->_p){
3269 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3270 case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3271 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
3272 case '{':
3273 exp->_p++;
3274 if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
3275 p0 = (unsigned short)trex_parsenumber(exp);
3276 /*******************************/
3277 switch(*exp->_p) {
3278 case '}':
3279 p1 = p0; exp->_p++;
3280 break;
3281 case ',':
3282 exp->_p++;
3283 p1 = 0xFFFF;
3284 if(isdigit(*exp->_p)){
3285 p1 = (unsigned short)trex_parsenumber(exp);
3286 }
3287 trex_expect(exp,'}');
3288 break;
3289 default:
3290 trex_error(exp,_SC(", or } expected"));
3291 }
3292 /*******************************/
3293 isgreedy = TRex_True;
3294 break;
3295
3296 }
3297 if(isgreedy) {
3298 int nnode = trex_newnode(exp,OP_GREEDY);
3299 exp->_nodes[nnode].left = ret;
3300 exp->_nodes[nnode].right = ((p0)<<16)|p1;
3301 ret = nnode;
3302 }
3303 }
3304 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')) {
3305 int nnode = trex_element(exp);
3306 exp->_nodes[ret].next = nnode;
3307 }
3308
3309 return ret;
3310 }
3311
trex_list(TRex * exp)3312 static int trex_list(TRex *exp)
3313 {
3314 int ret=-1,e;
3315 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
3316 exp->_p++;
3317 ret = trex_newnode(exp,OP_BOL);
3318 }
3319 e = trex_element(exp);
3320 if(ret != -1) {
3321 exp->_nodes[ret].next = e;
3322 }
3323 else ret = e;
3324
3325 if(*exp->_p == TREX_SYMBOL_BRANCH) {
3326 int temp,tright;
3327 exp->_p++;
3328 temp = trex_newnode(exp,OP_OR);
3329 exp->_nodes[temp].left = ret;
3330 tright = trex_list(exp);
3331 exp->_nodes[temp].right = tright;
3332 ret = temp;
3333 }
3334 return ret;
3335 }
3336
trex_matchcclass(int cclass,TRexChar c)3337 static TRexBool trex_matchcclass(int cclass,TRexChar c)
3338 {
3339 switch(cclass) {
3340 case 'a': return isalpha(c)?TRex_True:TRex_False;
3341 case 'A': return !isalpha(c)?TRex_True:TRex_False;
3342 case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
3343 case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
3344 case 's': return ISSPACE(c)?TRex_True:TRex_False;
3345 case 'S': return !ISSPACE(c)?TRex_True:TRex_False;
3346 case 'd': return isdigit(c)?TRex_True:TRex_False;
3347 case 'D': return !isdigit(c)?TRex_True:TRex_False;
3348 case 'x': return isxdigit(c)?TRex_True:TRex_False;
3349 case 'X': return !isxdigit(c)?TRex_True:TRex_False;
3350 case 'c': return iscntrl(c)?TRex_True:TRex_False;
3351 case 'C': return !iscntrl(c)?TRex_True:TRex_False;
3352 case 'p': return ispunct(c)?TRex_True:TRex_False;
3353 case 'P': return !ispunct(c)?TRex_True:TRex_False;
3354 case 'l': return islower(c)?TRex_True:TRex_False;
3355 case 'u': return isupper(c)?TRex_True:TRex_False;
3356 }
3357 return TRex_False; /*cannot happen*/
3358 }
3359
3360 #ifdef _MSC_VER
3361 #pragma warning( push )
3362 #pragma warning( disable : 4706 )
3363 #endif
3364
trex_matchclass(TRex * exp,TRexNode * node,TRexChar c)3365 static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
3366 {
3367 do {
3368 switch(node->type) {
3369 case OP_RANGE:
3370 if (exp->_flags & TREX_ICASE)
3371 {
3372 if(c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True;
3373 if(c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True;
3374 }
3375 else
3376 {
3377 if(c >= node->left && c <= node->right) return TRex_True;
3378 }
3379 break;
3380 case OP_CCLASS:
3381 if(trex_matchcclass(node->left,c)) return TRex_True;
3382 break;
3383 default:
3384 if (exp->_flags & TREX_ICASE)
3385 {
3386 if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;
3387 }
3388 else
3389 {
3390 if(c == node->type)return TRex_True;
3391 }
3392
3393 }
3394 } while((node->next != -1) && (node = &exp->_nodes[node->next]));
3395 return TRex_False;
3396 }
3397
trex_matchnode(TRex * exp,TRexNode * node,const TRexChar * str,TRexNode * next)3398 static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
3399 {
3400
3401 TRexNodeType type = node->type;
3402 switch(type) {
3403 case OP_GREEDY: {
3404 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3405 TRexNode *greedystop = NULL;
3406 int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
3407 const TRexChar *s=str, *good = str;
3408
3409 if(node->next != -1) {
3410 greedystop = &exp->_nodes[node->next];
3411 }
3412 else {
3413 greedystop = next;
3414 }
3415
3416 while((nmaches == 0xFFFF || nmaches < p1)) {
3417
3418 const TRexChar *stop;
3419 if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
3420 break;
3421 nmaches++;
3422 good=s;
3423 if(greedystop) {
3424 //checks that 0 matches satisfy the expression(if so skips)
3425 //if not would always stop(for instance if is a '?')
3426 if(greedystop->type != OP_GREEDY ||
3427 (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
3428 {
3429 TRexNode *gnext = NULL;
3430 if(greedystop->next != -1) {
3431 gnext = &exp->_nodes[greedystop->next];
3432 }else if(next && next->next != -1){
3433 gnext = &exp->_nodes[next->next];
3434 }
3435 stop = trex_matchnode(exp,greedystop,s,gnext);
3436 if(stop) {
3437 //if satisfied stop it
3438 if(p0 == p1 && p0 == nmaches) break;
3439 else if(nmaches >= p0 && p1 == 0xFFFF) break;
3440 else if(nmaches >= p0 && nmaches <= p1) break;
3441 }
3442 }
3443 }
3444
3445 if(s >= exp->_eol)
3446 break;
3447 }
3448 if(p0 == p1 && p0 == nmaches) return good;
3449 else if(nmaches >= p0 && p1 == 0xFFFF) return good;
3450 else if(nmaches >= p0 && nmaches <= p1) return good;
3451 return NULL;
3452 }
3453 case OP_OR: {
3454 const TRexChar *asd = str;
3455 TRexNode *temp=&exp->_nodes[node->left];
3456 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3457 if(temp->next != -1)
3458 temp = &exp->_nodes[temp->next];
3459 else
3460 return asd;
3461 }
3462 asd = str;
3463 temp = &exp->_nodes[node->right];
3464 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3465 if(temp->next != -1)
3466 temp = &exp->_nodes[temp->next];
3467 else
3468 return asd;
3469 }
3470 return NULL;
3471 break;
3472 }
3473 case OP_EXPR:
3474 case OP_NOCAPEXPR:{
3475 TRexNode *n = &exp->_nodes[node->left];
3476 const TRexChar *cur = str;
3477 int capture = -1;
3478 if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
3479 capture = exp->_currsubexp;
3480 exp->_matches[capture].begin = cur;
3481 exp->_currsubexp++;
3482 }
3483
3484 do {
3485 TRexNode *subnext = NULL;
3486 if(n->next != -1) {
3487 subnext = &exp->_nodes[n->next];
3488 }else {
3489 subnext = next;
3490 }
3491 if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
3492 if(capture != -1){
3493 exp->_matches[capture].begin = 0;
3494 exp->_matches[capture].len = 0;
3495 }
3496 return NULL;
3497 }
3498 } while((n->next != -1) && (n = &exp->_nodes[n->next]));
3499
3500 if(capture != -1)
3501 exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin);
3502 return cur;
3503 }
3504 case OP_WB:
3505 if((str == exp->_bol && !ISSPACE(*str))
3506 || ((str == exp->_eol && !ISSPACE(*(str-1))))
3507 || ((!ISSPACE(*str) && ISSPACE(*(str+1))))
3508 || ((ISSPACE(*str) && !ISSPACE(*(str+1)))) ) {
3509 return (node->left == 'b')?str:NULL;
3510 }
3511 return (node->left == 'b')?NULL:str;
3512 case OP_BOL:
3513 if(str == exp->_bol) return str;
3514 return NULL;
3515 case OP_EOL:
3516 if(str == exp->_eol) return str;
3517 return NULL;
3518 case OP_DOT:
3519 str++;
3520 return str;
3521 case OP_NCLASS:
3522 case OP_CLASS:
3523 if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
3524 str++;
3525 return str;
3526 }
3527 return NULL;
3528 case OP_CCLASS:
3529 if(trex_matchcclass(node->left,*str)) {
3530 str++;
3531 return str;
3532 }
3533 return NULL;
3534 default: /* char */
3535 if (exp->_flags & TREX_ICASE)
3536 {
3537 if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL;
3538 }
3539 else
3540 {
3541 if (*str != node->type) return NULL;
3542 }
3543 str++;
3544 return str;
3545 }
3546 }
3547 #ifdef _MSC_VER
3548 #pragma warning( pop )
3549 #endif
3550
3551 /* public api */
trex_compile(const TRexChar * pattern,const TRexChar ** error,int flags)3552 TRex *trex_compile(const TRexChar *pattern,const TRexChar **error,int flags)
3553 {
3554 // allocated data is volatile, its safe to setjmp
3555 TRex * volatile exp = NULL;
3556 do {
3557 exp = (TRex *)malloc(sizeof(TRex));
3558 if (!exp) break;
3559 memset((void*)exp, 0, sizeof(TRex));
3560
3561 exp->_eol = exp->_bol = NULL;
3562 exp->_p = pattern;
3563 exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
3564 exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
3565 if (!exp->_nodes) break;
3566 exp->_nsize = 0;
3567 exp->_matches = 0;
3568 exp->_nsubexpr = 0;
3569 exp->_first = trex_newnode((TRex*)exp,OP_EXPR);
3570 exp->_error = error;
3571 exp->_jmpbuf = malloc(sizeof(jmp_buf));
3572 if (!exp->_jmpbuf) break;
3573 exp->_flags = flags;
3574 if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
3575 int res = trex_list((TRex*)exp);
3576 exp->_nodes[exp->_first].left = res;
3577 if(*exp->_p!='\0')
3578 trex_error((TRex*)exp,_SC("unexpected character"));
3579 #ifdef _DEBUG
3580 {
3581 int nsize,i;
3582 TRexNode *t;
3583 nsize = exp->_nsize;
3584 t = &exp->_nodes[0];
3585 scprintf(_SC("\n"));
3586 for(i = 0;i < nsize; i++) {
3587 if(exp->_nodes[i].type>MAX_CHAR)
3588 scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
3589 else
3590 scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
3591 scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
3592 }
3593 scprintf(_SC("\n"));
3594 }
3595 #endif
3596 exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
3597 if (!exp->_matches) break;
3598 memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
3599 }
3600 else {
3601 break;
3602 }
3603 return (TRex*)exp;
3604 } while (0);
3605
3606 trex_free((TRex*)exp);
3607 return NULL;
3608 }
3609
trex_free(TRex * exp)3610 void trex_free(TRex *exp)
3611 {
3612 if(exp) {
3613 if(exp->_nodes) free(exp->_nodes);
3614 if(exp->_jmpbuf) free(exp->_jmpbuf);
3615 if(exp->_matches) free(exp->_matches);
3616 free(exp);
3617 }
3618 }
3619
trex_match(TRex * exp,const TRexChar * text)3620 TRexBool trex_match(TRex* exp,const TRexChar* text)
3621 {
3622 const TRexChar* res = NULL;
3623 exp->_bol = text;
3624 exp->_eol = text + scstrlen(text);
3625 exp->_currsubexp = 0;
3626 res = trex_matchnode(exp,exp->_nodes,text,NULL);
3627 if(res == NULL || res != exp->_eol)
3628 return TRex_False;
3629 return TRex_True;
3630 }
3631
trex_searchrange(TRex * exp,const TRexChar * text_begin,const TRexChar * text_end,const TRexChar ** out_begin,const TRexChar ** out_end)3632 TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
3633 {
3634 const TRexChar *cur = NULL;
3635 int node = exp->_first;
3636 if(text_begin >= text_end) return TRex_False;
3637 exp->_bol = text_begin;
3638 exp->_eol = text_end;
3639 do {
3640 cur = text_begin;
3641 while(node != -1) {
3642 exp->_currsubexp = 0;
3643 cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
3644 if(!cur)
3645 break;
3646 node = exp->_nodes[node].next;
3647 }
3648 text_begin++;
3649 } while(cur == NULL && text_begin != text_end);
3650
3651 if(cur == NULL)
3652 return TRex_False;
3653
3654 --text_begin;
3655
3656 if(out_begin) *out_begin = text_begin;
3657 if(out_end) *out_end = cur;
3658 return TRex_True;
3659 }
3660
trex_search(TRex * exp,const TRexChar * text,const TRexChar ** out_begin,const TRexChar ** out_end)3661 TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
3662 {
3663 return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
3664 }
3665
trex_getsubexpcount(TRex * exp)3666 int trex_getsubexpcount(TRex* exp)
3667 {
3668 return exp->_nsubexpr;
3669 }
3670
trex_getsubexp(TRex * exp,int n,TRexMatch * subexp)3671 TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
3672 {
3673 if( n<0 || n >= exp->_nsubexpr) return TRex_False;
3674 *subexp = exp->_matches[n];
3675 return TRex_True;
3676 }
3677 /*******************************************************************************
3678 * This file is part of the argtable3 library.
3679 *
3680 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3681 * <sheitmann@users.sourceforge.net>
3682 * All rights reserved.
3683 *
3684 * Redistribution and use in source and binary forms, with or without
3685 * modification, are permitted provided that the following conditions are met:
3686 * * Redistributions of source code must retain the above copyright
3687 * notice, this list of conditions and the following disclaimer.
3688 * * Redistributions in binary form must reproduce the above copyright
3689 * notice, this list of conditions and the following disclaimer in the
3690 * documentation and/or other materials provided with the distribution.
3691 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3692 * may be used to endorse or promote products derived from this software
3693 * without specific prior written permission.
3694 *
3695 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3696 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3697 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3698 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3699 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3700 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3701 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3702 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3703 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3704 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3705 ******************************************************************************/
3706
3707 #include <stdlib.h>
3708
3709 #include "argtable3.h"
3710
3711
arg_str_resetfn(struct arg_str * parent)3712 static void arg_str_resetfn(struct arg_str *parent)
3713 {
3714 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
3715 parent->count = 0;
3716 }
3717
3718
arg_str_scanfn(struct arg_str * parent,const char * argval)3719 static int arg_str_scanfn(struct arg_str *parent, const char *argval)
3720 {
3721 int errorcode = 0;
3722
3723 if (parent->count == parent->hdr.maxcount)
3724 {
3725 /* maximum number of arguments exceeded */
3726 errorcode = EMAXCOUNT;
3727 }
3728 else if (!argval)
3729 {
3730 /* a valid argument with no argument value was given. */
3731 /* This happens when an optional argument value was invoked. */
3732 /* leave parent arguiment value unaltered but still count the argument. */
3733 parent->count++;
3734 }
3735 else
3736 {
3737 parent->sval[parent->count++] = argval;
3738 }
3739
3740 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
3741 return errorcode;
3742 }
3743
3744
arg_str_checkfn(struct arg_str * parent)3745 static int arg_str_checkfn(struct arg_str *parent)
3746 {
3747 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
3748
3749 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
3750 return errorcode;
3751 }
3752
3753
arg_str_errorfn(struct arg_str * parent,FILE * fp,int errorcode,const char * argval,const char * progname)3754 static void arg_str_errorfn(
3755 struct arg_str *parent,
3756 FILE *fp,
3757 int errorcode,
3758 const char *argval,
3759 const char *progname)
3760 {
3761 const char *shortopts = parent->hdr.shortopts;
3762 const char *longopts = parent->hdr.longopts;
3763 const char *datatype = parent->hdr.datatype;
3764
3765 /* make argval NULL safe */
3766 argval = argval ? argval : "";
3767
3768 fprintf(fp, "%s: ", progname);
3769 switch(errorcode)
3770 {
3771 case EMINCOUNT:
3772 fputs("missing option ", fp);
3773 arg_print_option(fp, shortopts, longopts, datatype, "\n");
3774 break;
3775
3776 case EMAXCOUNT:
3777 fputs("excess option ", fp);
3778 arg_print_option(fp, shortopts, longopts, argval, "\n");
3779 break;
3780 }
3781 }
3782
3783
arg_str0(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)3784 struct arg_str * arg_str0(
3785 const char *shortopts,
3786 const char *longopts,
3787 const char *datatype,
3788 const char *glossary)
3789 {
3790 return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
3791 }
3792
3793
arg_str1(const char * shortopts,const char * longopts,const char * datatype,const char * glossary)3794 struct arg_str * arg_str1(
3795 const char *shortopts,
3796 const char *longopts,
3797 const char *datatype,
3798 const char *glossary)
3799 {
3800 return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
3801 }
3802
3803
arg_strn(const char * shortopts,const char * longopts,const char * datatype,int mincount,int maxcount,const char * glossary)3804 struct arg_str * arg_strn(
3805 const char *shortopts,
3806 const char *longopts,
3807 const char *datatype,
3808 int mincount,
3809 int maxcount,
3810 const char *glossary)
3811 {
3812 size_t nbytes;
3813 struct arg_str *result;
3814
3815 /* should not allow this stupid error */
3816 /* we should return an error code warning this logic error */
3817 /* foolproof things by ensuring maxcount is not less than mincount */
3818 maxcount = (maxcount < mincount) ? mincount : maxcount;
3819
3820 nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
3821 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
3822
3823 result = (struct arg_str *)malloc(nbytes);
3824 if (result)
3825 {
3826 int i;
3827
3828 /* init the arg_hdr struct */
3829 result->hdr.flag = ARG_HASVALUE;
3830 result->hdr.shortopts = shortopts;
3831 result->hdr.longopts = longopts;
3832 result->hdr.datatype = datatype ? datatype : "<string>";
3833 result->hdr.glossary = glossary;
3834 result->hdr.mincount = mincount;
3835 result->hdr.maxcount = maxcount;
3836 result->hdr.parent = result;
3837 result->hdr.resetfn = (arg_resetfn *)arg_str_resetfn;
3838 result->hdr.scanfn = (arg_scanfn *)arg_str_scanfn;
3839 result->hdr.checkfn = (arg_checkfn *)arg_str_checkfn;
3840 result->hdr.errorfn = (arg_errorfn *)arg_str_errorfn;
3841
3842 /* store the sval[maxcount] array immediately after the arg_str struct */
3843 result->sval = (const char * *)(result + 1);
3844 result->count = 0;
3845
3846 /* foolproof the string pointers by initialising them to reference empty strings */
3847 for (i = 0; i < maxcount; i++)
3848 result->sval[i] = "";
3849 }
3850
3851 ARG_TRACE(("arg_strn() returns %p\n", result));
3852 return result;
3853 }
3854 /*******************************************************************************
3855 * This file is part of the argtable3 library.
3856 *
3857 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3858 * <sheitmann@users.sourceforge.net>
3859 * All rights reserved.
3860 *
3861 * Redistribution and use in source and binary forms, with or without
3862 * modification, are permitted provided that the following conditions are met:
3863 * * Redistributions of source code must retain the above copyright
3864 * notice, this list of conditions and the following disclaimer.
3865 * * Redistributions in binary form must reproduce the above copyright
3866 * notice, this list of conditions and the following disclaimer in the
3867 * documentation and/or other materials provided with the distribution.
3868 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3869 * may be used to endorse or promote products derived from this software
3870 * without specific prior written permission.
3871 *
3872 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3873 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3874 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3875 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3876 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3877 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3878 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3879 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3880 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3881 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3882 ******************************************************************************/
3883
3884 #include <stdlib.h>
3885 #include <string.h>
3886 #include <stdlib.h>
3887 #include <ctype.h>
3888
3889 #include "argtable3.h"
3890
3891 static
arg_register_error(struct arg_end * end,void * parent,int error,const char * argval)3892 void arg_register_error(struct arg_end *end,
3893 void *parent,
3894 int error,
3895 const char *argval)
3896 {
3897 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3898 if (end->count < end->hdr.maxcount)
3899 {
3900 end->error[end->count] = error;
3901 end->parent[end->count] = parent;
3902 end->argval[end->count] = argval;
3903 end->count++;
3904 }
3905 else
3906 {
3907 end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;
3908 end->parent[end->hdr.maxcount - 1] = end;
3909 end->argval[end->hdr.maxcount - 1] = NULL;
3910 }
3911 }
3912
3913
3914 /*
3915 * Return index of first table entry with a matching short option
3916 * or -1 if no match was found.
3917 */
3918 static
find_shortoption(struct arg_hdr ** table,char shortopt)3919 int find_shortoption(struct arg_hdr * *table, char shortopt)
3920 {
3921 int tabindex;
3922 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3923 {
3924 if (table[tabindex]->shortopts &&
3925 strchr(table[tabindex]->shortopts, shortopt))
3926 return tabindex;
3927 }
3928 return -1;
3929 }
3930
3931
3932 struct longoptions
3933 {
3934 int getoptval;
3935 int noptions;
3936 struct option *options;
3937 };
3938
3939 #if 0
3940 static
3941 void dump_longoptions(struct longoptions * longoptions)
3942 {
3943 int i;
3944 printf("getoptval = %d\n", longoptions->getoptval);
3945 printf("noptions = %d\n", longoptions->noptions);
3946 for (i = 0; i < longoptions->noptions; i++)
3947 {
3948 printf("options[%d].name = \"%s\"\n",
3949 i,
3950 longoptions->options[i].name);
3951 printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);
3952 printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);
3953 printf("options[%d].val = %d\n", i, longoptions->options[i].val);
3954 }
3955 }
3956 #endif
3957
3958 static
alloc_longoptions(struct arg_hdr ** table)3959 struct longoptions * alloc_longoptions(struct arg_hdr * *table)
3960 {
3961 struct longoptions *result;
3962 size_t nbytes;
3963 int noptions = 1;
3964 size_t longoptlen = 0;
3965 int tabindex;
3966
3967 /*
3968 * Determine the total number of option structs required
3969 * by counting the number of comma separated long options
3970 * in all table entries and return the count in noptions.
3971 * note: noptions starts at 1 not 0 because we getoptlong
3972 * requires a NULL option entry to terminate the option array.
3973 * While we are at it, count the number of chars required
3974 * to store private copies of all the longoption strings
3975 * and return that count in logoptlen.
3976 */
3977 tabindex = 0;
3978 do
3979 {
3980 const char *longopts = table[tabindex]->longopts;
3981 longoptlen += (longopts ? strlen(longopts) : 0) + 1;
3982 while (longopts)
3983 {
3984 noptions++;
3985 longopts = strchr(longopts + 1, ',');
3986 }
3987 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
3988 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3989
3990
3991 /* allocate storage for return data structure as: */
3992 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3993 nbytes = sizeof(struct longoptions)
3994 + sizeof(struct option) * noptions
3995 + longoptlen;
3996 result = (struct longoptions *)malloc(nbytes);
3997 if (result)
3998 {
3999 int option_index = 0;
4000 char *store;
4001
4002 result->getoptval = 0;
4003 result->noptions = noptions;
4004 result->options = (struct option *)(result + 1);
4005 store = (char *)(result->options + noptions);
4006
4007 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4008 {
4009 const char *longopts = table[tabindex]->longopts;
4010
4011 while(longopts && *longopts)
4012 {
4013 char *storestart = store;
4014
4015 /* copy progressive longopt strings into the store */
4016 while (*longopts != 0 && *longopts != ',')
4017 *store++ = *longopts++;
4018 *store++ = 0;
4019 if (*longopts == ',')
4020 longopts++;
4021 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
4022
4023 result->options[option_index].name = storestart;
4024 result->options[option_index].flag = &(result->getoptval);
4025 result->options[option_index].val = tabindex;
4026 if (table[tabindex]->flag & ARG_HASOPTVALUE)
4027 result->options[option_index].has_arg = 2;
4028 else if (table[tabindex]->flag & ARG_HASVALUE)
4029 result->options[option_index].has_arg = 1;
4030 else
4031 result->options[option_index].has_arg = 0;
4032
4033 option_index++;
4034 }
4035 }
4036 /* terminate the options array with a zero-filled entry */
4037 result->options[option_index].name = 0;
4038 result->options[option_index].has_arg = 0;
4039 result->options[option_index].flag = 0;
4040 result->options[option_index].val = 0;
4041 }
4042
4043 /*dump_longoptions(result);*/
4044 return result;
4045 }
4046
4047 static
alloc_shortoptions(struct arg_hdr ** table)4048 char * alloc_shortoptions(struct arg_hdr * *table)
4049 {
4050 char *result;
4051 size_t len = 2;
4052 int tabindex;
4053
4054 /* determine the total number of option chars required */
4055 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4056 {
4057 struct arg_hdr *hdr = table[tabindex];
4058 len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);
4059 }
4060
4061 result = malloc(len);
4062 if (result)
4063 {
4064 char *res = result;
4065
4066 /* add a leading ':' so getopt return codes distinguish */
4067 /* unrecognised option and options missing argument values */
4068 *res++ = ':';
4069
4070 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4071 {
4072 struct arg_hdr *hdr = table[tabindex];
4073 const char *shortopts = hdr->shortopts;
4074 while(shortopts && *shortopts)
4075 {
4076 *res++ = *shortopts++;
4077 if (hdr->flag & ARG_HASVALUE)
4078 *res++ = ':';
4079 if (hdr->flag & ARG_HASOPTVALUE)
4080 *res++ = ':';
4081 }
4082 }
4083 /* null terminate the string */
4084 *res = 0;
4085 }
4086
4087 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
4088 return result;
4089 }
4090
4091
4092 /* return index of the table terminator entry */
4093 static
arg_endindex(struct arg_hdr ** table)4094 int arg_endindex(struct arg_hdr * *table)
4095 {
4096 int tabindex = 0;
4097 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4098 tabindex++;
4099 return tabindex;
4100 }
4101
4102
4103 static
arg_parse_tagged(int argc,char ** argv,struct arg_hdr ** table,struct arg_end * endtable)4104 void arg_parse_tagged(int argc,
4105 char * *argv,
4106 struct arg_hdr * *table,
4107 struct arg_end *endtable)
4108 {
4109 struct longoptions *longoptions;
4110 char *shortoptions;
4111 int copt;
4112
4113 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4114
4115 /* allocate short and long option arrays for the given opttable[]. */
4116 /* if the allocs fail then put an error msg in the last table entry. */
4117 longoptions = alloc_longoptions(table);
4118 shortoptions = alloc_shortoptions(table);
4119 if (!longoptions || !shortoptions)
4120 {
4121 /* one or both memory allocs failed */
4122 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4123 /* free anything that was allocated (this is null safe) */
4124 free(shortoptions);
4125 free(longoptions);
4126 return;
4127 }
4128
4129 /*dump_longoptions(longoptions);*/
4130
4131 /* reset getopts internal option-index to zero, and disable error reporting */
4132 optind = 0;
4133 opterr = 0;
4134
4135 /* fetch and process args using getopt_long */
4136 while( (copt =
4137 getopt_long(argc, argv, shortoptions, longoptions->options,
4138 NULL)) != -1)
4139 {
4140 /*
4141 printf("optarg='%s'\n",optarg);
4142 printf("optind=%d\n",optind);
4143 printf("copt=%c\n",(char)copt);
4144 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
4145 */
4146 switch(copt)
4147 {
4148 case 0:
4149 {
4150 int tabindex = longoptions->getoptval;
4151 void *parent = table[tabindex]->parent;
4152 /*printf("long option detected from argtable[%d]\n", tabindex);*/
4153 if (optarg && optarg[0] == 0 &&
4154 (table[tabindex]->flag & ARG_HASVALUE))
4155 {
4156 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
4157 arg_register_error(endtable, endtable, ARG_EMISSARG,
4158 argv[optind - 1]);
4159 /* continue to scan the (empty) argument value to enforce argument count checking */
4160 }
4161 if (table[tabindex]->scanfn)
4162 {
4163 int errorcode = table[tabindex]->scanfn(parent, optarg);
4164 if (errorcode != 0)
4165 arg_register_error(endtable, parent, errorcode, optarg);
4166 }
4167 }
4168 break;
4169
4170 case '?':
4171 /*
4172 * getopt_long() found an unrecognised short option.
4173 * if it was a short option its value is in optopt
4174 * if it was a long option then optopt=0
4175 */
4176 switch (optopt)
4177 {
4178 case 0:
4179 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4180 arg_register_error(endtable, endtable, ARG_ELONGOPT,
4181 argv[optind - 1]);
4182 break;
4183 default:
4184 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4185 arg_register_error(endtable, endtable, optopt, NULL);
4186 break;
4187 }
4188 break;
4189
4190 case ':':
4191 /*
4192 * getopt_long() found an option with its argument missing.
4193 */
4194 /*printf(": option %s requires an argument\n",argv[optind-1]); */
4195 arg_register_error(endtable, endtable, ARG_EMISSARG,
4196 argv[optind - 1]);
4197 break;
4198
4199 default:
4200 {
4201 /* getopt_long() found a valid short option */
4202 int tabindex = find_shortoption(table, (char)copt);
4203 /*printf("short option detected from argtable[%d]\n", tabindex);*/
4204 if (tabindex == -1)
4205 {
4206 /* should never get here - but handle it just in case */
4207 /*printf("unrecognised short option %d\n",copt);*/
4208 arg_register_error(endtable, endtable, copt, NULL);
4209 }
4210 else
4211 {
4212 if (table[tabindex]->scanfn)
4213 {
4214 void *parent = table[tabindex]->parent;
4215 int errorcode = table[tabindex]->scanfn(parent, optarg);
4216 if (errorcode != 0)
4217 arg_register_error(endtable, parent, errorcode, optarg);
4218 }
4219 }
4220 break;
4221 }
4222 }
4223 }
4224
4225 free(shortoptions);
4226 free(longoptions);
4227 }
4228
4229
4230 static
arg_parse_untagged(int argc,char ** argv,struct arg_hdr ** table,struct arg_end * endtable)4231 void arg_parse_untagged(int argc,
4232 char * *argv,
4233 struct arg_hdr * *table,
4234 struct arg_end *endtable)
4235 {
4236 int tabindex = 0;
4237 int errorlast = 0;
4238 const char *optarglast = NULL;
4239 void *parentlast = NULL;
4240
4241 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4242 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4243 {
4244 void *parent;
4245 int errorcode;
4246
4247 /* if we have exhausted our argv[optind] entries then we have finished */
4248 if (optind >= argc)
4249 {
4250 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4251 return;
4252 }
4253
4254 /* skip table entries with non-null long or short options (they are not untagged entries) */
4255 if (table[tabindex]->longopts || table[tabindex]->shortopts)
4256 {
4257 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
4258 tabindex++;
4259 continue;
4260 }
4261
4262 /* skip table entries with NULL scanfn */
4263 if (!(table[tabindex]->scanfn))
4264 {
4265 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4266 tabindex++;
4267 continue;
4268 }
4269
4270 /* attempt to scan the current argv[optind] with the current */
4271 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
4272 /* try again with the next table[] entry. */
4273 parent = table[tabindex]->parent;
4274 errorcode = table[tabindex]->scanfn(parent, argv[optind]);
4275 if (errorcode == 0)
4276 {
4277 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4278 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4279 optind++;
4280
4281 /* clear the last tentative error */
4282 errorlast = 0;
4283 }
4284 else
4285 {
4286 /* failure, try same argv[optind] with next table[tabindex] entry */
4287 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4288 tabindex++;
4289
4290 /* remember this as a tentative error we may wish to reinstate later */
4291 errorlast = errorcode;
4292 optarglast = argv[optind];
4293 parentlast = parent;
4294 }
4295
4296 }
4297
4298 /* if a tenative error still remains at this point then register it as a proper error */
4299 if (errorlast)
4300 {
4301 arg_register_error(endtable, parentlast, errorlast, optarglast);
4302 optind++;
4303 }
4304
4305 /* only get here when not all argv[] entries were consumed */
4306 /* register an error for each unused argv[] entry */
4307 while (optind < argc)
4308 {
4309 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4310 arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
4311 }
4312
4313 return;
4314 }
4315
4316
4317 static
arg_parse_check(struct arg_hdr ** table,struct arg_end * endtable)4318 void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable)
4319 {
4320 int tabindex = 0;
4321 /* printf("arg_parse_check()\n"); */
4322 do
4323 {
4324 if (table[tabindex]->checkfn)
4325 {
4326 void *parent = table[tabindex]->parent;
4327 int errorcode = table[tabindex]->checkfn(parent);
4328 if (errorcode != 0)
4329 arg_register_error(endtable, parent, errorcode, NULL);
4330 }
4331 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4332 }
4333
4334
4335 static
arg_reset(void ** argtable)4336 void arg_reset(void * *argtable)
4337 {
4338 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4339 int tabindex = 0;
4340 /*printf("arg_reset(%p)\n",argtable);*/
4341 do
4342 {
4343 if (table[tabindex]->resetfn)
4344 table[tabindex]->resetfn(table[tabindex]->parent);
4345 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4346 }
4347
4348
arg_parse(int argc,char ** argv,void ** argtable)4349 int arg_parse(int argc, char * *argv, void * *argtable)
4350 {
4351 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4352 struct arg_end *endtable;
4353 int endindex;
4354 char * *argvcopy = NULL;
4355
4356 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4357
4358 /* reset any argtable data from previous invocations */
4359 arg_reset(argtable);
4360
4361 /* locate the first end-of-table marker within the array */
4362 endindex = arg_endindex(table);
4363 endtable = (struct arg_end *)table[endindex];
4364
4365 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4366 /* Failure to trap this case results in an unwanted NULL result from */
4367 /* the malloc for argvcopy (next code block). */
4368 if (argc == 0)
4369 {
4370 /* We must still perform post-parse checks despite the absence of command line arguments */
4371 arg_parse_check(table, endtable);
4372
4373 /* Now we are finished */
4374 return endtable->count;
4375 }
4376
4377 argvcopy = (char **)malloc(sizeof(char *) * (argc + 1));
4378 if (argvcopy)
4379 {
4380 int i;
4381
4382 /*
4383 Fill in the local copy of argv[]. We need a local copy
4384 because getopt rearranges argv[] which adversely affects
4385 susbsequent parsing attempts.
4386 */
4387 for (i = 0; i < argc; i++)
4388 argvcopy[i] = argv[i];
4389
4390 argvcopy[argc] = NULL;
4391
4392 /* parse the command line (local copy) for tagged options */
4393 arg_parse_tagged(argc, argvcopy, table, endtable);
4394
4395 /* parse the command line (local copy) for untagged options */
4396 arg_parse_untagged(argc, argvcopy, table, endtable);
4397
4398 /* if no errors so far then perform post-parse checks otherwise dont bother */
4399 if (endtable->count == 0)
4400 arg_parse_check(table, endtable);
4401
4402 /* release the local copt of argv[] */
4403 free(argvcopy);
4404 }
4405 else
4406 {
4407 /* memory alloc failed */
4408 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4409 }
4410
4411 return endtable->count;
4412 }
4413
4414
4415 /*
4416 * Concatenate contents of src[] string onto *pdest[] string.
4417 * The *pdest pointer is altered to point to the end of the
4418 * target string and *pndest is decremented by the same number
4419 * of chars.
4420 * Does not append more than *pndest chars into *pdest[]
4421 * so as to prevent buffer overruns.
4422 * Its something like strncat() but more efficient for repeated
4423 * calls on the same destination string.
4424 * Example of use:
4425 * char dest[30] = "good"
4426 * size_t ndest = sizeof(dest);
4427 * char *pdest = dest;
4428 * arg_char(&pdest,"bye ",&ndest);
4429 * arg_char(&pdest,"cruel ",&ndest);
4430 * arg_char(&pdest,"world!",&ndest);
4431 * Results in:
4432 * dest[] == "goodbye cruel world!"
4433 * ndest == 10
4434 */
4435 static
arg_cat(char ** pdest,const char * src,size_t * pndest)4436 void arg_cat(char * *pdest, const char *src, size_t *pndest)
4437 {
4438 char *dest = *pdest;
4439 char *end = dest + *pndest;
4440
4441 /*locate null terminator of dest string */
4442 while(dest < end && *dest != 0)
4443 dest++;
4444
4445 /* concat src string to dest string */
4446 while(dest < end && *src != 0)
4447 *dest++ = *src++;
4448
4449 /* null terminate dest string */
4450 *dest = 0;
4451
4452 /* update *pdest and *pndest */
4453 *pndest = end - dest;
4454 *pdest = dest;
4455 }
4456
4457
4458 static
arg_cat_option(char * dest,size_t ndest,const char * shortopts,const char * longopts,const char * datatype,int optvalue)4459 void arg_cat_option(char *dest,
4460 size_t ndest,
4461 const char *shortopts,
4462 const char *longopts,
4463 const char *datatype,
4464 int optvalue)
4465 {
4466 if (shortopts)
4467 {
4468 char option[3];
4469
4470 /* note: option array[] is initialiazed dynamically here to satisfy */
4471 /* a deficiency in the watcom compiler wrt static array initializers. */
4472 option[0] = '-';
4473 option[1] = shortopts[0];
4474 option[2] = 0;
4475
4476 arg_cat(&dest, option, &ndest);
4477 if (datatype)
4478 {
4479 arg_cat(&dest, " ", &ndest);
4480 if (optvalue)
4481 {
4482 arg_cat(&dest, "[", &ndest);
4483 arg_cat(&dest, datatype, &ndest);
4484 arg_cat(&dest, "]", &ndest);
4485 }
4486 else
4487 arg_cat(&dest, datatype, &ndest);
4488 }
4489 }
4490 else if (longopts)
4491 {
4492 size_t ncspn;
4493
4494 /* add "--" tag prefix */
4495 arg_cat(&dest, "--", &ndest);
4496
4497 /* add comma separated option tag */
4498 ncspn = strcspn(longopts, ",");
4499 #ifdef __STDC_WANT_SECURE_LIB__
4500 strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest);
4501 #else
4502 strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
4503 #endif
4504
4505 if (datatype)
4506 {
4507 arg_cat(&dest, "=", &ndest);
4508 if (optvalue)
4509 {
4510 arg_cat(&dest, "[", &ndest);
4511 arg_cat(&dest, datatype, &ndest);
4512 arg_cat(&dest, "]", &ndest);
4513 }
4514 else
4515 arg_cat(&dest, datatype, &ndest);
4516 }
4517 }
4518 else if (datatype)
4519 {
4520 if (optvalue)
4521 {
4522 arg_cat(&dest, "[", &ndest);
4523 arg_cat(&dest, datatype, &ndest);
4524 arg_cat(&dest, "]", &ndest);
4525 }
4526 else
4527 arg_cat(&dest, datatype, &ndest);
4528 }
4529 }
4530
4531 static
arg_cat_optionv(char * dest,size_t ndest,const char * shortopts,const char * longopts,const char * datatype,int optvalue,const char * separator)4532 void arg_cat_optionv(char *dest,
4533 size_t ndest,
4534 const char *shortopts,
4535 const char *longopts,
4536 const char *datatype,
4537 int optvalue,
4538 const char *separator)
4539 {
4540 separator = separator ? separator : "";
4541
4542 if (shortopts)
4543 {
4544 const char *c = shortopts;
4545 while(*c)
4546 {
4547 /* "-a|-b|-c" */
4548 char shortopt[3];
4549
4550 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4551 /* a deficiency in the watcom compiler wrt static array initializers. */
4552 shortopt[0] = '-';
4553 shortopt[1] = *c;
4554 shortopt[2] = 0;
4555
4556 arg_cat(&dest, shortopt, &ndest);
4557 if (*++c)
4558 arg_cat(&dest, separator, &ndest);
4559 }
4560 }
4561
4562 /* put separator between long opts and short opts */
4563 if (shortopts && longopts)
4564 arg_cat(&dest, separator, &ndest);
4565
4566 if (longopts)
4567 {
4568 const char *c = longopts;
4569 while(*c)
4570 {
4571 size_t ncspn;
4572
4573 /* add "--" tag prefix */
4574 arg_cat(&dest, "--", &ndest);
4575
4576 /* add comma separated option tag */
4577 ncspn = strcspn(c, ",");
4578 #ifdef __STDC_WANT_SECURE_LIB__
4579 strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest);
4580 #else
4581 strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
4582 #endif
4583 c += ncspn;
4584
4585 /* add given separator in place of comma */
4586 if (*c == ',')
4587 {
4588 arg_cat(&dest, separator, &ndest);
4589 c++;
4590 }
4591 }
4592 }
4593
4594 if (datatype)
4595 {
4596 if (longopts)
4597 arg_cat(&dest, "=", &ndest);
4598 else if (shortopts)
4599 arg_cat(&dest, " ", &ndest);
4600
4601 if (optvalue)
4602 {
4603 arg_cat(&dest, "[", &ndest);
4604 arg_cat(&dest, datatype, &ndest);
4605 arg_cat(&dest, "]", &ndest);
4606 }
4607 else
4608 arg_cat(&dest, datatype, &ndest);
4609 }
4610 }
4611
4612
4613 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
arg_print_option(FILE * fp,const char * shortopts,const char * longopts,const char * datatype,const char * suffix)4614 void arg_print_option(FILE *fp,
4615 const char *shortopts,
4616 const char *longopts,
4617 const char *datatype,
4618 const char *suffix)
4619 {
4620 char syntax[200] = "";
4621 suffix = suffix ? suffix : "";
4622
4623 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4624 arg_cat_optionv(syntax,
4625 sizeof(syntax),
4626 shortopts,
4627 longopts,
4628 datatype,
4629 0,
4630 "|");
4631
4632 fputs(syntax, fp);
4633 fputs(suffix, fp);
4634 }
4635
4636
4637 /*
4638 * Print a GNU style [OPTION] string in which all short options that
4639 * do not take argument values are presented in abbreviated form, as
4640 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4641 */
4642 static
arg_print_gnuswitch(FILE * fp,struct arg_hdr ** table)4643 void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table)
4644 {
4645 int tabindex;
4646 char *format1 = " -%c";
4647 char *format2 = " [-%c";
4648 char *suffix = "";
4649
4650 /* print all mandatory switches that are without argument values */
4651 for(tabindex = 0;
4652 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4653 tabindex++)
4654 {
4655 /* skip optional options */
4656 if (table[tabindex]->mincount < 1)
4657 continue;
4658
4659 /* skip non-short options */
4660 if (table[tabindex]->shortopts == NULL)
4661 continue;
4662
4663 /* skip options that take argument values */
4664 if (table[tabindex]->flag & ARG_HASVALUE)
4665 continue;
4666
4667 /* print the short option (only the first short option char, ignore multiple choices)*/
4668 fprintf(fp, format1, table[tabindex]->shortopts[0]);
4669 format1 = "%c";
4670 format2 = "[%c";
4671 }
4672
4673 /* print all optional switches that are without argument values */
4674 for(tabindex = 0;
4675 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4676 tabindex++)
4677 {
4678 /* skip mandatory args */
4679 if (table[tabindex]->mincount > 0)
4680 continue;
4681
4682 /* skip args without short options */
4683 if (table[tabindex]->shortopts == NULL)
4684 continue;
4685
4686 /* skip args with values */
4687 if (table[tabindex]->flag & ARG_HASVALUE)
4688 continue;
4689
4690 /* print first short option */
4691 fprintf(fp, format2, table[tabindex]->shortopts[0]);
4692 format2 = "%c";
4693 suffix = "]";
4694 }
4695
4696 fprintf(fp, "%s", suffix);
4697 }
4698
4699
arg_print_syntax(FILE * fp,void ** argtable,const char * suffix)4700 void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix)
4701 {
4702 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4703 int i, tabindex;
4704
4705 /* print GNU style [OPTION] string */
4706 arg_print_gnuswitch(fp, table);
4707
4708 /* print remaining options in abbreviated style */
4709 for(tabindex = 0;
4710 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4711 tabindex++)
4712 {
4713 char syntax[200] = "";
4714 const char *shortopts, *longopts, *datatype;
4715
4716 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4717 if (table[tabindex]->shortopts &&
4718 !(table[tabindex]->flag & ARG_HASVALUE))
4719 continue;
4720
4721 shortopts = table[tabindex]->shortopts;
4722 longopts = table[tabindex]->longopts;
4723 datatype = table[tabindex]->datatype;
4724 arg_cat_option(syntax,
4725 sizeof(syntax),
4726 shortopts,
4727 longopts,
4728 datatype,
4729 table[tabindex]->flag & ARG_HASOPTVALUE);
4730
4731 if (strlen(syntax) > 0)
4732 {
4733 /* print mandatory instances of this option */
4734 for (i = 0; i < table[tabindex]->mincount; i++)
4735 fprintf(fp, " %s", syntax);
4736
4737 /* print optional instances enclosed in "[..]" */
4738 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4739 {
4740 case 0:
4741 break;
4742 case 1:
4743 fprintf(fp, " [%s]", syntax);
4744 break;
4745 case 2:
4746 fprintf(fp, " [%s] [%s]", syntax, syntax);
4747 break;
4748 default:
4749 fprintf(fp, " [%s]...", syntax);
4750 break;
4751 }
4752 }
4753 }
4754
4755 if (suffix)
4756 fprintf(fp, "%s", suffix);
4757 }
4758
4759
arg_print_syntaxv(FILE * fp,void ** argtable,const char * suffix)4760 void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix)
4761 {
4762 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4763 int i, tabindex;
4764
4765 /* print remaining options in abbreviated style */
4766 for(tabindex = 0;
4767 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4768 tabindex++)
4769 {
4770 char syntax[200] = "";
4771 const char *shortopts, *longopts, *datatype;
4772
4773 shortopts = table[tabindex]->shortopts;
4774 longopts = table[tabindex]->longopts;
4775 datatype = table[tabindex]->datatype;
4776 arg_cat_optionv(syntax,
4777 sizeof(syntax),
4778 shortopts,
4779 longopts,
4780 datatype,
4781 table[tabindex]->flag & ARG_HASOPTVALUE,
4782 "|");
4783
4784 /* print mandatory options */
4785 for (i = 0; i < table[tabindex]->mincount; i++)
4786 fprintf(fp, " %s", syntax);
4787
4788 /* print optional args enclosed in "[..]" */
4789 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4790 {
4791 case 0:
4792 break;
4793 case 1:
4794 fprintf(fp, " [%s]", syntax);
4795 break;
4796 case 2:
4797 fprintf(fp, " [%s] [%s]", syntax, syntax);
4798 break;
4799 default:
4800 fprintf(fp, " [%s]...", syntax);
4801 break;
4802 }
4803 }
4804
4805 if (suffix)
4806 fprintf(fp, "%s", suffix);
4807 }
4808
4809
arg_print_glossary(FILE * fp,void ** argtable,const char * format)4810 void arg_print_glossary(FILE *fp, void * *argtable, const char *format)
4811 {
4812 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4813 int tabindex;
4814
4815 format = format ? format : " %-20s %s\n";
4816 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4817 {
4818 if (table[tabindex]->glossary)
4819 {
4820 char syntax[200] = "";
4821 const char *shortopts = table[tabindex]->shortopts;
4822 const char *longopts = table[tabindex]->longopts;
4823 const char *datatype = table[tabindex]->datatype;
4824 const char *glossary = table[tabindex]->glossary;
4825 arg_cat_optionv(syntax,
4826 sizeof(syntax),
4827 shortopts,
4828 longopts,
4829 datatype,
4830 table[tabindex]->flag & ARG_HASOPTVALUE,
4831 ", ");
4832 fprintf(fp, format, syntax, glossary);
4833 }
4834 }
4835 }
4836
4837
4838 /**
4839 * Print a piece of text formatted, which means in a column with a
4840 * left and a right margin. The lines are wrapped at whitspaces next
4841 * to right margin. The function does not indent the first line, but
4842 * only the following ones.
4843 *
4844 * Example:
4845 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4846 * will result in the following output:
4847 *
4848 * Some
4849 * text
4850 * that
4851 * doesn'
4852 * t fit.
4853 *
4854 * Too long lines will be wrapped in the middle of a word.
4855 *
4856 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4857 * will result in the following output:
4858 *
4859 * Some
4860 * text
4861 * that
4862 * doesn'
4863 * t fit.
4864 *
4865 * As you see, the first line is not indented. This enables output of
4866 * lines, which start in a line where output already happened.
4867 *
4868 * Author: Uli Fouquet
4869 */
4870 static
arg_print_formatted(FILE * fp,const unsigned lmargin,const unsigned rmargin,const char * text)4871 void arg_print_formatted( FILE *fp,
4872 const unsigned lmargin,
4873 const unsigned rmargin,
4874 const char *text )
4875 {
4876 const unsigned textlen = (unsigned)strlen( text );
4877 unsigned line_start = 0;
4878 unsigned line_end = textlen + 1;
4879 const unsigned colwidth = (rmargin - lmargin) + 1;
4880
4881 /* Someone doesn't like us... */
4882 if ( line_end < line_start )
4883 { fprintf( fp, "%s\n", text ); }
4884
4885 while (line_end - 1 > line_start )
4886 {
4887 /* Eat leading whitespaces. This is essential because while
4888 wrapping lines, there will often be a whitespace at beginning
4889 of line */
4890 while ( ISSPACE(*(text + line_start)) )
4891 { line_start++; }
4892
4893 if ((line_end - line_start) > colwidth )
4894 { line_end = line_start + colwidth; }
4895
4896 /* Find last whitespace, that fits into line */
4897 while ( ( line_end > line_start )
4898 && ( line_end - line_start > colwidth )
4899 && !ISSPACE(*(text + line_end)))
4900 { line_end--; }
4901
4902 /* Do not print trailing whitespace. If this text
4903 has got only one line, line_end now points to the
4904 last char due to initialization. */
4905 line_end--;
4906
4907 /* Output line of text */
4908 while ( line_start < line_end )
4909 {
4910 fputc(*(text + line_start), fp );
4911 line_start++;
4912 }
4913 fputc( '\n', fp );
4914
4915 /* Initialize another line */
4916 if ( line_end + 1 < textlen )
4917 {
4918 unsigned i;
4919
4920 for (i = 0; i < lmargin; i++ )
4921 { fputc( ' ', fp ); }
4922
4923 line_end = textlen;
4924 }
4925
4926 /* If we have to print another line, get also the last char. */
4927 line_end++;
4928
4929 } /* lines of text */
4930 }
4931
4932 /**
4933 * Prints the glossary in strict GNU format.
4934 * Differences to arg_print_glossary() are:
4935 * - wraps lines after 80 chars
4936 * - indents lines without shortops
4937 * - does not accept formatstrings
4938 *
4939 * Contributed by Uli Fouquet
4940 */
arg_print_glossary_gnu(FILE * fp,void ** argtable)4941 void arg_print_glossary_gnu(FILE *fp, void * *argtable )
4942 {
4943 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4944 int tabindex;
4945
4946 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4947 {
4948 if (table[tabindex]->glossary)
4949 {
4950 char syntax[200] = "";
4951 const char *shortopts = table[tabindex]->shortopts;
4952 const char *longopts = table[tabindex]->longopts;
4953 const char *datatype = table[tabindex]->datatype;
4954 const char *glossary = table[tabindex]->glossary;
4955
4956 if ( !shortopts && longopts )
4957 {
4958 /* Indent trailing line by 4 spaces... */
4959 memset( syntax, ' ', 4 );
4960 *(syntax + 4) = '\0';
4961 }
4962
4963 arg_cat_optionv(syntax,
4964 sizeof(syntax),
4965 shortopts,
4966 longopts,
4967 datatype,
4968 table[tabindex]->flag & ARG_HASOPTVALUE,
4969 ", ");
4970
4971 /* If syntax fits not into column, print glossary in new line... */
4972 if ( strlen(syntax) > 25 )
4973 {
4974 fprintf( fp, " %-25s %s\n", syntax, "" );
4975 *syntax = '\0';
4976 }
4977
4978 fprintf( fp, " %-25s ", syntax );
4979 arg_print_formatted( fp, 28, 79, glossary );
4980 }
4981 } /* for each table entry */
4982
4983 fputc( '\n', fp );
4984 }
4985
4986
4987 /**
4988 * Checks the argtable[] array for NULL entries and returns 1
4989 * if any are found, zero otherwise.
4990 */
arg_nullcheck(void ** argtable)4991 int arg_nullcheck(void * *argtable)
4992 {
4993 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4994 int tabindex;
4995 /*printf("arg_nullcheck(%p)\n",argtable);*/
4996
4997 if (!table)
4998 return 1;
4999
5000 tabindex = 0;
5001 do
5002 {
5003 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
5004 if (!table[tabindex])
5005 return 1;
5006 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
5007
5008 return 0;
5009 }
5010
5011
5012 /*
5013 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
5014 * The flaw results in memory leak in the (very rare) case that an intermediate
5015 * entry in the argtable array failed its memory allocation while others following
5016 * that entry were still allocated ok. Those subsequent allocations will not be
5017 * deallocated by arg_free().
5018 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
5019 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
5020 * with the newer arg_freetable() function.
5021 * We still keep arg_free() for backwards compatibility.
5022 */
arg_free(void ** argtable)5023 void arg_free(void * *argtable)
5024 {
5025 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
5026 int tabindex = 0;
5027 int flag;
5028 /*printf("arg_free(%p)\n",argtable);*/
5029 do
5030 {
5031 /*
5032 if we encounter a NULL entry then somewhat incorrectly we presume
5033 we have come to the end of the array. It isnt strictly true because
5034 an intermediate entry could be NULL with other non-NULL entries to follow.
5035 The subsequent argtable entries would then not be freed as they should.
5036 */
5037 if (table[tabindex] == NULL)
5038 break;
5039
5040 flag = table[tabindex]->flag;
5041 free(table[tabindex]);
5042 table[tabindex++] = NULL;
5043
5044 } while(!(flag & ARG_TERMINATOR));
5045 }
5046
5047 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
arg_freetable(void ** argtable,size_t n)5048 void arg_freetable(void * *argtable, size_t n)
5049 {
5050 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
5051 size_t tabindex = 0;
5052 /*printf("arg_freetable(%p)\n",argtable);*/
5053 for (tabindex = 0; tabindex < n; tabindex++)
5054 {
5055 if (table[tabindex] == NULL)
5056 continue;
5057
5058 free(table[tabindex]);
5059 table[tabindex] = NULL;
5060 };
5061 }
5062
5063