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