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