Mfp commands (#698)
[proxmark3-svn] / client / cliparser / argtable3.c
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 // On Windows isspace crashes app in case of using Unicode character set and string to be above ASCII
34 // so you have to use _istspace instead of space
35 #ifdef UNICODE
36 #include <tchar.h>
37 #define ISSPACE _istspace
38 #else
39 #define ISSPACE isspace
40 #endif
41
42 /*******************************************************************************
43 * This file is part of the argtable3 library.
44 *
45 * Copyright (C) 2013 Tom G. Huang
46 * <tomghuang@gmail.com>
47 * All rights reserved.
48 *
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions are met:
51 * * Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * * Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * * Neither the name of STEWART HEITMANN nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
61 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
64 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
66 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
67 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
69 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 ******************************************************************************/
71
72 #ifndef ARG_UTILS_H
73 #define ARG_UTILS_H
74
75 #define ARG_ENABLE_TRACE 0
76 #define ARG_ENABLE_LOG 1
77
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
81
82 enum
83 {
84 EMINCOUNT = 1,
85 EMAXCOUNT,
86 EBADINT,
87 // The same name define EOVERFLOW in errno.h on windows platform
88 #ifdef __STDC_WANT_SECURE_LIB__
89 EOVERFLOW_,
90 #else
91 EOVERFLOW,
92 #endif
93 EBADDOUBLE,
94 EBADDATE,
95 EREGNOMATCH
96 };
97
98
99 #if defined(_MSC_VER)
100 #define ARG_TRACE(x) \
101 __pragma(warning(push)) \
102 __pragma(warning(disable:4127)) \
103 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0) \
104 __pragma(warning(pop))
105
106 #define ARG_LOG(x) \
107 __pragma(warning(push)) \
108 __pragma(warning(disable:4127)) \
109 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0) \
110 __pragma(warning(pop))
111 #else
112 #define ARG_TRACE(x) \
113 do { if (ARG_ENABLE_TRACE) dbg_printf x; } while (0)
114
115 #define ARG_LOG(x) \
116 do { if (ARG_ENABLE_LOG) dbg_printf x; } while (0)
117 #endif
118
119 extern void dbg_printf(const char *fmt, ...);
120
121 #ifdef __cplusplus
122 }
123 #endif
124
125 #endif
126
127 /*******************************************************************************
128 * This file is part of the argtable3 library.
129 *
130 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
131 * <sheitmann@users.sourceforge.net>
132 * All rights reserved.
133 *
134 * Redistribution and use in source and binary forms, with or without
135 * modification, are permitted provided that the following conditions are met:
136 * * Redistributions of source code must retain the above copyright
137 * notice, this list of conditions and the following disclaimer.
138 * * Redistributions in binary form must reproduce the above copyright
139 * notice, this list of conditions and the following disclaimer in the
140 * documentation and/or other materials provided with the distribution.
141 * * Neither the name of STEWART HEITMANN nor the names of its contributors
142 * may be used to endorse or promote products derived from this software
143 * without specific prior written permission.
144 *
145 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
146 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
147 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
148 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
149 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
150 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
151 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
152 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
153 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
154 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
155 ******************************************************************************/
156
157 #include <stdarg.h>
158 #include <stdio.h>
159
160
161 void dbg_printf(const char *fmt, ...)
162 {
163 va_list args;
164 va_start(args, fmt);
165 vfprintf(stderr, fmt, args);
166 va_end(args);
167 }
168
169 /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
170 /* $FreeBSD$ */
171
172 /*-
173 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
174 *
175 * Copyright (c) 2000 The NetBSD Foundation, Inc.
176 * All rights reserved.
177 *
178 * This code is derived from software contributed to The NetBSD Foundation
179 * by Dieter Baron and Thomas Klausner.
180 *
181 * Redistribution and use in source and binary forms, with or without
182 * modification, are permitted provided that the following conditions
183 * are met:
184 * 1. Redistributions of source code must retain the above copyright
185 * notice, this list of conditions and the following disclaimer.
186 * 2. Redistributions in binary form must reproduce the above copyright
187 * notice, this list of conditions and the following disclaimer in the
188 * documentation and/or other materials provided with the distribution.
189 *
190 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
191 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
194 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
195 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
196 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
197 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
198 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
199 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
200 * POSSIBILITY OF SUCH DAMAGE.
201 */
202
203 #ifndef _GETOPT_H_
204 #define _GETOPT_H_
205
206 #include <sys/cdefs.h>
207
208 /*
209 * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension.
210 * getopt() is declared here too for GNU programs.
211 */
212 #define no_argument 0
213 #define required_argument 1
214 #define optional_argument 2
215
216 struct option {
217 /* name of long option */
218 const char *name;
219 /*
220 * one of no_argument, required_argument, and optional_argument:
221 * whether option takes an argument
222 */
223 int has_arg;
224 /* if not NULL, set *flag to val when option found */
225 int *flag;
226 /* if flag not NULL, value to set *flag to; else return value */
227 int val;
228 };
229
230 __BEGIN_DECLS
231 int getopt_long(int, char * const *, const char *,
232 const struct option *, int *);
233 int getopt_long_only(int, char * const *, const char *,
234 const struct option *, int *);
235 #ifndef _GETOPT_DECLARED
236 #define _GETOPT_DECLARED
237 int getopt(int, char * const [], const char *);
238
239 extern char *optarg; /* getopt(3) external variables */
240 extern int optind, opterr, optopt;
241 #endif
242 #ifndef _OPTRESET_DECLARED
243 #define _OPTRESET_DECLARED
244 extern int optreset; /* getopt(3) external variable */
245 #endif
246 __END_DECLS
247
248 #endif /* !_GETOPT_H_ */
249 /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
250 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
251 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
252
253 /*
254 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
255 *
256 * Permission to use, copy, modify, and distribute this software for any
257 * purpose with or without fee is hereby granted, provided that the above
258 * copyright notice and this permission notice appear in all copies.
259 *
260 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
261 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
262 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
263 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
264 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
265 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
266 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
267 *
268 * Sponsored in part by the Defense Advanced Research Projects
269 * Agency (DARPA) and Air Force Research Laboratory, Air Force
270 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
271 */
272
273 // $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $"
274
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 #if 0
305 #include <err.h>
306 #endif
307 #include <errno.h>
308 #include <stdlib.h>
309 #include <string.h>
310
311
312 #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
313
314 #ifdef REPLACE_GETOPT
315 int opterr = 1; /* if error message should be printed */
316 int optind = 1; /* index into parent argv vector */
317 int optopt = '?'; /* character checked for validity */
318 int optreset; /* reset getopt */
319 char *optarg; /* argument associated with option */
320 #endif
321
322 #define PRINT_ERROR ((opterr) && (*options != ':'))
323
324 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
325 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
326 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
327
328 /* return values */
329 #define BADCH (int)'?'
330 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
331 #define INORDER (int)1
332
333 #define EMSG ""
334
335 static int getopt_internal(int, char * const *, const char *,
336 const struct option *, int *, int);
337 static int parse_long_options(char * const *, const char *,
338 const struct option *, int *, int);
339 static int gcd(int, int);
340 static void permute_args(int, int, int, char * const *);
341
342 static char *place = EMSG; /* option letter processing */
343
344 /* XXX: set optreset to 1 rather than these two */
345 static int nonopt_start = -1; /* first non option argument (for permute) */
346 static int nonopt_end = -1; /* first option after non options (for permute) */
347
348 /* Error messages */
349 static const char recargchar[] = "option requires an argument -- %c";
350 static const char recargstring[] = "option requires an argument -- %s";
351 static const char ambig[] = "ambiguous option -- %.*s";
352 static const char noarg[] = "option doesn't take an argument -- %.*s";
353 static const char illoptchar[] = "unknown option -- %c";
354 static const char illoptstring[] = "unknown option -- %s";
355
356
357
358 #ifdef _WIN32
359
360 /* Windows needs warnx(). We change the definition though:
361 * 1. (another) global is defined, opterrmsg, which holds the error message
362 * 2. errors are always printed out on stderr w/o the program name
363 * Note that opterrmsg always gets set no matter what opterr is set to. The
364 * error message will not be printed if opterr is 0 as usual.
365 */
366
367 #include <stdio.h>
368 #include <stdarg.h>
369
370 #define MAX_OPTER_MSG_SIZE 128
371
372 extern char opterrmsg[MAX_OPTER_MSG_SIZE];
373 char opterrmsg[MAX_OPTER_MSG_SIZE]; /* buffer for the last error message */
374
375 static void warnx(const char *fmt, ...)
376 {
377 va_list ap;
378 va_start(ap, fmt);
379 /*
380 Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
381 implementation specifics and manually suppress the warning.
382 */
383 memset(opterrmsg, 0, sizeof opterrmsg);
384 if (fmt != NULL)
385 #ifdef __STDC_WANT_SECURE_LIB__
386 _vsnprintf_s(opterrmsg, MAX_OPTER_MSG_SIZE, sizeof(opterrmsg) - 1, fmt, ap);
387 #else
388 _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
389 #endif
390 va_end(ap);
391
392 #pragma warning(suppress: 6053)
393 fprintf(stderr, "%s\n", opterrmsg);
394 }
395
396 #else
397 #include <err.h>
398 #endif /*_WIN32*/
399
400
401 /*
402 * Compute the greatest common divisor of a and b.
403 */
404 static int
405 gcd(int a, int b)
406 {
407 int c;
408
409 c = a % b;
410 while (c != 0) {
411 a = b;
412 b = c;
413 c = a % b;
414 }
415
416 return (b);
417 }
418
419 /*
420 * Exchange the block from nonopt_start to nonopt_end with the block
421 * from nonopt_end to opt_end (keeping the same order of arguments
422 * in each block).
423 */
424 static void
425 permute_args(int panonopt_start, int panonopt_end, int opt_end,
426 char * const *nargv)
427 {
428 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
429 char *swap;
430
431 /*
432 * compute lengths of blocks and number and size of cycles
433 */
434 nnonopts = panonopt_end - panonopt_start;
435 nopts = opt_end - panonopt_end;
436 ncycle = gcd(nnonopts, nopts);
437 cyclelen = (opt_end - panonopt_start) / ncycle;
438
439 for (i = 0; i < ncycle; i++) {
440 cstart = panonopt_end+i;
441 pos = cstart;
442 for (j = 0; j < cyclelen; j++) {
443 if (pos >= panonopt_end)
444 pos -= nnonopts;
445 else
446 pos += nopts;
447 swap = nargv[pos];
448 /* LINTED const cast */
449 ((char **) nargv)[pos] = nargv[cstart];
450 /* LINTED const cast */
451 ((char **)nargv)[cstart] = swap;
452 }
453 }
454 }
455
456 /*
457 * parse_long_options --
458 * Parse long options in argc/argv argument vector.
459 * Returns -1 if short_too is set and the option does not match long_options.
460 */
461 static int
462 parse_long_options(char * const *nargv, const char *options,
463 const struct option *long_options, int *idx, int short_too)
464 {
465 char *current_argv, *has_equal;
466 size_t current_argv_len;
467 int i, match;
468
469 current_argv = place;
470 match = -1;
471
472 optind++;
473
474 if ((has_equal = strchr(current_argv, '=')) != NULL) {
475 /* argument found (--option=arg) */
476 current_argv_len = has_equal - current_argv;
477 has_equal++;
478 } else
479 current_argv_len = strlen(current_argv);
480
481 for (i = 0; long_options[i].name; i++) {
482 /* find matching long option */
483 if (strncmp(current_argv, long_options[i].name,
484 current_argv_len))
485 continue;
486
487 if (strlen(long_options[i].name) == current_argv_len) {
488 /* exact match */
489 match = i;
490 break;
491 }
492 /*
493 * If this is a known short option, don't allow
494 * a partial match of a single character.
495 */
496 if (short_too && current_argv_len == 1)
497 continue;
498
499 if (match == -1) /* partial match */
500 match = i;
501 else {
502 /* ambiguous abbreviation */
503 if (PRINT_ERROR)
504 warnx(ambig, (int)current_argv_len,
505 current_argv);
506 optopt = 0;
507 return (BADCH);
508 }
509 }
510 if (match != -1) { /* option found */
511 if (long_options[match].has_arg == no_argument
512 && has_equal) {
513 if (PRINT_ERROR)
514 warnx(noarg, (int)current_argv_len,
515 current_argv);
516 /*
517 * XXX: GNU sets optopt to val regardless of flag
518 */
519 if (long_options[match].flag == NULL)
520 optopt = long_options[match].val;
521 else
522 optopt = 0;
523 return (BADARG);
524 }
525 if (long_options[match].has_arg == required_argument ||
526 long_options[match].has_arg == optional_argument) {
527 if (has_equal)
528 optarg = has_equal;
529 else if (long_options[match].has_arg ==
530 required_argument) {
531 /*
532 * optional argument doesn't use next nargv
533 */
534 optarg = nargv[optind++];
535 }
536 }
537 if ((long_options[match].has_arg == required_argument)
538 && (optarg == NULL)) {
539 /*
540 * Missing argument; leading ':' indicates no error
541 * should be generated.
542 */
543 if (PRINT_ERROR)
544 warnx(recargstring,
545 current_argv);
546 /*
547 * XXX: GNU sets optopt to val regardless of flag
548 */
549 if (long_options[match].flag == NULL)
550 optopt = long_options[match].val;
551 else
552 optopt = 0;
553 --optind;
554 return (BADARG);
555 }
556 } else { /* unknown option */
557 if (short_too) {
558 --optind;
559 return (-1);
560 }
561 if (PRINT_ERROR)
562 warnx(illoptstring, current_argv);
563 optopt = 0;
564 return (BADCH);
565 }
566 if (idx)
567 *idx = match;
568 if (long_options[match].flag) {
569 *long_options[match].flag = long_options[match].val;
570 return (0);
571 } else
572 return (long_options[match].val);
573 }
574
575 /*
576 * getopt_internal --
577 * Parse argc/argv argument vector. Called by user level routines.
578 */
579 static int
580 getopt_internal(int nargc, char * const *nargv, const char *options,
581 const struct option *long_options, int *idx, int flags)
582 {
583 char *oli; /* option letter list index */
584 int optchar, short_too;
585 static int posixly_correct = -1;
586 #ifdef __STDC_WANT_SECURE_LIB__
587 char* buffer = NULL;
588 size_t buffer_size = 0;
589 errno_t err = 0;
590 #endif
591
592 if (options == NULL)
593 return (-1);
594
595 /*
596 * Disable GNU extensions if POSIXLY_CORRECT is set or options
597 * string begins with a '+'.
598 */
599
600 #ifdef __STDC_WANT_SECURE_LIB__
601 if (posixly_correct == -1) {
602 err = _dupenv_s(&buffer, &buffer_size, "POSIXLY_CORRECT") == 0;
603 posixly_correct = buffer != NULL;
604 if(buffer != NULL && err == 0) {
605 free(buffer);
606 }
607 }
608 #else
609 if (posixly_correct == -1)
610 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
611 #endif
612 if (posixly_correct || *options == '+')
613 flags &= ~FLAG_PERMUTE;
614 else if (*options == '-')
615 flags |= FLAG_ALLARGS;
616 if (*options == '+' || *options == '-')
617 options++;
618
619 /*
620 * XXX Some GNU programs (like cvs) set optind to 0 instead of
621 * XXX using optreset. Work around this braindamage.
622 */
623 if (optind == 0)
624 optind = optreset = 1;
625
626 optarg = NULL;
627 if (optreset)
628 nonopt_start = nonopt_end = -1;
629 start:
630 if (optreset || !*place) { /* update scanning pointer */
631 optreset = 0;
632 if (optind >= nargc) { /* end of argument vector */
633 place = EMSG;
634 if (nonopt_end != -1) {
635 /* do permutation, if we have to */
636 permute_args(nonopt_start, nonopt_end,
637 optind, nargv);
638 optind -= nonopt_end - nonopt_start;
639 }
640 else if (nonopt_start != -1) {
641 /*
642 * If we skipped non-options, set optind
643 * to the first of them.
644 */
645 optind = nonopt_start;
646 }
647 nonopt_start = nonopt_end = -1;
648 return (-1);
649 }
650 if (*(place = nargv[optind]) != '-' ||
651 (place[1] == '\0' && strchr(options, '-') == NULL)) {
652 place = EMSG; /* found non-option */
653 if (flags & FLAG_ALLARGS) {
654 /*
655 * GNU extension:
656 * return non-option as argument to option 1
657 */
658 optarg = nargv[optind++];
659 return (INORDER);
660 }
661 if (!(flags & FLAG_PERMUTE)) {
662 /*
663 * If no permutation wanted, stop parsing
664 * at first non-option.
665 */
666 return (-1);
667 }
668 /* do permutation */
669 if (nonopt_start == -1)
670 nonopt_start = optind;
671 else if (nonopt_end != -1) {
672 permute_args(nonopt_start, nonopt_end,
673 optind, nargv);
674 nonopt_start = optind -
675 (nonopt_end - nonopt_start);
676 nonopt_end = -1;
677 }
678 optind++;
679 /* process next argument */
680 goto start;
681 }
682 if (nonopt_start != -1 && nonopt_end == -1)
683 nonopt_end = optind;
684
685 /*
686 * If we have "-" do nothing, if "--" we are done.
687 */
688 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
689 optind++;
690 place = EMSG;
691 /*
692 * We found an option (--), so if we skipped
693 * non-options, we have to permute.
694 */
695 if (nonopt_end != -1) {
696 permute_args(nonopt_start, nonopt_end,
697 optind, nargv);
698 optind -= nonopt_end - nonopt_start;
699 }
700 nonopt_start = nonopt_end = -1;
701 return (-1);
702 }
703 }
704
705 /*
706 * Check long options if:
707 * 1) we were passed some
708 * 2) the arg is not just "-"
709 * 3) either the arg starts with -- we are getopt_long_only()
710 */
711 if (long_options != NULL && place != nargv[optind] &&
712 (*place == '-' || (flags & FLAG_LONGONLY))) {
713 short_too = 0;
714 if (*place == '-')
715 place++; /* --foo long option */
716 else if (*place != ':' && strchr(options, *place) != NULL)
717 short_too = 1; /* could be short option too */
718
719 optchar = parse_long_options(nargv, options, long_options,
720 idx, short_too);
721 if (optchar != -1) {
722 place = EMSG;
723 return (optchar);
724 }
725 }
726
727 if ((optchar = (int)*place++) == (int)':' ||
728 (optchar == (int)'-' && *place != '\0') ||
729 (oli = strchr(options, optchar)) == NULL) {
730 /*
731 * If the user specified "-" and '-' isn't listed in
732 * options, return -1 (non-option) as per POSIX.
733 * Otherwise, it is an unknown option character (or ':').
734 */
735 if (optchar == (int)'-' && *place == '\0')
736 return (-1);
737 if (!*place)
738 ++optind;
739 if (PRINT_ERROR)
740 warnx(illoptchar, optchar);
741 optopt = optchar;
742 return (BADCH);
743 }
744 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
745 /* -W long-option */
746 if (*place) /* no space */
747 /* NOTHING */;
748 else if (++optind >= nargc) { /* no arg */
749 place = EMSG;
750 if (PRINT_ERROR)
751 warnx(recargchar, optchar);
752 optopt = optchar;
753 return (BADARG);
754 } else /* white space */
755 place = nargv[optind];
756 optchar = parse_long_options(nargv, options, long_options,
757 idx, 0);
758 place = EMSG;
759 return (optchar);
760 }
761 if (*++oli != ':') { /* doesn't take argument */
762 if (!*place)
763 ++optind;
764 } else { /* takes (optional) argument */
765 optarg = NULL;
766 if (*place) /* no white space */
767 optarg = place;
768 else if (oli[1] != ':') { /* arg not optional */
769 if (++optind >= nargc) { /* no arg */
770 place = EMSG;
771 if (PRINT_ERROR)
772 warnx(recargchar, optchar);
773 optopt = optchar;
774 return (BADARG);
775 } else
776 optarg = nargv[optind];
777 }
778 place = EMSG;
779 ++optind;
780 }
781 /* dump back option letter */
782 return (optchar);
783 }
784
785 #ifdef REPLACE_GETOPT
786 /*
787 * getopt --
788 * Parse argc/argv argument vector.
789 *
790 * [eventually this will replace the BSD getopt]
791 */
792 int
793 getopt(int nargc, char * const *nargv, const char *options)
794 {
795
796 /*
797 * We don't pass FLAG_PERMUTE to getopt_internal() since
798 * the BSD getopt(3) (unlike GNU) has never done this.
799 *
800 * Furthermore, since many privileged programs call getopt()
801 * before dropping privileges it makes sense to keep things
802 * as simple (and bug-free) as possible.
803 */
804 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
805 }
806 #endif /* REPLACE_GETOPT */
807
808 /*
809 * getopt_long --
810 * Parse argc/argv argument vector.
811 */
812 int
813 getopt_long(int nargc, char * const *nargv, const char *options,
814 const struct option *long_options, int *idx)
815 {
816
817 return (getopt_internal(nargc, nargv, options, long_options, idx,
818 FLAG_PERMUTE));
819 }
820
821 /*
822 * getopt_long_only --
823 * Parse argc/argv argument vector.
824 */
825 int
826 getopt_long_only(int nargc, char * const *nargv, const char *options,
827 const struct option *long_options, int *idx)
828 {
829
830 return (getopt_internal(nargc, nargv, options, long_options, idx,
831 FLAG_PERMUTE|FLAG_LONGONLY));
832 }
833 /*******************************************************************************
834 * This file is part of the argtable3 library.
835 *
836 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
837 * <sheitmann@users.sourceforge.net>
838 * All rights reserved.
839 *
840 * Redistribution and use in source and binary forms, with or without
841 * modification, are permitted provided that the following conditions are met:
842 * * Redistributions of source code must retain the above copyright
843 * notice, this list of conditions and the following disclaimer.
844 * * Redistributions in binary form must reproduce the above copyright
845 * notice, this list of conditions and the following disclaimer in the
846 * documentation and/or other materials provided with the distribution.
847 * * Neither the name of STEWART HEITMANN nor the names of its contributors
848 * may be used to endorse or promote products derived from this software
849 * without specific prior written permission.
850 *
851 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
852 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
853 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
854 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
855 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
856 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
857 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
858 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
859 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
860 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
861 ******************************************************************************/
862
863 #include <stdlib.h>
864 #include <string.h>
865
866 #include "argtable3.h"
867
868
869 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm);
870
871
872 static void arg_date_resetfn(struct arg_date *parent)
873 {
874 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
875 parent->count = 0;
876 }
877
878
879 static int arg_date_scanfn(struct arg_date *parent, const char *argval)
880 {
881 int errorcode = 0;
882
883 if (parent->count == parent->hdr.maxcount)
884 {
885 errorcode = EMAXCOUNT;
886 }
887 else if (!argval)
888 {
889 /* no argument value was given, leave parent->tmval[] unaltered but still count it */
890 parent->count++;
891 }
892 else
893 {
894 const char *pend;
895 struct tm tm = parent->tmval[parent->count];
896
897 /* parse the given argument value, store result in parent->tmval[] */
898 pend = arg_strptime(argval, parent->format, &tm);
899 if (pend && pend[0] == '\0')
900 parent->tmval[parent->count++] = tm;
901 else
902 errorcode = EBADDATE;
903 }
904
905 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
906 return errorcode;
907 }
908
909
910 static int arg_date_checkfn(struct arg_date *parent)
911 {
912 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
913
914 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
915 return errorcode;
916 }
917
918
919 static void arg_date_errorfn(
920 struct arg_date *parent,
921 FILE *fp,
922 int errorcode,
923 const char *argval,
924 const char *progname)
925 {
926 const char *shortopts = parent->hdr.shortopts;
927 const char *longopts = parent->hdr.longopts;
928 const char *datatype = parent->hdr.datatype;
929
930 /* make argval NULL safe */
931 argval = argval ? argval : "";
932
933 fprintf(fp, "%s: ", progname);
934 switch(errorcode)
935 {
936 case EMINCOUNT:
937 fputs("missing option ", fp);
938 arg_print_option(fp, shortopts, longopts, datatype, "\n");
939 break;
940
941 case EMAXCOUNT:
942 fputs("excess option ", fp);
943 arg_print_option(fp, shortopts, longopts, argval, "\n");
944 break;
945
946 case EBADDATE:
947 {
948 struct tm tm;
949 char buff[200];
950
951 fprintf(fp, "illegal timestamp format \"%s\"\n", argval);
952 memset(&tm, 0, sizeof(tm));
953 arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
954 strftime(buff, sizeof(buff), parent->format, &tm);
955 printf("correct format is \"%s\"\n", buff);
956 break;
957 }
958 }
959 }
960
961
962 struct arg_date * arg_date0(
963 const char * shortopts,
964 const char * longopts,
965 const char * format,
966 const char *datatype,
967 const char *glossary)
968 {
969 return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
970 }
971
972
973 struct arg_date * arg_date1(
974 const char * shortopts,
975 const char * longopts,
976 const char * format,
977 const char *datatype,
978 const char *glossary)
979 {
980 return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
981 }
982
983
984 struct arg_date * arg_daten(
985 const char * shortopts,
986 const char * longopts,
987 const char * format,
988 const char *datatype,
989 int mincount,
990 int maxcount,
991 const char *glossary)
992 {
993 size_t nbytes;
994 struct arg_date *result;
995
996 /* foolproof things by ensuring maxcount is not less than mincount */
997 maxcount = (maxcount < mincount) ? mincount : maxcount;
998
999 /* default time format is the national date format for the locale */
1000 if (!format)
1001 format = "%x";
1002
1003 nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
1004 + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
1005
1006 /* allocate storage for the arg_date struct + tmval[] array. */
1007 /* we use calloc because we want the tmval[] array zero filled. */
1008 result = (struct arg_date *)calloc(1, nbytes);
1009 if (result)
1010 {
1011 /* init the arg_hdr struct */
1012 result->hdr.flag = ARG_HASVALUE;
1013 result->hdr.shortopts = shortopts;
1014 result->hdr.longopts = longopts;
1015 result->hdr.datatype = datatype ? datatype : format;
1016 result->hdr.glossary = glossary;
1017 result->hdr.mincount = mincount;
1018 result->hdr.maxcount = maxcount;
1019 result->hdr.parent = result;
1020 result->hdr.resetfn = (arg_resetfn *)arg_date_resetfn;
1021 result->hdr.scanfn = (arg_scanfn *)arg_date_scanfn;
1022 result->hdr.checkfn = (arg_checkfn *)arg_date_checkfn;
1023 result->hdr.errorfn = (arg_errorfn *)arg_date_errorfn;
1024
1025 /* store the tmval[maxcount] array immediately after the arg_date struct */
1026 result->tmval = (struct tm *)(result + 1);
1027
1028 /* init the remaining arg_date member variables */
1029 result->count = 0;
1030 result->format = format;
1031 }
1032
1033 ARG_TRACE(("arg_daten() returns %p\n", result));
1034 return result;
1035 }
1036
1037
1038 /*-
1039 * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1040 * All rights reserved.
1041 *
1042 * This code was contributed to The NetBSD Foundation by Klaus Klein.
1043 * Heavily optimised by David Laight
1044 *
1045 * Redistribution and use in source and binary forms, with or without
1046 * modification, are permitted provided that the following conditions
1047 * are met:
1048 * 1. Redistributions of source code must retain the above copyright
1049 * notice, this list of conditions and the following disclaimer.
1050 * 2. Redistributions in binary form must reproduce the above copyright
1051 * notice, this list of conditions and the following disclaimer in the
1052 * documentation and/or other materials provided with the distribution.
1053 *
1054 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1055 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1056 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1057 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1058 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1060 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1061 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1062 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1063 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1064 * POSSIBILITY OF SUCH DAMAGE.
1065 */
1066
1067 #include <ctype.h>
1068 #include <string.h>
1069 #include <time.h>
1070
1071 /*
1072 * We do not implement alternate representations. However, we always
1073 * check whether a given modifier is allowed for a certain conversion.
1074 */
1075 #define ALT_E 0x01
1076 #define ALT_O 0x02
1077 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
1078 #define TM_YEAR_BASE (1900)
1079
1080 static int conv_num(const char * *, int *, int, int);
1081
1082 static const char *day[7] = {
1083 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
1084 "Friday", "Saturday"
1085 };
1086
1087 static const char *abday[7] = {
1088 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1089 };
1090
1091 static const char *mon[12] = {
1092 "January", "February", "March", "April", "May", "June", "July",
1093 "August", "September", "October", "November", "December"
1094 };
1095
1096 static const char *abmon[12] = {
1097 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1098 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1099 };
1100
1101 static const char *am_pm[2] = {
1102 "AM", "PM"
1103 };
1104
1105
1106 static int arg_strcasecmp(const char *s1, const char *s2)
1107 {
1108 const unsigned char *us1 = (const unsigned char *)s1;
1109 const unsigned char *us2 = (const unsigned char *)s2;
1110 while (tolower(*us1) == tolower(*us2++))
1111 if (*us1++ == '\0')
1112 return 0;
1113
1114 return tolower(*us1) - tolower(*--us2);
1115 }
1116
1117
1118 static int arg_strncasecmp(const char *s1, const char *s2, size_t n)
1119 {
1120 if (n != 0)
1121 {
1122 const unsigned char *us1 = (const unsigned char *)s1;
1123 const unsigned char *us2 = (const unsigned char *)s2;
1124 do
1125 {
1126 if (tolower(*us1) != tolower(*us2++))
1127 return tolower(*us1) - tolower(*--us2);
1128
1129 if (*us1++ == '\0')
1130 break;
1131 } while (--n != 0);
1132 }
1133
1134 return 0;
1135 }
1136
1137
1138 char * arg_strptime(const char *buf, const char *fmt, struct tm *tm)
1139 {
1140 char c;
1141 const char *bp;
1142 size_t len = 0;
1143 int alt_format, i, split_year = 0;
1144
1145 bp = buf;
1146
1147 while ((c = *fmt) != '\0') {
1148 /* Clear `alternate' modifier prior to new conversion. */
1149 alt_format = 0;
1150
1151 /* Eat up white-space. */
1152 if (ISSPACE(c)) {
1153 while (ISSPACE(*bp))
1154 bp++;
1155
1156 fmt++;
1157 continue;
1158 }
1159
1160 if ((c = *fmt++) != '%')
1161 goto literal;
1162
1163
1164 again:
1165 switch (c = *fmt++)
1166 {
1167 case '%': /* "%%" is converted to "%". */
1168 literal:
1169 if (c != *bp++)
1170 return (0);
1171 break;
1172
1173 /*
1174 * "Alternative" modifiers. Just set the appropriate flag
1175 * and start over again.
1176 */
1177 case 'E': /* "%E?" alternative conversion modifier. */
1178 LEGAL_ALT(0);
1179 alt_format |= ALT_E;
1180 goto again;
1181
1182 case 'O': /* "%O?" alternative conversion modifier. */
1183 LEGAL_ALT(0);
1184 alt_format |= ALT_O;
1185 goto again;
1186
1187 /*
1188 * "Complex" conversion rules, implemented through recursion.
1189 */
1190 case 'c': /* Date and time, using the locale's format. */
1191 LEGAL_ALT(ALT_E);
1192 bp = arg_strptime(bp, "%x %X", tm);
1193 if (!bp)
1194 return (0);
1195 break;
1196
1197 case 'D': /* The date as "%m/%d/%y". */
1198 LEGAL_ALT(0);
1199 bp = arg_strptime(bp, "%m/%d/%y", tm);
1200 if (!bp)
1201 return (0);
1202 break;
1203
1204 case 'R': /* The time as "%H:%M". */
1205 LEGAL_ALT(0);
1206 bp = arg_strptime(bp, "%H:%M", tm);
1207 if (!bp)
1208 return (0);
1209 break;
1210
1211 case 'r': /* The time in 12-hour clock representation. */
1212 LEGAL_ALT(0);
1213 bp = arg_strptime(bp, "%I:%M:%S %p", tm);
1214 if (!bp)
1215 return (0);
1216 break;
1217
1218 case 'T': /* The time as "%H:%M:%S". */
1219 LEGAL_ALT(0);
1220 bp = arg_strptime(bp, "%H:%M:%S", tm);
1221 if (!bp)
1222 return (0);
1223 break;
1224
1225 case 'X': /* The time, using the locale's format. */
1226 LEGAL_ALT(ALT_E);
1227 bp = arg_strptime(bp, "%H:%M:%S", tm);
1228 if (!bp)
1229 return (0);
1230 break;
1231
1232 case 'x': /* The date, using the locale's format. */
1233 LEGAL_ALT(ALT_E);
1234 bp = arg_strptime(bp, "%m/%d/%y", tm);
1235 if (!bp)
1236 return (0);
1237 break;
1238
1239 /*
1240 * "Elementary" conversion rules.
1241 */
1242 case 'A': /* The day of week, using the locale's form. */
1243 case 'a':
1244 LEGAL_ALT(0);
1245 for (i = 0; i < 7; i++) {
1246 /* Full name. */
1247 len = strlen(day[i]);
1248 if (arg_strncasecmp(day[i], bp, len) == 0)
1249 break;
1250
1251 /* Abbreviated name. */
1252 len = strlen(abday[i]);
1253 if (arg_strncasecmp(abday[i], bp, len) == 0)
1254 break;
1255 }
1256
1257 /* Nothing matched. */
1258 if (i == 7)
1259 return (0);
1260
1261 tm->tm_wday = i;
1262 bp += len;
1263 break;
1264
1265 case 'B': /* The month, using the locale's form. */
1266 case 'b':
1267 case 'h':
1268 LEGAL_ALT(0);
1269 for (i = 0; i < 12; i++) {
1270 /* Full name. */
1271 len = strlen(mon[i]);
1272 if (arg_strncasecmp(mon[i], bp, len) == 0)
1273 break;
1274
1275 /* Abbreviated name. */
1276 len = strlen(abmon[i]);
1277 if (arg_strncasecmp(abmon[i], bp, len) == 0)
1278 break;
1279 }
1280
1281 /* Nothing matched. */
1282 if (i == 12)
1283 return (0);
1284
1285 tm->tm_mon = i;
1286 bp += len;
1287 break;
1288
1289 case 'C': /* The century number. */
1290 LEGAL_ALT(ALT_E);
1291 if (!(conv_num(&bp, &i, 0, 99)))
1292 return (0);
1293
1294 if (split_year) {
1295 tm->tm_year = (tm->tm_year % 100) + (i * 100);
1296 } else {
1297 tm->tm_year = i * 100;
1298 split_year = 1;
1299 }
1300 break;
1301
1302 case 'd': /* The day of month. */
1303 case 'e':
1304 LEGAL_ALT(ALT_O);
1305 if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
1306 return (0);
1307 break;
1308
1309 case 'k': /* The hour (24-hour clock representation). */
1310 LEGAL_ALT(0);
1311 /* FALLTHROUGH */
1312 case 'H':
1313 LEGAL_ALT(ALT_O);
1314 if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
1315 return (0);
1316 break;
1317
1318 case 'l': /* The hour (12-hour clock representation). */
1319 LEGAL_ALT(0);
1320 /* FALLTHROUGH */
1321 case 'I':
1322 LEGAL_ALT(ALT_O);
1323 if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
1324 return (0);
1325 if (tm->tm_hour == 12)
1326 tm->tm_hour = 0;
1327 break;
1328
1329 case 'j': /* The day of year. */
1330 LEGAL_ALT(0);
1331 if (!(conv_num(&bp, &i, 1, 366)))
1332 return (0);
1333 tm->tm_yday = i - 1;
1334 break;
1335
1336 case 'M': /* The minute. */
1337 LEGAL_ALT(ALT_O);
1338 if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
1339 return (0);
1340 break;
1341
1342 case 'm': /* The month. */
1343 LEGAL_ALT(ALT_O);
1344 if (!(conv_num(&bp, &i, 1, 12)))
1345 return (0);
1346 tm->tm_mon = i - 1;
1347 break;
1348
1349 case 'p': /* The locale's equivalent of AM/PM. */
1350 LEGAL_ALT(0);
1351 /* AM? */
1352 if (arg_strcasecmp(am_pm[0], bp) == 0) {
1353 if (tm->tm_hour > 11)
1354 return (0);
1355
1356 bp += strlen(am_pm[0]);
1357 break;
1358 }
1359 /* PM? */
1360 else if (arg_strcasecmp(am_pm[1], bp) == 0) {
1361 if (tm->tm_hour > 11)
1362 return (0);
1363
1364 tm->tm_hour += 12;
1365 bp += strlen(am_pm[1]);
1366 break;
1367 }
1368
1369 /* Nothing matched. */
1370 return (0);
1371
1372 case 'S': /* The seconds. */
1373 LEGAL_ALT(ALT_O);
1374 if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
1375 return (0);
1376 break;
1377
1378 case 'U': /* The week of year, beginning on sunday. */
1379 case 'W': /* The week of year, beginning on monday. */
1380 LEGAL_ALT(ALT_O);
1381 /*
1382 * XXX This is bogus, as we can not assume any valid
1383 * information present in the tm structure at this
1384 * point to calculate a real value, so just check the
1385 * range for now.
1386 */
1387 if (!(conv_num(&bp, &i, 0, 53)))
1388 return (0);
1389 break;
1390
1391 case 'w': /* The day of week, beginning on sunday. */
1392 LEGAL_ALT(ALT_O);
1393 if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
1394 return (0);
1395 break;
1396
1397 case 'Y': /* The year. */
1398 LEGAL_ALT(ALT_E);
1399 if (!(conv_num(&bp, &i, 0, 9999)))
1400 return (0);
1401
1402 tm->tm_year = i - TM_YEAR_BASE;
1403 break;
1404
1405 case 'y': /* The year within 100 years of the epoch. */
1406 LEGAL_ALT(ALT_E | ALT_O);
1407 if (!(conv_num(&bp, &i, 0, 99)))
1408 return (0);
1409
1410 if (split_year) {
1411 tm->tm_year = ((tm->tm_year / 100) * 100) + i;
1412 break;
1413 }
1414 split_year = 1;
1415 if (i <= 68)
1416 tm->tm_year = i + 2000 - TM_YEAR_BASE;
1417 else
1418 tm->tm_year = i + 1900 - TM_YEAR_BASE;
1419 break;
1420
1421 /*
1422 * Miscellaneous conversions.
1423 */
1424 case 'n': /* Any kind of white-space. */
1425 case 't':
1426 LEGAL_ALT(0);
1427 while (ISSPACE(*bp))
1428 bp++;
1429 break;
1430
1431
1432 default: /* Unknown/unsupported conversion. */
1433 return (0);
1434 }
1435
1436
1437 }
1438
1439 /* LINTED functional specification */
1440 return ((char *)bp);
1441 }
1442
1443
1444 static int conv_num(const char * *buf, int *dest, int llim, int ulim)
1445 {
1446 int result = 0;
1447
1448 /* The limit also determines the number of valid digits. */
1449 int rulim = ulim;
1450
1451 if (**buf < '0' || **buf > '9')
1452 return (0);
1453
1454 do {
1455 result *= 10;
1456 result += *(*buf)++ - '0';
1457 rulim /= 10;
1458 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
1459
1460 if (result < llim || result > ulim)
1461 return (0);
1462
1463 *dest = result;
1464 return (1);
1465 }
1466 /*******************************************************************************
1467 * This file is part of the argtable3 library.
1468 *
1469 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1470 * <sheitmann@users.sourceforge.net>
1471 * All rights reserved.
1472 *
1473 * Redistribution and use in source and binary forms, with or without
1474 * modification, are permitted provided that the following conditions are met:
1475 * * Redistributions of source code must retain the above copyright
1476 * notice, this list of conditions and the following disclaimer.
1477 * * Redistributions in binary form must reproduce the above copyright
1478 * notice, this list of conditions and the following disclaimer in the
1479 * documentation and/or other materials provided with the distribution.
1480 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1481 * may be used to endorse or promote products derived from this software
1482 * without specific prior written permission.
1483 *
1484 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1485 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1486 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1487 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1488 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1489 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1490 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1491 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1492 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1493 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1494 ******************************************************************************/
1495
1496 #include <stdlib.h>
1497
1498 #include "argtable3.h"
1499
1500
1501 static void arg_dbl_resetfn(struct arg_dbl *parent)
1502 {
1503 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1504 parent->count = 0;
1505 }
1506
1507
1508 static int arg_dbl_scanfn(struct arg_dbl *parent, const char *argval)
1509 {
1510 int errorcode = 0;
1511
1512 if (parent->count == parent->hdr.maxcount)
1513 {
1514 /* maximum number of arguments exceeded */
1515 errorcode = EMAXCOUNT;
1516 }
1517 else if (!argval)
1518 {
1519 /* a valid argument with no argument value was given. */
1520 /* This happens when an optional argument value was invoked. */
1521 /* leave parent argument value unaltered but still count the argument. */
1522 parent->count++;
1523 }
1524 else
1525 {
1526 double val;
1527 char *end;
1528
1529 /* extract double from argval into val */
1530 val = strtod(argval, &end);
1531
1532 /* if success then store result in parent->dval[] array otherwise return error*/
1533 if (*end == 0)
1534 parent->dval[parent->count++] = val;
1535 else
1536 errorcode = EBADDOUBLE;
1537 }
1538
1539 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1540 return errorcode;
1541 }
1542
1543
1544 static int arg_dbl_checkfn(struct arg_dbl *parent)
1545 {
1546 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1547
1548 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1549 return errorcode;
1550 }
1551
1552
1553 static void arg_dbl_errorfn(
1554 struct arg_dbl *parent,
1555 FILE *fp,
1556 int errorcode,
1557 const char *argval,
1558 const char *progname)
1559 {
1560 const char *shortopts = parent->hdr.shortopts;
1561 const char *longopts = parent->hdr.longopts;
1562 const char *datatype = parent->hdr.datatype;
1563
1564 /* make argval NULL safe */
1565 argval = argval ? argval : "";
1566
1567 fprintf(fp, "%s: ", progname);
1568 switch(errorcode)
1569 {
1570 case EMINCOUNT:
1571 fputs("missing option ", fp);
1572 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1573 break;
1574
1575 case EMAXCOUNT:
1576 fputs("excess option ", fp);
1577 arg_print_option(fp, shortopts, longopts, argval, "\n");
1578 break;
1579
1580 case EBADDOUBLE:
1581 fprintf(fp, "invalid argument \"%s\" to option ", argval);
1582 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1583 break;
1584 }
1585 }
1586
1587
1588 struct arg_dbl * arg_dbl0(
1589 const char * shortopts,
1590 const char * longopts,
1591 const char *datatype,
1592 const char *glossary)
1593 {
1594 return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
1595 }
1596
1597
1598 struct arg_dbl * arg_dbl1(
1599 const char * shortopts,
1600 const char * longopts,
1601 const char *datatype,
1602 const char *glossary)
1603 {
1604 return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
1605 }
1606
1607
1608 struct arg_dbl * arg_dbln(
1609 const char * shortopts,
1610 const char * longopts,
1611 const char *datatype,
1612 int mincount,
1613 int maxcount,
1614 const char *glossary)
1615 {
1616 size_t nbytes;
1617 struct arg_dbl *result;
1618
1619 /* foolproof things by ensuring maxcount is not less than mincount */
1620 maxcount = (maxcount < mincount) ? mincount : maxcount;
1621
1622 nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
1623 + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
1624
1625 result = (struct arg_dbl *)malloc(nbytes);
1626 if (result)
1627 {
1628 size_t addr;
1629 size_t rem;
1630
1631 /* init the arg_hdr struct */
1632 result->hdr.flag = ARG_HASVALUE;
1633 result->hdr.shortopts = shortopts;
1634 result->hdr.longopts = longopts;
1635 result->hdr.datatype = datatype ? datatype : "<double>";
1636 result->hdr.glossary = glossary;
1637 result->hdr.mincount = mincount;
1638 result->hdr.maxcount = maxcount;
1639 result->hdr.parent = result;
1640 result->hdr.resetfn = (arg_resetfn *)arg_dbl_resetfn;
1641 result->hdr.scanfn = (arg_scanfn *)arg_dbl_scanfn;
1642 result->hdr.checkfn = (arg_checkfn *)arg_dbl_checkfn;
1643 result->hdr.errorfn = (arg_errorfn *)arg_dbl_errorfn;
1644
1645 /* Store the dval[maxcount] array on the first double boundary that
1646 * immediately follows the arg_dbl struct. We do the memory alignment
1647 * purely for SPARC and Motorola systems. They require floats and
1648 * doubles to be aligned on natural boundaries.
1649 */
1650 addr = (size_t)(result + 1);
1651 rem = addr % sizeof(double);
1652 result->dval = (double *)(addr + sizeof(double) - rem);
1653 ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
1654
1655 result->count = 0;
1656 }
1657
1658 ARG_TRACE(("arg_dbln() returns %p\n", result));
1659 return result;
1660 }
1661 /*******************************************************************************
1662 * This file is part of the argtable3 library.
1663 *
1664 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1665 * <sheitmann@users.sourceforge.net>
1666 * All rights reserved.
1667 *
1668 * Redistribution and use in source and binary forms, with or without
1669 * modification, are permitted provided that the following conditions are met:
1670 * * Redistributions of source code must retain the above copyright
1671 * notice, this list of conditions and the following disclaimer.
1672 * * Redistributions in binary form must reproduce the above copyright
1673 * notice, this list of conditions and the following disclaimer in the
1674 * documentation and/or other materials provided with the distribution.
1675 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1676 * may be used to endorse or promote products derived from this software
1677 * without specific prior written permission.
1678 *
1679 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1680 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1681 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1682 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1683 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1684 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1685 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1686 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1687 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1688 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1689 ******************************************************************************/
1690
1691 #include <stdlib.h>
1692
1693 #include "argtable3.h"
1694
1695
1696 static void arg_end_resetfn(struct arg_end *parent)
1697 {
1698 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1699 parent->count = 0;
1700 }
1701
1702 static void arg_end_errorfn(
1703 void *parent,
1704 FILE *fp,
1705 int error,
1706 const char *argval,
1707 const char *progname)
1708 {
1709 /* suppress unreferenced formal parameter warning */
1710 (void)parent;
1711
1712 progname = progname ? progname : "";
1713 argval = argval ? argval : "";
1714
1715 fprintf(fp, "%s: ", progname);
1716 switch(error)
1717 {
1718 case ARG_ELIMIT:
1719 fputs("too many errors to display", fp);
1720 break;
1721 case ARG_EMALLOC:
1722 fputs("insufficent memory", fp);
1723 break;
1724 case ARG_ENOMATCH:
1725 fprintf(fp, "unexpected argument \"%s\"", argval);
1726 break;
1727 case ARG_EMISSARG:
1728 fprintf(fp, "option \"%s\" requires an argument", argval);
1729 break;
1730 case ARG_ELONGOPT:
1731 fprintf(fp, "invalid option \"%s\"", argval);
1732 break;
1733 default:
1734 fprintf(fp, "invalid option \"-%c\"", error);
1735 break;
1736 }
1737
1738 fputc('\n', fp);
1739 }
1740
1741
1742 struct arg_end * arg_end(int maxcount)
1743 {
1744 size_t nbytes;
1745 struct arg_end *result;
1746
1747 nbytes = sizeof(struct arg_end)
1748 + maxcount * sizeof(int) /* storage for int error[maxcount] array*/
1749 + maxcount * sizeof(void *) /* storage for void* parent[maxcount] array */
1750 + maxcount * sizeof(char *); /* storage for char* argval[maxcount] array */
1751
1752 result = (struct arg_end *)malloc(nbytes);
1753 if (result)
1754 {
1755 /* init the arg_hdr struct */
1756 result->hdr.flag = ARG_TERMINATOR;
1757 result->hdr.shortopts = NULL;
1758 result->hdr.longopts = NULL;
1759 result->hdr.datatype = NULL;
1760 result->hdr.glossary = NULL;
1761 result->hdr.mincount = 1;
1762 result->hdr.maxcount = maxcount;
1763 result->hdr.parent = result;
1764 result->hdr.resetfn = (arg_resetfn *)arg_end_resetfn;
1765 result->hdr.scanfn = NULL;
1766 result->hdr.checkfn = NULL;
1767 result->hdr.errorfn = (arg_errorfn *)arg_end_errorfn;
1768
1769 /* store error[maxcount] array immediately after struct arg_end */
1770 result->error = (int *)(result + 1);
1771
1772 /* store parent[maxcount] array immediately after error[] array */
1773 result->parent = (void * *)(result->error + maxcount );
1774
1775 /* store argval[maxcount] array immediately after parent[] array */
1776 result->argval = (const char * *)(result->parent + maxcount );
1777 }
1778
1779 ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
1780 return result;
1781 }
1782
1783
1784 void arg_print_errors(FILE * fp, struct arg_end * end, const char * progname)
1785 {
1786 int i;
1787 ARG_TRACE(("arg_errors()\n"));
1788 for (i = 0; i < end->count; i++)
1789 {
1790 struct arg_hdr *errorparent = (struct arg_hdr *)(end->parent[i]);
1791 if (errorparent->errorfn)
1792 errorparent->errorfn(end->parent[i],
1793 fp,
1794 end->error[i],
1795 end->argval[i],
1796 progname);
1797 }
1798 }
1799 /*******************************************************************************
1800 * This file is part of the argtable3 library.
1801 *
1802 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
1803 * <sheitmann@users.sourceforge.net>
1804 * All rights reserved.
1805 *
1806 * Redistribution and use in source and binary forms, with or without
1807 * modification, are permitted provided that the following conditions are met:
1808 * * Redistributions of source code must retain the above copyright
1809 * notice, this list of conditions and the following disclaimer.
1810 * * Redistributions in binary form must reproduce the above copyright
1811 * notice, this list of conditions and the following disclaimer in the
1812 * documentation and/or other materials provided with the distribution.
1813 * * Neither the name of STEWART HEITMANN nor the names of its contributors
1814 * may be used to endorse or promote products derived from this software
1815 * without specific prior written permission.
1816 *
1817 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1818 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1819 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1820 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
1821 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1822 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1823 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1824 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1825 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1826 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1827 ******************************************************************************/
1828
1829 #include <string.h>
1830 #include <stdlib.h>
1831
1832 #include "argtable3.h"
1833
1834 #ifdef WIN32
1835 # define FILESEPARATOR1 '\\'
1836 # define FILESEPARATOR2 '/'
1837 #else
1838 # define FILESEPARATOR1 '/'
1839 # define FILESEPARATOR2 '/'
1840 #endif
1841
1842
1843 static void arg_file_resetfn(struct arg_file *parent)
1844 {
1845 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
1846 parent->count = 0;
1847 }
1848
1849
1850 /* Returns ptr to the base filename within *filename */
1851 static const char * arg_basename(const char *filename)
1852 {
1853 const char *result = NULL, *result1, *result2;
1854
1855 /* Find the last occurrence of eother file separator character. */
1856 /* Two alternative file separator chars are supported as legal */
1857 /* file separators but not both together in the same filename. */
1858 result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
1859 result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
1860
1861 if (result2)
1862 result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
1863
1864 if (result1)
1865 result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
1866
1867 if (!result)
1868 result = filename; /* neither file separator was found so basename is the whole filename */
1869
1870 /* special cases of "." and ".." are not considered basenames */
1871 if (result && ( strcmp(".", result) == 0 || strcmp("..", result) == 0 ))
1872 result = filename + strlen(filename);
1873
1874 return result;
1875 }
1876
1877
1878 /* Returns ptr to the file extension within *basename */
1879 static const char * arg_extension(const char *basename)
1880 {
1881 /* find the last occurrence of '.' in basename */
1882 const char *result = (basename ? strrchr(basename, '.') : NULL);
1883
1884 /* if no '.' was found then return pointer to end of basename */
1885 if (basename && !result)
1886 result = basename + strlen(basename);
1887
1888 /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
1889 if (basename && result == basename)
1890 result = basename + strlen(basename);
1891
1892 /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
1893 if (basename && result && result[1] == '\0')
1894 result = basename + strlen(basename);
1895
1896 return result;
1897 }
1898
1899
1900 static int arg_file_scanfn(struct arg_file *parent, const char *argval)
1901 {
1902 int errorcode = 0;
1903
1904 if (parent->count == parent->hdr.maxcount)
1905 {
1906 /* maximum number of arguments exceeded */
1907 errorcode = EMAXCOUNT;
1908 }
1909 else if (!argval)
1910 {
1911 /* a valid argument with no argument value was given. */
1912 /* This happens when an optional argument value was invoked. */
1913 /* leave parent arguiment value unaltered but still count the argument. */
1914 parent->count++;
1915 }
1916 else
1917 {
1918 parent->filename[parent->count] = argval;
1919 parent->basename[parent->count] = arg_basename(argval);
1920 parent->extension[parent->count] =
1921 arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
1922 parent->count++;
1923 }
1924
1925 ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
1926 return errorcode;
1927 }
1928
1929
1930 static int arg_file_checkfn(struct arg_file *parent)
1931 {
1932 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
1933
1934 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
1935 return errorcode;
1936 }
1937
1938
1939 static void arg_file_errorfn(
1940 struct arg_file *parent,
1941 FILE *fp,
1942 int errorcode,
1943 const char *argval,
1944 const char *progname)
1945 {
1946 const char *shortopts = parent->hdr.shortopts;
1947 const char *longopts = parent->hdr.longopts;
1948 const char *datatype = parent->hdr.datatype;
1949
1950 /* make argval NULL safe */
1951 argval = argval ? argval : "";
1952
1953 fprintf(fp, "%s: ", progname);
1954 switch(errorcode)
1955 {
1956 case EMINCOUNT:
1957 fputs("missing option ", fp);
1958 arg_print_option(fp, shortopts, longopts, datatype, "\n");
1959 break;
1960
1961 case EMAXCOUNT:
1962 fputs("excess option ", fp);
1963 arg_print_option(fp, shortopts, longopts, argval, "\n");
1964 break;
1965
1966 default:
1967 fprintf(fp, "unknown error at \"%s\"\n", argval);
1968 }
1969 }
1970
1971
1972 struct arg_file * arg_file0(
1973 const char * shortopts,
1974 const char * longopts,
1975 const char *datatype,
1976 const char *glossary)
1977 {
1978 return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
1979 }
1980
1981
1982 struct arg_file * arg_file1(
1983 const char * shortopts,
1984 const char * longopts,
1985 const char *datatype,
1986 const char *glossary)
1987 {
1988 return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
1989 }
1990
1991
1992 struct arg_file * arg_filen(
1993 const char * shortopts,
1994 const char * longopts,
1995 const char *datatype,
1996 int mincount,
1997 int maxcount,
1998 const char *glossary)
1999 {
2000 size_t nbytes;
2001 struct arg_file *result;
2002
2003 /* foolproof things by ensuring maxcount is not less than mincount */
2004 maxcount = (maxcount < mincount) ? mincount : maxcount;
2005
2006 nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
2007 + sizeof(char *) * maxcount /* storage for filename[maxcount] array */
2008 + sizeof(char *) * maxcount /* storage for basename[maxcount] array */
2009 + sizeof(char *) * maxcount; /* storage for extension[maxcount] array */
2010
2011 result = (struct arg_file *)malloc(nbytes);
2012 if (result)
2013 {
2014 int i;
2015
2016 /* init the arg_hdr struct */
2017 result->hdr.flag = ARG_HASVALUE;
2018 result->hdr.shortopts = shortopts;
2019 result->hdr.longopts = longopts;
2020 result->hdr.glossary = glossary;
2021 result->hdr.datatype = datatype ? datatype : "<file>";
2022 result->hdr.mincount = mincount;
2023 result->hdr.maxcount = maxcount;
2024 result->hdr.parent = result;
2025 result->hdr.resetfn = (arg_resetfn *)arg_file_resetfn;
2026 result->hdr.scanfn = (arg_scanfn *)arg_file_scanfn;
2027 result->hdr.checkfn = (arg_checkfn *)arg_file_checkfn;
2028 result->hdr.errorfn = (arg_errorfn *)arg_file_errorfn;
2029
2030 /* store the filename,basename,extension arrays immediately after the arg_file struct */
2031 result->filename = (const char * *)(result + 1);
2032 result->basename = result->filename + maxcount;
2033 result->extension = result->basename + maxcount;
2034 result->count = 0;
2035
2036 /* foolproof the string pointers by initialising them with empty strings */
2037 for (i = 0; i < maxcount; i++)
2038 {
2039 result->filename[i] = "";
2040 result->basename[i] = "";
2041 result->extension[i] = "";
2042 }
2043 }
2044
2045 ARG_TRACE(("arg_filen() returns %p\n", result));
2046 return result;
2047 }
2048 /*******************************************************************************
2049 * This file is part of the argtable3 library.
2050 *
2051 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2052 * <sheitmann@users.sourceforge.net>
2053 * All rights reserved.
2054 *
2055 * Redistribution and use in source and binary forms, with or without
2056 * modification, are permitted provided that the following conditions are met:
2057 * * Redistributions of source code must retain the above copyright
2058 * notice, this list of conditions and the following disclaimer.
2059 * * Redistributions in binary form must reproduce the above copyright
2060 * notice, this list of conditions and the following disclaimer in the
2061 * documentation and/or other materials provided with the distribution.
2062 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2063 * may be used to endorse or promote products derived from this software
2064 * without specific prior written permission.
2065 *
2066 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2067 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2068 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2069 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2070 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2071 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2072 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2073 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2074 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2075 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2076 ******************************************************************************/
2077
2078 #include <stdlib.h>
2079 #include <limits.h>
2080 #include <ctype.h>
2081
2082 #include "argtable3.h"
2083
2084
2085 static void arg_int_resetfn(struct arg_int *parent)
2086 {
2087 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2088 parent->count = 0;
2089 }
2090
2091
2092 /* strtol0x() is like strtol() except that the numeric string is */
2093 /* expected to be prefixed by "0X" where X is a user supplied char. */
2094 /* The string may optionally be prefixed by white space and + or - */
2095 /* as in +0X123 or -0X123. */
2096 /* Once the prefix has been scanned, the remainder of the numeric */
2097 /* string is converted using strtol() with the given base. */
2098 /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
2099 /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
2100 /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
2101 /* Failure of conversion is indicated by result where *endptr==str. */
2102 static long int strtol0X(const char * str,
2103 const char * *endptr,
2104 char X,
2105 int base)
2106 {
2107 long int val; /* stores result */
2108 int s = 1; /* sign is +1 or -1 */
2109 const char *ptr = str; /* ptr to current position in str */
2110
2111 /* skip leading whitespace */
2112 while (ISSPACE(*ptr))
2113 ptr++;
2114 /* printf("1) %s\n",ptr); */
2115
2116 /* scan optional sign character */
2117 switch (*ptr)
2118 {
2119 case '+':
2120 ptr++;
2121 s = 1;
2122 break;
2123 case '-':
2124 ptr++;
2125 s = -1;
2126 break;
2127 default:
2128 s = 1;
2129 break;
2130 }
2131 /* printf("2) %s\n",ptr); */
2132
2133 /* '0X' prefix */
2134 if ((*ptr++) != '0')
2135 {
2136 /* printf("failed to detect '0'\n"); */
2137 *endptr = str;
2138 return 0;
2139 }
2140 /* printf("3) %s\n",ptr); */
2141 if (toupper(*ptr++) != toupper(X))
2142 {
2143 /* printf("failed to detect '%c'\n",X); */
2144 *endptr = str;
2145 return 0;
2146 }
2147 /* printf("4) %s\n",ptr); */
2148
2149 /* attempt conversion on remainder of string using strtol() */
2150 val = strtol(ptr, (char * *)endptr, base);
2151 if (*endptr == ptr)
2152 {
2153 /* conversion failed */
2154 *endptr = str;
2155 return 0;
2156 }
2157
2158 /* success */
2159 return s * val;
2160 }
2161
2162
2163 /* Returns 1 if str matches suffix (case insensitive). */
2164 /* Str may contain trailing whitespace, but nothing else. */
2165 static int detectsuffix(const char *str, const char *suffix)
2166 {
2167 /* scan pairwise through strings until mismatch detected */
2168 while( toupper(*str) == toupper(*suffix) )
2169 {
2170 /* printf("'%c' '%c'\n", *str, *suffix); */
2171
2172 /* return 1 (success) if match persists until the string terminator */
2173 if (*str == '\0')
2174 return 1;
2175
2176 /* next chars */
2177 str++;
2178 suffix++;
2179 }
2180 /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
2181
2182 /* return 0 (fail) if the matching did not consume the entire suffix */
2183 if (*suffix != 0)
2184 return 0; /* failed to consume entire suffix */
2185
2186 /* skip any remaining whitespace in str */
2187 while (ISSPACE(*str))
2188 str++;
2189
2190 /* return 1 (success) if we have reached end of str else return 0 (fail) */
2191 return (*str == '\0') ? 1 : 0;
2192 }
2193
2194
2195 static int arg_int_scanfn(struct arg_int *parent, const char *argval)
2196 {
2197 int errorcode = 0;
2198
2199 if (parent->count == parent->hdr.maxcount)
2200 {
2201 /* maximum number of arguments exceeded */
2202 errorcode = EMAXCOUNT;
2203 }
2204 else if (!argval)
2205 {
2206 /* a valid argument with no argument value was given. */
2207 /* This happens when an optional argument value was invoked. */
2208 /* leave parent arguiment value unaltered but still count the argument. */
2209 parent->count++;
2210 }
2211 else
2212 {
2213 long int val;
2214 const char *end;
2215
2216 /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
2217 val = strtol0X(argval, &end, 'X', 16);
2218 if (end == argval)
2219 {
2220 /* hex failed, attempt octal conversion (eg +0o123) */
2221 val = strtol0X(argval, &end, 'O', 8);
2222 if (end == argval)
2223 {
2224 /* octal failed, attempt binary conversion (eg +0B101) */
2225 val = strtol0X(argval, &end, 'B', 2);
2226 if (end == argval)
2227 {
2228 /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
2229 val = strtol(argval, (char * *)&end, 10);
2230 if (end == argval)
2231 {
2232 /* all supported number formats failed */
2233 return EBADINT;
2234 }
2235 }
2236 }
2237 }
2238
2239 /* Safety check for integer overflow. WARNING: this check */
2240 /* achieves nothing on machines where size(int)==size(long). */
2241 if ( val > INT_MAX || val < INT_MIN )
2242 #ifdef __STDC_WANT_SECURE_LIB__
2243 errorcode = EOVERFLOW_;
2244 #else
2245 errorcode = EOVERFLOW;
2246 #endif
2247
2248 /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
2249 /* We need to be mindful of integer overflows when using such big numbers. */
2250 if (detectsuffix(end, "KB")) /* kilobytes */
2251 {
2252 if ( val > (INT_MAX / 1024) || val < (INT_MIN / 1024) )
2253 #ifdef __STDC_WANT_SECURE_LIB__
2254 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2255 #else
2256 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2257 #endif
2258 else
2259 val *= 1024; /* 1KB = 1024 */
2260 }
2261 else if (detectsuffix(end, "MB")) /* megabytes */
2262 {
2263 if ( val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576) )
2264 #ifdef __STDC_WANT_SECURE_LIB__
2265 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2266 #else
2267 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2268 #endif
2269 else
2270 val *= 1048576; /* 1MB = 1024*1024 */
2271 }
2272 else if (detectsuffix(end, "GB")) /* gigabytes */
2273 {
2274 if ( val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824) )
2275 #ifdef __STDC_WANT_SECURE_LIB__
2276 errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
2277 #else
2278 errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
2279 #endif
2280 else
2281 val *= 1073741824; /* 1GB = 1024*1024*1024 */
2282 }
2283 else if (!detectsuffix(end, ""))
2284 errorcode = EBADINT; /* invalid suffix detected */
2285
2286 /* if success then store result in parent->ival[] array */
2287 if (errorcode == 0)
2288 parent->ival[parent->count++] = val;
2289 }
2290
2291 /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
2292 return errorcode;
2293 }
2294
2295
2296 static int arg_int_checkfn(struct arg_int *parent)
2297 {
2298 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2299 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2300 return errorcode;
2301 }
2302
2303
2304 static void arg_int_errorfn(
2305 struct arg_int *parent,
2306 FILE *fp,
2307 int errorcode,
2308 const char *argval,
2309 const char *progname)
2310 {
2311 const char *shortopts = parent->hdr.shortopts;
2312 const char *longopts = parent->hdr.longopts;
2313 const char *datatype = parent->hdr.datatype;
2314
2315 /* make argval NULL safe */
2316 argval = argval ? argval : "";
2317
2318 fprintf(fp, "%s: ", progname);
2319 switch(errorcode)
2320 {
2321 case EMINCOUNT:
2322 fputs("missing option ", fp);
2323 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2324 break;
2325
2326 case EMAXCOUNT:
2327 fputs("excess option ", fp);
2328 arg_print_option(fp, shortopts, longopts, argval, "\n");
2329 break;
2330
2331 case EBADINT:
2332 fprintf(fp, "invalid argument \"%s\" to option ", argval);
2333 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2334 break;
2335
2336 #ifdef __STDC_WANT_SECURE_LIB__
2337 case EOVERFLOW_:
2338 #else
2339 case EOVERFLOW:
2340 #endif
2341 fputs("integer overflow at option ", fp);
2342 arg_print_option(fp, shortopts, longopts, datatype, " ");
2343 fprintf(fp, "(%s is too large)\n", argval);
2344 break;
2345 }
2346 }
2347
2348
2349 struct arg_int * arg_int0(
2350 const char *shortopts,
2351 const char *longopts,
2352 const char *datatype,
2353 const char *glossary)
2354 {
2355 return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
2356 }
2357
2358
2359 struct arg_int * arg_int1(
2360 const char *shortopts,
2361 const char *longopts,
2362 const char *datatype,
2363 const char *glossary)
2364 {
2365 return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
2366 }
2367
2368
2369 struct arg_int * arg_intn(
2370 const char *shortopts,
2371 const char *longopts,
2372 const char *datatype,
2373 int mincount,
2374 int maxcount,
2375 const char *glossary)
2376 {
2377 size_t nbytes;
2378 struct arg_int *result;
2379
2380 /* foolproof things by ensuring maxcount is not less than mincount */
2381 maxcount = (maxcount < mincount) ? mincount : maxcount;
2382
2383 nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
2384 + maxcount * sizeof(int); /* storage for ival[maxcount] array */
2385
2386 result = (struct arg_int *)malloc(nbytes);
2387 if (result)
2388 {
2389 /* init the arg_hdr struct */
2390 result->hdr.flag = ARG_HASVALUE;
2391 result->hdr.shortopts = shortopts;
2392 result->hdr.longopts = longopts;
2393 result->hdr.datatype = datatype ? datatype : "<int>";
2394 result->hdr.glossary = glossary;
2395 result->hdr.mincount = mincount;
2396 result->hdr.maxcount = maxcount;
2397 result->hdr.parent = result;
2398 result->hdr.resetfn = (arg_resetfn *)arg_int_resetfn;
2399 result->hdr.scanfn = (arg_scanfn *)arg_int_scanfn;
2400 result->hdr.checkfn = (arg_checkfn *)arg_int_checkfn;
2401 result->hdr.errorfn = (arg_errorfn *)arg_int_errorfn;
2402
2403 /* store the ival[maxcount] array immediately after the arg_int struct */
2404 result->ival = (int *)(result + 1);
2405 result->count = 0;
2406 }
2407
2408 ARG_TRACE(("arg_intn() returns %p\n", result));
2409 return result;
2410 }
2411 /*******************************************************************************
2412 * This file is part of the argtable3 library.
2413 *
2414 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2415 * <sheitmann@users.sourceforge.net>
2416 * All rights reserved.
2417 *
2418 * Redistribution and use in source and binary forms, with or without
2419 * modification, are permitted provided that the following conditions are met:
2420 * * Redistributions of source code must retain the above copyright
2421 * notice, this list of conditions and the following disclaimer.
2422 * * Redistributions in binary form must reproduce the above copyright
2423 * notice, this list of conditions and the following disclaimer in the
2424 * documentation and/or other materials provided with the distribution.
2425 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2426 * may be used to endorse or promote products derived from this software
2427 * without specific prior written permission.
2428 *
2429 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2430 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2431 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2432 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2433 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2434 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2435 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2436 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2437 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2438 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2439 ******************************************************************************/
2440
2441 #include <stdlib.h>
2442
2443 #include "argtable3.h"
2444
2445
2446 static void arg_lit_resetfn(struct arg_lit *parent)
2447 {
2448 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2449 parent->count = 0;
2450 }
2451
2452
2453 static int arg_lit_scanfn(struct arg_lit *parent, const char *argval)
2454 {
2455 int errorcode = 0;
2456 if (parent->count < parent->hdr.maxcount )
2457 parent->count++;
2458 else
2459 errorcode = EMAXCOUNT;
2460
2461 ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval,
2462 errorcode));
2463 return errorcode;
2464 }
2465
2466
2467 static int arg_lit_checkfn(struct arg_lit *parent)
2468 {
2469 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2470 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
2471 return errorcode;
2472 }
2473
2474
2475 static void arg_lit_errorfn(
2476 struct arg_lit *parent,
2477 FILE *fp,
2478 int errorcode,
2479 const char *argval,
2480 const char *progname)
2481 {
2482 const char *shortopts = parent->hdr.shortopts;
2483 const char *longopts = parent->hdr.longopts;
2484 const char *datatype = parent->hdr.datatype;
2485
2486 switch(errorcode)
2487 {
2488 case EMINCOUNT:
2489 fprintf(fp, "%s: missing option ", progname);
2490 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2491 fprintf(fp, "\n");
2492 break;
2493
2494 case EMAXCOUNT:
2495 fprintf(fp, "%s: extraneous option ", progname);
2496 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2497 break;
2498 }
2499
2500 ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
2501 errorcode, argval, progname));
2502 }
2503
2504
2505 struct arg_lit * arg_lit0(
2506 const char * shortopts,
2507 const char * longopts,
2508 const char * glossary)
2509 {
2510 return arg_litn(shortopts, longopts, 0, 1, glossary);
2511 }
2512
2513
2514 struct arg_lit * arg_lit1(
2515 const char *shortopts,
2516 const char *longopts,
2517 const char *glossary)
2518 {
2519 return arg_litn(shortopts, longopts, 1, 1, glossary);
2520 }
2521
2522
2523 struct arg_lit * arg_litn(
2524 const char *shortopts,
2525 const char *longopts,
2526 int mincount,
2527 int maxcount,
2528 const char *glossary)
2529 {
2530 struct arg_lit *result;
2531
2532 /* foolproof things by ensuring maxcount is not less than mincount */
2533 maxcount = (maxcount < mincount) ? mincount : maxcount;
2534
2535 result = (struct arg_lit *)malloc(sizeof(struct arg_lit));
2536 if (result)
2537 {
2538 /* init the arg_hdr struct */
2539 result->hdr.flag = 0;
2540 result->hdr.shortopts = shortopts;
2541 result->hdr.longopts = longopts;
2542 result->hdr.datatype = NULL;
2543 result->hdr.glossary = glossary;
2544 result->hdr.mincount = mincount;
2545 result->hdr.maxcount = maxcount;
2546 result->hdr.parent = result;
2547 result->hdr.resetfn = (arg_resetfn *)arg_lit_resetfn;
2548 result->hdr.scanfn = (arg_scanfn *)arg_lit_scanfn;
2549 result->hdr.checkfn = (arg_checkfn *)arg_lit_checkfn;
2550 result->hdr.errorfn = (arg_errorfn *)arg_lit_errorfn;
2551
2552 /* init local variables */
2553 result->count = 0;
2554 }
2555
2556 ARG_TRACE(("arg_litn() returns %p\n", result));
2557 return result;
2558 }
2559 /*******************************************************************************
2560 * This file is part of the argtable3 library.
2561 *
2562 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2563 * <sheitmann@users.sourceforge.net>
2564 * All rights reserved.
2565 *
2566 * Redistribution and use in source and binary forms, with or without
2567 * modification, are permitted provided that the following conditions are met:
2568 * * Redistributions of source code must retain the above copyright
2569 * notice, this list of conditions and the following disclaimer.
2570 * * Redistributions in binary form must reproduce the above copyright
2571 * notice, this list of conditions and the following disclaimer in the
2572 * documentation and/or other materials provided with the distribution.
2573 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2574 * may be used to endorse or promote products derived from this software
2575 * without specific prior written permission.
2576 *
2577 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2578 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2579 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2580 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2581 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2582 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2583 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2584 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2585 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2586 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2587 ******************************************************************************/
2588
2589 #include <stdlib.h>
2590
2591 #include "argtable3.h"
2592
2593 struct arg_rem *arg_rem(const char *datatype, const char *glossary)
2594 {
2595 struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem));
2596 if (result)
2597 {
2598 result->hdr.flag = 0;
2599 result->hdr.shortopts = NULL;
2600 result->hdr.longopts = NULL;
2601 result->hdr.datatype = datatype;
2602 result->hdr.glossary = glossary;
2603 result->hdr.mincount = 1;
2604 result->hdr.maxcount = 1;
2605 result->hdr.parent = result;
2606 result->hdr.resetfn = NULL;
2607 result->hdr.scanfn = NULL;
2608 result->hdr.checkfn = NULL;
2609 result->hdr.errorfn = NULL;
2610 }
2611
2612 ARG_TRACE(("arg_rem() returns %p\n", result));
2613 return result;
2614 }
2615
2616 /*******************************************************************************
2617 * This file is part of the argtable3 library.
2618 *
2619 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
2620 * <sheitmann@users.sourceforge.net>
2621 * All rights reserved.
2622 *
2623 * Redistribution and use in source and binary forms, with or without
2624 * modification, are permitted provided that the following conditions are met:
2625 * * Redistributions of source code must retain the above copyright
2626 * notice, this list of conditions and the following disclaimer.
2627 * * Redistributions in binary form must reproduce the above copyright
2628 * notice, this list of conditions and the following disclaimer in the
2629 * documentation and/or other materials provided with the distribution.
2630 * * Neither the name of STEWART HEITMANN nor the names of its contributors
2631 * may be used to endorse or promote products derived from this software
2632 * without specific prior written permission.
2633 *
2634 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2635 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2636 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2637 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
2638 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2639 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2640 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2641 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2642 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2643 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2644 ******************************************************************************/
2645
2646 #include <stdlib.h>
2647 #include <string.h>
2648
2649 #include "argtable3.h"
2650
2651
2652 #ifndef _TREX_H_
2653 #define _TREX_H_
2654 /***************************************************************
2655 T-Rex a tiny regular expression library
2656
2657 Copyright (C) 2003-2006 Alberto Demichelis
2658
2659 This software is provided 'as-is', without any express
2660 or implied warranty. In no event will the authors be held
2661 liable for any damages arising from the use of this software.
2662
2663 Permission is granted to anyone to use this software for
2664 any purpose, including commercial applications, and to alter
2665 it and redistribute it freely, subject to the following restrictions:
2666
2667 1. The origin of this software must not be misrepresented;
2668 you must not claim that you wrote the original software.
2669 If you use this software in a product, an acknowledgment
2670 in the product documentation would be appreciated but
2671 is not required.
2672
2673 2. Altered source versions must be plainly marked as such,
2674 and must not be misrepresented as being the original software.
2675
2676 3. This notice may not be removed or altered from any
2677 source distribution.
2678
2679 ****************************************************************/
2680
2681 #ifdef __cplusplus
2682 extern "C" {
2683 #endif
2684
2685 #ifdef _UNICODE
2686 #define TRexChar unsigned short
2687 #define MAX_CHAR 0xFFFF
2688 #define _TREXC(c) L##c
2689 #define trex_strlen wcslen
2690 #define trex_printf wprintf
2691 #else
2692 #define TRexChar char
2693 #define MAX_CHAR 0xFF
2694 #define _TREXC(c) (c)
2695 #define trex_strlen strlen
2696 #define trex_printf printf
2697 #endif
2698
2699 #ifndef TREX_API
2700 #define TREX_API extern
2701 #endif
2702
2703 #define TRex_True 1
2704 #define TRex_False 0
2705
2706 #define TREX_ICASE ARG_REX_ICASE
2707
2708 typedef unsigned int TRexBool;
2709 typedef struct TRex TRex;
2710
2711 typedef struct {
2712 const TRexChar *begin;
2713 int len;
2714 } TRexMatch;
2715
2716 TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags);
2717 TREX_API void trex_free(TRex *exp);
2718 TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);
2719 TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
2720 TREX_API TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);
2721 TREX_API int trex_getsubexpcount(TRex* exp);
2722 TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
2723
2724 #ifdef __cplusplus
2725 }
2726 #endif
2727
2728 #endif
2729
2730
2731
2732 struct privhdr
2733 {
2734 const char *pattern;
2735 int flags;
2736 };
2737
2738
2739 static void arg_rex_resetfn(struct arg_rex *parent)
2740 {
2741 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
2742 parent->count = 0;
2743 }
2744
2745 static int arg_rex_scanfn(struct arg_rex *parent, const char *argval)
2746 {
2747 int errorcode = 0;
2748 const TRexChar *error = NULL;
2749 TRex *rex = NULL;
2750 TRexBool is_match = TRex_False;
2751
2752 if (parent->count == parent->hdr.maxcount )
2753 {
2754 /* maximum number of arguments exceeded */
2755 errorcode = EMAXCOUNT;
2756 }
2757 else if (!argval)
2758 {
2759 /* a valid argument with no argument value was given. */
2760 /* This happens when an optional argument value was invoked. */
2761 /* leave parent argument value unaltered but still count the argument. */
2762 parent->count++;
2763 }
2764 else
2765 {
2766 struct privhdr *priv = (struct privhdr *)parent->hdr.priv;
2767
2768 /* test the current argument value for a match with the regular expression */
2769 /* if a match is detected, record the argument value in the arg_rex struct */
2770
2771 rex = trex_compile(priv->pattern, &error, priv->flags);
2772 is_match = trex_match(rex, argval);
2773 if (!is_match)
2774 errorcode = EREGNOMATCH;
2775 else
2776 parent->sval[parent->count++] = argval;
2777
2778 trex_free(rex);
2779 }
2780
2781 ARG_TRACE(("%s:scanfn(%p) returns %d\n",__FILE__,parent,errorcode));
2782 return errorcode;
2783 }
2784
2785 static int arg_rex_checkfn(struct arg_rex *parent)
2786 {
2787 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
2788 //struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
2789
2790 /* free the regex "program" we constructed in resetfn */
2791 //regfree(&(priv->regex));
2792
2793 /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
2794 return errorcode;
2795 }
2796
2797 static void arg_rex_errorfn(struct arg_rex *parent,
2798 FILE *fp,
2799 int errorcode,
2800 const char *argval,
2801 const char *progname)
2802 {
2803 const char *shortopts = parent->hdr.shortopts;
2804 const char *longopts = parent->hdr.longopts;
2805 const char *datatype = parent->hdr.datatype;
2806
2807 /* make argval NULL safe */
2808 argval = argval ? argval : "";
2809
2810 fprintf(fp, "%s: ", progname);
2811 switch(errorcode)
2812 {
2813 case EMINCOUNT:
2814 fputs("missing option ", fp);
2815 arg_print_option(fp, shortopts, longopts, datatype, "\n");
2816 break;
2817
2818 case EMAXCOUNT:
2819 fputs("excess option ", fp);
2820 arg_print_option(fp, shortopts, longopts, argval, "\n");
2821 break;
2822
2823 case EREGNOMATCH:
2824 fputs("illegal value ", fp);
2825 arg_print_option(fp, shortopts, longopts, argval, "\n");
2826 break;
2827
2828 default:
2829 {
2830 //char errbuff[256];
2831 //regerror(errorcode, NULL, errbuff, sizeof(errbuff));
2832 //printf("%s\n", errbuff);
2833 }
2834 break;
2835 }
2836 }
2837
2838
2839 struct arg_rex * arg_rex0(const char * shortopts,
2840 const char * longopts,
2841 const char * pattern,
2842 const char *datatype,
2843 int flags,
2844 const char *glossary)
2845 {
2846 return arg_rexn(shortopts,
2847 longopts,
2848 pattern,
2849 datatype,
2850 0,
2851 1,
2852 flags,
2853 glossary);
2854 }
2855
2856 struct arg_rex * arg_rex1(const char * shortopts,
2857 const char * longopts,
2858 const char * pattern,
2859 const char *datatype,
2860 int flags,
2861 const char *glossary)
2862 {
2863 return arg_rexn(shortopts,
2864 longopts,
2865 pattern,
2866 datatype,
2867 1,
2868 1,
2869 flags,
2870 glossary);
2871 }
2872
2873
2874 struct arg_rex * arg_rexn(const char * shortopts,
2875 const char * longopts,
2876 const char * pattern,
2877 const char *datatype,
2878 int mincount,
2879 int maxcount,
2880 int flags,
2881 const char *glossary)
2882 {
2883 size_t nbytes;
2884 struct arg_rex *result;
2885 struct privhdr *priv;
2886 int i;
2887 const TRexChar *error = NULL;
2888 TRex *rex = NULL;
2889
2890 if (!pattern)
2891 {
2892 printf(
2893 "argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
2894 printf("argtable: Bad argument table.\n");
2895 return NULL;
2896 }
2897
2898 /* foolproof things by ensuring maxcount is not less than mincount */
2899 maxcount = (maxcount < mincount) ? mincount : maxcount;
2900
2901 nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */
2902 + sizeof(struct privhdr) /* storage for private arg_rex data */
2903 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
2904
2905 result = (struct arg_rex *)malloc(nbytes);
2906 if (result == NULL)
2907 return result;
2908
2909 /* init the arg_hdr struct */
2910 result->hdr.flag = ARG_HASVALUE;
2911 result->hdr.shortopts = shortopts;
2912 result->hdr.longopts = longopts;
2913 result->hdr.datatype = datatype ? datatype : pattern;
2914 result->hdr.glossary = glossary;
2915 result->hdr.mincount = mincount;
2916 result->hdr.maxcount = maxcount;
2917 result->hdr.parent = result;
2918 result->hdr.resetfn = (arg_resetfn *)arg_rex_resetfn;
2919 result->hdr.scanfn = (arg_scanfn *)arg_rex_scanfn;
2920 result->hdr.checkfn = (arg_checkfn *)arg_rex_checkfn;
2921 result->hdr.errorfn = (arg_errorfn *)arg_rex_errorfn;
2922
2923 /* store the arg_rex_priv struct immediately after the arg_rex struct */
2924 result->hdr.priv = result + 1;
2925 priv = (struct privhdr *)(result->hdr.priv);
2926 priv->pattern = pattern;
2927 priv->flags = flags;
2928
2929 /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
2930 result->sval = (const char * *)(priv + 1);
2931 result->count = 0;
2932
2933 /* foolproof the string pointers by initializing them to reference empty strings */
2934 for (i = 0; i < maxcount; i++)
2935 result->sval[i] = "";
2936
2937 /* here we construct and destroy a regex representation of the regular
2938 * expression for no other reason than to force any regex errors to be
2939 * trapped now rather than later. If we don't, then errors may go undetected
2940 * until an argument is actually parsed.
2941 */
2942
2943 rex = trex_compile(priv->pattern, &error, priv->flags);
2944 if (rex == NULL)
2945 {
2946 ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
2947 ARG_LOG(("argtable: Bad argument table.\n"));
2948 }
2949
2950 trex_free(rex);
2951
2952 ARG_TRACE(("arg_rexn() returns %p\n", result));
2953 return result;
2954 }
2955
2956
2957
2958 /* see copyright notice in trex.h */
2959 #include <string.h>
2960 #include <stdlib.h>
2961 #include <ctype.h>
2962 #include <setjmp.h>
2963
2964 #ifdef _UINCODE
2965 #define scisprint iswprint
2966 #define scstrlen wcslen
2967 #define scprintf wprintf
2968 #define _SC(x) L(x)
2969 #else
2970 #define scisprint isprint
2971 #define scstrlen strlen
2972 #define scprintf printf
2973 #define _SC(x) (x)
2974 #endif
2975
2976 #ifdef _DEBUG
2977 #include <stdio.h>
2978
2979 static const TRexChar *g_nnames[] =
2980 {
2981 _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
2982 _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
2983 _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
2984 _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
2985 };
2986
2987 #endif
2988 #define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
2989 #define OP_OR (MAX_CHAR+2)
2990 #define OP_EXPR (MAX_CHAR+3) //parentesis ()
2991 #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
2992 #define OP_DOT (MAX_CHAR+5)
2993 #define OP_CLASS (MAX_CHAR+6)
2994 #define OP_CCLASS (MAX_CHAR+7)
2995 #define OP_NCLASS (MAX_CHAR+8) //negates class the [^
2996 #define OP_RANGE (MAX_CHAR+9)
2997 #define OP_CHAR (MAX_CHAR+10)
2998 #define OP_EOL (MAX_CHAR+11)
2999 #define OP_BOL (MAX_CHAR+12)
3000 #define OP_WB (MAX_CHAR+13)
3001
3002 #define TREX_SYMBOL_ANY_CHAR ('.')
3003 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
3004 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
3005 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
3006 #define TREX_SYMBOL_BRANCH ('|')
3007 #define TREX_SYMBOL_END_OF_STRING ('$')
3008 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
3009 #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
3010
3011
3012 typedef int TRexNodeType;
3013
3014 typedef struct tagTRexNode{
3015 TRexNodeType type;
3016 int left;
3017 int right;
3018 int next;
3019 }TRexNode;
3020
3021 struct TRex{
3022 const TRexChar *_eol;
3023 const TRexChar *_bol;
3024 const TRexChar *_p;
3025 int _first;
3026 int _op;
3027 TRexNode *_nodes;
3028 int _nallocated;
3029 int _nsize;
3030 int _nsubexpr;
3031 TRexMatch *_matches;
3032 int _currsubexp;
3033 void *_jmpbuf;
3034 const TRexChar **_error;
3035 int _flags;
3036 };
3037
3038 static int trex_list(TRex *exp);
3039
3040 static int trex_newnode(TRex *exp, TRexNodeType type)
3041 {
3042 TRexNode n;
3043 int newid;
3044 n.type = type;
3045 n.next = n.right = n.left = -1;
3046 if(type == OP_EXPR)
3047 n.right = exp->_nsubexpr++;
3048 if(exp->_nallocated < (exp->_nsize + 1)) {
3049 exp->_nallocated *= 2;
3050 exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
3051 }
3052 exp->_nodes[exp->_nsize++] = n;
3053 newid = exp->_nsize - 1;
3054 return (int)newid;
3055 }
3056
3057 static void trex_error(TRex *exp,const TRexChar *error)
3058 {
3059 if(exp->_error) *exp->_error = error;
3060 longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
3061 }
3062
3063 static void trex_expect(TRex *exp, int n){
3064 if((*exp->_p) != n)
3065 trex_error(exp, _SC("expected paren"));
3066 exp->_p++;
3067 }
3068
3069 static TRexChar trex_escapechar(TRex *exp)
3070 {
3071 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
3072 exp->_p++;
3073 switch(*exp->_p) {
3074 case 'v': exp->_p++; return '\v';
3075 case 'n': exp->_p++; return '\n';
3076 case 't': exp->_p++; return '\t';
3077 case 'r': exp->_p++; return '\r';
3078 case 'f': exp->_p++; return '\f';
3079 default: return (*exp->_p++);
3080 }
3081 } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
3082 return (*exp->_p++);
3083 }
3084
3085 static int trex_charclass(TRex *exp,int classid)
3086 {
3087 int n = trex_newnode(exp,OP_CCLASS);
3088 exp->_nodes[n].left = classid;
3089 return n;
3090 }
3091
3092 static int trex_charnode(TRex *exp,TRexBool isclass)
3093 {
3094 TRexChar t;
3095 if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
3096 exp->_p++;
3097 switch(*exp->_p) {
3098 case 'n': exp->_p++; return trex_newnode(exp,'\n');
3099 case 't': exp->_p++; return trex_newnode(exp,'\t');
3100 case 'r': exp->_p++; return trex_newnode(exp,'\r');
3101 case 'f': exp->_p++; return trex_newnode(exp,'\f');
3102 case 'v': exp->_p++; return trex_newnode(exp,'\v');
3103 case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
3104 case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
3105 case 'p': case 'P': case 'l': case 'u':
3106 {
3107 t = *exp->_p; exp->_p++;
3108 return trex_charclass(exp,t);
3109 }
3110 case 'b':
3111 case 'B':
3112 if(!isclass) {
3113 int node = trex_newnode(exp,OP_WB);
3114 exp->_nodes[node].left = *exp->_p;
3115 exp->_p++;
3116 return node;
3117 } //else default
3118 default:
3119 t = *exp->_p; exp->_p++;
3120 return trex_newnode(exp,t);
3121 }
3122 }
3123 else if(!scisprint(*exp->_p)) {
3124
3125 trex_error(exp,_SC("letter expected"));
3126 }
3127 t = *exp->_p; exp->_p++;
3128 return trex_newnode(exp,t);
3129 }
3130 static int trex_class(TRex *exp)
3131 {
3132 int ret = -1;
3133 int first = -1,chain;
3134 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
3135 ret = trex_newnode(exp,OP_NCLASS);
3136 exp->_p++;
3137 }else ret = trex_newnode(exp,OP_CLASS);
3138
3139 if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
3140 chain = ret;
3141 while(*exp->_p != ']' && exp->_p != exp->_eol) {
3142 if(*exp->_p == '-' && first != -1){
3143 int r,t;
3144 if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
3145 r = trex_newnode(exp,OP_RANGE);
3146 if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
3147 if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
3148 exp->_nodes[r].left = exp->_nodes[first].type;
3149 t = trex_escapechar(exp);
3150 exp->_nodes[r].right = t;
3151 exp->_nodes[chain].next = r;
3152 chain = r;
3153 first = -1;
3154 }
3155 else{
3156 if(first!=-1){
3157 int c = first;
3158 exp->_nodes[chain].next = c;
3159 chain = c;
3160 first = trex_charnode(exp,TRex_True);
3161 }
3162 else{
3163 first = trex_charnode(exp,TRex_True);
3164 }
3165 }
3166 }
3167 if(first!=-1){
3168 int c = first;
3169 exp->_nodes[chain].next = c;
3170 chain = c;
3171 first = -1;
3172 }
3173 /* hack? */
3174 exp->_nodes[ret].left = exp->_nodes[ret].next;
3175 exp->_nodes[ret].next = -1;
3176 return ret;
3177 }
3178
3179 static int trex_parsenumber(TRex *exp)
3180 {
3181 int ret = *exp->_p-'0';
3182 int positions = 10;
3183 exp->_p++;
3184 while(isdigit(*exp->_p)) {
3185 ret = ret*10+(*exp->_p++-'0');
3186 if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
3187 positions *= 10;
3188 };
3189 return ret;
3190 }
3191
3192 static int trex_element(TRex *exp)
3193 {
3194 int ret = -1;
3195 switch(*exp->_p)
3196 {
3197 case '(': {
3198 int expr,newn;
3199 exp->_p++;
3200
3201
3202 if(*exp->_p =='?') {
3203 exp->_p++;
3204 trex_expect(exp,':');
3205 expr = trex_newnode(exp,OP_NOCAPEXPR);
3206 }
3207 else
3208 expr = trex_newnode(exp,OP_EXPR);
3209 newn = trex_list(exp);
3210 exp->_nodes[expr].left = newn;
3211 ret = expr;
3212 trex_expect(exp,')');
3213 }
3214 break;
3215 case '[':
3216 exp->_p++;
3217 ret = trex_class(exp);
3218 trex_expect(exp,']');
3219 break;
3220 case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
3221 case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
3222 default:
3223 ret = trex_charnode(exp,TRex_False);
3224 break;
3225 }
3226
3227 {
3228 TRexBool isgreedy = TRex_False;
3229 unsigned short p0 = 0, p1 = 0;
3230 switch(*exp->_p){
3231 case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3232 case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
3233 case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
3234 case '{':
3235 exp->_p++;
3236 if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
3237 p0 = (unsigned short)trex_parsenumber(exp);
3238 /*******************************/
3239 switch(*exp->_p) {
3240 case '}':
3241 p1 = p0; exp->_p++;
3242 break;
3243 case ',':
3244 exp->_p++;
3245 p1 = 0xFFFF;
3246 if(isdigit(*exp->_p)){
3247 p1 = (unsigned short)trex_parsenumber(exp);
3248 }
3249 trex_expect(exp,'}');
3250 break;
3251 default:
3252 trex_error(exp,_SC(", or } expected"));
3253 }
3254 /*******************************/
3255 isgreedy = TRex_True;
3256 break;
3257
3258 }
3259 if(isgreedy) {
3260 int nnode = trex_newnode(exp,OP_GREEDY);
3261 exp->_nodes[nnode].left = ret;
3262 exp->_nodes[nnode].right = ((p0)<<16)|p1;
3263 ret = nnode;
3264 }
3265 }
3266 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')) {
3267 int nnode = trex_element(exp);
3268 exp->_nodes[ret].next = nnode;
3269 }
3270
3271 return ret;
3272 }
3273
3274 static int trex_list(TRex *exp)
3275 {
3276 int ret=-1,e;
3277 if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
3278 exp->_p++;
3279 ret = trex_newnode(exp,OP_BOL);
3280 }
3281 e = trex_element(exp);
3282 if(ret != -1) {
3283 exp->_nodes[ret].next = e;
3284 }
3285 else ret = e;
3286
3287 if(*exp->_p == TREX_SYMBOL_BRANCH) {
3288 int temp,tright;
3289 exp->_p++;
3290 temp = trex_newnode(exp,OP_OR);
3291 exp->_nodes[temp].left = ret;
3292 tright = trex_list(exp);
3293 exp->_nodes[temp].right = tright;
3294 ret = temp;
3295 }
3296 return ret;
3297 }
3298
3299 static TRexBool trex_matchcclass(int cclass,TRexChar c)
3300 {
3301 switch(cclass) {
3302 case 'a': return isalpha(c)?TRex_True:TRex_False;
3303 case 'A': return !isalpha(c)?TRex_True:TRex_False;
3304 case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
3305 case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
3306 case 's': return ISSPACE(c)?TRex_True:TRex_False;
3307 case 'S': return !ISSPACE(c)?TRex_True:TRex_False;
3308 case 'd': return isdigit(c)?TRex_True:TRex_False;
3309 case 'D': return !isdigit(c)?TRex_True:TRex_False;
3310 case 'x': return isxdigit(c)?TRex_True:TRex_False;
3311 case 'X': return !isxdigit(c)?TRex_True:TRex_False;
3312 case 'c': return iscntrl(c)?TRex_True:TRex_False;
3313 case 'C': return !iscntrl(c)?TRex_True:TRex_False;
3314 case 'p': return ispunct(c)?TRex_True:TRex_False;
3315 case 'P': return !ispunct(c)?TRex_True:TRex_False;
3316 case 'l': return islower(c)?TRex_True:TRex_False;
3317 case 'u': return isupper(c)?TRex_True:TRex_False;
3318 }
3319 return TRex_False; /*cannot happen*/
3320 }
3321
3322 static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
3323 {
3324 do {
3325 switch(node->type) {
3326 case OP_RANGE:
3327 if (exp->_flags & TREX_ICASE)
3328 {
3329 if(c >= toupper(node->left) && c <= toupper(node->right)) return TRex_True;
3330 if(c >= tolower(node->left) && c <= tolower(node->right)) return TRex_True;
3331 }
3332 else
3333 {
3334 if(c >= node->left && c <= node->right) return TRex_True;
3335 }
3336 break;
3337 case OP_CCLASS:
3338 if(trex_matchcclass(node->left,c)) return TRex_True;
3339 break;
3340 default:
3341 if (exp->_flags & TREX_ICASE)
3342 {
3343 if (c == tolower(node->type) || c == toupper(node->type)) return TRex_True;
3344 }
3345 else
3346 {
3347 if(c == node->type)return TRex_True;
3348 }
3349
3350 }
3351 } while((node->next != -1) && (node = &exp->_nodes[node->next]));
3352 return TRex_False;
3353 }
3354
3355 static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
3356 {
3357
3358 TRexNodeType type = node->type;
3359 switch(type) {
3360 case OP_GREEDY: {
3361 //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
3362 TRexNode *greedystop = NULL;
3363 int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
3364 const TRexChar *s=str, *good = str;
3365
3366 if(node->next != -1) {
3367 greedystop = &exp->_nodes[node->next];
3368 }
3369 else {
3370 greedystop = next;
3371 }
3372
3373 while((nmaches == 0xFFFF || nmaches < p1)) {
3374
3375 const TRexChar *stop;
3376 if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
3377 break;
3378 nmaches++;
3379 good=s;
3380 if(greedystop) {
3381 //checks that 0 matches satisfy the expression(if so skips)
3382 //if not would always stop(for instance if is a '?')
3383 if(greedystop->type != OP_GREEDY ||
3384 (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
3385 {
3386 TRexNode *gnext = NULL;
3387 if(greedystop->next != -1) {
3388 gnext = &exp->_nodes[greedystop->next];
3389 }else if(next && next->next != -1){
3390 gnext = &exp->_nodes[next->next];
3391 }
3392 stop = trex_matchnode(exp,greedystop,s,gnext);
3393 if(stop) {
3394 //if satisfied stop it
3395 if(p0 == p1 && p0 == nmaches) break;
3396 else if(nmaches >= p0 && p1 == 0xFFFF) break;
3397 else if(nmaches >= p0 && nmaches <= p1) break;
3398 }
3399 }
3400 }
3401
3402 if(s >= exp->_eol)
3403 break;
3404 }
3405 if(p0 == p1 && p0 == nmaches) return good;
3406 else if(nmaches >= p0 && p1 == 0xFFFF) return good;
3407 else if(nmaches >= p0 && nmaches <= p1) return good;
3408 return NULL;
3409 }
3410 case OP_OR: {
3411 const TRexChar *asd = str;
3412 TRexNode *temp=&exp->_nodes[node->left];
3413 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3414 if(temp->next != -1)
3415 temp = &exp->_nodes[temp->next];
3416 else
3417 return asd;
3418 }
3419 asd = str;
3420 temp = &exp->_nodes[node->right];
3421 while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
3422 if(temp->next != -1)
3423 temp = &exp->_nodes[temp->next];
3424 else
3425 return asd;
3426 }
3427 return NULL;
3428 break;
3429 }
3430 case OP_EXPR:
3431 case OP_NOCAPEXPR:{
3432 TRexNode *n = &exp->_nodes[node->left];
3433 const TRexChar *cur = str;
3434 int capture = -1;
3435 if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
3436 capture = exp->_currsubexp;
3437 exp->_matches[capture].begin = cur;
3438 exp->_currsubexp++;
3439 }
3440
3441 do {
3442 TRexNode *subnext = NULL;
3443 if(n->next != -1) {
3444 subnext = &exp->_nodes[n->next];
3445 }else {
3446 subnext = next;
3447 }
3448 if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
3449 if(capture != -1){
3450 exp->_matches[capture].begin = 0;
3451 exp->_matches[capture].len = 0;
3452 }
3453 return NULL;
3454 }
3455 } while((n->next != -1) && (n = &exp->_nodes[n->next]));
3456
3457 if(capture != -1)
3458 exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin);
3459 return cur;
3460 }
3461 case OP_WB:
3462 if((str == exp->_bol && !ISSPACE(*str))
3463 || ((str == exp->_eol && !ISSPACE(*(str-1))))
3464 || ((!ISSPACE(*str) && ISSPACE(*(str+1))))
3465 || ((ISSPACE(*str) && !ISSPACE(*(str+1)))) ) {
3466 return (node->left == 'b')?str:NULL;
3467 }
3468 return (node->left == 'b')?NULL:str;
3469 case OP_BOL:
3470 if(str == exp->_bol) return str;
3471 return NULL;
3472 case OP_EOL:
3473 if(str == exp->_eol) return str;
3474 return NULL;
3475 case OP_DOT:
3476 str++;
3477 return str;
3478 case OP_NCLASS:
3479 case OP_CLASS:
3480 if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
3481 str++;
3482 return str;
3483 }
3484 return NULL;
3485 case OP_CCLASS:
3486 if(trex_matchcclass(node->left,*str)) {
3487 str++;
3488 return str;
3489 }
3490 return NULL;
3491 default: /* char */
3492 if (exp->_flags & TREX_ICASE)
3493 {
3494 if(*str != tolower(node->type) && *str != toupper(node->type)) return NULL;
3495 }
3496 else
3497 {
3498 if (*str != node->type) return NULL;
3499 }
3500 str++;
3501 return str;
3502 }
3503 return NULL;
3504 }
3505
3506 /* public api */
3507 TRex *trex_compile(const TRexChar *pattern,const TRexChar **error,int flags)
3508 {
3509 TRex *exp = (TRex *)malloc(sizeof(TRex));
3510 exp->_eol = exp->_bol = NULL;
3511 exp->_p = pattern;
3512 exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
3513 exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
3514 exp->_nsize = 0;
3515 exp->_matches = 0;
3516 exp->_nsubexpr = 0;
3517 exp->_first = trex_newnode(exp,OP_EXPR);
3518 exp->_error = error;
3519 exp->_jmpbuf = malloc(sizeof(jmp_buf));
3520 exp->_flags = flags;
3521 if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
3522 int res = trex_list(exp);
3523 exp->_nodes[exp->_first].left = res;
3524 if(*exp->_p!='\0')
3525 trex_error(