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