]> cvs.zerfleddert.de Git - proxmark3-svn/blob - client/cliparser/argtable3.c
Fix format-truncation warning, missing string.h inclusion and strnlen warning (#723)
[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(exp,_SC("unexpected character"));
3526 #ifdef _DEBUG
3527 {
3528 int nsize,i;
3529 TRexNode *t;
3530 nsize = exp->_nsize;
3531 t = &exp->_nodes[0];
3532 scprintf(_SC("\n"));
3533 for(i = 0;i < nsize; i++) {
3534 if(exp->_nodes[i].type>MAX_CHAR)
3535 scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
3536 else
3537 scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
3538 scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
3539 }
3540 scprintf(_SC("\n"));
3541 }
3542 #endif
3543 exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
3544 memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
3545 }
3546 else{
3547 trex_free(exp);
3548 return NULL;
3549 }
3550 return exp;
3551 }
3552
3553 void trex_free(TRex *exp)
3554 {
3555 if(exp) {
3556 if(exp->_nodes) free(exp->_nodes);
3557 if(exp->_jmpbuf) free(exp->_jmpbuf);
3558 if(exp->_matches) free(exp->_matches);
3559 free(exp);
3560 }
3561 }
3562
3563 TRexBool trex_match(TRex* exp,const TRexChar* text)
3564 {
3565 const TRexChar* res = NULL;
3566 exp->_bol = text;
3567 exp->_eol = text + scstrlen(text);
3568 exp->_currsubexp = 0;
3569 res = trex_matchnode(exp,exp->_nodes,text,NULL);
3570 if(res == NULL || res != exp->_eol)
3571 return TRex_False;
3572 return TRex_True;
3573 }
3574
3575 TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
3576 {
3577 const TRexChar *cur = NULL;
3578 int node = exp->_first;
3579 if(text_begin >= text_end) return TRex_False;
3580 exp->_bol = text_begin;
3581 exp->_eol = text_end;
3582 do {
3583 cur = text_begin;
3584 while(node != -1) {
3585 exp->_currsubexp = 0;
3586 cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
3587 if(!cur)
3588 break;
3589 node = exp->_nodes[node].next;
3590 }
3591 text_begin++;
3592 } while(cur == NULL && text_begin != text_end);
3593
3594 if(cur == NULL)
3595 return TRex_False;
3596
3597 --text_begin;
3598
3599 if(out_begin) *out_begin = text_begin;
3600 if(out_end) *out_end = cur;
3601 return TRex_True;
3602 }
3603
3604 TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
3605 {
3606 return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
3607 }
3608
3609 int trex_getsubexpcount(TRex* exp)
3610 {
3611 return exp->_nsubexpr;
3612 }
3613
3614 TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
3615 {
3616 if( n<0 || n >= exp->_nsubexpr) return TRex_False;
3617 *subexp = exp->_matches[n];
3618 return TRex_True;
3619 }
3620 /*******************************************************************************
3621 * This file is part of the argtable3 library.
3622 *
3623 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3624 * <sheitmann@users.sourceforge.net>
3625 * All rights reserved.
3626 *
3627 * Redistribution and use in source and binary forms, with or without
3628 * modification, are permitted provided that the following conditions are met:
3629 * * Redistributions of source code must retain the above copyright
3630 * notice, this list of conditions and the following disclaimer.
3631 * * Redistributions in binary form must reproduce the above copyright
3632 * notice, this list of conditions and the following disclaimer in the
3633 * documentation and/or other materials provided with the distribution.
3634 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3635 * may be used to endorse or promote products derived from this software
3636 * without specific prior written permission.
3637 *
3638 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3639 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3640 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3641 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3642 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3643 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3644 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3645 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3646 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3647 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3648 ******************************************************************************/
3649
3650 #include <stdlib.h>
3651
3652 #include "argtable3.h"
3653
3654
3655 static void arg_str_resetfn(struct arg_str *parent)
3656 {
3657 ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
3658 parent->count = 0;
3659 }
3660
3661
3662 static int arg_str_scanfn(struct arg_str *parent, const char *argval)
3663 {
3664 int errorcode = 0;
3665
3666 if (parent->count == parent->hdr.maxcount)
3667 {
3668 /* maximum number of arguments exceeded */
3669 errorcode = EMAXCOUNT;
3670 }
3671 else if (!argval)
3672 {
3673 /* a valid argument with no argument value was given. */
3674 /* This happens when an optional argument value was invoked. */
3675 /* leave parent arguiment value unaltered but still count the argument. */
3676 parent->count++;
3677 }
3678 else
3679 {
3680 parent->sval[parent->count++] = argval;
3681 }
3682
3683 ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
3684 return errorcode;
3685 }
3686
3687
3688 static int arg_str_checkfn(struct arg_str *parent)
3689 {
3690 int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
3691
3692 ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
3693 return errorcode;
3694 }
3695
3696
3697 static void arg_str_errorfn(
3698 struct arg_str *parent,
3699 FILE *fp,
3700 int errorcode,
3701 const char *argval,
3702 const char *progname)
3703 {
3704 const char *shortopts = parent->hdr.shortopts;
3705 const char *longopts = parent->hdr.longopts;
3706 const char *datatype = parent->hdr.datatype;
3707
3708 /* make argval NULL safe */
3709 argval = argval ? argval : "";
3710
3711 fprintf(fp, "%s: ", progname);
3712 switch(errorcode)
3713 {
3714 case EMINCOUNT:
3715 fputs("missing option ", fp);
3716 arg_print_option(fp, shortopts, longopts, datatype, "\n");
3717 break;
3718
3719 case EMAXCOUNT:
3720 fputs("excess option ", fp);
3721 arg_print_option(fp, shortopts, longopts, argval, "\n");
3722 break;
3723 }
3724 }
3725
3726
3727 struct arg_str * arg_str0(
3728 const char *shortopts,
3729 const char *longopts,
3730 const char *datatype,
3731 const char *glossary)
3732 {
3733 return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
3734 }
3735
3736
3737 struct arg_str * arg_str1(
3738 const char *shortopts,
3739 const char *longopts,
3740 const char *datatype,
3741 const char *glossary)
3742 {
3743 return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
3744 }
3745
3746
3747 struct arg_str * arg_strn(
3748 const char *shortopts,
3749 const char *longopts,
3750 const char *datatype,
3751 int mincount,
3752 int maxcount,
3753 const char *glossary)
3754 {
3755 size_t nbytes;
3756 struct arg_str *result;
3757
3758 /* should not allow this stupid error */
3759 /* we should return an error code warning this logic error */
3760 /* foolproof things by ensuring maxcount is not less than mincount */
3761 maxcount = (maxcount < mincount) ? mincount : maxcount;
3762
3763 nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
3764 + maxcount * sizeof(char *); /* storage for sval[maxcount] array */
3765
3766 result = (struct arg_str *)malloc(nbytes);
3767 if (result)
3768 {
3769 int i;
3770
3771 /* init the arg_hdr struct */
3772 result->hdr.flag = ARG_HASVALUE;
3773 result->hdr.shortopts = shortopts;
3774 result->hdr.longopts = longopts;
3775 result->hdr.datatype = datatype ? datatype : "<string>";
3776 result->hdr.glossary = glossary;
3777 result->hdr.mincount = mincount;
3778 result->hdr.maxcount = maxcount;
3779 result->hdr.parent = result;
3780 result->hdr.resetfn = (arg_resetfn *)arg_str_resetfn;
3781 result->hdr.scanfn = (arg_scanfn *)arg_str_scanfn;
3782 result->hdr.checkfn = (arg_checkfn *)arg_str_checkfn;
3783 result->hdr.errorfn = (arg_errorfn *)arg_str_errorfn;
3784
3785 /* store the sval[maxcount] array immediately after the arg_str struct */
3786 result->sval = (const char * *)(result + 1);
3787 result->count = 0;
3788
3789 /* foolproof the string pointers by initialising them to reference empty strings */
3790 for (i = 0; i < maxcount; i++)
3791 result->sval[i] = "";
3792 }
3793
3794 ARG_TRACE(("arg_strn() returns %p\n", result));
3795 return result;
3796 }
3797 /*******************************************************************************
3798 * This file is part of the argtable3 library.
3799 *
3800 * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
3801 * <sheitmann@users.sourceforge.net>
3802 * All rights reserved.
3803 *
3804 * Redistribution and use in source and binary forms, with or without
3805 * modification, are permitted provided that the following conditions are met:
3806 * * Redistributions of source code must retain the above copyright
3807 * notice, this list of conditions and the following disclaimer.
3808 * * Redistributions in binary form must reproduce the above copyright
3809 * notice, this list of conditions and the following disclaimer in the
3810 * documentation and/or other materials provided with the distribution.
3811 * * Neither the name of STEWART HEITMANN nor the names of its contributors
3812 * may be used to endorse or promote products derived from this software
3813 * without specific prior written permission.
3814 *
3815 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3816 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3817 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3818 * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
3819 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3820 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3821 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3822 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3823 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3824 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3825 ******************************************************************************/
3826
3827 #include <stdlib.h>
3828 #include <string.h>
3829 #include <stdlib.h>
3830 #include <ctype.h>
3831
3832 #include "argtable3.h"
3833
3834 static
3835 void arg_register_error(struct arg_end *end,
3836 void *parent,
3837 int error,
3838 const char *argval)
3839 {
3840 /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
3841 if (end->count < end->hdr.maxcount)
3842 {
3843 end->error[end->count] = error;
3844 end->parent[end->count] = parent;
3845 end->argval[end->count] = argval;
3846 end->count++;
3847 }
3848 else
3849 {
3850 end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;
3851 end->parent[end->hdr.maxcount - 1] = end;
3852 end->argval[end->hdr.maxcount - 1] = NULL;
3853 }
3854 }
3855
3856
3857 /*
3858 * Return index of first table entry with a matching short option
3859 * or -1 if no match was found.
3860 */
3861 static
3862 int find_shortoption(struct arg_hdr * *table, char shortopt)
3863 {
3864 int tabindex;
3865 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3866 {
3867 if (table[tabindex]->shortopts &&
3868 strchr(table[tabindex]->shortopts, shortopt))
3869 return tabindex;
3870 }
3871 return -1;
3872 }
3873
3874
3875 struct longoptions
3876 {
3877 int getoptval;
3878 int noptions;
3879 struct option *options;
3880 };
3881
3882 #if 0
3883 static
3884 void dump_longoptions(struct longoptions * longoptions)
3885 {
3886 int i;
3887 printf("getoptval = %d\n", longoptions->getoptval);
3888 printf("noptions = %d\n", longoptions->noptions);
3889 for (i = 0; i < longoptions->noptions; i++)
3890 {
3891 printf("options[%d].name = \"%s\"\n",
3892 i,
3893 longoptions->options[i].name);
3894 printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);
3895 printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);
3896 printf("options[%d].val = %d\n", i, longoptions->options[i].val);
3897 }
3898 }
3899 #endif
3900
3901 static
3902 struct longoptions * alloc_longoptions(struct arg_hdr * *table)
3903 {
3904 struct longoptions *result;
3905 size_t nbytes;
3906 int noptions = 1;
3907 size_t longoptlen = 0;
3908 int tabindex;
3909
3910 /*
3911 * Determine the total number of option structs required
3912 * by counting the number of comma separated long options
3913 * in all table entries and return the count in noptions.
3914 * note: noptions starts at 1 not 0 because we getoptlong
3915 * requires a NULL option entry to terminate the option array.
3916 * While we are at it, count the number of chars required
3917 * to store private copies of all the longoption strings
3918 * and return that count in logoptlen.
3919 */
3920 tabindex = 0;
3921 do
3922 {
3923 const char *longopts = table[tabindex]->longopts;
3924 longoptlen += (longopts ? strlen(longopts) : 0) + 1;
3925 while (longopts)
3926 {
3927 noptions++;
3928 longopts = strchr(longopts + 1, ',');
3929 }
3930 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
3931 /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
3932
3933
3934 /* allocate storage for return data structure as: */
3935 /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
3936 nbytes = sizeof(struct longoptions)
3937 + sizeof(struct option) * noptions
3938 + longoptlen;
3939 result = (struct longoptions *)malloc(nbytes);
3940 if (result)
3941 {
3942 int option_index = 0;
3943 char *store;
3944
3945 result->getoptval = 0;
3946 result->noptions = noptions;
3947 result->options = (struct option *)(result + 1);
3948 store = (char *)(result->options + noptions);
3949
3950 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3951 {
3952 const char *longopts = table[tabindex]->longopts;
3953
3954 while(longopts && *longopts)
3955 {
3956 char *storestart = store;
3957
3958 /* copy progressive longopt strings into the store */
3959 while (*longopts != 0 && *longopts != ',')
3960 *store++ = *longopts++;
3961 *store++ = 0;
3962 if (*longopts == ',')
3963 longopts++;
3964 /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
3965
3966 result->options[option_index].name = storestart;
3967 result->options[option_index].flag = &(result->getoptval);
3968 result->options[option_index].val = tabindex;
3969 if (table[tabindex]->flag & ARG_HASOPTVALUE)
3970 result->options[option_index].has_arg = 2;
3971 else if (table[tabindex]->flag & ARG_HASVALUE)
3972 result->options[option_index].has_arg = 1;
3973 else
3974 result->options[option_index].has_arg = 0;
3975
3976 option_index++;
3977 }
3978 }
3979 /* terminate the options array with a zero-filled entry */
3980 result->options[option_index].name = 0;
3981 result->options[option_index].has_arg = 0;
3982 result->options[option_index].flag = 0;
3983 result->options[option_index].val = 0;
3984 }
3985
3986 /*dump_longoptions(result);*/
3987 return result;
3988 }
3989
3990 static
3991 char * alloc_shortoptions(struct arg_hdr * *table)
3992 {
3993 char *result;
3994 size_t len = 2;
3995 int tabindex;
3996
3997 /* determine the total number of option chars required */
3998 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
3999 {
4000 struct arg_hdr *hdr = table[tabindex];
4001 len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);
4002 }
4003
4004 result = malloc(len);
4005 if (result)
4006 {
4007 char *res = result;
4008
4009 /* add a leading ':' so getopt return codes distinguish */
4010 /* unrecognised option and options missing argument values */
4011 *res++ = ':';
4012
4013 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4014 {
4015 struct arg_hdr *hdr = table[tabindex];
4016 const char *shortopts = hdr->shortopts;
4017 while(shortopts && *shortopts)
4018 {
4019 *res++ = *shortopts++;
4020 if (hdr->flag & ARG_HASVALUE)
4021 *res++ = ':';
4022 if (hdr->flag & ARG_HASOPTVALUE)
4023 *res++ = ':';
4024 }
4025 }
4026 /* null terminate the string */
4027 *res = 0;
4028 }
4029
4030 /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
4031 return result;
4032 }
4033
4034
4035 /* return index of the table terminator entry */
4036 static
4037 int arg_endindex(struct arg_hdr * *table)
4038 {
4039 int tabindex = 0;
4040 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4041 tabindex++;
4042 return tabindex;
4043 }
4044
4045
4046 static
4047 void arg_parse_tagged(int argc,
4048 char * *argv,
4049 struct arg_hdr * *table,
4050 struct arg_end *endtable)
4051 {
4052 struct longoptions *longoptions;
4053 char *shortoptions;
4054 int copt;
4055
4056 /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4057
4058 /* allocate short and long option arrays for the given opttable[]. */
4059 /* if the allocs fail then put an error msg in the last table entry. */
4060 longoptions = alloc_longoptions(table);
4061 shortoptions = alloc_shortoptions(table);
4062 if (!longoptions || !shortoptions)
4063 {
4064 /* one or both memory allocs failed */
4065 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4066 /* free anything that was allocated (this is null safe) */
4067 free(shortoptions);
4068 free(longoptions);
4069 return;
4070 }
4071
4072 /*dump_longoptions(longoptions);*/
4073
4074 /* reset getopts internal option-index to zero, and disable error reporting */
4075 optind = 0;
4076 opterr = 0;
4077
4078 /* fetch and process args using getopt_long */
4079 while( (copt =
4080 getopt_long(argc, argv, shortoptions, longoptions->options,
4081 NULL)) != -1)
4082 {
4083 /*
4084 printf("optarg='%s'\n",optarg);
4085 printf("optind=%d\n",optind);
4086 printf("copt=%c\n",(char)copt);
4087 printf("optopt=%c (%d)\n",optopt, (int)(optopt));
4088 */
4089 switch(copt)
4090 {
4091 case 0:
4092 {
4093 int tabindex = longoptions->getoptval;
4094 void *parent = table[tabindex]->parent;
4095 /*printf("long option detected from argtable[%d]\n", tabindex);*/
4096 if (optarg && optarg[0] == 0 &&
4097 (table[tabindex]->flag & ARG_HASVALUE))
4098 {
4099 /* printf(": long option %s requires an argument\n",argv[optind-1]); */
4100 arg_register_error(endtable, endtable, ARG_EMISSARG,
4101 argv[optind - 1]);
4102 /* continue to scan the (empty) argument value to enforce argument count checking */
4103 }
4104 if (table[tabindex]->scanfn)
4105 {
4106 int errorcode = table[tabindex]->scanfn(parent, optarg);
4107 if (errorcode != 0)
4108 arg_register_error(endtable, parent, errorcode, optarg);
4109 }
4110 }
4111 break;
4112
4113 case '?':
4114 /*
4115 * getopt_long() found an unrecognised short option.
4116 * if it was a short option its value is in optopt
4117 * if it was a long option then optopt=0
4118 */
4119 switch (optopt)
4120 {
4121 case 0:
4122 /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
4123 arg_register_error(endtable, endtable, ARG_ELONGOPT,
4124 argv[optind - 1]);
4125 break;
4126 default:
4127 /*printf("?* unrecognised short option '%c'\n",optopt);*/
4128 arg_register_error(endtable, endtable, optopt, NULL);
4129 break;
4130 }
4131 break;
4132
4133 case ':':
4134 /*
4135 * getopt_long() found an option with its argument missing.
4136 */
4137 /*printf(": option %s requires an argument\n",argv[optind-1]); */
4138 arg_register_error(endtable, endtable, ARG_EMISSARG,
4139 argv[optind - 1]);
4140 break;
4141
4142 default:
4143 {
4144 /* getopt_long() found a valid short option */
4145 int tabindex = find_shortoption(table, (char)copt);
4146 /*printf("short option detected from argtable[%d]\n", tabindex);*/
4147 if (tabindex == -1)
4148 {
4149 /* should never get here - but handle it just in case */
4150 /*printf("unrecognised short option %d\n",copt);*/
4151 arg_register_error(endtable, endtable, copt, NULL);
4152 }
4153 else
4154 {
4155 if (table[tabindex]->scanfn)
4156 {
4157 void *parent = table[tabindex]->parent;
4158 int errorcode = table[tabindex]->scanfn(parent, optarg);
4159 if (errorcode != 0)
4160 arg_register_error(endtable, parent, errorcode, optarg);
4161 }
4162 }
4163 break;
4164 }
4165 }
4166 }
4167
4168 free(shortoptions);
4169 free(longoptions);
4170 }
4171
4172
4173 static
4174 void arg_parse_untagged(int argc,
4175 char * *argv,
4176 struct arg_hdr * *table,
4177 struct arg_end *endtable)
4178 {
4179 int tabindex = 0;
4180 int errorlast = 0;
4181 const char *optarglast = NULL;
4182 void *parentlast = NULL;
4183
4184 /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
4185 while (!(table[tabindex]->flag & ARG_TERMINATOR))
4186 {
4187 void *parent;
4188 int errorcode;
4189
4190 /* if we have exhausted our argv[optind] entries then we have finished */
4191 if (optind >= argc)
4192 {
4193 /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
4194 return;
4195 }
4196
4197 /* skip table entries with non-null long or short options (they are not untagged entries) */
4198 if (table[tabindex]->longopts || table[tabindex]->shortopts)
4199 {
4200 /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
4201 tabindex++;
4202 continue;
4203 }
4204
4205 /* skip table entries with NULL scanfn */
4206 if (!(table[tabindex]->scanfn))
4207 {
4208 /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
4209 tabindex++;
4210 continue;
4211 }
4212
4213 /* attempt to scan the current argv[optind] with the current */
4214 /* table[tabindex] entry. If it succeeds then keep it, otherwise */
4215 /* try again with the next table[] entry. */
4216 parent = table[tabindex]->parent;
4217 errorcode = table[tabindex]->scanfn(parent, argv[optind]);
4218 if (errorcode == 0)
4219 {
4220 /* success, move onto next argv[optind] but stay with same table[tabindex] */
4221 /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
4222 optind++;
4223
4224 /* clear the last tentative error */
4225 errorlast = 0;
4226 }
4227 else
4228 {
4229 /* failure, try same argv[optind] with next table[tabindex] entry */
4230 /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
4231 tabindex++;
4232
4233 /* remember this as a tentative error we may wish to reinstate later */
4234 errorlast = errorcode;
4235 optarglast = argv[optind];
4236 parentlast = parent;
4237 }
4238
4239 }
4240
4241 /* if a tenative error still remains at this point then register it as a proper error */
4242 if (errorlast)
4243 {
4244 arg_register_error(endtable, parentlast, errorlast, optarglast);
4245 optind++;
4246 }
4247
4248 /* only get here when not all argv[] entries were consumed */
4249 /* register an error for each unused argv[] entry */
4250 while (optind < argc)
4251 {
4252 /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
4253 arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
4254 }
4255
4256 return;
4257 }
4258
4259
4260 static
4261 void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable)
4262 {
4263 int tabindex = 0;
4264 /* printf("arg_parse_check()\n"); */
4265 do
4266 {
4267 if (table[tabindex]->checkfn)
4268 {
4269 void *parent = table[tabindex]->parent;
4270 int errorcode = table[tabindex]->checkfn(parent);
4271 if (errorcode != 0)
4272 arg_register_error(endtable, parent, errorcode, NULL);
4273 }
4274 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4275 }
4276
4277
4278 static
4279 void arg_reset(void * *argtable)
4280 {
4281 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4282 int tabindex = 0;
4283 /*printf("arg_reset(%p)\n",argtable);*/
4284 do
4285 {
4286 if (table[tabindex]->resetfn)
4287 table[tabindex]->resetfn(table[tabindex]->parent);
4288 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4289 }
4290
4291
4292 int arg_parse(int argc, char * *argv, void * *argtable)
4293 {
4294 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4295 struct arg_end *endtable;
4296 int endindex;
4297 char * *argvcopy = NULL;
4298
4299 /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
4300
4301 /* reset any argtable data from previous invocations */
4302 arg_reset(argtable);
4303
4304 /* locate the first end-of-table marker within the array */
4305 endindex = arg_endindex(table);
4306 endtable = (struct arg_end *)table[endindex];
4307
4308 /* Special case of argc==0. This can occur on Texas Instruments DSP. */
4309 /* Failure to trap this case results in an unwanted NULL result from */
4310 /* the malloc for argvcopy (next code block). */
4311 if (argc == 0)
4312 {
4313 /* We must still perform post-parse checks despite the absence of command line arguments */
4314 arg_parse_check(table, endtable);
4315
4316 /* Now we are finished */
4317 return endtable->count;
4318 }
4319
4320 argvcopy = (char **)malloc(sizeof(char *) * (argc + 1));
4321 if (argvcopy)
4322 {
4323 int i;
4324
4325 /*
4326 Fill in the local copy of argv[]. We need a local copy
4327 because getopt rearranges argv[] which adversely affects
4328 susbsequent parsing attempts.
4329 */
4330 for (i = 0; i < argc; i++)
4331 argvcopy[i] = argv[i];
4332
4333 argvcopy[argc] = NULL;
4334
4335 /* parse the command line (local copy) for tagged options */
4336 arg_parse_tagged(argc, argvcopy, table, endtable);
4337
4338 /* parse the command line (local copy) for untagged options */
4339 arg_parse_untagged(argc, argvcopy, table, endtable);
4340
4341 /* if no errors so far then perform post-parse checks otherwise dont bother */
4342 if (endtable->count == 0)
4343 arg_parse_check(table, endtable);
4344
4345 /* release the local copt of argv[] */
4346 free(argvcopy);
4347 }
4348 else
4349 {
4350 /* memory alloc failed */
4351 arg_register_error(endtable, endtable, ARG_EMALLOC, NULL);
4352 }
4353
4354 return endtable->count;
4355 }
4356
4357
4358 /*
4359 * Concatenate contents of src[] string onto *pdest[] string.
4360 * The *pdest pointer is altered to point to the end of the
4361 * target string and *pndest is decremented by the same number
4362 * of chars.
4363 * Does not append more than *pndest chars into *pdest[]
4364 * so as to prevent buffer overruns.
4365 * Its something like strncat() but more efficient for repeated
4366 * calls on the same destination string.
4367 * Example of use:
4368 * char dest[30] = "good"
4369 * size_t ndest = sizeof(dest);
4370 * char *pdest = dest;
4371 * arg_char(&pdest,"bye ",&ndest);
4372 * arg_char(&pdest,"cruel ",&ndest);
4373 * arg_char(&pdest,"world!",&ndest);
4374 * Results in:
4375 * dest[] == "goodbye cruel world!"
4376 * ndest == 10
4377 */
4378 static
4379 void arg_cat(char * *pdest, const char *src, size_t *pndest)
4380 {
4381 char *dest = *pdest;
4382 char *end = dest + *pndest;
4383
4384 /*locate null terminator of dest string */
4385 while(dest < end && *dest != 0)
4386 dest++;
4387
4388 /* concat src string to dest string */
4389 while(dest < end && *src != 0)
4390 *dest++ = *src++;
4391
4392 /* null terminate dest string */
4393 *dest = 0;
4394
4395 /* update *pdest and *pndest */
4396 *pndest = end - dest;
4397 *pdest = dest;
4398 }
4399
4400
4401 static
4402 void arg_cat_option(char *dest,
4403 size_t ndest,
4404 const char *shortopts,
4405 const char *longopts,
4406 const char *datatype,
4407 int optvalue)
4408 {
4409 if (shortopts)
4410 {
4411 char option[3];
4412
4413 /* note: option array[] is initialiazed dynamically here to satisfy */
4414 /* a deficiency in the watcom compiler wrt static array initializers. */
4415 option[0] = '-';
4416 option[1] = shortopts[0];
4417 option[2] = 0;
4418
4419 arg_cat(&dest, option, &ndest);
4420 if (datatype)
4421 {
4422 arg_cat(&dest, " ", &ndest);
4423 if (optvalue)
4424 {
4425 arg_cat(&dest, "[", &ndest);
4426 arg_cat(&dest, datatype, &ndest);
4427 arg_cat(&dest, "]", &ndest);
4428 }
4429 else
4430 arg_cat(&dest, datatype, &ndest);
4431 }
4432 }
4433 else if (longopts)
4434 {
4435 size_t ncspn;
4436
4437 /* add "--" tag prefix */
4438 arg_cat(&dest, "--", &ndest);
4439
4440 /* add comma separated option tag */
4441 ncspn = strcspn(longopts, ",");
4442 #ifdef __STDC_WANT_SECURE_LIB__
4443 strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest);
4444 #else
4445 strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
4446 #endif
4447
4448 if (datatype)
4449 {
4450 arg_cat(&dest, "=", &ndest);
4451 if (optvalue)
4452 {
4453 arg_cat(&dest, "[", &ndest);
4454 arg_cat(&dest, datatype, &ndest);
4455 arg_cat(&dest, "]", &ndest);
4456 }
4457 else
4458 arg_cat(&dest, datatype, &ndest);
4459 }
4460 }
4461 else if (datatype)
4462 {
4463 if (optvalue)
4464 {
4465 arg_cat(&dest, "[", &ndest);
4466 arg_cat(&dest, datatype, &ndest);
4467 arg_cat(&dest, "]", &ndest);
4468 }
4469 else
4470 arg_cat(&dest, datatype, &ndest);
4471 }
4472 }
4473
4474 static
4475 void arg_cat_optionv(char *dest,
4476 size_t ndest,
4477 const char *shortopts,
4478 const char *longopts,
4479 const char *datatype,
4480 int optvalue,
4481 const char *separator)
4482 {
4483 separator = separator ? separator : "";
4484
4485 if (shortopts)
4486 {
4487 const char *c = shortopts;
4488 while(*c)
4489 {
4490 /* "-a|-b|-c" */
4491 char shortopt[3];
4492
4493 /* note: shortopt array[] is initialiazed dynamically here to satisfy */
4494 /* a deficiency in the watcom compiler wrt static array initializers. */
4495 shortopt[0] = '-';
4496 shortopt[1] = *c;
4497 shortopt[2] = 0;
4498
4499 arg_cat(&dest, shortopt, &ndest);
4500 if (*++c)
4501 arg_cat(&dest, separator, &ndest);
4502 }
4503 }
4504
4505 /* put separator between long opts and short opts */
4506 if (shortopts && longopts)
4507 arg_cat(&dest, separator, &ndest);
4508
4509 if (longopts)
4510 {
4511 const char *c = longopts;
4512 while(*c)
4513 {
4514 size_t ncspn;
4515
4516 /* add "--" tag prefix */
4517 arg_cat(&dest, "--", &ndest);
4518
4519 /* add comma separated option tag */
4520 ncspn = strcspn(c, ",");
4521 #ifdef __STDC_WANT_SECURE_LIB__
4522 strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest);
4523 #else
4524 strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
4525 #endif
4526 c += ncspn;
4527
4528 /* add given separator in place of comma */
4529 if (*c == ',')
4530 {
4531 arg_cat(&dest, separator, &ndest);
4532 c++;
4533 }
4534 }
4535 }
4536
4537 if (datatype)
4538 {
4539 if (longopts)
4540 arg_cat(&dest, "=", &ndest);
4541 else if (shortopts)
4542 arg_cat(&dest, " ", &ndest);
4543
4544 if (optvalue)
4545 {
4546 arg_cat(&dest, "[", &ndest);
4547 arg_cat(&dest, datatype, &ndest);
4548 arg_cat(&dest, "]", &ndest);
4549 }
4550 else
4551 arg_cat(&dest, datatype, &ndest);
4552 }
4553 }
4554
4555
4556 /* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */
4557 void arg_print_option(FILE *fp,
4558 const char *shortopts,
4559 const char *longopts,
4560 const char *datatype,
4561 const char *suffix)
4562 {
4563 char syntax[200] = "";
4564 suffix = suffix ? suffix : "";
4565
4566 /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
4567 arg_cat_optionv(syntax,
4568 sizeof(syntax),
4569 shortopts,
4570 longopts,
4571 datatype,
4572 0,
4573 "|");
4574
4575 fputs(syntax, fp);
4576 fputs(suffix, fp);
4577 }
4578
4579
4580 /*
4581 * Print a GNU style [OPTION] string in which all short options that
4582 * do not take argument values are presented in abbreviated form, as
4583 * in: -xvfsd, or -xvf[sd], or [-xvsfd]
4584 */
4585 static
4586 void arg_print_gnuswitch(FILE *fp, struct arg_hdr * *table)
4587 {
4588 int tabindex;
4589 char *format1 = " -%c";
4590 char *format2 = " [-%c";
4591 char *suffix = "";
4592
4593 /* print all mandatory switches that are without argument values */
4594 for(tabindex = 0;
4595 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4596 tabindex++)
4597 {
4598 /* skip optional options */
4599 if (table[tabindex]->mincount < 1)
4600 continue;
4601
4602 /* skip non-short options */
4603 if (table[tabindex]->shortopts == NULL)
4604 continue;
4605
4606 /* skip options that take argument values */
4607 if (table[tabindex]->flag & ARG_HASVALUE)
4608 continue;
4609
4610 /* print the short option (only the first short option char, ignore multiple choices)*/
4611 fprintf(fp, format1, table[tabindex]->shortopts[0]);
4612 format1 = "%c";
4613 format2 = "[%c";
4614 }
4615
4616 /* print all optional switches that are without argument values */
4617 for(tabindex = 0;
4618 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4619 tabindex++)
4620 {
4621 /* skip mandatory args */
4622 if (table[tabindex]->mincount > 0)
4623 continue;
4624
4625 /* skip args without short options */
4626 if (table[tabindex]->shortopts == NULL)
4627 continue;
4628
4629 /* skip args with values */
4630 if (table[tabindex]->flag & ARG_HASVALUE)
4631 continue;
4632
4633 /* print first short option */
4634 fprintf(fp, format2, table[tabindex]->shortopts[0]);
4635 format2 = "%c";
4636 suffix = "]";
4637 }
4638
4639 fprintf(fp, "%s", suffix);
4640 }
4641
4642
4643 void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix)
4644 {
4645 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4646 int i, tabindex;
4647
4648 /* print GNU style [OPTION] string */
4649 arg_print_gnuswitch(fp, table);
4650
4651 /* print remaining options in abbreviated style */
4652 for(tabindex = 0;
4653 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4654 tabindex++)
4655 {
4656 char syntax[200] = "";
4657 const char *shortopts, *longopts, *datatype;
4658
4659 /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
4660 if (table[tabindex]->shortopts &&
4661 !(table[tabindex]->flag & ARG_HASVALUE))
4662 continue;
4663
4664 shortopts = table[tabindex]->shortopts;
4665 longopts = table[tabindex]->longopts;
4666 datatype = table[tabindex]->datatype;
4667 arg_cat_option(syntax,
4668 sizeof(syntax),
4669 shortopts,
4670 longopts,
4671 datatype,
4672 table[tabindex]->flag & ARG_HASOPTVALUE);
4673
4674 if (strlen(syntax) > 0)
4675 {
4676 /* print mandatory instances of this option */
4677 for (i = 0; i < table[tabindex]->mincount; i++)
4678 fprintf(fp, " %s", syntax);
4679
4680 /* print optional instances enclosed in "[..]" */
4681 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4682 {
4683 case 0:
4684 break;
4685 case 1:
4686 fprintf(fp, " [%s]", syntax);
4687 break;
4688 case 2:
4689 fprintf(fp, " [%s] [%s]", syntax, syntax);
4690 break;
4691 default:
4692 fprintf(fp, " [%s]...", syntax);
4693 break;
4694 }
4695 }
4696 }
4697
4698 if (suffix)
4699 fprintf(fp, "%s", suffix);
4700 }
4701
4702
4703 void arg_print_syntaxv(FILE *fp, void * *argtable, const char *suffix)
4704 {
4705 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4706 int i, tabindex;
4707
4708 /* print remaining options in abbreviated style */
4709 for(tabindex = 0;
4710 table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
4711 tabindex++)
4712 {
4713 char syntax[200] = "";
4714 const char *shortopts, *longopts, *datatype;
4715
4716 shortopts = table[tabindex]->shortopts;
4717 longopts = table[tabindex]->longopts;
4718 datatype = table[tabindex]->datatype;
4719 arg_cat_optionv(syntax,
4720 sizeof(syntax),
4721 shortopts,
4722 longopts,
4723 datatype,
4724 table[tabindex]->flag & ARG_HASOPTVALUE,
4725 "|");
4726
4727 /* print mandatory options */
4728 for (i = 0; i < table[tabindex]->mincount; i++)
4729 fprintf(fp, " %s", syntax);
4730
4731 /* print optional args enclosed in "[..]" */
4732 switch ( table[tabindex]->maxcount - table[tabindex]->mincount )
4733 {
4734 case 0:
4735 break;
4736 case 1:
4737 fprintf(fp, " [%s]", syntax);
4738 break;
4739 case 2:
4740 fprintf(fp, " [%s] [%s]", syntax, syntax);
4741 break;
4742 default:
4743 fprintf(fp, " [%s]...", syntax);
4744 break;
4745 }
4746 }
4747
4748 if (suffix)
4749 fprintf(fp, "%s", suffix);
4750 }
4751
4752
4753 void arg_print_glossary(FILE *fp, void * *argtable, const char *format)
4754 {
4755 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4756 int tabindex;
4757
4758 format = format ? format : " %-20s %s\n";
4759 for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4760 {
4761 if (table[tabindex]->glossary)
4762 {
4763 char syntax[200] = "";
4764 const char *shortopts = table[tabindex]->shortopts;
4765 const char *longopts = table[tabindex]->longopts;
4766 const char *datatype = table[tabindex]->datatype;
4767 const char *glossary = table[tabindex]->glossary;
4768 arg_cat_optionv(syntax,
4769 sizeof(syntax),
4770 shortopts,
4771 longopts,
4772 datatype,
4773 table[tabindex]->flag & ARG_HASOPTVALUE,
4774 ", ");
4775 fprintf(fp, format, syntax, glossary);
4776 }
4777 }
4778 }
4779
4780
4781 /**
4782 * Print a piece of text formatted, which means in a column with a
4783 * left and a right margin. The lines are wrapped at whitspaces next
4784 * to right margin. The function does not indent the first line, but
4785 * only the following ones.
4786 *
4787 * Example:
4788 * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
4789 * will result in the following output:
4790 *
4791 * Some
4792 * text
4793 * that
4794 * doesn'
4795 * t fit.
4796 *
4797 * Too long lines will be wrapped in the middle of a word.
4798 *
4799 * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
4800 * will result in the following output:
4801 *
4802 * Some
4803 * text
4804 * that
4805 * doesn'
4806 * t fit.
4807 *
4808 * As you see, the first line is not indented. This enables output of
4809 * lines, which start in a line where output already happened.
4810 *
4811 * Author: Uli Fouquet
4812 */
4813 static
4814 void arg_print_formatted( FILE *fp,
4815 const unsigned lmargin,
4816 const unsigned rmargin,
4817 const char *text )
4818 {
4819 const unsigned textlen = (unsigned)strlen( text );
4820 unsigned line_start = 0;
4821 unsigned line_end = textlen + 1;
4822 const unsigned colwidth = (rmargin - lmargin) + 1;
4823
4824 /* Someone doesn't like us... */
4825 if ( line_end < line_start )
4826 { fprintf( fp, "%s\n", text ); }
4827
4828 while (line_end - 1 > line_start )
4829 {
4830 /* Eat leading whitespaces. This is essential because while
4831 wrapping lines, there will often be a whitespace at beginning
4832 of line */
4833 while ( ISSPACE(*(text + line_start)) )
4834 { line_start++; }
4835
4836 if ((line_end - line_start) > colwidth )
4837 { line_end = line_start + colwidth; }
4838
4839 /* Find last whitespace, that fits into line */
4840 while ( ( line_end > line_start )
4841 && ( line_end - line_start > colwidth )
4842 && !ISSPACE(*(text + line_end)))
4843 { line_end--; }
4844
4845 /* Do not print trailing whitespace. If this text
4846 has got only one line, line_end now points to the
4847 last char due to initialization. */
4848 line_end--;
4849
4850 /* Output line of text */
4851 while ( line_start < line_end )
4852 {
4853 fputc(*(text + line_start), fp );
4854 line_start++;
4855 }
4856 fputc( '\n', fp );
4857
4858 /* Initialize another line */
4859 if ( line_end + 1 < textlen )
4860 {
4861 unsigned i;
4862
4863 for (i = 0; i < lmargin; i++ )
4864 { fputc( ' ', fp ); }
4865
4866 line_end = textlen;
4867 }
4868
4869 /* If we have to print another line, get also the last char. */
4870 line_end++;
4871
4872 } /* lines of text */
4873 }
4874
4875 /**
4876 * Prints the glossary in strict GNU format.
4877 * Differences to arg_print_glossary() are:
4878 * - wraps lines after 80 chars
4879 * - indents lines without shortops
4880 * - does not accept formatstrings
4881 *
4882 * Contributed by Uli Fouquet
4883 */
4884 void arg_print_glossary_gnu(FILE *fp, void * *argtable )
4885 {
4886 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4887 int tabindex;
4888
4889 for(tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++)
4890 {
4891 if (table[tabindex]->glossary)
4892 {
4893 char syntax[200] = "";
4894 const char *shortopts = table[tabindex]->shortopts;
4895 const char *longopts = table[tabindex]->longopts;
4896 const char *datatype = table[tabindex]->datatype;
4897 const char *glossary = table[tabindex]->glossary;
4898
4899 if ( !shortopts && longopts )
4900 {
4901 /* Indent trailing line by 4 spaces... */
4902 memset( syntax, ' ', 4 );
4903 *(syntax + 4) = '\0';
4904 }
4905
4906 arg_cat_optionv(syntax,
4907 sizeof(syntax),
4908 shortopts,
4909 longopts,
4910 datatype,
4911 table[tabindex]->flag & ARG_HASOPTVALUE,
4912 ", ");
4913
4914 /* If syntax fits not into column, print glossary in new line... */
4915 if ( strlen(syntax) > 25 )
4916 {
4917 fprintf( fp, " %-25s %s\n", syntax, "" );
4918 *syntax = '\0';
4919 }
4920
4921 fprintf( fp, " %-25s ", syntax );
4922 arg_print_formatted( fp, 28, 79, glossary );
4923 }
4924 } /* for each table entry */
4925
4926 fputc( '\n', fp );
4927 }
4928
4929
4930 /**
4931 * Checks the argtable[] array for NULL entries and returns 1
4932 * if any are found, zero otherwise.
4933 */
4934 int arg_nullcheck(void * *argtable)
4935 {
4936 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4937 int tabindex;
4938 /*printf("arg_nullcheck(%p)\n",argtable);*/
4939
4940 if (!table)
4941 return 1;
4942
4943 tabindex = 0;
4944 do
4945 {
4946 /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
4947 if (!table[tabindex])
4948 return 1;
4949 } while(!(table[tabindex++]->flag & ARG_TERMINATOR));
4950
4951 return 0;
4952 }
4953
4954
4955 /*
4956 * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
4957 * The flaw results in memory leak in the (very rare) case that an intermediate
4958 * entry in the argtable array failed its memory allocation while others following
4959 * that entry were still allocated ok. Those subsequent allocations will not be
4960 * deallocated by arg_free().
4961 * Despite the unlikeliness of the problem occurring, and the even unlikelier event
4962 * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
4963 * with the newer arg_freetable() function.
4964 * We still keep arg_free() for backwards compatibility.
4965 */
4966 void arg_free(void * *argtable)
4967 {
4968 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4969 int tabindex = 0;
4970 int flag;
4971 /*printf("arg_free(%p)\n",argtable);*/
4972 do
4973 {
4974 /*
4975 if we encounter a NULL entry then somewhat incorrectly we presume
4976 we have come to the end of the array. It isnt strictly true because
4977 an intermediate entry could be NULL with other non-NULL entries to follow.
4978 The subsequent argtable entries would then not be freed as they should.
4979 */
4980 if (table[tabindex] == NULL)
4981 break;
4982
4983 flag = table[tabindex]->flag;
4984 free(table[tabindex]);
4985 table[tabindex++] = NULL;
4986
4987 } while(!(flag & ARG_TERMINATOR));
4988 }
4989
4990 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
4991 void arg_freetable(void * *argtable, size_t n)
4992 {
4993 struct arg_hdr * *table = (struct arg_hdr * *)argtable;
4994 size_t tabindex = 0;
4995 /*printf("arg_freetable(%p)\n",argtable);*/
4996 for (tabindex = 0; tabindex < n; tabindex++)
4997 {
4998 if (table[tabindex] == NULL)
4999 continue;
5000
5001 free(table[tabindex]);
5002 table[tabindex] = NULL;
5003 };
5004 }
5005
Impressum, Datenschutz