1
0

find.c 22 KB

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