1 2 /* 3 * stack.c 4 * $Id: stack.c,v 4.13 2007/02/04 17:44:12 bkorb Exp $ 5 * Time-stamp: "2007-01-13 10:43:21 bkorb" 6 * 7 * This is a special option processing routine that will save the 8 * argument to an option in a FIFO queue. 9 */ 10 11 /* 12 * Automated Options copyright 1992-2007 Bruce Korb 13 * 14 * Automated Options is free software. 15 * You may redistribute it and/or modify it under the terms of the 16 * GNU General Public License, as published by the Free Software 17 * Foundation; either version 2, or (at your option) any later version. 18 * 19 * Automated Options is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with Automated Options. See the file "COPYING". If not, 26 * write to: The Free Software Foundation, Inc., 27 * 51 Franklin Street, Fifth Floor, 28 * Boston, MA 02110-1301, USA. 29 * 30 * As a special exception, Bruce Korb gives permission for additional 31 * uses of the text contained in his release of AutoOpts. 32 * 33 * The exception is that, if you link the AutoOpts library with other 34 * files to produce an executable, this does not by itself cause the 35 * resulting executable to be covered by the GNU General Public License. 36 * Your use of that executable is in no way restricted on account of 37 * linking the AutoOpts library code into it. 38 * 39 * This exception does not however invalidate any other reasons why 40 * the executable file might be covered by the GNU General Public License. 41 * 42 * This exception applies only to the code released by Bruce Korb under 43 * the name AutoOpts. If you copy code from other sources under the 44 * General Public License into a copy of AutoOpts, as the General Public 45 * License permits, the exception does not apply to the code that you add 46 * in this way. To avoid misleading anyone as to the status of such 47 * modified files, you must delete this exception notice from them. 48 * 49 * If you write modifications of your own for AutoOpts, it is your choice 50 * whether to permit this exception to apply to your modifications. 51 * If you do not wish that, delete this exception notice. 52 */ 53 54 #ifdef WITH_LIBREGEX 55 # include REGEX_HEADER 56 #endif 57 58 /*=export_func optionUnstackArg 59 * private: 60 * 61 * what: Remove option args from a stack 62 * arg: + tOptions* + pOpts + program options descriptor + 63 * arg: + tOptDesc* + pOptDesc + the descriptor for this arg + 64 * 65 * doc: 66 * Invoked for options that are equivalenced to stacked options. 67 =*/ 68 void 69 optionUnstackArg( 70 tOptions* pOpts, 71 tOptDesc* pOptDesc ) 72 { 73 int res; 74 75 tArgList* pAL = (tArgList*)pOptDesc->optCookie; 76 /* 77 * IF we don't have any stacked options, 78 * THEN indicate that we don't have any of these options 79 */ 80 if (pAL == NULL) { 81 pOptDesc->fOptState &= OPTST_PERSISTENT_MASK; 82 if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0) 83 pOptDesc->fOptState |= OPTST_DISABLED; 84 return; 85 } 86 87 #ifdef WITH_LIBREGEX 88 { 89 regex_t re; 90 int i, ct, dIdx; 91 92 if (regcomp( &re, pOptDesc->optArg.argString, REG_NOSUB ) != 0) 93 return; 94 95 /* 96 * search the list for the entry(s) to remove. Entries that 97 * are removed are *not* copied into the result. The source 98 * index is incremented every time. The destination only when 99 * we are keeping a define. 100 */ 101 for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) { 102 tCC* pzSrc = pAL->apzArgs[ i ]; 103 char* pzEq = strchr( pzSrc, '=' ); 104 105 if (pzEq != NULL) 106 *pzEq = NUL; 107 108 res = regexec( &re, pzSrc, (size_t)0, NULL, 0 ); 109 switch (res) { 110 case 0: 111 /* 112 * Remove this entry by reducing the in-use count 113 * and *not* putting the string pointer back into 114 * the list. 115 */ 116 AGFREE(pzSrc); 117 pAL->useCt--; 118 break; 119 120 default: 121 case REG_NOMATCH: 122 if (pzEq != NULL) 123 *pzEq = '='; 124 125 /* 126 * IF we have dropped an entry 127 * THEN we have to move the current one. 128 */ 129 if (dIdx != i) 130 pAL->apzArgs[ dIdx ] = pzSrc; 131 dIdx++; 132 } 133 } 134 135 regfree( &re ); 136 } 137 #else /* not WITH_LIBREGEX */ 138 { 139 int i, ct, dIdx; 140 141 /* 142 * search the list for the entry(s) to remove. Entries that 143 * are removed are *not* copied into the result. The source 144 * index is incremented every time. The destination only when 145 * we are keeping a define. 146 */ 147 for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) { 148 tCC* pzSrc = pAL->apzArgs[ i ]; 149 char* pzEq = strchr( pzSrc, '=' ); 150 151 if (pzEq != NULL) 152 *pzEq = NUL; 153 154 if (strcmp( pzSrc, pOptDesc->optArg.argString ) == 0) { 155 /* 156 * Remove this entry by reducing the in-use count 157 * and *not* putting the string pointer back into 158 * the list. 159 */ 160 AGFREE(pzSrc); 161 pAL->useCt--; 162 } else { 163 if (pzEq != NULL) 164 *pzEq = '='; 165 166 /* 167 * IF we have dropped an entry 168 * THEN we have to move the current one. 169 */ 170 if (dIdx != i) 171 pAL->apzArgs[ dIdx ] = pzSrc; 172 dIdx++; 173 } 174 } 175 } 176 #endif /* WITH_LIBREGEX */ 177 /* 178 * IF we have unstacked everything, 179 * THEN indicate that we don't have any of these options 180 */ 181 if (pAL->useCt == 0) { 182 pOptDesc->fOptState &= OPTST_PERSISTENT_MASK; 183 if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0) 184 pOptDesc->fOptState |= OPTST_DISABLED; 185 AGFREE( (void*)pAL ); 186 pOptDesc->optCookie = NULL; 187 } 188 } 189 190 191 /* 192 * Put an entry into an argument list. The first argument points to 193 * a pointer to the argument list structure. It gets passed around 194 * as an opaque address. 195 */ 196 LOCAL void 197 addArgListEntry( void** ppAL, void* entry ) 198 { 199 tArgList* pAL = *(void**)ppAL; 200 201 /* 202 * IF we have never allocated one of these, 203 * THEN allocate one now 204 */ 205 if (pAL == NULL) { 206 pAL = (tArgList*)AGALOC( sizeof( *pAL ), "new option arg stack" ); 207 if (pAL == NULL) 208 return; 209 pAL->useCt = 0; 210 pAL->allocCt = MIN_ARG_ALLOC_CT; 211 *ppAL = (void*)pAL; 212 } 213 214 /* 215 * ELSE if we are out of room 216 * THEN make it bigger 217 */ 218 else if (pAL->useCt >= pAL->allocCt) { 219 size_t sz = sizeof( *pAL ); 220 pAL->allocCt += INCR_ARG_ALLOC_CT; 221 222 /* 223 * The base structure contains space for MIN_ARG_ALLOC_CT 224 * pointers. We subtract it off to find our augment size. 225 */ 226 sz += sizeof(char*) * (pAL->allocCt - MIN_ARG_ALLOC_CT); 227 pAL = (tArgList*)AGREALOC( (void*)pAL, sz, "expanded opt arg stack" ); 228 if (pAL == NULL) 229 return; 230 *ppAL = (void*)pAL; 231 } 232 233 /* 234 * Insert the new argument into the list 235 */ 236 pAL->apzArgs[ (pAL->useCt)++ ] = entry; 237 } 238 239 240 /*=export_func optionStackArg 241 * private: 242 * 243 * what: put option args on a stack 244 * arg: + tOptions* + pOpts + program options descriptor + 245 * arg: + tOptDesc* + pOptDesc + the descriptor for this arg + 246 * 247 * doc: 248 * Keep an entry-ordered list of option arguments. 249 =*/ 250 void 251 optionStackArg( 252 tOptions* pOpts, 253 tOptDesc* pOD ) 254 { 255 char * pz; 256 257 if (pOD->optArg.argString == NULL) 258 return; 259 260 AGDUPSTR(pz, pOD->optArg.argString, "stack arg"); 261 addArgListEntry( &(pOD->optCookie), (void*)pz ); 262 } 263 /* 264 * Local Variables: 265 * mode: C 266 * c-file-style: "stroustrup" 267 * indent-tabs-mode: nil 268 * End: 269 * end of autoopts/stack.c */ 270