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