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