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