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