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