autoopts.c revision 181834
1181834Sroberto 2181834Sroberto/* 3181834Sroberto * $Id: autoopts.c,v 4.25 2007/04/15 19:01:18 bkorb Exp $ 4181834Sroberto * Time-stamp: "2007-04-15 11:10:40 bkorb" 5181834Sroberto * 6181834Sroberto * This file contains all of the routines that must be linked into 7181834Sroberto * an executable to use the generated option processing. The optional 8181834Sroberto * routines are in separately compiled modules so that they will not 9181834Sroberto * necessarily be linked in. 10181834Sroberto */ 11181834Sroberto 12181834Sroberto/* 13181834Sroberto * Automated Options copyright 1992-2007 Bruce Korb 14181834Sroberto * 15181834Sroberto * Automated Options is free software. 16181834Sroberto * You may redistribute it and/or modify it under the terms of the 17181834Sroberto * GNU General Public License, as published by the Free Software 18181834Sroberto * Foundation; either version 2, or (at your option) any later version. 19181834Sroberto * 20181834Sroberto * Automated Options is distributed in the hope that it will be useful, 21181834Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of 22181834Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23181834Sroberto * GNU General Public License for more details. 24181834Sroberto * 25181834Sroberto * You should have received a copy of the GNU General Public License 26181834Sroberto * along with Automated Options. See the file "COPYING". If not, 27181834Sroberto * write to: The Free Software Foundation, Inc., 28181834Sroberto * 51 Franklin Street, Fifth Floor, 29181834Sroberto * Boston, MA 02110-1301, USA. 30181834Sroberto * 31181834Sroberto * As a special exception, Bruce Korb gives permission for additional 32181834Sroberto * uses of the text contained in his release of AutoOpts. 33181834Sroberto * 34181834Sroberto * The exception is that, if you link the AutoOpts library with other 35181834Sroberto * files to produce an executable, this does not by itself cause the 36181834Sroberto * resulting executable to be covered by the GNU General Public License. 37181834Sroberto * Your use of that executable is in no way restricted on account of 38181834Sroberto * linking the AutoOpts library code into it. 39181834Sroberto * 40181834Sroberto * This exception does not however invalidate any other reasons why 41181834Sroberto * the executable file might be covered by the GNU General Public License. 42181834Sroberto * 43181834Sroberto * This exception applies only to the code released by Bruce Korb under 44181834Sroberto * the name AutoOpts. If you copy code from other sources under the 45181834Sroberto * General Public License into a copy of AutoOpts, as the General Public 46181834Sroberto * License permits, the exception does not apply to the code that you add 47181834Sroberto * in this way. To avoid misleading anyone as to the status of such 48181834Sroberto * modified files, you must delete this exception notice from them. 49181834Sroberto * 50181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice 51181834Sroberto * whether to permit this exception to apply to your modifications. 52181834Sroberto * If you do not wish that, delete this exception notice. 53181834Sroberto */ 54181834Sroberto 55181834Srobertostatic char const zNil[] = ""; 56181834Sroberto 57181834Sroberto/* = = = START-STATIC-FORWARD = = = */ 58181834Sroberto/* static forward declarations maintained by :mkfwd */ 59181834Srobertostatic tSuccess 60181834SrobertofindOptDesc( tOptions* pOpts, tOptState* pOptState ); 61181834Sroberto 62181834Srobertostatic tSuccess 63181834SrobertonextOption( tOptions* pOpts, tOptState* pOptState ); 64181834Sroberto 65181834Srobertostatic tSuccess 66181834SrobertodoPresets( tOptions* pOpts ); 67181834Sroberto 68181834Srobertostatic int 69181834SrobertocheckConsistency( tOptions* pOpts ); 70181834Sroberto/* = = = END-STATIC-FORWARD = = = */ 71181834Sroberto 72181834SrobertoLOCAL void * 73181834Srobertoao_malloc( size_t sz ) 74181834Sroberto{ 75181834Sroberto void * res = malloc(sz); 76181834Sroberto if (res == NULL) { 77181834Sroberto fprintf( stderr, "malloc of %d bytes failed\n", (int)sz ); 78181834Sroberto exit( EXIT_FAILURE ); 79181834Sroberto } 80181834Sroberto return res; 81181834Sroberto} 82181834Sroberto#undef malloc 83181834Sroberto#define malloc(_s) ao_malloc(_s) 84181834Sroberto 85181834SrobertoLOCAL void * 86181834Srobertoao_realloc( void *p, size_t sz ) 87181834Sroberto{ 88181834Sroberto void * res = realloc(p, sz); 89181834Sroberto if (res == NULL) { 90181834Sroberto fprintf( stderr, "realloc of %d bytes at 0x%p failed\n", (int)sz, p ); 91181834Sroberto exit( EXIT_FAILURE ); 92181834Sroberto } 93181834Sroberto return res; 94181834Sroberto} 95181834Sroberto#undef realloc 96181834Sroberto#define realloc(_p,_s) ao_realloc(_p,_s) 97181834Sroberto 98181834Sroberto 99181834SrobertoLOCAL void 100181834Srobertoao_free( void *p ) 101181834Sroberto{ 102181834Sroberto if (p != NULL) 103181834Sroberto free(p); 104181834Sroberto} 105181834Sroberto#undef free 106181834Sroberto#define free(_p) ao_free(_p) 107181834Sroberto 108181834Sroberto 109181834SrobertoLOCAL char * 110181834Srobertoao_strdup( char const *str ) 111181834Sroberto{ 112181834Sroberto char * res = strdup(str); 113181834Sroberto if (res == NULL) { 114181834Sroberto fprintf( stderr, "strdup of %d byte string failed\n", (int)strlen(str) ); 115181834Sroberto exit( EXIT_FAILURE ); 116181834Sroberto } 117181834Sroberto return res; 118181834Sroberto} 119181834Sroberto#undef strdup 120181834Sroberto#define strdup(_p) ao_strdup(_p) 121181834Sroberto 122181834Sroberto#ifndef HAVE_PATHFIND 123181834Sroberto# include "compat/pathfind.c" 124181834Sroberto#endif 125181834Sroberto 126181834Sroberto#ifndef HAVE_SNPRINTF 127181834Sroberto# include "compat/snprintf.c" 128181834Sroberto#endif 129181834Sroberto 130181834Sroberto#ifndef HAVE_STRDUP 131181834Sroberto# include "compat/strdup.c" 132181834Sroberto#endif 133181834Sroberto 134181834Sroberto#ifndef HAVE_STRCHR 135181834Sroberto# include "compat/strchr.c" 136181834Sroberto#endif 137181834Sroberto 138181834Sroberto/* 139181834Sroberto * handleOption 140181834Sroberto * 141181834Sroberto * This routine handles equivalencing, sets the option state flags and 142181834Sroberto * invokes the handler procedure, if any. 143181834Sroberto */ 144181834SrobertoLOCAL tSuccess 145181834SrobertohandleOption( tOptions* pOpts, tOptState* pOptState ) 146181834Sroberto{ 147181834Sroberto /* 148181834Sroberto * Save a copy of the option procedure pointer. 149181834Sroberto * If this is an equivalence class option, we still want this proc. 150181834Sroberto */ 151181834Sroberto tOptDesc* pOD = pOptState->pOD; 152181834Sroberto tOptProc* pOP = pOD->pOptProc; 153181834Sroberto if (pOD->fOptState & OPTST_ALLOC_ARG) 154181834Sroberto AGFREE(pOD->optArg.argString); 155181834Sroberto 156181834Sroberto pOD->optArg.argString = pOptState->pzOptArg; 157181834Sroberto 158181834Sroberto /* 159181834Sroberto * IF we are presetting options, then we will ignore any un-presettable 160181834Sroberto * options. They are the ones either marked as such. 161181834Sroberto */ 162181834Sroberto if ( ((pOpts->fOptSet & OPTPROC_PRESETTING) != 0) 163181834Sroberto && ((pOD->fOptState & OPTST_NO_INIT) != 0) 164181834Sroberto ) 165181834Sroberto return PROBLEM; 166181834Sroberto 167181834Sroberto /* 168181834Sroberto * IF this is an equivalence class option, 169181834Sroberto * THEN 170181834Sroberto * Save the option value that got us to this option 171181834Sroberto * entry. (It may not be pOD->optChar[0], if this is an 172181834Sroberto * equivalence entry.) 173181834Sroberto * set the pointer to the equivalence class base 174181834Sroberto */ 175181834Sroberto if (pOD->optEquivIndex != NO_EQUIVALENT) { 176181834Sroberto tOptDesc* p = pOpts->pOptDesc + pOD->optEquivIndex; 177181834Sroberto 178181834Sroberto /* 179181834Sroberto * IF the current option state has not been defined (set on the 180181834Sroberto * command line), THEN we will allow continued resetting of 181181834Sroberto * the value. Once "defined", then it must not change. 182181834Sroberto */ 183181834Sroberto if ((pOD->fOptState & OPTST_DEFINED) != 0) { 184181834Sroberto /* 185181834Sroberto * The equivalenced-to option has been found on the command 186181834Sroberto * line before. Make sure new occurrences are the same type. 187181834Sroberto * 188181834Sroberto * IF this option has been previously equivalenced and 189181834Sroberto * it was not the same equivalenced-to option, 190181834Sroberto * THEN we have a usage problem. 191181834Sroberto */ 192181834Sroberto if (p->optActualIndex != pOD->optIndex) { 193181834Sroberto fprintf( stderr, (char*)zMultiEquiv, p->pz_Name, pOD->pz_Name, 194181834Sroberto (pOpts->pOptDesc + p->optActualIndex)->pz_Name); 195181834Sroberto return FAILURE; 196181834Sroberto } 197181834Sroberto } else { 198181834Sroberto /* 199181834Sroberto * Set the equivalenced-to actual option index to no-equivalent 200181834Sroberto * so that we set all the entries below. This option may either 201181834Sroberto * never have been selected before, or else it was selected by 202181834Sroberto * some sort of "presetting" mechanism. 203181834Sroberto */ 204181834Sroberto p->optActualIndex = NO_EQUIVALENT; 205181834Sroberto } 206181834Sroberto 207181834Sroberto if (p->optActualIndex != pOD->optIndex) { 208181834Sroberto /* 209181834Sroberto * First time through, copy over the state 210181834Sroberto * and add in the equivalence flag 211181834Sroberto */ 212181834Sroberto p->optActualValue = pOD->optValue; 213181834Sroberto p->optActualIndex = pOD->optIndex; 214181834Sroberto pOptState->flags |= OPTST_EQUIVALENCE; 215181834Sroberto } 216181834Sroberto 217181834Sroberto /* 218181834Sroberto * Copy the most recent option argument. set membership state 219181834Sroberto * is kept in ``p->optCookie''. Do not overwrite. 220181834Sroberto */ 221181834Sroberto p->optArg.argString = pOD->optArg.argString; 222181834Sroberto pOD = p; 223181834Sroberto 224181834Sroberto } else { 225181834Sroberto pOD->optActualValue = pOD->optValue; 226181834Sroberto pOD->optActualIndex = pOD->optIndex; 227181834Sroberto } 228181834Sroberto 229181834Sroberto pOD->fOptState &= OPTST_PERSISTENT_MASK; 230181834Sroberto pOD->fOptState |= (pOptState->flags & ~OPTST_PERSISTENT_MASK); 231181834Sroberto 232181834Sroberto /* 233181834Sroberto * Keep track of count only for DEFINED (command line) options. 234181834Sroberto * IF we have too many, build up an error message and bail. 235181834Sroberto */ 236181834Sroberto if ( (pOD->fOptState & OPTST_DEFINED) 237181834Sroberto && (++pOD->optOccCt > pOD->optMaxCt) ) { 238181834Sroberto 239181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 240181834Sroberto char const * pzEqv = 241181834Sroberto (pOD->optEquivIndex != NO_EQUIVALENT) ? zEquiv : zNil; 242181834Sroberto 243181834Sroberto fputs( zErrOnly, stderr ); 244181834Sroberto 245181834Sroberto if (pOD->optMaxCt > 1) 246181834Sroberto fprintf(stderr, zAtMost, pOD->optMaxCt, pOD->pz_Name, pzEqv); 247181834Sroberto else 248181834Sroberto fprintf(stderr, zOnlyOne, pOD->pz_Name, pzEqv); 249181834Sroberto } 250181834Sroberto 251181834Sroberto return FAILURE; 252181834Sroberto } 253181834Sroberto 254181834Sroberto /* 255181834Sroberto * If provided a procedure to call, call it 256181834Sroberto */ 257181834Sroberto if (pOP != (tpOptProc)NULL) 258181834Sroberto (*pOP)( pOpts, pOD ); 259181834Sroberto 260181834Sroberto return SUCCESS; 261181834Sroberto} 262181834Sroberto 263181834Sroberto 264181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 265181834Sroberto * 266181834Sroberto * HUNT FOR OPTIONS IN THE ARGUMENT LIST 267181834Sroberto * 268181834Sroberto * The next four procedures are "private" to nextOption(). 269181834Sroberto * nextOption() uses findOptDesc() to find the next descriptor and it, in 270181834Sroberto * turn, uses longOptionFind() and shortOptionFind() to actually do the hunt. 271181834Sroberto * 272181834Sroberto * longOptionFind 273181834Sroberto * 274181834Sroberto * Find the long option descriptor for the current option 275181834Sroberto */ 276181834SrobertoLOCAL tSuccess 277181834SrobertolongOptionFind( tOptions* pOpts, char* pzOptName, tOptState* pOptState ) 278181834Sroberto{ 279181834Sroberto ag_bool disable = AG_FALSE; 280181834Sroberto char* pzEq = strchr( pzOptName, '=' ); 281181834Sroberto tOptDesc* pOD = pOpts->pOptDesc; 282181834Sroberto int idx = 0; 283181834Sroberto int idxLim = pOpts->optCt; 284181834Sroberto int matchCt = 0; 285181834Sroberto int matchIdx = 0; 286181834Sroberto int nameLen; 287181834Sroberto 288181834Sroberto /* 289181834Sroberto * IF the value is attached to the name, 290181834Sroberto * THEN clip it off. 291181834Sroberto * Either way, figure out how long our name is 292181834Sroberto */ 293181834Sroberto if (pzEq != NULL) { 294181834Sroberto nameLen = (int)(pzEq - pzOptName); 295181834Sroberto *pzEq = NUL; 296181834Sroberto } else nameLen = strlen( pzOptName ); 297181834Sroberto 298181834Sroberto do { 299181834Sroberto if (SKIP_OPT(pOD)) 300181834Sroberto continue; 301181834Sroberto 302181834Sroberto if (strneqvcmp( pzOptName, pOD->pz_Name, nameLen ) == 0) { 303181834Sroberto /* 304181834Sroberto * IF we have a complete match 305181834Sroberto * THEN it takes priority over any already located partial 306181834Sroberto */ 307181834Sroberto if (pOD->pz_Name[ nameLen ] == NUL) { 308181834Sroberto matchCt = 1; 309181834Sroberto matchIdx = idx; 310181834Sroberto break; 311181834Sroberto } 312181834Sroberto } 313181834Sroberto 314181834Sroberto /* 315181834Sroberto * IF there is a disable name 316181834Sroberto * *AND* no argument value has been supplied 317181834Sroberto * (disabled options may have no argument) 318181834Sroberto * *AND* the option name matches the disable name 319181834Sroberto * THEN ... 320181834Sroberto */ 321181834Sroberto else if ( (pOD->pz_DisableName != NULL) 322181834Sroberto && (strneqvcmp(pzOptName, pOD->pz_DisableName, nameLen) == 0) 323181834Sroberto ) { 324181834Sroberto disable = AG_TRUE; 325181834Sroberto 326181834Sroberto /* 327181834Sroberto * IF we have a complete match 328181834Sroberto * THEN it takes priority over any already located partial 329181834Sroberto */ 330181834Sroberto if (pOD->pz_DisableName[ nameLen ] == NUL) { 331181834Sroberto matchCt = 1; 332181834Sroberto matchIdx = idx; 333181834Sroberto break; 334181834Sroberto } 335181834Sroberto } 336181834Sroberto 337181834Sroberto else 338181834Sroberto continue; 339181834Sroberto 340181834Sroberto /* 341181834Sroberto * We found a partial match, either regular or disabling. 342181834Sroberto * Remember the index for later. 343181834Sroberto */ 344181834Sroberto matchIdx = idx; 345181834Sroberto 346181834Sroberto if (++matchCt > 1) 347181834Sroberto break; 348181834Sroberto 349181834Sroberto } while (pOD++, (++idx < idxLim)); 350181834Sroberto 351181834Sroberto if (pzEq != NULL) 352181834Sroberto *(pzEq++) = '='; 353181834Sroberto 354181834Sroberto /* 355181834Sroberto * Make sure we either found an exact match or found only one partial 356181834Sroberto */ 357181834Sroberto if (matchCt == 1) { 358181834Sroberto /* 359181834Sroberto * IF we found a disablement name, 360181834Sroberto * THEN set the bit in the callers' flag word 361181834Sroberto */ 362181834Sroberto if (disable) 363181834Sroberto pOptState->flags |= OPTST_DISABLED; 364181834Sroberto 365181834Sroberto pOptState->pOD = pOpts->pOptDesc + matchIdx; 366181834Sroberto pOptState->pzOptArg = pzEq; 367181834Sroberto pOptState->optType = TOPT_LONG; 368181834Sroberto return SUCCESS; 369181834Sroberto } 370181834Sroberto 371181834Sroberto /* 372181834Sroberto * IF there is no equal sign 373181834Sroberto * *AND* we are using named arguments 374181834Sroberto * *AND* there is a default named option, 375181834Sroberto * THEN return that option. 376181834Sroberto */ 377181834Sroberto if ( (pzEq == NULL) 378181834Sroberto && NAMED_OPTS(pOpts) 379181834Sroberto && (pOpts->specOptIdx.default_opt != NO_EQUIVALENT)) { 380181834Sroberto pOptState->pOD = pOpts->pOptDesc + pOpts->specOptIdx.default_opt; 381181834Sroberto 382181834Sroberto pOptState->pzOptArg = pzOptName; 383181834Sroberto pOptState->optType = TOPT_DEFAULT; 384181834Sroberto return SUCCESS; 385181834Sroberto } 386181834Sroberto 387181834Sroberto /* 388181834Sroberto * IF we are to stop on errors (the default, actually) 389181834Sroberto * THEN call the usage procedure. 390181834Sroberto */ 391181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 392181834Sroberto fprintf( stderr, zIllOptStr, pOpts->pzProgPath, 393181834Sroberto (matchCt == 0) ? zIllegal : zAmbiguous, pzOptName ); 394181834Sroberto (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 395181834Sroberto } 396181834Sroberto 397181834Sroberto return FAILURE; 398181834Sroberto} 399181834Sroberto 400181834Sroberto 401181834Sroberto/* 402181834Sroberto * shortOptionFind 403181834Sroberto * 404181834Sroberto * Find the short option descriptor for the current option 405181834Sroberto */ 406181834SrobertoLOCAL tSuccess 407181834SrobertoshortOptionFind( tOptions* pOpts, uint_t optValue, tOptState* pOptState ) 408181834Sroberto{ 409181834Sroberto tOptDesc* pRes = pOpts->pOptDesc; 410181834Sroberto int ct = pOpts->optCt; 411181834Sroberto 412181834Sroberto /* 413181834Sroberto * Search the option list 414181834Sroberto */ 415181834Sroberto for (;;) { 416181834Sroberto /* 417181834Sroberto * IF the values match, 418181834Sroberto * THEN we stop here 419181834Sroberto */ 420181834Sroberto if ((! SKIP_OPT(pRes)) && (optValue == pRes->optValue)) { 421181834Sroberto pOptState->pOD = pRes; 422181834Sroberto pOptState->optType = TOPT_SHORT; 423181834Sroberto return SUCCESS; 424181834Sroberto } 425181834Sroberto 426181834Sroberto /* 427181834Sroberto * Advance to next option description 428181834Sroberto */ 429181834Sroberto pRes++; 430181834Sroberto 431181834Sroberto /* 432181834Sroberto * IF we have searched everything, ... 433181834Sroberto */ 434181834Sroberto if (--ct <= 0) 435181834Sroberto break; 436181834Sroberto } 437181834Sroberto 438181834Sroberto /* 439181834Sroberto * IF the character value is a digit 440181834Sroberto * AND there is a special number option ("-n") 441181834Sroberto * THEN the result is the "option" itself and the 442181834Sroberto * option is the specially marked "number" option. 443181834Sroberto */ 444181834Sroberto if ( isdigit( optValue ) 445181834Sroberto && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { 446181834Sroberto pOptState->pOD = \ 447181834Sroberto pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; 448181834Sroberto (pOpts->pzCurOpt)--; 449181834Sroberto pOptState->optType = TOPT_SHORT; 450181834Sroberto return SUCCESS; 451181834Sroberto } 452181834Sroberto 453181834Sroberto /* 454181834Sroberto * IF we are to stop on errors (the default, actually) 455181834Sroberto * THEN call the usage procedure. 456181834Sroberto */ 457181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 458181834Sroberto fprintf( stderr, zIllOptChr, pOpts->pzProgPath, optValue ); 459181834Sroberto (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 460181834Sroberto } 461181834Sroberto 462181834Sroberto return FAILURE; 463181834Sroberto} 464181834Sroberto 465181834Sroberto 466181834Sroberto/* 467181834Sroberto * findOptDesc 468181834Sroberto * 469181834Sroberto * Find the option descriptor for the current option 470181834Sroberto */ 471181834Srobertostatic tSuccess 472181834SrobertofindOptDesc( tOptions* pOpts, tOptState* pOptState ) 473181834Sroberto{ 474181834Sroberto /* 475181834Sroberto * IF we are continuing a short option list (e.g. -xyz...) 476181834Sroberto * THEN continue a single flag option. 477181834Sroberto * OTHERWISE see if there is room to advance and then do so. 478181834Sroberto */ 479181834Sroberto if ((pOpts->pzCurOpt != NULL) && (*pOpts->pzCurOpt != NUL)) 480181834Sroberto return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState ); 481181834Sroberto 482181834Sroberto if (pOpts->curOptIdx >= pOpts->origArgCt) 483181834Sroberto return PROBLEM; /* NORMAL COMPLETION */ 484181834Sroberto 485181834Sroberto pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx ]; 486181834Sroberto 487181834Sroberto /* 488181834Sroberto * IF all arguments must be named options, ... 489181834Sroberto */ 490181834Sroberto if (NAMED_OPTS(pOpts)) { 491181834Sroberto char* pz = pOpts->pzCurOpt; 492181834Sroberto pOpts->curOptIdx++; 493181834Sroberto 494181834Sroberto /* 495181834Sroberto * Skip over any flag/option markers. 496181834Sroberto * In this mode, they are not required. 497181834Sroberto */ 498181834Sroberto while (*pz == '-') pz++; 499181834Sroberto 500181834Sroberto return longOptionFind( pOpts, pz, pOptState ); 501181834Sroberto } 502181834Sroberto 503181834Sroberto /* 504181834Sroberto * Note the kind of flag/option marker 505181834Sroberto */ 506181834Sroberto if (*((pOpts->pzCurOpt)++) != '-') 507181834Sroberto return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 508181834Sroberto 509181834Sroberto /* 510181834Sroberto * Special hack for a hyphen by itself 511181834Sroberto */ 512181834Sroberto if (*(pOpts->pzCurOpt) == NUL) 513181834Sroberto return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 514181834Sroberto 515181834Sroberto /* 516181834Sroberto * The current argument is to be processed as an option argument 517181834Sroberto */ 518181834Sroberto pOpts->curOptIdx++; 519181834Sroberto 520181834Sroberto /* 521181834Sroberto * We have an option marker. 522181834Sroberto * Test the next character for long option indication 523181834Sroberto */ 524181834Sroberto if (pOpts->pzCurOpt[0] == '-') { 525181834Sroberto if (*++(pOpts->pzCurOpt) == NUL) 526181834Sroberto /* 527181834Sroberto * NORMAL COMPLETION - NOT this arg, but rest are operands 528181834Sroberto */ 529181834Sroberto return PROBLEM; 530181834Sroberto 531181834Sroberto /* 532181834Sroberto * We do not allow the hyphen to be used as a flag value. 533181834Sroberto * Therefore, if long options are not to be accepted, we punt. 534181834Sroberto */ 535181834Sroberto if ((pOpts->fOptSet & OPTPROC_LONGOPT) == 0) { 536181834Sroberto fprintf( stderr, zIllOptStr, pOpts->pzProgPath, 537181834Sroberto zIllegal, pOpts->pzCurOpt-2 ); 538181834Sroberto return FAILURE; 539181834Sroberto } 540181834Sroberto 541181834Sroberto return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState ); 542181834Sroberto } 543181834Sroberto 544181834Sroberto /* 545181834Sroberto * If short options are not allowed, then do long 546181834Sroberto * option processing. Otherwise the character must be a 547181834Sroberto * short (i.e. single character) option. 548181834Sroberto */ 549181834Sroberto if ((pOpts->fOptSet & OPTPROC_SHORTOPT) != 0) 550181834Sroberto return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState ); 551181834Sroberto 552181834Sroberto return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState ); 553181834Sroberto} 554181834Sroberto 555181834Sroberto 556181834Sroberto/* 557181834Sroberto * nextOption 558181834Sroberto * 559181834Sroberto * Find the option descriptor and option argument (if any) for the 560181834Sroberto * next command line argument. DO NOT modify the descriptor. Put 561181834Sroberto * all the state in the state argument so that the option can be skipped 562181834Sroberto * without consequence (side effect). 563181834Sroberto */ 564181834Srobertostatic tSuccess 565181834SrobertonextOption( tOptions* pOpts, tOptState* pOptState ) 566181834Sroberto{ 567181834Sroberto tSuccess res; 568181834Sroberto enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE; 569181834Sroberto teOptArgType at; 570181834Sroberto 571181834Sroberto res = findOptDesc( pOpts, pOptState ); 572181834Sroberto if (! SUCCESSFUL( res )) 573181834Sroberto return res; 574181834Sroberto pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK); 575181834Sroberto at = OPTST_GET_ARGTYPE(pOptState->flags); 576181834Sroberto 577181834Sroberto /* 578181834Sroberto * Figure out what to do about option arguments. An argument may be 579181834Sroberto * required, not associated with the option, or be optional. We detect the 580181834Sroberto * latter by examining for an option marker on the next possible argument. 581181834Sroberto * Disabled mode option selection also disables option arguments. 582181834Sroberto */ 583181834Sroberto if ((pOptState->flags & OPTST_DISABLED) != 0) 584181834Sroberto arg_type = ARG_NONE; 585181834Sroberto else if (at == OPARG_TYPE_NONE) 586181834Sroberto arg_type = ARG_NONE; 587181834Sroberto else if (pOptState->flags & OPTST_ARG_OPTIONAL) 588181834Sroberto arg_type = ARG_MAY; 589181834Sroberto else 590181834Sroberto arg_type = ARG_MUST; 591181834Sroberto 592181834Sroberto switch (arg_type) { 593181834Sroberto case ARG_MUST: 594181834Sroberto /* 595181834Sroberto * An option argument is required. Long options can either have 596181834Sroberto * a separate command line argument, or an argument attached by 597181834Sroberto * the '=' character. Figure out which. 598181834Sroberto */ 599181834Sroberto switch (pOptState->optType) { 600181834Sroberto case TOPT_SHORT: 601181834Sroberto /* 602181834Sroberto * See if an arg string follows the flag character 603181834Sroberto */ 604181834Sroberto if (*++(pOpts->pzCurOpt) == NUL) 605181834Sroberto pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx++ ]; 606181834Sroberto pOptState->pzOptArg = pOpts->pzCurOpt; 607181834Sroberto break; 608181834Sroberto 609181834Sroberto case TOPT_LONG: 610181834Sroberto /* 611181834Sroberto * See if an arg string has already been assigned (glued on 612181834Sroberto * with an `=' character) 613181834Sroberto */ 614181834Sroberto if (pOptState->pzOptArg == NULL) 615181834Sroberto pOptState->pzOptArg = pOpts->origArgVect[ pOpts->curOptIdx++ ]; 616181834Sroberto break; 617181834Sroberto 618181834Sroberto default: 619181834Sroberto#ifdef DEBUG 620181834Sroberto fputs( "AutoOpts lib error: option type not selected\n", 621181834Sroberto stderr ); 622181834Sroberto exit( EXIT_FAILURE ); 623181834Sroberto#endif 624181834Sroberto 625181834Sroberto case TOPT_DEFAULT: 626181834Sroberto /* 627181834Sroberto * The option was selected by default. The current token is 628181834Sroberto * the option argument. 629181834Sroberto */ 630181834Sroberto break; 631181834Sroberto } 632181834Sroberto 633181834Sroberto /* 634181834Sroberto * Make sure we did not overflow the argument list. 635181834Sroberto */ 636181834Sroberto if (pOpts->curOptIdx > pOpts->origArgCt) { 637181834Sroberto fprintf( stderr, zMisArg, pOpts->pzProgPath, 638181834Sroberto pOptState->pOD->pz_Name ); 639181834Sroberto return FAILURE; 640181834Sroberto } 641181834Sroberto 642181834Sroberto pOpts->pzCurOpt = NULL; /* next time advance to next arg */ 643181834Sroberto break; 644181834Sroberto 645181834Sroberto case ARG_MAY: 646181834Sroberto /* 647181834Sroberto * An option argument is optional. 648181834Sroberto */ 649181834Sroberto switch (pOptState->optType) { 650181834Sroberto case TOPT_SHORT: 651181834Sroberto if (*++pOpts->pzCurOpt != NUL) 652181834Sroberto pOptState->pzOptArg = pOpts->pzCurOpt; 653181834Sroberto else { 654181834Sroberto char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 655181834Sroberto 656181834Sroberto /* 657181834Sroberto * BECAUSE it is optional, we must make sure 658181834Sroberto * we did not find another flag and that there 659181834Sroberto * is such an argument. 660181834Sroberto */ 661181834Sroberto if ((pzLA == NULL) || (*pzLA == '-')) 662181834Sroberto pOptState->pzOptArg = NULL; 663181834Sroberto else { 664181834Sroberto pOpts->curOptIdx++; /* argument found */ 665181834Sroberto pOptState->pzOptArg = pzLA; 666181834Sroberto } 667181834Sroberto } 668181834Sroberto break; 669181834Sroberto 670181834Sroberto case TOPT_LONG: 671181834Sroberto /* 672181834Sroberto * Look for an argument if we don't already have one (glued on 673181834Sroberto * with a `=' character) *AND* we are not in named argument mode 674181834Sroberto */ 675181834Sroberto if ( (pOptState->pzOptArg == NULL) 676181834Sroberto && (! NAMED_OPTS(pOpts))) { 677181834Sroberto char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 678181834Sroberto 679181834Sroberto /* 680181834Sroberto * BECAUSE it is optional, we must make sure 681181834Sroberto * we did not find another flag and that there 682181834Sroberto * is such an argument. 683181834Sroberto */ 684181834Sroberto if ((pzLA == NULL) || (*pzLA == '-')) 685181834Sroberto pOptState->pzOptArg = NULL; 686181834Sroberto else { 687181834Sroberto pOpts->curOptIdx++; /* argument found */ 688181834Sroberto pOptState->pzOptArg = pzLA; 689181834Sroberto } 690181834Sroberto } 691181834Sroberto break; 692181834Sroberto 693181834Sroberto default: 694181834Sroberto case TOPT_DEFAULT: 695181834Sroberto fputs( "AutoOpts lib error: defaulted to option with optional arg\n", 696181834Sroberto stderr ); 697181834Sroberto exit( EX_SOFTWARE ); 698181834Sroberto } 699181834Sroberto 700181834Sroberto /* 701181834Sroberto * After an option with an optional argument, we will 702181834Sroberto * *always* start with the next option because if there 703181834Sroberto * were any characters following the option name/flag, 704181834Sroberto * they would be interpreted as the argument. 705181834Sroberto */ 706181834Sroberto pOpts->pzCurOpt = NULL; 707181834Sroberto break; 708181834Sroberto 709181834Sroberto default: /* CANNOT */ 710181834Sroberto /* 711181834Sroberto * No option argument. Make sure next time around we find 712181834Sroberto * the correct option flag character for short options 713181834Sroberto */ 714181834Sroberto if (pOptState->optType == TOPT_SHORT) 715181834Sroberto (pOpts->pzCurOpt)++; 716181834Sroberto 717181834Sroberto /* 718181834Sroberto * It is a long option. Make sure there was no ``=xxx'' argument 719181834Sroberto */ 720181834Sroberto else if (pOptState->pzOptArg != NULL) { 721181834Sroberto fprintf( stderr, zNoArg, pOpts->pzProgPath, 722181834Sroberto pOptState->pOD->pz_Name ); 723181834Sroberto return FAILURE; 724181834Sroberto } 725181834Sroberto 726181834Sroberto /* 727181834Sroberto * It is a long option. Advance to next command line argument. 728181834Sroberto */ 729181834Sroberto else 730181834Sroberto pOpts->pzCurOpt = NULL; 731181834Sroberto } 732181834Sroberto 733181834Sroberto return SUCCESS; 734181834Sroberto} 735181834Sroberto 736181834Sroberto 737181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 738181834Sroberto * 739181834Sroberto * DO PRESETS 740181834Sroberto * 741181834Sroberto * The next several routines do the immediate action pass on the command 742181834Sroberto * line options, then the environment variables, then the config files in 743181834Sroberto * reverse order. Once done with that, the order is reversed and all 744181834Sroberto * the config files and environment variables are processed again, this 745181834Sroberto * time only processing the non-immediate action options. doPresets() 746181834Sroberto * will then return for optionProcess() to do the final pass on the command 747181834Sroberto * line arguments. 748181834Sroberto */ 749181834Sroberto 750181834Sroberto/* 751181834Sroberto * doImmediateOpts - scan the command line for immediate action options 752181834Sroberto */ 753181834SrobertoLOCAL tSuccess 754181834SrobertodoImmediateOpts( tOptions* pOpts ) 755181834Sroberto{ 756181834Sroberto pOpts->curOptIdx = 1; /* start by skipping program name */ 757181834Sroberto pOpts->pzCurOpt = NULL; 758181834Sroberto 759181834Sroberto /* 760181834Sroberto * Examine all the options from the start. We process any options that 761181834Sroberto * are marked for immediate processing. 762181834Sroberto */ 763181834Sroberto for (;;) { 764181834Sroberto tOptState optState = OPTSTATE_INITIALIZER(PRESET); 765181834Sroberto 766181834Sroberto switch (nextOption( pOpts, &optState )) { 767181834Sroberto case FAILURE: goto optionsDone; 768181834Sroberto case PROBLEM: return SUCCESS; /* no more args */ 769181834Sroberto case SUCCESS: break; 770181834Sroberto } 771181834Sroberto 772181834Sroberto /* 773181834Sroberto * IF this *is* an immediate-attribute option, then do it. 774181834Sroberto */ 775181834Sroberto if (! DO_IMMEDIATELY(optState.flags)) 776181834Sroberto continue; 777181834Sroberto 778181834Sroberto if (! SUCCESSFUL( handleOption( pOpts, &optState ))) 779181834Sroberto break; 780181834Sroberto } optionsDone:; 781181834Sroberto 782181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) 783181834Sroberto (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 784181834Sroberto return FAILURE; 785181834Sroberto} 786181834Sroberto 787181834Sroberto 788181834SrobertoLOCAL tSuccess 789181834SrobertodoRegularOpts( tOptions* pOpts ) 790181834Sroberto{ 791181834Sroberto /* 792181834Sroberto * Now, process all the options from our current position onward. 793181834Sroberto * (This allows interspersed options and arguments for the few 794181834Sroberto * non-standard programs that require it.) 795181834Sroberto */ 796181834Sroberto for (;;) { 797181834Sroberto tOptState optState = OPTSTATE_INITIALIZER(DEFINED); 798181834Sroberto 799181834Sroberto switch (nextOption( pOpts, &optState )) { 800181834Sroberto case FAILURE: goto optionsDone; 801181834Sroberto case PROBLEM: return SUCCESS; /* no more args */ 802181834Sroberto case SUCCESS: break; 803181834Sroberto } 804181834Sroberto 805181834Sroberto /* 806181834Sroberto * IF this is not being processed normally (i.e. is immediate action) 807181834Sroberto * THEN skip it (unless we are supposed to do it a second time). 808181834Sroberto */ 809181834Sroberto if (! DO_NORMALLY(optState.flags)) { 810181834Sroberto if (! DO_SECOND_TIME(optState.flags)) 811181834Sroberto continue; 812181834Sroberto optState.pOD->optOccCt--; /* don't count last time */ 813181834Sroberto } 814181834Sroberto 815181834Sroberto if (! SUCCESSFUL( handleOption( pOpts, &optState ))) 816181834Sroberto break; 817181834Sroberto } optionsDone:; 818181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) 819181834Sroberto (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 820181834Sroberto return FAILURE; 821181834Sroberto} 822181834Sroberto 823181834Sroberto 824181834Sroberto/* 825181834Sroberto * doPresets - check for preset values from a config file or the envrionment 826181834Sroberto */ 827181834Srobertostatic tSuccess 828181834SrobertodoPresets( tOptions* pOpts ) 829181834Sroberto{ 830181834Sroberto tOptDesc * pOD = NULL; 831181834Sroberto 832181834Sroberto if (! SUCCESSFUL( doImmediateOpts( pOpts ))) 833181834Sroberto return FAILURE; 834181834Sroberto 835181834Sroberto /* 836181834Sroberto * IF this option set has a --save-opts option, then it also 837181834Sroberto * has a --load-opts option. See if a command line option has disabled 838181834Sroberto * option presetting. 839181834Sroberto */ 840181834Sroberto if (pOpts->specOptIdx.save_opts != 0) { 841181834Sroberto pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1; 842181834Sroberto if (DISABLED_OPT(pOD)) 843181834Sroberto return SUCCESS; 844181834Sroberto } 845181834Sroberto 846181834Sroberto /* 847181834Sroberto * Until we return from this procedure, disable non-presettable opts 848181834Sroberto */ 849181834Sroberto pOpts->fOptSet |= OPTPROC_PRESETTING; 850181834Sroberto /* 851181834Sroberto * IF there are no config files, 852181834Sroberto * THEN do any environment presets and leave. 853181834Sroberto */ 854181834Sroberto if (pOpts->papzHomeList == NULL) { 855181834Sroberto doEnvPresets( pOpts, ENV_ALL ); 856181834Sroberto } 857181834Sroberto else { 858181834Sroberto doEnvPresets( pOpts, ENV_IMM ); 859181834Sroberto 860181834Sroberto /* 861181834Sroberto * Check to see if environment variables have disabled presetting. 862181834Sroberto */ 863181834Sroberto if ((pOD != NULL) && ! DISABLED_OPT(pOD)) 864181834Sroberto internalFileLoad( pOpts ); 865181834Sroberto 866181834Sroberto /* 867181834Sroberto * ${PROGRAM_LOAD_OPTS} value of "no" cannot disable other environment 868181834Sroberto * variable options. Only the loading of .rc files. 869181834Sroberto */ 870181834Sroberto doEnvPresets( pOpts, ENV_NON_IMM ); 871181834Sroberto } 872181834Sroberto pOpts->fOptSet &= ~OPTPROC_PRESETTING; 873181834Sroberto 874181834Sroberto return SUCCESS; 875181834Sroberto} 876181834Sroberto 877181834Sroberto 878181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 879181834Sroberto * 880181834Sroberto * VERIFY OPTION CONSISTENCY 881181834Sroberto * 882181834Sroberto * Make sure that the argument list passes our consistency tests. 883181834Sroberto */ 884181834Srobertostatic int 885181834SrobertocheckConsistency( tOptions* pOpts ) 886181834Sroberto{ 887181834Sroberto int errCt = 0; 888181834Sroberto tOptDesc* pOD = pOpts->pOptDesc; 889181834Sroberto int oCt = pOpts->presetOptCt; 890181834Sroberto 891181834Sroberto /* 892181834Sroberto * FOR each of "oCt" options, ... 893181834Sroberto */ 894181834Sroberto for (;;) { 895181834Sroberto const int* pMust = pOD->pOptMust; 896181834Sroberto const int* pCant = pOD->pOptCant; 897181834Sroberto 898181834Sroberto /* 899181834Sroberto * IF the current option was provided on the command line 900181834Sroberto * THEN ensure that any "MUST" requirements are not 901181834Sroberto * "DEFAULT" (unspecified) *AND* ensure that any 902181834Sroberto * "CANT" options have not been SET or DEFINED. 903181834Sroberto */ 904181834Sroberto if (SELECTED_OPT(pOD)) { 905181834Sroberto if (pMust != NULL) for (;;) { 906181834Sroberto tOptDesc* p = pOpts->pOptDesc + *(pMust++); 907181834Sroberto if (UNUSED_OPT(p)) { 908181834Sroberto const tOptDesc* pN = pOpts->pOptDesc + pMust[-1]; 909181834Sroberto errCt++; 910181834Sroberto fprintf( stderr, zReqFmt, pOD->pz_Name, pN->pz_Name ); 911181834Sroberto } 912181834Sroberto 913181834Sroberto if (*pMust == NO_EQUIVALENT) 914181834Sroberto break; 915181834Sroberto } 916181834Sroberto 917181834Sroberto if (pCant != NULL) for (;;) { 918181834Sroberto tOptDesc* p = pOpts->pOptDesc + *(pCant++); 919181834Sroberto if (SELECTED_OPT(p)) { 920181834Sroberto const tOptDesc* pN = pOpts->pOptDesc + pCant[-1]; 921181834Sroberto errCt++; 922181834Sroberto fprintf( stderr, zCantFmt, pOD->pz_Name, pN->pz_Name ); 923181834Sroberto } 924181834Sroberto 925181834Sroberto if (*pCant == NO_EQUIVALENT) 926181834Sroberto break; 927181834Sroberto } 928181834Sroberto } 929181834Sroberto 930181834Sroberto /* 931181834Sroberto * IF this option is not equivalenced to another, 932181834Sroberto * OR it is equivalenced to itself (is the equiv. root) 933181834Sroberto * THEN we need to make sure it occurs often enough. 934181834Sroberto */ 935181834Sroberto if ( (pOD->optEquivIndex == NO_EQUIVALENT) 936181834Sroberto || (pOD->optEquivIndex == pOD->optIndex) ) do { 937181834Sroberto /* 938181834Sroberto * IF the occurrence counts have been satisfied, 939181834Sroberto * THEN there is no problem. 940181834Sroberto */ 941181834Sroberto if (pOD->optOccCt >= pOD->optMinCt) 942181834Sroberto break; 943181834Sroberto 944181834Sroberto /* 945181834Sroberto * IF MUST_SET means SET and PRESET are okay, 946181834Sroberto * so min occurrence count doesn't count 947181834Sroberto */ 948181834Sroberto if ( (pOD->fOptState & OPTST_MUST_SET) 949181834Sroberto && (pOD->fOptState & (OPTST_PRESET | OPTST_SET)) ) 950181834Sroberto break; 951181834Sroberto 952181834Sroberto errCt++; 953181834Sroberto if (pOD->optMinCt > 1) 954181834Sroberto fprintf( stderr, zNotEnough, pOD->pz_Name, pOD->optMinCt ); 955181834Sroberto else fprintf( stderr, zNeedOne, pOD->pz_Name ); 956181834Sroberto } while (0); 957181834Sroberto 958181834Sroberto if (--oCt <= 0) 959181834Sroberto break; 960181834Sroberto pOD++; 961181834Sroberto } 962181834Sroberto 963181834Sroberto /* 964181834Sroberto * IF we are stopping on errors, check to see if any remaining 965181834Sroberto * arguments are required to be there or prohibited from being there. 966181834Sroberto */ 967181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 968181834Sroberto 969181834Sroberto /* 970181834Sroberto * Check for prohibition 971181834Sroberto */ 972181834Sroberto if ((pOpts->fOptSet & OPTPROC_NO_ARGS) != 0) { 973181834Sroberto if (pOpts->origArgCt > pOpts->curOptIdx) { 974181834Sroberto fprintf( stderr, zNoArgs, pOpts->pzProgName ); 975181834Sroberto ++errCt; 976181834Sroberto } 977181834Sroberto } 978181834Sroberto 979181834Sroberto /* 980181834Sroberto * ELSE not prohibited, check for being required 981181834Sroberto */ 982181834Sroberto else if ((pOpts->fOptSet & OPTPROC_ARGS_REQ) != 0) { 983181834Sroberto if (pOpts->origArgCt <= pOpts->curOptIdx) { 984181834Sroberto fprintf( stderr, zArgsMust, pOpts->pzProgName ); 985181834Sroberto ++errCt; 986181834Sroberto } 987181834Sroberto } 988181834Sroberto } 989181834Sroberto 990181834Sroberto return errCt; 991181834Sroberto} 992181834Sroberto 993181834Sroberto 994181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 995181834Sroberto * 996181834Sroberto * THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE 997181834Sroberto */ 998181834Sroberto/*=--subblock=arg=arg_type,arg_name,arg_desc =*/ 999181834Sroberto/*=* 1000181834Sroberto * library: opts 1001181834Sroberto * header: your-opts.h 1002181834Sroberto * 1003181834Sroberto * lib_description: 1004181834Sroberto * 1005181834Sroberto * These are the routines that libopts users may call directly from their 1006181834Sroberto * code. There are several other routines that can be called by code 1007181834Sroberto * generated by the libopts option templates, but they are not to be 1008181834Sroberto * called from any other user code. The @file{options.h} header is 1009181834Sroberto * fairly clear about this, too. 1010181834Sroberto=*/ 1011181834Sroberto 1012181834Sroberto/*=export_func optionProcess 1013181834Sroberto * 1014181834Sroberto * what: this is the main option processing routine 1015181834Sroberto * 1016181834Sroberto * arg: + tOptions* + pOpts + program options descriptor + 1017181834Sroberto * arg: + int + argc + program arg count + 1018181834Sroberto * arg: + char** + argv + program arg vector + 1019181834Sroberto * 1020181834Sroberto * ret_type: int 1021181834Sroberto * ret_desc: the count of the arguments processed 1022181834Sroberto * 1023181834Sroberto * doc: 1024181834Sroberto * 1025181834Sroberto * This is the main entry point for processing options. It is intended 1026181834Sroberto * that this procedure be called once at the beginning of the execution of 1027181834Sroberto * a program. Depending on options selected earlier, it is sometimes 1028181834Sroberto * necessary to stop and restart option processing, or to select completely 1029181834Sroberto * different sets of options. This can be done easily, but you generally 1030181834Sroberto * do not want to do this. 1031181834Sroberto * 1032181834Sroberto * The number of arguments processed always includes the program name. 1033181834Sroberto * If one of the arguments is "--", then it is counted and the processing 1034181834Sroberto * stops. If an error was encountered and errors are to be tolerated, then 1035181834Sroberto * the returned value is the index of the argument causing the error. 1036181834Sroberto * A hyphen by itself ("-") will also cause processing to stop and will 1037181834Sroberto * @emph{not} be counted among the processed arguments. A hyphen by itself 1038181834Sroberto * is treated as an operand. Encountering an operand stops option 1039181834Sroberto * processing. 1040181834Sroberto * 1041181834Sroberto * err: Errors will cause diagnostics to be printed. @code{exit(3)} may 1042181834Sroberto * or may not be called. It depends upon whether or not the options 1043181834Sroberto * were generated with the "allow-errors" attribute, or if the 1044181834Sroberto * ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked. 1045181834Sroberto=*/ 1046181834Srobertoint 1047181834SrobertooptionProcess( 1048181834Sroberto tOptions* pOpts, 1049181834Sroberto int argCt, 1050181834Sroberto char** argVect ) 1051181834Sroberto{ 1052181834Sroberto if (! SUCCESSFUL( validateOptionsStruct( pOpts, argVect[0] ))) 1053181834Sroberto exit( EX_SOFTWARE ); 1054181834Sroberto 1055181834Sroberto /* 1056181834Sroberto * Establish the real program name, the program full path, 1057181834Sroberto * and do all the presetting the first time thru only. 1058181834Sroberto */ 1059181834Sroberto if ((pOpts->fOptSet & OPTPROC_INITDONE) == 0) { 1060181834Sroberto pOpts->origArgCt = argCt; 1061181834Sroberto pOpts->origArgVect = argVect; 1062181834Sroberto pOpts->fOptSet |= OPTPROC_INITDONE; 1063181834Sroberto 1064181834Sroberto if (! SUCCESSFUL( doPresets( pOpts ))) 1065181834Sroberto return 0; 1066181834Sroberto 1067181834Sroberto if ((pOpts->fOptSet & OPTPROC_REORDER) != 0) 1068181834Sroberto optionSort( pOpts ); 1069181834Sroberto 1070181834Sroberto pOpts->curOptIdx = 1; 1071181834Sroberto pOpts->pzCurOpt = NULL; 1072181834Sroberto } 1073181834Sroberto 1074181834Sroberto /* 1075181834Sroberto * IF we are (re)starting, 1076181834Sroberto * THEN reset option location 1077181834Sroberto */ 1078181834Sroberto else if (pOpts->curOptIdx <= 0) { 1079181834Sroberto pOpts->curOptIdx = 1; 1080181834Sroberto pOpts->pzCurOpt = NULL; 1081181834Sroberto } 1082181834Sroberto 1083181834Sroberto if (! SUCCESSFUL( doRegularOpts( pOpts ))) 1084181834Sroberto return pOpts->origArgCt; 1085181834Sroberto 1086181834Sroberto /* 1087181834Sroberto * IF there were no errors 1088181834Sroberto * AND we have RC/INI files 1089181834Sroberto * AND there is a request to save the files 1090181834Sroberto * THEN do that now before testing for conflicts. 1091181834Sroberto * (conflicts are ignored in preset options) 1092181834Sroberto */ 1093181834Sroberto if (pOpts->specOptIdx.save_opts != 0) { 1094181834Sroberto tOptDesc* pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts; 1095181834Sroberto 1096181834Sroberto if (SELECTED_OPT( pOD )) { 1097181834Sroberto optionSaveFile( pOpts ); 1098181834Sroberto exit( EXIT_SUCCESS ); 1099181834Sroberto } 1100181834Sroberto } 1101181834Sroberto 1102181834Sroberto /* 1103181834Sroberto * IF we are checking for errors, 1104181834Sroberto * THEN look for too few occurrences of required options 1105181834Sroberto */ 1106181834Sroberto if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 1107181834Sroberto if (checkConsistency( pOpts ) != 0) 1108181834Sroberto (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 1109181834Sroberto } 1110181834Sroberto 1111181834Sroberto return pOpts->curOptIdx; 1112181834Sroberto} 1113181834Sroberto 1114181834Sroberto/* 1115181834Sroberto * Local Variables: 1116181834Sroberto * mode: C 1117181834Sroberto * c-file-style: "stroustrup" 1118181834Sroberto * indent-tabs-mode: nil 1119181834Sroberto * End: 1120181834Sroberto * end of autoopts/autoopts.c */ 1121