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