1
0

autoopts.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. /*
  2. * $Id: autoopts.c,v 4.27 2007/07/04 21:36:36 bkorb Exp $
  3. * Time-stamp: "2007-07-04 14:33:39 bkorb"
  4. *
  5. * This file contains all of the routines that must be linked into
  6. * an executable to use the generated option processing. The optional
  7. * routines are in separately compiled modules so that they will not
  8. * necessarily be linked in.
  9. *
  10. * This file is part of AutoOpts, a companion to AutoGen.
  11. * AutoOpts is free software.
  12. * AutoOpts is copyright (c) 1992-2007 by Bruce Korb - all rights reserved
  13. *
  14. * AutoOpts is available under any one of two licenses. The license
  15. * in use must be one of these two and the choice is under the control
  16. * of the user of the license.
  17. *
  18. * The GNU Lesser General Public License, version 3 or later
  19. * See the files "COPYING.lgplv3" and "COPYING.gplv3"
  20. *
  21. * The Modified Berkeley Software Distribution License
  22. * See the file "COPYING.mbsd"
  23. *
  24. * These files have the following md5sums:
  25. *
  26. * 239588c55c22c60ffe159946a760a33e pkg/libopts/COPYING.gplv3
  27. * fa82ca978890795162346e661b47161a pkg/libopts/COPYING.lgplv3
  28. * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
  29. */
  30. static char const zNil[] = "";
  31. /* = = = START-STATIC-FORWARD = = = */
  32. /* static forward declarations maintained by :mkfwd */
  33. static tSuccess
  34. findOptDesc( tOptions* pOpts, tOptState* pOptState );
  35. static tSuccess
  36. nextOption( tOptions* pOpts, tOptState* pOptState );
  37. static tSuccess
  38. doPresets( tOptions* pOpts );
  39. static int
  40. checkConsistency( tOptions* pOpts );
  41. /* = = = END-STATIC-FORWARD = = = */
  42. LOCAL void *
  43. ao_malloc( size_t sz )
  44. {
  45. void * res = malloc(sz);
  46. if (res == NULL) {
  47. fprintf( stderr, "malloc of %d bytes failed\n", (int)sz );
  48. exit( EXIT_FAILURE );
  49. }
  50. return res;
  51. }
  52. #undef malloc
  53. #define malloc(_s) ao_malloc(_s)
  54. LOCAL void *
  55. ao_realloc( void *p, size_t sz )
  56. {
  57. void * res = realloc(p, sz);
  58. if (res == NULL) {
  59. fprintf( stderr, "realloc of %d bytes at 0x%p failed\n", (int)sz, p );
  60. exit( EXIT_FAILURE );
  61. }
  62. return res;
  63. }
  64. #undef realloc
  65. #define realloc(_p,_s) ao_realloc(_p,_s)
  66. LOCAL void
  67. ao_free( void *p )
  68. {
  69. if (p != NULL)
  70. free(p);
  71. }
  72. #undef free
  73. #define free(_p) ao_free(_p)
  74. LOCAL char *
  75. ao_strdup( char const *str )
  76. {
  77. char * res = strdup(str);
  78. if (res == NULL) {
  79. fprintf(stderr, "strdup of %d byte string failed\n", (int)strlen(str));
  80. exit( EXIT_FAILURE );
  81. }
  82. return res;
  83. }
  84. #undef strdup
  85. #define strdup(_p) ao_strdup(_p)
  86. #ifndef HAVE_PATHFIND
  87. # include "compat/pathfind.c"
  88. #endif
  89. #ifndef HAVE_SNPRINTF
  90. # include "compat/snprintf.c"
  91. #endif
  92. #ifndef HAVE_STRDUP
  93. # include "compat/strdup.c"
  94. #endif
  95. #ifndef HAVE_STRCHR
  96. # include "compat/strchr.c"
  97. #endif
  98. /*
  99. * handleOption
  100. *
  101. * This routine handles equivalencing, sets the option state flags and
  102. * invokes the handler procedure, if any.
  103. */
  104. LOCAL tSuccess
  105. handleOption( tOptions* pOpts, tOptState* pOptState )
  106. {
  107. /*
  108. * Save a copy of the option procedure pointer.
  109. * If this is an equivalence class option, we still want this proc.
  110. */
  111. tOptDesc* pOD = pOptState->pOD;
  112. tOptProc* pOP = pOD->pOptProc;
  113. if (pOD->fOptState & OPTST_ALLOC_ARG)
  114. AGFREE(pOD->optArg.argString);
  115. pOD->optArg.argString = pOptState->pzOptArg;
  116. /*
  117. * IF we are presetting options, then we will ignore any un-presettable
  118. * options. They are the ones either marked as such.
  119. */
  120. if ( ((pOpts->fOptSet & OPTPROC_PRESETTING) != 0)
  121. && ((pOD->fOptState & OPTST_NO_INIT) != 0)
  122. )
  123. return PROBLEM;
  124. /*
  125. * IF this is an equivalence class option,
  126. * THEN
  127. * Save the option value that got us to this option
  128. * entry. (It may not be pOD->optChar[0], if this is an
  129. * equivalence entry.)
  130. * set the pointer to the equivalence class base
  131. */
  132. if (pOD->optEquivIndex != NO_EQUIVALENT) {
  133. tOptDesc* p = pOpts->pOptDesc + pOD->optEquivIndex;
  134. /*
  135. * IF the current option state has not been defined (set on the
  136. * command line), THEN we will allow continued resetting of
  137. * the value. Once "defined", then it must not change.
  138. */
  139. if ((pOD->fOptState & OPTST_DEFINED) != 0) {
  140. /*
  141. * The equivalenced-to option has been found on the command
  142. * line before. Make sure new occurrences are the same type.
  143. *
  144. * IF this option has been previously equivalenced and
  145. * it was not the same equivalenced-to option,
  146. * THEN we have a usage problem.
  147. */
  148. if (p->optActualIndex != pOD->optIndex) {
  149. fprintf( stderr, (char*)zMultiEquiv, p->pz_Name, pOD->pz_Name,
  150. (pOpts->pOptDesc + p->optActualIndex)->pz_Name);
  151. return FAILURE;
  152. }
  153. } else {
  154. /*
  155. * Set the equivalenced-to actual option index to no-equivalent
  156. * so that we set all the entries below. This option may either
  157. * never have been selected before, or else it was selected by
  158. * some sort of "presetting" mechanism.
  159. */
  160. p->optActualIndex = NO_EQUIVALENT;
  161. }
  162. if (p->optActualIndex != pOD->optIndex) {
  163. /*
  164. * First time through, copy over the state
  165. * and add in the equivalence flag
  166. */
  167. p->optActualValue = pOD->optValue;
  168. p->optActualIndex = pOD->optIndex;
  169. pOptState->flags |= OPTST_EQUIVALENCE;
  170. }
  171. /*
  172. * Copy the most recent option argument. set membership state
  173. * is kept in ``p->optCookie''. Do not overwrite.
  174. */
  175. p->optArg.argString = pOD->optArg.argString;
  176. pOD = p;
  177. } else {
  178. pOD->optActualValue = pOD->optValue;
  179. pOD->optActualIndex = pOD->optIndex;
  180. }
  181. pOD->fOptState &= OPTST_PERSISTENT_MASK;
  182. pOD->fOptState |= (pOptState->flags & ~OPTST_PERSISTENT_MASK);
  183. /*
  184. * Keep track of count only for DEFINED (command line) options.
  185. * IF we have too many, build up an error message and bail.
  186. */
  187. if ( (pOD->fOptState & OPTST_DEFINED)
  188. && (++pOD->optOccCt > pOD->optMaxCt) ) {
  189. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
  190. char const * pzEqv =
  191. (pOD->optEquivIndex != NO_EQUIVALENT) ? zEquiv : zNil;
  192. fputs( zErrOnly, stderr );
  193. if (pOD->optMaxCt > 1)
  194. fprintf(stderr, zAtMost, pOD->optMaxCt, pOD->pz_Name, pzEqv);
  195. else
  196. fprintf(stderr, zOnlyOne, pOD->pz_Name, pzEqv);
  197. }
  198. return FAILURE;
  199. }
  200. /*
  201. * If provided a procedure to call, call it
  202. */
  203. if (pOP != (tpOptProc)NULL)
  204. (*pOP)( pOpts, pOD );
  205. return SUCCESS;
  206. }
  207. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  208. *
  209. * HUNT FOR OPTIONS IN THE ARGUMENT LIST
  210. *
  211. * The next four procedures are "private" to nextOption().
  212. * nextOption() uses findOptDesc() to find the next descriptor and it, in
  213. * turn, uses longOptionFind() and shortOptionFind() to actually do the hunt.
  214. *
  215. * longOptionFind
  216. *
  217. * Find the long option descriptor for the current option
  218. */
  219. LOCAL tSuccess
  220. longOptionFind( tOptions* pOpts, char* pzOptName, tOptState* pOptState )
  221. {
  222. ag_bool disable = AG_FALSE;
  223. char* pzEq = strchr( pzOptName, '=' );
  224. tOptDesc* pOD = pOpts->pOptDesc;
  225. int idx = 0;
  226. int idxLim = pOpts->optCt;
  227. int matchCt = 0;
  228. int matchIdx = 0;
  229. int nameLen;
  230. /*
  231. * IF the value is attached to the name,
  232. * THEN clip it off.
  233. * Either way, figure out how long our name is
  234. */
  235. if (pzEq != NULL) {
  236. nameLen = (int)(pzEq - pzOptName);
  237. *pzEq = NUL;
  238. } else nameLen = strlen( pzOptName );
  239. do {
  240. if (SKIP_OPT(pOD))
  241. continue;
  242. if (strneqvcmp( pzOptName, pOD->pz_Name, nameLen ) == 0) {
  243. /*
  244. * IF we have a complete match
  245. * THEN it takes priority over any already located partial
  246. */
  247. if (pOD->pz_Name[ nameLen ] == NUL) {
  248. matchCt = 1;
  249. matchIdx = idx;
  250. break;
  251. }
  252. }
  253. /*
  254. * IF there is a disable name
  255. * *AND* no argument value has been supplied
  256. * (disabled options may have no argument)
  257. * *AND* the option name matches the disable name
  258. * THEN ...
  259. */
  260. else if ( (pOD->pz_DisableName != NULL)
  261. && (strneqvcmp(pzOptName, pOD->pz_DisableName, nameLen) == 0)
  262. ) {
  263. disable = AG_TRUE;
  264. /*
  265. * IF we have a complete match
  266. * THEN it takes priority over any already located partial
  267. */
  268. if (pOD->pz_DisableName[ nameLen ] == NUL) {
  269. matchCt = 1;
  270. matchIdx = idx;
  271. break;
  272. }
  273. }
  274. else
  275. continue;
  276. /*
  277. * We found a partial match, either regular or disabling.
  278. * Remember the index for later.
  279. */
  280. matchIdx = idx;
  281. if (++matchCt > 1)
  282. break;
  283. } while (pOD++, (++idx < idxLim));
  284. if (pzEq != NULL)
  285. *(pzEq++) = '=';
  286. /*
  287. * Make sure we either found an exact match or found only one partial
  288. */
  289. if (matchCt == 1) {
  290. /*
  291. * IF we found a disablement name,
  292. * THEN set the bit in the callers' flag word
  293. */
  294. if (disable)
  295. pOptState->flags |= OPTST_DISABLED;
  296. pOptState->pOD = pOpts->pOptDesc + matchIdx;
  297. pOptState->pzOptArg = pzEq;
  298. pOptState->optType = TOPT_LONG;
  299. return SUCCESS;
  300. }
  301. /*
  302. * IF there is no equal sign
  303. * *AND* we are using named arguments
  304. * *AND* there is a default named option,
  305. * THEN return that option.
  306. */
  307. if ( (pzEq == NULL)
  308. && NAMED_OPTS(pOpts)
  309. && (pOpts->specOptIdx.default_opt != NO_EQUIVALENT)) {
  310. pOptState->pOD = pOpts->pOptDesc + pOpts->specOptIdx.default_opt;
  311. pOptState->pzOptArg = pzOptName;
  312. pOptState->optType = TOPT_DEFAULT;
  313. return SUCCESS;
  314. }
  315. /*
  316. * IF we are to stop on errors (the default, actually)
  317. * THEN call the usage procedure.
  318. */
  319. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
  320. fprintf( stderr, zIllOptStr, pOpts->pzProgPath,
  321. (matchCt == 0) ? zIllegal : zAmbiguous, pzOptName );
  322. (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
  323. }
  324. return FAILURE;
  325. }
  326. /*
  327. * shortOptionFind
  328. *
  329. * Find the short option descriptor for the current option
  330. */
  331. LOCAL tSuccess
  332. shortOptionFind( tOptions* pOpts, uint_t optValue, tOptState* pOptState )
  333. {
  334. tOptDesc* pRes = pOpts->pOptDesc;
  335. int ct = pOpts->optCt;
  336. /*
  337. * Search the option list
  338. */
  339. for (;;) {
  340. /*
  341. * IF the values match,
  342. * THEN we stop here
  343. */
  344. if ((! SKIP_OPT(pRes)) && (optValue == pRes->optValue)) {
  345. pOptState->pOD = pRes;
  346. pOptState->optType = TOPT_SHORT;
  347. return SUCCESS;
  348. }
  349. /*
  350. * Advance to next option description
  351. */
  352. pRes++;
  353. /*
  354. * IF we have searched everything, ...
  355. */
  356. if (--ct <= 0)
  357. break;
  358. }
  359. /*
  360. * IF the character value is a digit
  361. * AND there is a special number option ("-n")
  362. * THEN the result is the "option" itself and the
  363. * option is the specially marked "number" option.
  364. */
  365. if ( isdigit( optValue )
  366. && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) {
  367. pOptState->pOD = \
  368. pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option;
  369. (pOpts->pzCurOpt)--;
  370. pOptState->optType = TOPT_SHORT;
  371. return SUCCESS;
  372. }
  373. /*
  374. * IF we are to stop on errors (the default, actually)
  375. * THEN call the usage procedure.
  376. */
  377. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
  378. fprintf( stderr, zIllOptChr, pOpts->pzProgPath, optValue );
  379. (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
  380. }
  381. return FAILURE;
  382. }
  383. /*
  384. * findOptDesc
  385. *
  386. * Find the option descriptor for the current option
  387. */
  388. static tSuccess
  389. findOptDesc( tOptions* pOpts, tOptState* pOptState )
  390. {
  391. /*
  392. * IF we are continuing a short option list (e.g. -xyz...)
  393. * THEN continue a single flag option.
  394. * OTHERWISE see if there is room to advance and then do so.
  395. */
  396. if ((pOpts->pzCurOpt != NULL) && (*pOpts->pzCurOpt != NUL))
  397. return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState );
  398. if (pOpts->curOptIdx >= pOpts->origArgCt)
  399. return PROBLEM; /* NORMAL COMPLETION */
  400. pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx ];
  401. /*
  402. * IF all arguments must be named options, ...
  403. */
  404. if (NAMED_OPTS(pOpts)) {
  405. char* pz = pOpts->pzCurOpt;
  406. pOpts->curOptIdx++;
  407. /*
  408. * Skip over any flag/option markers.
  409. * In this mode, they are not required.
  410. */
  411. while (*pz == '-') pz++;
  412. return longOptionFind( pOpts, pz, pOptState );
  413. }
  414. /*
  415. * Note the kind of flag/option marker
  416. */
  417. if (*((pOpts->pzCurOpt)++) != '-')
  418. return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
  419. /*
  420. * Special hack for a hyphen by itself
  421. */
  422. if (*(pOpts->pzCurOpt) == NUL)
  423. return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
  424. /*
  425. * The current argument is to be processed as an option argument
  426. */
  427. pOpts->curOptIdx++;
  428. /*
  429. * We have an option marker.
  430. * Test the next character for long option indication
  431. */
  432. if (pOpts->pzCurOpt[0] == '-') {
  433. if (*++(pOpts->pzCurOpt) == NUL)
  434. /*
  435. * NORMAL COMPLETION - NOT this arg, but rest are operands
  436. */
  437. return PROBLEM;
  438. /*
  439. * We do not allow the hyphen to be used as a flag value.
  440. * Therefore, if long options are not to be accepted, we punt.
  441. */
  442. if ((pOpts->fOptSet & OPTPROC_LONGOPT) == 0) {
  443. fprintf( stderr, zIllOptStr, pOpts->pzProgPath,
  444. zIllegal, pOpts->pzCurOpt-2 );
  445. return FAILURE;
  446. }
  447. return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState );
  448. }
  449. /*
  450. * If short options are not allowed, then do long
  451. * option processing. Otherwise the character must be a
  452. * short (i.e. single character) option.
  453. */
  454. if ((pOpts->fOptSet & OPTPROC_SHORTOPT) != 0)
  455. return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState );
  456. return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState );
  457. }
  458. /*
  459. * nextOption
  460. *
  461. * Find the option descriptor and option argument (if any) for the
  462. * next command line argument. DO NOT modify the descriptor. Put
  463. * all the state in the state argument so that the option can be skipped
  464. * without consequence (side effect).
  465. */
  466. static tSuccess
  467. nextOption( tOptions* pOpts, tOptState* pOptState )
  468. {
  469. tSuccess res;
  470. enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE;
  471. teOptArgType at;
  472. res = findOptDesc( pOpts, pOptState );
  473. if (! SUCCESSFUL( res ))
  474. return res;
  475. pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK);
  476. at = OPTST_GET_ARGTYPE(pOptState->flags);
  477. /*
  478. * Figure out what to do about option arguments. An argument may be
  479. * required, not associated with the option, or be optional. We detect the
  480. * latter by examining for an option marker on the next possible argument.
  481. * Disabled mode option selection also disables option arguments.
  482. */
  483. if ((pOptState->flags & OPTST_DISABLED) != 0)
  484. arg_type = ARG_NONE;
  485. else if (at == OPARG_TYPE_NONE)
  486. arg_type = ARG_NONE;
  487. else if (pOptState->flags & OPTST_ARG_OPTIONAL)
  488. arg_type = ARG_MAY;
  489. else
  490. arg_type = ARG_MUST;
  491. switch (arg_type) {
  492. case ARG_MUST:
  493. /*
  494. * An option argument is required. Long options can either have
  495. * a separate command line argument, or an argument attached by
  496. * the '=' character. Figure out which.
  497. */
  498. switch (pOptState->optType) {
  499. case TOPT_SHORT:
  500. /*
  501. * See if an arg string follows the flag character
  502. */
  503. if (*++(pOpts->pzCurOpt) == NUL)
  504. pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx++ ];
  505. pOptState->pzOptArg = pOpts->pzCurOpt;
  506. break;
  507. case TOPT_LONG:
  508. /*
  509. * See if an arg string has already been assigned (glued on
  510. * with an `=' character)
  511. */
  512. if (pOptState->pzOptArg == NULL)
  513. pOptState->pzOptArg = pOpts->origArgVect[ pOpts->curOptIdx++ ];
  514. break;
  515. default:
  516. #ifdef DEBUG
  517. fputs( "AutoOpts lib error: option type not selected\n",
  518. stderr );
  519. exit( EXIT_FAILURE );
  520. #endif
  521. case TOPT_DEFAULT:
  522. /*
  523. * The option was selected by default. The current token is
  524. * the option argument.
  525. */
  526. break;
  527. }
  528. /*
  529. * Make sure we did not overflow the argument list.
  530. */
  531. if (pOpts->curOptIdx > pOpts->origArgCt) {
  532. fprintf( stderr, zMisArg, pOpts->pzProgPath,
  533. pOptState->pOD->pz_Name );
  534. return FAILURE;
  535. }
  536. pOpts->pzCurOpt = NULL; /* next time advance to next arg */
  537. break;
  538. case ARG_MAY:
  539. /*
  540. * An option argument is optional.
  541. */
  542. switch (pOptState->optType) {
  543. case TOPT_SHORT:
  544. if (*++pOpts->pzCurOpt != NUL)
  545. pOptState->pzOptArg = pOpts->pzCurOpt;
  546. else {
  547. char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
  548. /*
  549. * BECAUSE it is optional, we must make sure
  550. * we did not find another flag and that there
  551. * is such an argument.
  552. */
  553. if ((pzLA == NULL) || (*pzLA == '-'))
  554. pOptState->pzOptArg = NULL;
  555. else {
  556. pOpts->curOptIdx++; /* argument found */
  557. pOptState->pzOptArg = pzLA;
  558. }
  559. }
  560. break;
  561. case TOPT_LONG:
  562. /*
  563. * Look for an argument if we don't already have one (glued on
  564. * with a `=' character) *AND* we are not in named argument mode
  565. */
  566. if ( (pOptState->pzOptArg == NULL)
  567. && (! NAMED_OPTS(pOpts))) {
  568. char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
  569. /*
  570. * BECAUSE it is optional, we must make sure
  571. * we did not find another flag and that there
  572. * is such an argument.
  573. */
  574. if ((pzLA == NULL) || (*pzLA == '-'))
  575. pOptState->pzOptArg = NULL;
  576. else {
  577. pOpts->curOptIdx++; /* argument found */
  578. pOptState->pzOptArg = pzLA;
  579. }
  580. }
  581. break;
  582. default:
  583. case TOPT_DEFAULT:
  584. fputs( "AutoOpts lib error: defaulted to option with optional arg\n",
  585. stderr );
  586. exit( EX_SOFTWARE );
  587. }
  588. /*
  589. * After an option with an optional argument, we will
  590. * *always* start with the next option because if there
  591. * were any characters following the option name/flag,
  592. * they would be interpreted as the argument.
  593. */
  594. pOpts->pzCurOpt = NULL;
  595. break;
  596. default: /* CANNOT */
  597. /*
  598. * No option argument. Make sure next time around we find
  599. * the correct option flag character for short options
  600. */
  601. if (pOptState->optType == TOPT_SHORT)
  602. (pOpts->pzCurOpt)++;
  603. /*
  604. * It is a long option. Make sure there was no ``=xxx'' argument
  605. */
  606. else if (pOptState->pzOptArg != NULL) {
  607. fprintf( stderr, zNoArg, pOpts->pzProgPath,
  608. pOptState->pOD->pz_Name );
  609. return FAILURE;
  610. }
  611. /*
  612. * It is a long option. Advance to next command line argument.
  613. */
  614. else
  615. pOpts->pzCurOpt = NULL;
  616. }
  617. return SUCCESS;
  618. }
  619. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  620. *
  621. * DO PRESETS
  622. *
  623. * The next several routines do the immediate action pass on the command
  624. * line options, then the environment variables, then the config files in
  625. * reverse order. Once done with that, the order is reversed and all
  626. * the config files and environment variables are processed again, this
  627. * time only processing the non-immediate action options. doPresets()
  628. * will then return for optionProcess() to do the final pass on the command
  629. * line arguments.
  630. */
  631. /*
  632. * doImmediateOpts - scan the command line for immediate action options
  633. */
  634. LOCAL tSuccess
  635. doImmediateOpts( tOptions* pOpts )
  636. {
  637. pOpts->curOptIdx = 1; /* start by skipping program name */
  638. pOpts->pzCurOpt = NULL;
  639. /*
  640. * Examine all the options from the start. We process any options that
  641. * are marked for immediate processing.
  642. */
  643. for (;;) {
  644. tOptState optState = OPTSTATE_INITIALIZER(PRESET);
  645. switch (nextOption( pOpts, &optState )) {
  646. case FAILURE: goto optionsDone;
  647. case PROBLEM: return SUCCESS; /* no more args */
  648. case SUCCESS: break;
  649. }
  650. /*
  651. * IF this *is* an immediate-attribute option, then do it.
  652. */
  653. if (! DO_IMMEDIATELY(optState.flags))
  654. continue;
  655. if (! SUCCESSFUL( handleOption( pOpts, &optState )))
  656. break;
  657. } optionsDone:;
  658. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
  659. (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
  660. return FAILURE;
  661. }
  662. LOCAL tSuccess
  663. doRegularOpts( tOptions* pOpts )
  664. {
  665. /*
  666. * Now, process all the options from our current position onward.
  667. * (This allows interspersed options and arguments for the few
  668. * non-standard programs that require it.)
  669. */
  670. for (;;) {
  671. tOptState optState = OPTSTATE_INITIALIZER(DEFINED);
  672. switch (nextOption( pOpts, &optState )) {
  673. case FAILURE: goto optionsDone;
  674. case PROBLEM: return SUCCESS; /* no more args */
  675. case SUCCESS: break;
  676. }
  677. /*
  678. * IF this is not being processed normally (i.e. is immediate action)
  679. * THEN skip it (unless we are supposed to do it a second time).
  680. */
  681. if (! DO_NORMALLY(optState.flags)) {
  682. if (! DO_SECOND_TIME(optState.flags))
  683. continue;
  684. optState.pOD->optOccCt--; /* don't count last time */
  685. }
  686. if (! SUCCESSFUL( handleOption( pOpts, &optState )))
  687. break;
  688. } optionsDone:;
  689. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
  690. (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
  691. return FAILURE;
  692. }
  693. /*
  694. * doPresets - check for preset values from a config file or the envrionment
  695. */
  696. static tSuccess
  697. doPresets( tOptions* pOpts )
  698. {
  699. tOptDesc * pOD = NULL;
  700. if (! SUCCESSFUL( doImmediateOpts( pOpts )))
  701. return FAILURE;
  702. /*
  703. * IF this option set has a --save-opts option, then it also
  704. * has a --load-opts option. See if a command line option has disabled
  705. * option presetting.
  706. */
  707. if (pOpts->specOptIdx.save_opts != 0) {
  708. pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
  709. if (DISABLED_OPT(pOD))
  710. return SUCCESS;
  711. }
  712. /*
  713. * Until we return from this procedure, disable non-presettable opts
  714. */
  715. pOpts->fOptSet |= OPTPROC_PRESETTING;
  716. /*
  717. * IF there are no config files,
  718. * THEN do any environment presets and leave.
  719. */
  720. if (pOpts->papzHomeList == NULL) {
  721. doEnvPresets( pOpts, ENV_ALL );
  722. }
  723. else {
  724. doEnvPresets( pOpts, ENV_IMM );
  725. /*
  726. * Check to see if environment variables have disabled presetting.
  727. */
  728. if ((pOD != NULL) && ! DISABLED_OPT(pOD))
  729. internalFileLoad( pOpts );
  730. /*
  731. * ${PROGRAM_LOAD_OPTS} value of "no" cannot disable other environment
  732. * variable options. Only the loading of .rc files.
  733. */
  734. doEnvPresets( pOpts, ENV_NON_IMM );
  735. }
  736. pOpts->fOptSet &= ~OPTPROC_PRESETTING;
  737. return SUCCESS;
  738. }
  739. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  740. *
  741. * VERIFY OPTION CONSISTENCY
  742. *
  743. * Make sure that the argument list passes our consistency tests.
  744. */
  745. static int
  746. checkConsistency( tOptions* pOpts )
  747. {
  748. int errCt = 0;
  749. tOptDesc* pOD = pOpts->pOptDesc;
  750. int oCt = pOpts->presetOptCt;
  751. /*
  752. * FOR each of "oCt" options, ...
  753. */
  754. for (;;) {
  755. const int* pMust = pOD->pOptMust;
  756. const int* pCant = pOD->pOptCant;
  757. /*
  758. * IF the current option was provided on the command line
  759. * THEN ensure that any "MUST" requirements are not
  760. * "DEFAULT" (unspecified) *AND* ensure that any
  761. * "CANT" options have not been SET or DEFINED.
  762. */
  763. if (SELECTED_OPT(pOD)) {
  764. if (pMust != NULL) for (;;) {
  765. tOptDesc* p = pOpts->pOptDesc + *(pMust++);
  766. if (UNUSED_OPT(p)) {
  767. const tOptDesc* pN = pOpts->pOptDesc + pMust[-1];
  768. errCt++;
  769. fprintf( stderr, zReqFmt, pOD->pz_Name, pN->pz_Name );
  770. }
  771. if (*pMust == NO_EQUIVALENT)
  772. break;
  773. }
  774. if (pCant != NULL) for (;;) {
  775. tOptDesc* p = pOpts->pOptDesc + *(pCant++);
  776. if (SELECTED_OPT(p)) {
  777. const tOptDesc* pN = pOpts->pOptDesc + pCant[-1];
  778. errCt++;
  779. fprintf( stderr, zCantFmt, pOD->pz_Name, pN->pz_Name );
  780. }
  781. if (*pCant == NO_EQUIVALENT)
  782. break;
  783. }
  784. }
  785. /*
  786. * IF this option is not equivalenced to another,
  787. * OR it is equivalenced to itself (is the equiv. root)
  788. * THEN we need to make sure it occurs often enough.
  789. */
  790. if ( (pOD->optEquivIndex == NO_EQUIVALENT)
  791. || (pOD->optEquivIndex == pOD->optIndex) ) do {
  792. /*
  793. * IF the occurrence counts have been satisfied,
  794. * THEN there is no problem.
  795. */
  796. if (pOD->optOccCt >= pOD->optMinCt)
  797. break;
  798. /*
  799. * IF MUST_SET means SET and PRESET are okay,
  800. * so min occurrence count doesn't count
  801. */
  802. if ( (pOD->fOptState & OPTST_MUST_SET)
  803. && (pOD->fOptState & (OPTST_PRESET | OPTST_SET)) )
  804. break;
  805. errCt++;
  806. if (pOD->optMinCt > 1)
  807. fprintf( stderr, zNotEnough, pOD->pz_Name, pOD->optMinCt );
  808. else fprintf( stderr, zNeedOne, pOD->pz_Name );
  809. } while (0);
  810. if (--oCt <= 0)
  811. break;
  812. pOD++;
  813. }
  814. /*
  815. * IF we are stopping on errors, check to see if any remaining
  816. * arguments are required to be there or prohibited from being there.
  817. */
  818. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
  819. /*
  820. * Check for prohibition
  821. */
  822. if ((pOpts->fOptSet & OPTPROC_NO_ARGS) != 0) {
  823. if (pOpts->origArgCt > pOpts->curOptIdx) {
  824. fprintf( stderr, zNoArgs, pOpts->pzProgName );
  825. ++errCt;
  826. }
  827. }
  828. /*
  829. * ELSE not prohibited, check for being required
  830. */
  831. else if ((pOpts->fOptSet & OPTPROC_ARGS_REQ) != 0) {
  832. if (pOpts->origArgCt <= pOpts->curOptIdx) {
  833. fprintf( stderr, zArgsMust, pOpts->pzProgName );
  834. ++errCt;
  835. }
  836. }
  837. }
  838. return errCt;
  839. }
  840. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  841. *
  842. * THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE
  843. */
  844. /*=--subblock=arg=arg_type,arg_name,arg_desc =*/
  845. /*=*
  846. * library: opts
  847. * header: your-opts.h
  848. *
  849. * lib_description:
  850. *
  851. * These are the routines that libopts users may call directly from their
  852. * code. There are several other routines that can be called by code
  853. * generated by the libopts option templates, but they are not to be
  854. * called from any other user code. The @file{options.h} header is
  855. * fairly clear about this, too.
  856. =*/
  857. /*=export_func optionProcess
  858. *
  859. * what: this is the main option processing routine
  860. *
  861. * arg: + tOptions* + pOpts + program options descriptor +
  862. * arg: + int + argc + program arg count +
  863. * arg: + char** + argv + program arg vector +
  864. *
  865. * ret_type: int
  866. * ret_desc: the count of the arguments processed
  867. *
  868. * doc:
  869. *
  870. * This is the main entry point for processing options. It is intended
  871. * that this procedure be called once at the beginning of the execution of
  872. * a program. Depending on options selected earlier, it is sometimes
  873. * necessary to stop and restart option processing, or to select completely
  874. * different sets of options. This can be done easily, but you generally
  875. * do not want to do this.
  876. *
  877. * The number of arguments processed always includes the program name.
  878. * If one of the arguments is "--", then it is counted and the processing
  879. * stops. If an error was encountered and errors are to be tolerated, then
  880. * the returned value is the index of the argument causing the error.
  881. * A hyphen by itself ("-") will also cause processing to stop and will
  882. * @emph{not} be counted among the processed arguments. A hyphen by itself
  883. * is treated as an operand. Encountering an operand stops option
  884. * processing.
  885. *
  886. * err: Errors will cause diagnostics to be printed. @code{exit(3)} may
  887. * or may not be called. It depends upon whether or not the options
  888. * were generated with the "allow-errors" attribute, or if the
  889. * ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked.
  890. =*/
  891. int
  892. optionProcess(
  893. tOptions* pOpts,
  894. int argCt,
  895. char** argVect )
  896. {
  897. if (! SUCCESSFUL( validateOptionsStruct( pOpts, argVect[0] )))
  898. exit( EX_SOFTWARE );
  899. /*
  900. * Establish the real program name, the program full path,
  901. * and do all the presetting the first time thru only.
  902. */
  903. if ((pOpts->fOptSet & OPTPROC_INITDONE) == 0) {
  904. pOpts->origArgCt = argCt;
  905. pOpts->origArgVect = argVect;
  906. pOpts->fOptSet |= OPTPROC_INITDONE;
  907. if (! SUCCESSFUL( doPresets( pOpts )))
  908. return 0;
  909. if ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
  910. optionSort( pOpts );
  911. pOpts->curOptIdx = 1;
  912. pOpts->pzCurOpt = NULL;
  913. }
  914. /*
  915. * IF we are (re)starting,
  916. * THEN reset option location
  917. */
  918. else if (pOpts->curOptIdx <= 0) {
  919. pOpts->curOptIdx = 1;
  920. pOpts->pzCurOpt = NULL;
  921. }
  922. if (! SUCCESSFUL( doRegularOpts( pOpts )))
  923. return pOpts->origArgCt;
  924. /*
  925. * IF there were no errors
  926. * AND we have RC/INI files
  927. * AND there is a request to save the files
  928. * THEN do that now before testing for conflicts.
  929. * (conflicts are ignored in preset options)
  930. */
  931. if (pOpts->specOptIdx.save_opts != 0) {
  932. tOptDesc* pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts;
  933. if (SELECTED_OPT( pOD )) {
  934. optionSaveFile( pOpts );
  935. exit( EXIT_SUCCESS );
  936. }
  937. }
  938. /*
  939. * IF we are checking for errors,
  940. * THEN look for too few occurrences of required options
  941. */
  942. if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
  943. if (checkConsistency( pOpts ) != 0)
  944. (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
  945. }
  946. return pOpts->curOptIdx;
  947. }
  948. /*
  949. * Local Variables:
  950. * mode: C
  951. * c-file-style: "stroustrup"
  952. * indent-tabs-mode: nil
  953. * End:
  954. * end of autoopts/autoopts.c */