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