1/* $NetBSD: restore.c,v 1.1.1.2 2012/01/31 21:27:49 kardel Exp $ */ 2 3 4/* 5 * \file restore.c 6 * 7 * Time-stamp: "2010-08-22 11:04:00 bkorb" 8 * 9 * This module's routines will save the current option state to memory 10 * and restore it. If saved prior to the initial optionProcess call, 11 * then the initial state will be restored. 12 * 13 * This file is part of AutoOpts, a companion to AutoGen. 14 * AutoOpts is free software. 15 * AutoOpts is Copyright (c) 1992-2011 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 md5sums: 28 * 29 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3 30 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3 31 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/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 */ 40static void 41fixupSavedOptionArgs(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=*/ 96void 97optionSaveState(tOptions* pOpts) 98{ 99 tOptions* p = (tOptions*)pOpts->pSavedState; 100 101 if (p == NULL) { 102 size_t sz = sizeof(*pOpts) + (pOpts->optCt * sizeof(tOptDesc)); 103 p = AGALOC(sz, "saved option state"); 104 if (p == NULL) { 105 tCC* pzName = pOpts->pzProgName; 106 if (pzName == NULL) { 107 pzName = pOpts->pzPROGNAME; 108 if (pzName == NULL) 109 pzName = zNil; 110 } 111 fprintf(stderr, zCantSave, pzName, sz); 112 exit(EXIT_FAILURE); 113 } 114 115 pOpts->pSavedState = p; 116 } 117 118 memcpy(p, pOpts, sizeof(*p)); 119 memcpy(p + 1, pOpts->pOptDesc, p->optCt * sizeof(tOptDesc)); 120 121 fixupSavedOptionArgs(pOpts); 122} 123 124 125/*=export_func optionRestore 126 * 127 * what: restore option state from memory copy 128 * arg: tOptions*, pOpts, program options descriptor 129 * 130 * doc: Copy back the option state from saved memory. 131 * The allocated memory is left intact, so this routine can be 132 * called repeatedly without having to call optionSaveState again. 133 * If you are restoring a state that was saved before the first call 134 * to optionProcess(3AO), then you may change the contents of the 135 * argc/argv parameters to optionProcess. 136 * 137 * err: If you have not called @code{optionSaveState} before, a diagnostic is 138 * printed to @code{stderr} and exit is called. 139=*/ 140void 141optionRestore(tOptions* pOpts) 142{ 143 tOptions* p = (tOptions*)pOpts->pSavedState; 144 145 if (p == NULL) { 146 tCC* pzName = pOpts->pzProgName; 147 if (pzName == NULL) { 148 pzName = pOpts->pzPROGNAME; 149 if (pzName == NULL) 150 pzName = zNil; 151 } 152 fprintf(stderr, zNoState, pzName); 153 exit(EXIT_FAILURE); 154 } 155 156 pOpts->pSavedState = NULL; 157 optionFree(pOpts); 158 159 memcpy(pOpts, p, sizeof(*p)); 160 memcpy(pOpts->pOptDesc, p+1, p->optCt * sizeof(tOptDesc)); 161 pOpts->pSavedState = p; 162 163 fixupSavedOptionArgs(pOpts); 164} 165 166/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ 167 168/*=export_func optionFree 169 * 170 * what: free allocated option processing memory 171 * arg: tOptions*, pOpts, program options descriptor 172 * 173 * doc: AutoOpts sometimes allocates memory and puts pointers to it in the 174 * option state structures. This routine deallocates all such memory. 175 * 176 * err: As long as memory has not been corrupted, 177 * this routine is always successful. 178=*/ 179void 180optionFree(tOptions* pOpts) 181{ 182 free_saved_state: 183 { 184 tOptDesc* p = pOpts->pOptDesc; 185 int ct = pOpts->optCt; 186 do { 187 if (p->fOptState & OPTST_ALLOC_ARG) { 188 AGFREE(p->optArg.argString); 189 p->optArg.argString = NULL; 190 p->fOptState &= ~OPTST_ALLOC_ARG; 191 } 192 193 switch (OPTST_GET_ARGTYPE(p->fOptState)) { 194 case OPARG_TYPE_STRING: 195#ifdef WITH_LIBREGEX 196 if ( (p->fOptState & OPTST_STACKED) 197 && (p->optCookie != NULL)) { 198 p->optArg.argString = ".*"; 199 optionUnstackArg(pOpts, p); 200 } 201#else 202 /* leak memory */; 203#endif 204 break; 205 206 case OPARG_TYPE_HIERARCHY: 207 if (p->optCookie != NULL) 208 unload_arg_list(p->optCookie); 209 break; 210 } 211 212 p->optCookie = NULL; 213 } while (p++, --ct > 0); 214 } 215 if (pOpts->pSavedState != NULL) { 216 tOptions * p = (tOptions*)pOpts->pSavedState; 217 memcpy(pOpts, p, sizeof(*p)); 218 memcpy(pOpts->pOptDesc, p+1, p->optCt * sizeof(tOptDesc)); 219 AGFREE(pOpts->pSavedState); 220 pOpts->pSavedState = NULL; 221 goto free_saved_state; 222 } 223} 224/* 225 * Local Variables: 226 * mode: C 227 * c-file-style: "stroustrup" 228 * indent-tabs-mode: nil 229 * End: 230 * end of autoopts/restore.c */ 231