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