1 /* $NetBSD: find.c,v 1.9 2024/08/18 20:47:24 christos Exp $ */ 2 3 /** 4 * @file check.c 5 * 6 * @brief Hunt for options in the option descriptor list 7 * 8 * This file contains the routines that deal with processing quoted strings 9 * into an internal format. 10 * 11 * @addtogroup autoopts 12 * @{ 13 */ 14 /* 15 * This file is part of AutoOpts, a companion to AutoGen. 16 * AutoOpts is free software. 17 * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 18 * 19 * AutoOpts is available under any one of two licenses. The license 20 * in use must be one of these two and the choice is under the control 21 * of the user of the license. 22 * 23 * The GNU Lesser General Public License, version 3 or later 24 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 25 * 26 * The Modified Berkeley Software Distribution License 27 * See the file "COPYING.mbsd" 28 * 29 * These files have the following sha256 sums: 30 * 31 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 32 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 33 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 34 */ 35 36 /** 37 * find the name and name length we are looking for 38 */ 39 static int 40 parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz) 41 { 42 int res = 0; 43 char const * p = *nm_pp; 44 *arg_pp = NULL; 45 46 for (;;) { 47 switch (*(p++)) { 48 case NUL: return res; 49 50 case '=': 51 memcpy(buf, *nm_pp, (size_t)res); 52 53 buf[res] = NUL; 54 *nm_pp = buf; 55 *arg_pp = __UNCONST(p); 56 return res; 57 58 default: 59 if (++res >= (int)bufsz) 60 return -1; 61 } 62 } 63 } 64 65 /** 66 * print out the options that match the given name. 67 * 68 * @param pOpts option data 69 * @param opt_name name of option to look for 70 */ 71 static void 72 opt_ambiguities(tOptions * opts, char const * name, int nm_len) 73 { 74 char const * const hyph = 75 NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER; 76 77 tOptDesc * pOD = opts->pOptDesc; 78 int idx = 0; 79 80 fputs(zambig_list_msg, stderr); 81 do { 82 if (pOD->pz_Name == NULL) 83 continue; /* doc option */ 84 85 if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) 86 fprintf(stderr, zambig_file, hyph, pOD->pz_Name); 87 88 else if ( (pOD->pz_DisableName != NULL) 89 && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) 90 ) 91 fprintf(stderr, zambig_file, hyph, pOD->pz_DisableName); 92 } while (pOD++, (++idx < opts->optCt)); 93 } 94 95 /** 96 * Determine the number of options that match the name 97 * 98 * @param pOpts option data 99 * @param opt_name name of option to look for 100 * @param nm_len length of provided name 101 * @param index pointer to int for option index 102 * @param disable pointer to bool to mark disabled option 103 * @return count of options that match 104 */ 105 static int 106 opt_match_ct(tOptions * opts, char const * name, int nm_len, 107 int * ixp, bool * disable) 108 { 109 int matchCt = 0; 110 int idx = 0; 111 int idxLim = opts->optCt; 112 tOptDesc * pOD = opts->pOptDesc; 113 114 do { 115 /* 116 * If option disabled or a doc option, skip to next 117 */ 118 if (pOD->pz_Name == NULL) 119 continue; 120 121 if ( SKIP_OPT(pOD) 122 && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT))) 123 continue; 124 125 if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) { 126 /* 127 * IF we have a complete match 128 * THEN it takes priority over any already located partial 129 */ 130 if (pOD->pz_Name[ nm_len ] == NUL) { 131 *ixp = idx; 132 return 1; 133 } 134 } 135 136 /* 137 * IF there is a disable name 138 * *AND* the option name matches the disable name 139 * THEN ... 140 */ 141 else if ( (pOD->pz_DisableName != NULL) 142 && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) 143 ) { 144 *disable = true; 145 146 /* 147 * IF we have a complete match 148 * THEN it takes priority over any already located partial 149 */ 150 if (pOD->pz_DisableName[ nm_len ] == NUL) { 151 *ixp = idx; 152 return 1; 153 } 154 } 155 156 else 157 continue; /* does not match any option */ 158 159 /* 160 * We found a full or partial match, either regular or disabling. 161 * Remember the index for later. 162 */ 163 *ixp = idx; 164 ++matchCt; 165 166 } while (pOD++, (++idx < idxLim)); 167 168 return matchCt; 169 } 170 171 /** 172 * Set the option to the indicated option number. 173 * 174 * @param opts option data 175 * @param arg option argument (if glued to name) 176 * @param idx option index 177 * @param disable mark disabled option 178 * @param st state about current option 179 */ 180 static tSuccess 181 opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st) 182 { 183 tOptDesc * pOD = opts->pOptDesc + idx; 184 185 if (SKIP_OPT(pOD)) { 186 if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) 187 return FAILURE; 188 189 fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name); 190 if (pOD->pzText != NULL) 191 fprintf(stderr, SET_OFF_FMT, pOD->pzText); 192 fputc(NL, stderr); 193 (*opts->pUsageProc)(opts, EXIT_FAILURE); 194 /* NOTREACHED */ 195 _exit(EXIT_FAILURE); /* to be certain */ 196 } 197 198 /* 199 * IF we found a disablement name, 200 * THEN set the bit in the callers' flag word 201 */ 202 if (disable) 203 st->flags |= OPTST_DISABLED; 204 205 st->pOD = pOD; 206 st->pzOptArg = arg; 207 st->optType = TOPT_LONG; 208 209 return SUCCESS; 210 } 211 212 /** 213 * An option was not found. Check for default option and set it 214 * if there is one. Otherwise, handle the error. 215 * 216 * @param opts option data 217 * @param name name of option to look for 218 * @param arg option argument 219 * @param st state about current option 220 * 221 * @return success status 222 */ 223 static tSuccess 224 opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st) 225 { 226 /* 227 * IF there is no equal sign 228 * *AND* we are using named arguments 229 * *AND* there is a default named option, 230 * THEN return that option. 231 */ 232 if ( (arg == NULL) 233 && NAMED_OPTS(opts) 234 && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) { 235 236 st->pOD = opts->pOptDesc + opts->specOptIdx.default_opt; 237 st->pzOptArg = name; 238 st->optType = TOPT_DEFAULT; 239 return SUCCESS; 240 } 241 242 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { 243 fprintf(stderr, zIllOptStr, opts->pzProgPath, name); 244 (*opts->pUsageProc)(opts, EXIT_FAILURE); 245 /* NOTREACHED */ 246 _exit(EXIT_FAILURE); /* to be certain */ 247 } 248 249 return FAILURE; 250 } 251 252 /** 253 * Several options match the provided name. 254 * 255 * @param opts option data 256 * @param name name of option to look for 257 * @param match_ct number of matching options 258 * 259 * @return success status (always FAILURE, if it returns) 260 */ 261 static tSuccess 262 opt_ambiguous(tOptions * opts, char const * name, int match_ct) 263 { 264 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { 265 fprintf(stderr, zambig_opt_fmt, opts->pzProgPath, name, match_ct); 266 if (match_ct <= 4) 267 opt_ambiguities(opts, name, (int)strlen(name)); 268 (*opts->pUsageProc)(opts, EXIT_FAILURE); 269 /* NOTREACHED */ 270 _exit(EXIT_FAILURE); /* to be certain */ 271 } 272 return FAILURE; 273 } 274 275 /*=export_func optionVendorOption 276 * private: 277 * 278 * what: Process a vendor option 279 * arg: + tOptions * + pOpts + program options descriptor + 280 * arg: + tOptDesc * + pOptDesc + the descriptor for this arg + 281 * 282 * doc: 283 * For POSIX specified utilities, the options are constrained to the options, 284 * @xref{config attributes, Program Configuration}. AutoOpts clients should 285 * never specify this directly. It gets referenced when the option 286 * definitions contain a "vendor-opt" attribute. 287 =*/ 288 void 289 optionVendorOption(tOptions * pOpts, tOptDesc * pOD) 290 { 291 tOptState opt_st = OPTSTATE_INITIALIZER(PRESET); 292 char const * vopt_str = pOD->optArg.argString; 293 294 if (pOpts <= OPTPROC_EMIT_LIMIT) 295 return; 296 297 if ((pOD->fOptState & OPTST_RESET) != 0) 298 return; 299 300 if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0) 301 opt_st.flags = OPTST_DEFINED; 302 303 if ( ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0) 304 || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st)) 305 || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) ) 306 { 307 fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str); 308 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 309 /* NOTREACHED */ 310 _exit(EXIT_FAILURE); /* to be certain */ 311 } 312 313 /* 314 * See if we are in immediate handling state. 315 */ 316 if (pOpts->fOptSet & OPTPROC_IMMEDIATE) { 317 /* 318 * See if the enclosed option is okay with that state. 319 */ 320 if (DO_IMMEDIATELY(opt_st.flags)) 321 (void)handle_opt(pOpts, &opt_st); 322 323 } else { 324 /* 325 * non-immediate direction. 326 * See if the enclosed option is okay with that state. 327 */ 328 if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags)) 329 (void)handle_opt(pOpts, &opt_st); 330 } 331 } 332 333 /** 334 * Find the option descriptor by full name. 335 * 336 * @param opts option data 337 * @param opt_name name of option to look for 338 * @param state state about current option 339 * 340 * @return success status 341 */ 342 static tSuccess 343 opt_find_long(tOptions * opts, char const * opt_name, tOptState * state) 344 { 345 char name_buf[128]; 346 char * opt_arg; 347 int nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf)); 348 349 int idx = 0; 350 bool disable = false; 351 int ct; 352 353 if (nm_len <= 1) { 354 if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) 355 return FAILURE; 356 357 fprintf(stderr, zInvalOptName, opts->pzProgName, opt_name); 358 (*opts->pUsageProc)(opts, EXIT_FAILURE); 359 /* NOTREACHED */ 360 _exit(EXIT_FAILURE); /* to be certain */ 361 } 362 363 ct = opt_match_ct(opts, opt_name, nm_len, &idx, &disable); 364 365 /* 366 * See if we found one match, no matches or multiple matches. 367 */ 368 switch (ct) { 369 case 1: return opt_set(opts, opt_arg, idx, disable, state); 370 case 0: return opt_unknown(opts, opt_name, opt_arg, state); 371 default: return opt_ambiguous(opts, opt_name, ct); 372 } 373 } 374 375 376 /** 377 * Find the short option descriptor for the current option 378 * 379 * @param pOpts option data 380 * @param optValue option flag character 381 * @param pOptState state about current option 382 */ 383 static tSuccess 384 opt_find_short(tOptions * pOpts, uint_t optValue, tOptState * pOptState) 385 { 386 tOptDesc * pRes = pOpts->pOptDesc; 387 int ct = pOpts->optCt; 388 389 /* 390 * Search the option list 391 */ 392 do { 393 if (optValue != pRes->optValue) 394 continue; 395 396 if (SKIP_OPT(pRes)) { 397 if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) 398 && (pRes->pz_Name != NULL)) { 399 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0) 400 return FAILURE; 401 402 fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name); 403 if (pRes->pzText != NULL) 404 fprintf(stderr, SET_OFF_FMT, pRes->pzText); 405 fputc(NL, stderr); 406 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 407 /* NOTREACHED */ 408 _exit(EXIT_FAILURE); /* to be certain */ 409 } 410 goto short_opt_error; 411 } 412 413 pOptState->pOD = pRes; 414 pOptState->optType = TOPT_SHORT; 415 return SUCCESS; 416 417 } while (pRes++, --ct > 0); 418 419 /* 420 * IF the character value is a digit 421 * AND there is a special number option ("-n") 422 * THEN the result is the "option" itself and the 423 * option is the specially marked "number" option. 424 */ 425 if ( IS_DEC_DIGIT_CHAR(optValue) 426 && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { 427 pOptState->pOD = \ 428 pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; 429 (pOpts->pzCurOpt)--; 430 pOptState->optType = TOPT_SHORT; 431 return SUCCESS; 432 } 433 434 short_opt_error: 435 436 /* 437 * IF we are to stop on errors (the default, actually) 438 * THEN call the usage procedure. 439 */ 440 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 441 fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue); 442 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 443 /* NOTREACHED */ 444 _exit(EXIT_FAILURE); /* to be certain */ 445 } 446 447 return FAILURE; 448 } 449 450 /** 451 * Process option with a required argument. Long options can either have a 452 * separate command line argument, or an argument attached by the '=' 453 * character. Figure out which. 454 * 455 * @param[in,out] opts the program option descriptor 456 * @param[in,out] o_st the option processing state 457 * @returns SUCCESS or FAILURE 458 */ 459 static tSuccess 460 get_opt_arg_must(tOptions * opts, tOptState * o_st) 461 { 462 switch (o_st->optType) { 463 case TOPT_SHORT: 464 /* 465 * See if an arg string follows the flag character 466 */ 467 if (*++(opts->pzCurOpt) == NUL) 468 opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ]; 469 o_st->pzOptArg = opts->pzCurOpt; 470 break; 471 472 case TOPT_LONG: 473 /* 474 * See if an arg string has already been assigned (glued on 475 * with an `=' character) 476 */ 477 if (o_st->pzOptArg == NULL) 478 o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ]; 479 break; 480 481 default: 482 #ifdef DEBUG 483 fputs("AutoOpts lib error: option type not selected\n", stderr); 484 option_exits(EXIT_FAILURE); 485 #endif 486 487 case TOPT_DEFAULT: 488 /* 489 * The option was selected by default. The current token is 490 * the option argument. 491 */ 492 break; 493 } 494 495 /* 496 * Make sure we did not overflow the argument list. 497 */ 498 if (opts->curOptIdx > opts->origArgCt) { 499 fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name); 500 return FAILURE; 501 } 502 503 opts->pzCurOpt = NULL; /* next time advance to next arg */ 504 return SUCCESS; 505 } 506 507 /** 508 * Process an option with an optional argument. For short options, it looks 509 * at the character after the option character, or it consumes the next full 510 * argument. For long options, it looks for an '=' character attachment to 511 * the long option name before deciding to take the next command line 512 * argument. 513 * 514 * @param pOpts the option descriptor 515 * @param o_st a structure for managing the current processing state 516 * @returns SUCCESS or does not return 517 */ 518 static tSuccess 519 get_opt_arg_may(tOptions * pOpts, tOptState * o_st) 520 { 521 /* 522 * An option argument is optional. 523 */ 524 switch (o_st->optType) { 525 case TOPT_SHORT: 526 if (*++pOpts->pzCurOpt != NUL) 527 o_st->pzOptArg = pOpts->pzCurOpt; 528 else { 529 char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 530 531 /* 532 * BECAUSE it is optional, we must make sure 533 * we did not find another flag and that there 534 * is such an argument. 535 */ 536 if ((pzLA == NULL) || (*pzLA == '-')) 537 o_st->pzOptArg = NULL; 538 else { 539 pOpts->curOptIdx++; /* argument found */ 540 o_st->pzOptArg = pzLA; 541 } 542 } 543 break; 544 545 case TOPT_LONG: 546 /* 547 * Look for an argument if we don't already have one (glued on 548 * with a `=' character) *AND* we are not in named argument mode 549 */ 550 if ( (o_st->pzOptArg == NULL) 551 && (! NAMED_OPTS(pOpts))) { 552 char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 553 554 /* 555 * BECAUSE it is optional, we must make sure 556 * we did not find another flag and that there 557 * is such an argument. 558 */ 559 if ((pzLA == NULL) || (*pzLA == '-')) 560 o_st->pzOptArg = NULL; 561 else { 562 pOpts->curOptIdx++; /* argument found */ 563 o_st->pzOptArg = pzLA; 564 } 565 } 566 break; 567 568 default: 569 case TOPT_DEFAULT: 570 ao_bug(zbad_default_msg); 571 } 572 573 /* 574 * After an option with an optional argument, we will 575 * *always* start with the next option because if there 576 * were any characters following the option name/flag, 577 * they would be interpreted as the argument. 578 */ 579 pOpts->pzCurOpt = NULL; 580 return SUCCESS; 581 } 582 583 /** 584 * Process option that does not have an argument. 585 * 586 * @param[in,out] opts the program option descriptor 587 * @param[in,out] o_st the option processing state 588 * @returns SUCCESS or FAILURE 589 */ 590 static tSuccess 591 get_opt_arg_none(tOptions * pOpts, tOptState * o_st) 592 { 593 /* 594 * No option argument. Make sure next time around we find 595 * the correct option flag character for short options 596 */ 597 if (o_st->optType == TOPT_SHORT) 598 (pOpts->pzCurOpt)++; 599 600 /* 601 * It is a long option. Make sure there was no ``=xxx'' argument 602 */ 603 else if (o_st->pzOptArg != NULL) { 604 fprintf(stderr, zNoArg, pOpts->pzProgPath, o_st->pOD->pz_Name); 605 return FAILURE; 606 } 607 608 /* 609 * It is a long option. Advance to next command line argument. 610 */ 611 else 612 pOpts->pzCurOpt = NULL; 613 614 return SUCCESS; 615 } 616 617 /** 618 * Process option. Figure out whether or not to look for an option argument. 619 * 620 * @param[in,out] opts the program option descriptor 621 * @param[in,out] o_st the option processing state 622 * @returns SUCCESS or FAILURE 623 */ 624 static tSuccess 625 get_opt_arg(tOptions * opts, tOptState * o_st) 626 { 627 o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK); 628 629 /* 630 * Disabled options and options specified to not have arguments 631 * are handled with the "none" procedure. Otherwise, check the 632 * optional flag and call either the "may" or "must" function. 633 */ 634 if ((o_st->flags & OPTST_DISABLED) != 0) 635 return get_opt_arg_none(opts, o_st); 636 637 switch (OPTST_GET_ARGTYPE(o_st->flags)) { 638 case OPARG_TYPE_STATIC: 639 { 640 /* 641 * Propagate the static arg 642 */ 643 tSuccess res = get_opt_arg_none(opts, o_st); 644 o_st->pzOptArg = o_st->pOD->optArg.argString; 645 return res; 646 } 647 648 case OPARG_TYPE_NONE: 649 return get_opt_arg_none(opts, o_st); 650 } 651 652 if (o_st->flags & OPTST_ARG_OPTIONAL) 653 return get_opt_arg_may( opts, o_st); 654 655 return get_opt_arg_must(opts, o_st); 656 } 657 658 /** 659 * Find the option descriptor for the current option. 660 * 661 * @param[in,out] opts the program option descriptor 662 * @param[in,out] o_st the option processing state 663 * @returns SUCCESS or FAILURE 664 */ 665 static tSuccess 666 find_opt(tOptions * opts, tOptState * o_st) 667 { 668 /* 669 * IF we are continuing a short option list (e.g. -xyz...) 670 * THEN continue a single flag option. 671 * OTHERWISE see if there is room to advance and then do so. 672 */ 673 if ((opts->pzCurOpt != NULL) && (*opts->pzCurOpt != NUL)) 674 return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); 675 676 if (opts->curOptIdx >= opts->origArgCt) 677 return PROBLEM; /* NORMAL COMPLETION */ 678 679 opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx ]; 680 681 /* 682 * IF all arguments must be named options, ... 683 */ 684 if (NAMED_OPTS(opts)) { 685 char * pz = opts->pzCurOpt; 686 int def; 687 tSuccess res; 688 uint16_t * def_opt; 689 690 opts->curOptIdx++; 691 692 if (*pz != '-') 693 return opt_find_long(opts, pz, o_st); 694 695 /* 696 * The name is prefixed with one or more hyphens. Strip them off 697 * and disable the "default_opt" setting. Use heavy recasting to 698 * strip off the "const" quality of the "default_opt" field. 699 */ 700 while (*(++pz) == '-') ; 701 def_opt = VOIDP(&(opts->specOptIdx.default_opt)); 702 def = *def_opt; 703 *def_opt = NO_EQUIVALENT; 704 res = opt_find_long(opts, pz, o_st); 705 *def_opt = (uint16_t)def; 706 return res; 707 } 708 709 /* 710 * Note the kind of flag/option marker 711 */ 712 if (*((opts->pzCurOpt)++) != '-') 713 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 714 715 /* 716 * Special hack for a hyphen by itself 717 */ 718 if (*(opts->pzCurOpt) == NUL) 719 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 720 721 /* 722 * The current argument is to be processed as an option argument 723 */ 724 opts->curOptIdx++; 725 726 /* 727 * We have an option marker. 728 * Test the next character for long option indication 729 */ 730 if (opts->pzCurOpt[0] == '-') { 731 if (*++(opts->pzCurOpt) == NUL) 732 /* 733 * NORMAL COMPLETION - NOT this arg, but rest are operands 734 */ 735 return PROBLEM; 736 737 /* 738 * We do not allow the hyphen to be used as a flag value. 739 * Therefore, if long options are not to be accepted, we punt. 740 */ 741 if ((opts->fOptSet & OPTPROC_LONGOPT) == 0) { 742 fprintf(stderr, zIllOptStr, opts->pzProgPath, opts->pzCurOpt-2); 743 return FAILURE; 744 } 745 746 return opt_find_long(opts, opts->pzCurOpt, o_st); 747 } 748 749 /* 750 * If short options are not allowed, then do long 751 * option processing. Otherwise the character must be a 752 * short (i.e. single character) option. 753 */ 754 if ((opts->fOptSet & OPTPROC_SHORTOPT) != 0) 755 return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); 756 757 return opt_find_long(opts, opts->pzCurOpt, o_st); 758 } 759 760 /** @} 761 * 762 * Local Variables: 763 * mode: C 764 * c-file-style: "stroustrup" 765 * indent-tabs-mode: nil 766 * End: 767 * end of autoopts/find.c */ 768