1181834Sroberto 2181834Sroberto/* 3181834Sroberto * stack.c 4181834Sroberto * $Id: stack.c,v 4.13 2007/02/04 17:44:12 bkorb Exp $ 5181834Sroberto * Time-stamp: "2007-01-13 10:43:21 bkorb" 6181834Sroberto * 7181834Sroberto * This is a special option processing routine that will save the 8181834Sroberto * argument to an option in a FIFO queue. 9181834Sroberto */ 10181834Sroberto 11181834Sroberto/* 12181834Sroberto * Automated Options copyright 1992-2007 Bruce Korb 13181834Sroberto * 14181834Sroberto * Automated Options is free software. 15181834Sroberto * You may redistribute it and/or modify it under the terms of the 16181834Sroberto * GNU General Public License, as published by the Free Software 17181834Sroberto * Foundation; either version 2, or (at your option) any later version. 18181834Sroberto * 19181834Sroberto * Automated Options is distributed in the hope that it will be useful, 20181834Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of 21181834Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22181834Sroberto * GNU General Public License for more details. 23181834Sroberto * 24181834Sroberto * You should have received a copy of the GNU General Public License 25181834Sroberto * along with Automated Options. See the file "COPYING". If not, 26181834Sroberto * write to: The Free Software Foundation, Inc., 27181834Sroberto * 51 Franklin Street, Fifth Floor, 28181834Sroberto * Boston, MA 02110-1301, USA. 29181834Sroberto * 30181834Sroberto * As a special exception, Bruce Korb gives permission for additional 31181834Sroberto * uses of the text contained in his release of AutoOpts. 32181834Sroberto * 33181834Sroberto * The exception is that, if you link the AutoOpts library with other 34181834Sroberto * files to produce an executable, this does not by itself cause the 35181834Sroberto * resulting executable to be covered by the GNU General Public License. 36181834Sroberto * Your use of that executable is in no way restricted on account of 37181834Sroberto * linking the AutoOpts library code into it. 38181834Sroberto * 39181834Sroberto * This exception does not however invalidate any other reasons why 40181834Sroberto * the executable file might be covered by the GNU General Public License. 41181834Sroberto * 42181834Sroberto * This exception applies only to the code released by Bruce Korb under 43181834Sroberto * the name AutoOpts. If you copy code from other sources under the 44181834Sroberto * General Public License into a copy of AutoOpts, as the General Public 45181834Sroberto * License permits, the exception does not apply to the code that you add 46181834Sroberto * in this way. To avoid misleading anyone as to the status of such 47181834Sroberto * modified files, you must delete this exception notice from them. 48181834Sroberto * 49181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice 50181834Sroberto * whether to permit this exception to apply to your modifications. 51181834Sroberto * If you do not wish that, delete this exception notice. 52181834Sroberto */ 53181834Sroberto 54181834Sroberto#ifdef WITH_LIBREGEX 55181834Sroberto# include REGEX_HEADER 56181834Sroberto#endif 57181834Sroberto 58181834Sroberto/*=export_func optionUnstackArg 59181834Sroberto * private: 60181834Sroberto * 61181834Sroberto * what: Remove option args from a stack 62181834Sroberto * arg: + tOptions* + pOpts + program options descriptor + 63181834Sroberto * arg: + tOptDesc* + pOptDesc + the descriptor for this arg + 64181834Sroberto * 65181834Sroberto * doc: 66181834Sroberto * Invoked for options that are equivalenced to stacked options. 67181834Sroberto=*/ 68181834Srobertovoid 69181834SrobertooptionUnstackArg( 70181834Sroberto tOptions* pOpts, 71181834Sroberto tOptDesc* pOptDesc ) 72181834Sroberto{ 73181834Sroberto int res; 74181834Sroberto 75181834Sroberto tArgList* pAL = (tArgList*)pOptDesc->optCookie; 76181834Sroberto /* 77181834Sroberto * IF we don't have any stacked options, 78181834Sroberto * THEN indicate that we don't have any of these options 79181834Sroberto */ 80181834Sroberto if (pAL == NULL) { 81181834Sroberto pOptDesc->fOptState &= OPTST_PERSISTENT_MASK; 82181834Sroberto if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0) 83181834Sroberto pOptDesc->fOptState |= OPTST_DISABLED; 84181834Sroberto return; 85181834Sroberto } 86181834Sroberto 87181834Sroberto#ifdef WITH_LIBREGEX 88181834Sroberto { 89181834Sroberto regex_t re; 90181834Sroberto int i, ct, dIdx; 91181834Sroberto 92181834Sroberto if (regcomp( &re, pOptDesc->optArg.argString, REG_NOSUB ) != 0) 93181834Sroberto return; 94181834Sroberto 95181834Sroberto /* 96181834Sroberto * search the list for the entry(s) to remove. Entries that 97181834Sroberto * are removed are *not* copied into the result. The source 98181834Sroberto * index is incremented every time. The destination only when 99181834Sroberto * we are keeping a define. 100181834Sroberto */ 101181834Sroberto for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) { 102181834Sroberto tCC* pzSrc = pAL->apzArgs[ i ]; 103181834Sroberto char* pzEq = strchr( pzSrc, '=' ); 104181834Sroberto 105181834Sroberto if (pzEq != NULL) 106181834Sroberto *pzEq = NUL; 107181834Sroberto 108181834Sroberto res = regexec( &re, pzSrc, (size_t)0, NULL, 0 ); 109181834Sroberto switch (res) { 110181834Sroberto case 0: 111181834Sroberto /* 112181834Sroberto * Remove this entry by reducing the in-use count 113181834Sroberto * and *not* putting the string pointer back into 114181834Sroberto * the list. 115181834Sroberto */ 116181834Sroberto AGFREE(pzSrc); 117181834Sroberto pAL->useCt--; 118181834Sroberto break; 119181834Sroberto 120181834Sroberto default: 121181834Sroberto case REG_NOMATCH: 122181834Sroberto if (pzEq != NULL) 123181834Sroberto *pzEq = '='; 124181834Sroberto 125181834Sroberto /* 126181834Sroberto * IF we have dropped an entry 127181834Sroberto * THEN we have to move the current one. 128181834Sroberto */ 129181834Sroberto if (dIdx != i) 130181834Sroberto pAL->apzArgs[ dIdx ] = pzSrc; 131181834Sroberto dIdx++; 132181834Sroberto } 133181834Sroberto } 134181834Sroberto 135181834Sroberto regfree( &re ); 136181834Sroberto } 137181834Sroberto#else /* not WITH_LIBREGEX */ 138181834Sroberto { 139181834Sroberto int i, ct, dIdx; 140181834Sroberto 141181834Sroberto /* 142181834Sroberto * search the list for the entry(s) to remove. Entries that 143181834Sroberto * are removed are *not* copied into the result. The source 144181834Sroberto * index is incremented every time. The destination only when 145181834Sroberto * we are keeping a define. 146181834Sroberto */ 147181834Sroberto for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) { 148181834Sroberto tCC* pzSrc = pAL->apzArgs[ i ]; 149181834Sroberto char* pzEq = strchr( pzSrc, '=' ); 150181834Sroberto 151181834Sroberto if (pzEq != NULL) 152181834Sroberto *pzEq = NUL; 153181834Sroberto 154181834Sroberto if (strcmp( pzSrc, pOptDesc->optArg.argString ) == 0) { 155181834Sroberto /* 156181834Sroberto * Remove this entry by reducing the in-use count 157181834Sroberto * and *not* putting the string pointer back into 158181834Sroberto * the list. 159181834Sroberto */ 160181834Sroberto AGFREE(pzSrc); 161181834Sroberto pAL->useCt--; 162181834Sroberto } else { 163181834Sroberto if (pzEq != NULL) 164181834Sroberto *pzEq = '='; 165181834Sroberto 166181834Sroberto /* 167181834Sroberto * IF we have dropped an entry 168181834Sroberto * THEN we have to move the current one. 169181834Sroberto */ 170181834Sroberto if (dIdx != i) 171181834Sroberto pAL->apzArgs[ dIdx ] = pzSrc; 172181834Sroberto dIdx++; 173181834Sroberto } 174181834Sroberto } 175181834Sroberto } 176181834Sroberto#endif /* WITH_LIBREGEX */ 177181834Sroberto /* 178181834Sroberto * IF we have unstacked everything, 179181834Sroberto * THEN indicate that we don't have any of these options 180181834Sroberto */ 181181834Sroberto if (pAL->useCt == 0) { 182181834Sroberto pOptDesc->fOptState &= OPTST_PERSISTENT_MASK; 183181834Sroberto if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0) 184181834Sroberto pOptDesc->fOptState |= OPTST_DISABLED; 185181834Sroberto AGFREE( (void*)pAL ); 186181834Sroberto pOptDesc->optCookie = NULL; 187181834Sroberto } 188181834Sroberto} 189181834Sroberto 190181834Sroberto 191181834Sroberto/* 192181834Sroberto * Put an entry into an argument list. The first argument points to 193181834Sroberto * a pointer to the argument list structure. It gets passed around 194181834Sroberto * as an opaque address. 195181834Sroberto */ 196181834SrobertoLOCAL void 197181834SrobertoaddArgListEntry( void** ppAL, void* entry ) 198181834Sroberto{ 199181834Sroberto tArgList* pAL = *(void**)ppAL; 200181834Sroberto 201181834Sroberto /* 202181834Sroberto * IF we have never allocated one of these, 203181834Sroberto * THEN allocate one now 204181834Sroberto */ 205181834Sroberto if (pAL == NULL) { 206181834Sroberto pAL = (tArgList*)AGALOC( sizeof( *pAL ), "new option arg stack" ); 207181834Sroberto if (pAL == NULL) 208181834Sroberto return; 209181834Sroberto pAL->useCt = 0; 210181834Sroberto pAL->allocCt = MIN_ARG_ALLOC_CT; 211181834Sroberto *ppAL = (void*)pAL; 212181834Sroberto } 213181834Sroberto 214181834Sroberto /* 215181834Sroberto * ELSE if we are out of room 216181834Sroberto * THEN make it bigger 217181834Sroberto */ 218181834Sroberto else if (pAL->useCt >= pAL->allocCt) { 219181834Sroberto size_t sz = sizeof( *pAL ); 220181834Sroberto pAL->allocCt += INCR_ARG_ALLOC_CT; 221181834Sroberto 222181834Sroberto /* 223181834Sroberto * The base structure contains space for MIN_ARG_ALLOC_CT 224181834Sroberto * pointers. We subtract it off to find our augment size. 225181834Sroberto */ 226181834Sroberto sz += sizeof(char*) * (pAL->allocCt - MIN_ARG_ALLOC_CT); 227181834Sroberto pAL = (tArgList*)AGREALOC( (void*)pAL, sz, "expanded opt arg stack" ); 228181834Sroberto if (pAL == NULL) 229181834Sroberto return; 230181834Sroberto *ppAL = (void*)pAL; 231181834Sroberto } 232181834Sroberto 233181834Sroberto /* 234181834Sroberto * Insert the new argument into the list 235181834Sroberto */ 236181834Sroberto pAL->apzArgs[ (pAL->useCt)++ ] = entry; 237181834Sroberto} 238181834Sroberto 239181834Sroberto 240181834Sroberto/*=export_func optionStackArg 241181834Sroberto * private: 242181834Sroberto * 243181834Sroberto * what: put option args on a stack 244181834Sroberto * arg: + tOptions* + pOpts + program options descriptor + 245181834Sroberto * arg: + tOptDesc* + pOptDesc + the descriptor for this arg + 246181834Sroberto * 247181834Sroberto * doc: 248181834Sroberto * Keep an entry-ordered list of option arguments. 249181834Sroberto=*/ 250181834Srobertovoid 251181834SrobertooptionStackArg( 252181834Sroberto tOptions* pOpts, 253181834Sroberto tOptDesc* pOD ) 254181834Sroberto{ 255181834Sroberto char * pz; 256181834Sroberto 257181834Sroberto if (pOD->optArg.argString == NULL) 258181834Sroberto return; 259181834Sroberto 260181834Sroberto AGDUPSTR(pz, pOD->optArg.argString, "stack arg"); 261181834Sroberto addArgListEntry( &(pOD->optCookie), (void*)pz ); 262181834Sroberto} 263181834Sroberto/* 264181834Sroberto * Local Variables: 265181834Sroberto * mode: C 266181834Sroberto * c-file-style: "stroustrup" 267181834Sroberto * indent-tabs-mode: nil 268181834Sroberto * End: 269181834Sroberto * end of autoopts/stack.c */ 270