1 /* $NetBSD: restore.c,v 1.4 2016/01/08 21:35:41 christos Exp $ */ 2 3 4 /* 5 * \file restore.c 6 * 7 * This module's routines will save the current option state to memory 8 * and restore it. If saved prior to the initial optionProcess call, 9 * then the initial state will be restored. 10 * 11 * @addtogroup autoopts 12 * @{ 13 */ 14 /* 15 * This file is part of AutoOpts, a companion to AutoGen. 16 * AutoOpts is free software. 17 * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 18 * 19 * AutoOpts is available under any one of two licenses. The license 20 * in use must be one of these two and the choice is under the control 21 * of the user of the license. 22 * 23 * The GNU Lesser General Public License, version 3 or later 24 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 25 * 26 * The Modified Berkeley Software Distribution License 27 * See the file "COPYING.mbsd" 28 * 29 * These files have the following sha256 sums: 30 * 31 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 32 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 33 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 34 */ 35 36 /* 37 * optionFixupSavedOpts Really, it just wipes out option state for 38 * options that are troublesome to copy. viz., stacked strings and 39 * hierarcicaly valued option args. We do duplicate string args that 40 * have been marked as allocated though. 41 */ 42 static void 43 fixupSavedOptionArgs(tOptions * pOpts) 44 { 45 tOptions * p = pOpts->pSavedState; 46 tOptDesc * pOD = pOpts->pOptDesc; 47 int ct = pOpts->optCt; 48 49 /* 50 * Make sure that allocated stuff is only referenced in the 51 * archived copy of the data. 52 */ 53 for (; ct-- > 0; pOD++) { 54 switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { 55 case OPARG_TYPE_STRING: 56 if (pOD->fOptState & OPTST_STACKED) { 57 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc); 58 q->optCookie = NULL; 59 } 60 if (pOD->fOptState & OPTST_ALLOC_ARG) { 61 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc); 62 AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg"); 63 } 64 break; 65 66 case OPARG_TYPE_HIERARCHY: 67 { 68 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc); 69 q->optCookie = NULL; 70 } 71 } 72 } 73 } 74 75 /*=export_func optionSaveState 76 * 77 * what: saves the option state to memory 78 * arg: tOptions *, pOpts, program options descriptor 79 * 80 * doc: 81 * 82 * This routine will allocate enough memory to save the current option 83 * processing state. If this routine has been called before, that memory 84 * will be reused. You may only save one copy of the option state. This 85 * routine may be called before optionProcess(3AO). If you do call it 86 * before the first call to optionProcess, then you may also change the 87 * contents of argc/argv after you call optionRestore(3AO) 88 * 89 * In fact, more strongly put: it is safest to only use this function 90 * before having processed any options. In particular, the saving and 91 * restoring of stacked string arguments and hierarchical values is 92 * disabled. The values are not saved. 93 * 94 * err: If it fails to allocate the memory, 95 * it will print a message to stderr and exit. 96 * Otherwise, it will always succeed. 97 =*/ 98 void 99 optionSaveState(tOptions * pOpts) 100 { 101 tOptions * p = (tOptions *)pOpts->pSavedState; 102 103 if (p == NULL) { 104 size_t sz = sizeof(*pOpts) 105 + ((size_t)pOpts->optCt * sizeof(tOptDesc)); 106 p = AGALOC(sz, "saved option state"); 107 108 pOpts->pSavedState = p; 109 } 110 111 memcpy(p, pOpts, sizeof(*p)); 112 memcpy(p + 1, pOpts->pOptDesc, (size_t)p->optCt * sizeof(tOptDesc)); 113 114 fixupSavedOptionArgs(pOpts); 115 } 116 117 118 /*=export_func optionRestore 119 * 120 * what: restore option state from memory copy 121 * arg: tOptions *, pOpts, program options descriptor 122 * 123 * doc: Copy back the option state from saved memory. 124 * The allocated memory is left intact, so this routine can be 125 * called repeatedly without having to call optionSaveState again. 126 * If you are restoring a state that was saved before the first call 127 * to optionProcess(3AO), then you may change the contents of the 128 * argc/argv parameters to optionProcess. 129 * 130 * err: If you have not called @code{optionSaveState} before, a diagnostic is 131 * printed to @code{stderr} and exit is called. 132 =*/ 133 void 134 optionRestore(tOptions * pOpts) 135 { 136 tOptions * p = (tOptions *)pOpts->pSavedState; 137 138 if (p == NULL) { 139 char const * pzName = pOpts->pzProgName; 140 if (pzName == NULL) { 141 pzName = pOpts->pzPROGNAME; 142 if (pzName == NULL) 143 pzName = zNil; 144 } 145 fprintf(stderr, zNoState, pzName); 146 option_exits(EXIT_FAILURE); 147 } 148 149 pOpts->pSavedState = NULL; 150 optionFree(pOpts); 151 152 memcpy(pOpts, p, sizeof(*p)); 153 memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc)); 154 pOpts->pSavedState = p; 155 156 fixupSavedOptionArgs(pOpts); 157 } 158 159 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ 160 161 /*=export_func optionFree 162 * 163 * what: free allocated option processing memory 164 * arg: tOptions *, pOpts, program options descriptor 165 * 166 * doc: AutoOpts sometimes allocates memory and puts pointers to it in the 167 * option state structures. This routine deallocates all such memory. 168 * 169 * err: As long as memory has not been corrupted, 170 * this routine is always successful. 171 =*/ 172 void 173 optionFree(tOptions * pOpts) 174 { 175 free_saved_state: 176 { 177 tOptDesc * p = pOpts->pOptDesc; 178 int ct = pOpts->optCt; 179 do { 180 if (p->fOptState & OPTST_ALLOC_ARG) { 181 AGFREE(p->optArg.argString); 182 p->optArg.argString = NULL; 183 p->fOptState &= ~OPTST_ALLOC_ARG; 184 } 185 186 switch (OPTST_GET_ARGTYPE(p->fOptState)) { 187 case OPARG_TYPE_STRING: 188 #ifdef WITH_LIBREGEX 189 if ( (p->fOptState & OPTST_STACKED) 190 && (p->optCookie != NULL)) { 191 p->optArg.argString = ".*"; 192 optionUnstackArg(pOpts, p); 193 } 194 #else 195 /* leak memory */; 196 #endif 197 break; 198 199 case OPARG_TYPE_HIERARCHY: 200 if (p->optCookie != NULL) 201 unload_arg_list(p->optCookie); 202 break; 203 } 204 205 p->optCookie = NULL; 206 } while (p++, --ct > 0); 207 } 208 if (pOpts->pSavedState != NULL) { 209 tOptions * p = (tOptions *)pOpts->pSavedState; 210 memcpy(pOpts, p, sizeof(*p)); 211 memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc)); 212 AGFREE(pOpts->pSavedState); 213 pOpts->pSavedState = NULL; 214 goto free_saved_state; 215 } 216 } 217 218 /** @} 219 * 220 * Local Variables: 221 * mode: C 222 * c-file-style: "stroustrup" 223 * indent-tabs-mode: nil 224 * End: 225 * end of autoopts/restore.c */ 226