1 2 /** 3 * \file stack.c 4 * 5 * This is a special option processing routine that will save the 6 * argument to an option in a FIFO queue. 7 * 8 * @addtogroup autoopts 9 * @{ 10 */ 11 /* 12 * This file is part of AutoOpts, a companion to AutoGen. 13 * AutoOpts is free software. 14 * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 15 * 16 * AutoOpts is available under any one of two licenses. The license 17 * in use must be one of these two and the choice is under the control 18 * of the user of the license. 19 * 20 * The GNU Lesser General Public License, version 3 or later 21 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 22 * 23 * The Modified Berkeley Software Distribution License 24 * See the file "COPYING.mbsd" 25 * 26 * These files have the following sha256 sums: 27 * 28 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 29 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 30 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 31 */ 32 33 #ifdef WITH_LIBREGEX 34 # include REGEX_HEADER 35 #endif 36 37 /*=export_func optionUnstackArg 38 * private: 39 * 40 * what: Remove option args from a stack 41 * arg: + tOptions * + opts + program options descriptor + 42 * arg: + tOptDesc * + od + the descriptor for this arg + 43 * 44 * doc: 45 * Invoked for options that are equivalenced to stacked options. 46 =*/ 47 void 48 optionUnstackArg(tOptions * opts, tOptDesc * od) 49 { 50 tArgList * arg_list; 51 52 if (INQUERY_CALL(opts, od)) 53 return; 54 55 arg_list = (tArgList *)od->optCookie; 56 57 /* 58 * IF we don't have any stacked options, 59 * THEN indicate that we don't have any of these options 60 */ 61 if (arg_list == NULL) { 62 od->fOptState &= OPTST_PERSISTENT_MASK; 63 if ((od->fOptState & OPTST_INITENABLED) == 0) 64 od->fOptState |= OPTST_DISABLED; 65 return; 66 } 67 68 #ifdef WITH_LIBREGEX 69 { 70 regex_t re; 71 int i, ct, dIdx; 72 73 if (regcomp(&re, od->optArg.argString, REG_NOSUB) != 0) 74 return; 75 76 /* 77 * search the list for the entry(s) to remove. Entries that 78 * are removed are *not* copied into the result. The source 79 * index is incremented every time. The destination only when 80 * we are keeping a define. 81 */ 82 for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) { 83 char const * pzSrc = arg_list->apzArgs[ i ]; 84 char * pzEq = strchr(pzSrc, '='); 85 int res; 86 87 88 if (pzEq != NULL) 89 *pzEq = NUL; 90 91 res = regexec(&re, pzSrc, (size_t)0, NULL, 0); 92 switch (res) { 93 case 0: 94 /* 95 * Remove this entry by reducing the in-use count 96 * and *not* putting the string pointer back into 97 * the list. 98 */ 99 AGFREE(pzSrc); 100 arg_list->useCt--; 101 break; 102 103 default: 104 case REG_NOMATCH: 105 if (pzEq != NULL) 106 *pzEq = '='; 107 108 /* 109 * IF we have dropped an entry 110 * THEN we have to move the current one. 111 */ 112 if (dIdx != i) 113 arg_list->apzArgs[ dIdx ] = pzSrc; 114 dIdx++; 115 } 116 } 117 118 regfree(&re); 119 } 120 #else /* not WITH_LIBREGEX */ 121 { 122 int i, ct, dIdx; 123 124 /* 125 * search the list for the entry(s) to remove. Entries that 126 * are removed are *not* copied into the result. The source 127 * index is incremented every time. The destination only when 128 * we are keeping a define. 129 */ 130 for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) { 131 const char * pzSrc = arg_list->apzArgs[ i ]; 132 char * pzEq = strchr(pzSrc, '='); 133 134 if (pzEq != NULL) 135 *pzEq = NUL; 136 137 if (strcmp(pzSrc, od->optArg.argString) == 0) { 138 /* 139 * Remove this entry by reducing the in-use count 140 * and *not* putting the string pointer back into 141 * the list. 142 */ 143 AGFREE(pzSrc); 144 arg_list->useCt--; 145 } else { 146 if (pzEq != NULL) 147 *pzEq = '='; 148 149 /* 150 * IF we have dropped an entry 151 * THEN we have to move the current one. 152 */ 153 if (dIdx != i) 154 arg_list->apzArgs[ dIdx ] = pzSrc; 155 dIdx++; 156 } 157 } 158 } 159 #endif /* WITH_LIBREGEX */ 160 /* 161 * IF we have unstacked everything, 162 * THEN indicate that we don't have any of these options 163 */ 164 if (arg_list->useCt == 0) { 165 od->fOptState &= OPTST_PERSISTENT_MASK; 166 if ((od->fOptState & OPTST_INITENABLED) == 0) 167 od->fOptState |= OPTST_DISABLED; 168 AGFREE(arg_list); 169 od->optCookie = NULL; 170 } 171 } 172 173 174 /* 175 * Put an entry into an argument list. The first argument points to 176 * a pointer to the argument list structure. It gets passed around 177 * as an opaque address. 178 */ 179 static void 180 addArgListEntry(void ** ppAL, void * entry) 181 { 182 tArgList * pAL = *(void **)ppAL; 183 184 /* 185 * IF we have never allocated one of these, 186 * THEN allocate one now 187 */ 188 if (pAL == NULL) { 189 pAL = (tArgList *)AGALOC(sizeof(*pAL), "new option arg stack"); 190 if (pAL == NULL) 191 return; 192 pAL->useCt = 0; 193 pAL->allocCt = MIN_ARG_ALLOC_CT; 194 *ppAL = VOIDP(pAL); 195 } 196 197 /* 198 * ELSE if we are out of room 199 * THEN make it bigger 200 */ 201 else if (pAL->useCt >= pAL->allocCt) { 202 size_t sz = sizeof(*pAL); 203 pAL->allocCt += INCR_ARG_ALLOC_CT; 204 205 /* 206 * The base structure contains space for MIN_ARG_ALLOC_CT 207 * pointers. We subtract it off to find our augment size. 208 */ 209 sz += sizeof(char *) * ((size_t)pAL->allocCt - MIN_ARG_ALLOC_CT); 210 pAL = (tArgList *)AGREALOC(VOIDP(pAL), sz, "expanded opt arg stack"); 211 if (pAL == NULL) 212 return; 213 *ppAL = VOIDP(pAL); 214 } 215 216 /* 217 * Insert the new argument into the list 218 */ 219 pAL->apzArgs[ (pAL->useCt)++ ] = entry; 220 } 221 222 223 /*=export_func optionStackArg 224 * private: 225 * 226 * what: put option args on a stack 227 * arg: + tOptions * + opts + program options descriptor + 228 * arg: + tOptDesc * + od + the descriptor for this arg + 229 * 230 * doc: 231 * Keep an entry-ordered list of option arguments. 232 =*/ 233 void 234 optionStackArg(tOptions * opts, tOptDesc * od) 235 { 236 char * pz; 237 238 if (INQUERY_CALL(opts, od)) 239 return; 240 241 if ((od->fOptState & OPTST_RESET) != 0) { 242 tArgList * arg_list = od->optCookie; 243 int ix; 244 if (arg_list == NULL) 245 return; 246 247 ix = arg_list->useCt; 248 while (--ix >= 0) 249 AGFREE(arg_list->apzArgs[ix]); 250 AGFREE(arg_list); 251 252 } else { 253 if (od->optArg.argString == NULL) 254 return; 255 256 AGDUPSTR(pz, od->optArg.argString, "stack arg"); 257 addArgListEntry(&(od->optCookie), VOIDP(pz)); 258 } 259 } 260 /** @} 261 * 262 * Local Variables: 263 * mode: C 264 * c-file-style: "stroustrup" 265 * indent-tabs-mode: nil 266 * End: 267 * end of autoopts/stack.c */ 268