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