📄 autoopts.c
字号:
/* * $Id: autoopts.c,v 4.25 2007/04/15 19:01:18 bkorb Exp $ * Time-stamp: "2007-04-15 11:10:40 bkorb" * * This file contains all of the routines that must be linked into * an executable to use the generated option processing. The optional * routines are in separately compiled modules so that they will not * necessarily be linked in. *//* * Automated Options copyright 1992-2007 Bruce Korb * * Automated Options is free software. * You may redistribute it and/or modify it under the terms of the * GNU General Public License, as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * Automated Options is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Automated Options. See the file "COPYING". If not, * write to: The Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * As a special exception, Bruce Korb gives permission for additional * uses of the text contained in his release of AutoOpts. * * The exception is that, if you link the AutoOpts library with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the AutoOpts library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by Bruce Korb under * the name AutoOpts. If you copy code from other sources under the * General Public License into a copy of AutoOpts, as the General Public * License permits, the exception does not apply to the code that you add * in this way. To avoid misleading anyone as to the status of such * modified files, you must delete this exception notice from them. * * If you write modifications of your own for AutoOpts, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. */static char const zNil[] = "";/* = = = START-STATIC-FORWARD = = = *//* static forward declarations maintained by :mkfwd */static tSuccessfindOptDesc( tOptions* pOpts, tOptState* pOptState );static tSuccessnextOption( tOptions* pOpts, tOptState* pOptState );static tSuccessdoPresets( tOptions* pOpts );static intcheckConsistency( tOptions* pOpts );/* = = = END-STATIC-FORWARD = = = */LOCAL void *ao_malloc( size_t sz ){ void * res = malloc(sz); if (res == NULL) { fprintf( stderr, "malloc of %d bytes failed\n", (int)sz ); exit( EXIT_FAILURE ); } return res;}#undef malloc#define malloc(_s) ao_malloc(_s)LOCAL void *ao_realloc( void *p, size_t sz ){ void * res = realloc(p, sz); if (res == NULL) { fprintf( stderr, "realloc of %d bytes at 0x%p failed\n", (int)sz, p ); exit( EXIT_FAILURE ); } return res;}#undef realloc#define realloc(_p,_s) ao_realloc(_p,_s)LOCAL voidao_free( void *p ){ if (p != NULL) free(p);}#undef free#define free(_p) ao_free(_p)LOCAL char *ao_strdup( char const *str ){ char * res = strdup(str); if (res == NULL) { fprintf( stderr, "strdup of %d byte string failed\n", (int)strlen(str) ); exit( EXIT_FAILURE ); } return res;}#undef strdup#define strdup(_p) ao_strdup(_p)#ifndef HAVE_PATHFIND# include "compat/pathfind.c"#endif#ifndef HAVE_SNPRINTF# include "compat/snprintf.c"#endif#ifndef HAVE_STRDUP# include "compat/strdup.c"#endif#ifndef HAVE_STRCHR# include "compat/strchr.c"#endif/* * handleOption * * This routine handles equivalencing, sets the option state flags and * invokes the handler procedure, if any. */LOCAL tSuccesshandleOption( tOptions* pOpts, tOptState* pOptState ){ /* * Save a copy of the option procedure pointer. * If this is an equivalence class option, we still want this proc. */ tOptDesc* pOD = pOptState->pOD; tOptProc* pOP = pOD->pOptProc; if (pOD->fOptState & OPTST_ALLOC_ARG) AGFREE(pOD->optArg.argString); pOD->optArg.argString = pOptState->pzOptArg; /* * IF we are presetting options, then we will ignore any un-presettable * options. They are the ones either marked as such. */ if ( ((pOpts->fOptSet & OPTPROC_PRESETTING) != 0) && ((pOD->fOptState & OPTST_NO_INIT) != 0) ) return PROBLEM; /* * IF this is an equivalence class option, * THEN * Save the option value that got us to this option * entry. (It may not be pOD->optChar[0], if this is an * equivalence entry.) * set the pointer to the equivalence class base */ if (pOD->optEquivIndex != NO_EQUIVALENT) { tOptDesc* p = pOpts->pOptDesc + pOD->optEquivIndex; /* * IF the current option state has not been defined (set on the * command line), THEN we will allow continued resetting of * the value. Once "defined", then it must not change. */ if ((pOD->fOptState & OPTST_DEFINED) != 0) { /* * The equivalenced-to option has been found on the command * line before. Make sure new occurrences are the same type. * * IF this option has been previously equivalenced and * it was not the same equivalenced-to option, * THEN we have a usage problem. */ if (p->optActualIndex != pOD->optIndex) { fprintf( stderr, (char*)zMultiEquiv, p->pz_Name, pOD->pz_Name, (pOpts->pOptDesc + p->optActualIndex)->pz_Name); return FAILURE; } } else { /* * Set the equivalenced-to actual option index to no-equivalent * so that we set all the entries below. This option may either * never have been selected before, or else it was selected by * some sort of "presetting" mechanism. */ p->optActualIndex = NO_EQUIVALENT; } if (p->optActualIndex != pOD->optIndex) { /* * First time through, copy over the state * and add in the equivalence flag */ p->optActualValue = pOD->optValue; p->optActualIndex = pOD->optIndex; pOptState->flags |= OPTST_EQUIVALENCE; } /* * Copy the most recent option argument. set membership state * is kept in ``p->optCookie''. Do not overwrite. */ p->optArg.argString = pOD->optArg.argString; pOD = p; } else { pOD->optActualValue = pOD->optValue; pOD->optActualIndex = pOD->optIndex; } pOD->fOptState &= OPTST_PERSISTENT_MASK; pOD->fOptState |= (pOptState->flags & ~OPTST_PERSISTENT_MASK); /* * Keep track of count only for DEFINED (command line) options. * IF we have too many, build up an error message and bail. */ if ( (pOD->fOptState & OPTST_DEFINED) && (++pOD->optOccCt > pOD->optMaxCt) ) { if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { char const * pzEqv = (pOD->optEquivIndex != NO_EQUIVALENT) ? zEquiv : zNil; fputs( zErrOnly, stderr ); if (pOD->optMaxCt > 1) fprintf(stderr, zAtMost, pOD->optMaxCt, pOD->pz_Name, pzEqv); else fprintf(stderr, zOnlyOne, pOD->pz_Name, pzEqv); } return FAILURE; } /* * If provided a procedure to call, call it */ if (pOP != (tpOptProc)NULL) (*pOP)( pOpts, pOD ); return SUCCESS;}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * HUNT FOR OPTIONS IN THE ARGUMENT LIST * * The next four procedures are "private" to nextOption(). * nextOption() uses findOptDesc() to find the next descriptor and it, in * turn, uses longOptionFind() and shortOptionFind() to actually do the hunt. * * longOptionFind * * Find the long option descriptor for the current option */LOCAL tSuccesslongOptionFind( tOptions* pOpts, char* pzOptName, tOptState* pOptState ){ ag_bool disable = AG_FALSE; char* pzEq = strchr( pzOptName, '=' ); tOptDesc* pOD = pOpts->pOptDesc; int idx = 0; int idxLim = pOpts->optCt; int matchCt = 0; int matchIdx = 0; int nameLen; /* * IF the value is attached to the name, * THEN clip it off. * Either way, figure out how long our name is */ if (pzEq != NULL) { nameLen = (int)(pzEq - pzOptName); *pzEq = NUL; } else nameLen = strlen( pzOptName ); do { if (SKIP_OPT(pOD)) continue; if (strneqvcmp( pzOptName, pOD->pz_Name, nameLen ) == 0) { /* * IF we have a complete match * THEN it takes priority over any already located partial */ if (pOD->pz_Name[ nameLen ] == NUL) { matchCt = 1; matchIdx = idx; break; } } /* * IF there is a disable name * *AND* no argument value has been supplied * (disabled options may have no argument) * *AND* the option name matches the disable name * THEN ... */ else if ( (pOD->pz_DisableName != NULL) && (strneqvcmp(pzOptName, pOD->pz_DisableName, nameLen) == 0) ) { disable = AG_TRUE; /* * IF we have a complete match * THEN it takes priority over any already located partial */ if (pOD->pz_DisableName[ nameLen ] == NUL) { matchCt = 1; matchIdx = idx; break; } } else continue; /* * We found a partial match, either regular or disabling. * Remember the index for later. */ matchIdx = idx; if (++matchCt > 1) break; } while (pOD++, (++idx < idxLim)); if (pzEq != NULL) *(pzEq++) = '='; /* * Make sure we either found an exact match or found only one partial */ if (matchCt == 1) { /* * IF we found a disablement name, * THEN set the bit in the callers' flag word */ if (disable) pOptState->flags |= OPTST_DISABLED; pOptState->pOD = pOpts->pOptDesc + matchIdx; pOptState->pzOptArg = pzEq; pOptState->optType = TOPT_LONG; return SUCCESS; } /* * IF there is no equal sign * *AND* we are using named arguments * *AND* there is a default named option,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -