restore.c revision 181834
1181834Sroberto 2181834Sroberto/* 3181834Sroberto * restore.c $Id: restore.c,v 4.10 2007/02/04 17:44:12 bkorb Exp $ 4181834Sroberto * Time-stamp: "2007-01-13 14:13:17 bkorb" 5181834Sroberto * 6181834Sroberto * This module's routines will save the current option state to memory 7181834Sroberto * and restore it. If saved prior to the initial optionProcess call, 8181834Sroberto * then the initial state will be restored. 9181834Sroberto */ 10181834Sroberto 11181834Sroberto/* 12181834Sroberto * Automated Options copyright 1992-2007 Bruce Korb 13181834Sroberto * 14181834Sroberto * Automated Options is free software. 15181834Sroberto * You may redistribute it and/or modify it under the terms of the 16181834Sroberto * GNU General Public License, as published by the Free Software 17181834Sroberto * Foundation; either version 2, or (at your option) any later version. 18181834Sroberto * 19181834Sroberto * Automated Options is distributed in the hope that it will be useful, 20181834Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of 21181834Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22181834Sroberto * GNU General Public License for more details. 23181834Sroberto * 24181834Sroberto * You should have received a copy of the GNU General Public License 25181834Sroberto * along with Automated Options. See the file "COPYING". If not, 26181834Sroberto * write to: The Free Software Foundation, Inc., 27181834Sroberto * 51 Franklin Street, Fifth Floor, 28181834Sroberto * Boston, MA 02110-1301, USA. 29181834Sroberto * 30181834Sroberto * As a special exception, Bruce Korb gives permission for additional 31181834Sroberto * uses of the text contained in his release of AutoOpts. 32181834Sroberto * 33181834Sroberto * The exception is that, if you link the AutoOpts library with other 34181834Sroberto * files to produce an executable, this does not by itself cause the 35181834Sroberto * resulting executable to be covered by the GNU General Public License. 36181834Sroberto * Your use of that executable is in no way restricted on account of 37181834Sroberto * linking the AutoOpts library code into it. 38181834Sroberto * 39181834Sroberto * This exception does not however invalidate any other reasons why 40181834Sroberto * the executable file might be covered by the GNU General Public License. 41181834Sroberto * 42181834Sroberto * This exception applies only to the code released by Bruce Korb under 43181834Sroberto * the name AutoOpts. If you copy code from other sources under the 44181834Sroberto * General Public License into a copy of AutoOpts, as the General Public 45181834Sroberto * License permits, the exception does not apply to the code that you add 46181834Sroberto * in this way. To avoid misleading anyone as to the status of such 47181834Sroberto * modified files, you must delete this exception notice from them. 48181834Sroberto * 49181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice 50181834Sroberto * whether to permit this exception to apply to your modifications. 51181834Sroberto * If you do not wish that, delete this exception notice. 52181834Sroberto */ 53181834Sroberto 54181834Sroberto/* 55181834Sroberto * optionFixupSavedOpts Really, it just wipes out option state for 56181834Sroberto * options that are troublesome to copy. viz., stacked strings and 57181834Sroberto * hierarcicaly valued option args. We do duplicate string args that 58181834Sroberto * have been marked as allocated though. 59181834Sroberto */ 60181834Srobertostatic void 61181834SrobertofixupSavedOptionArgs(tOptions* pOpts) 62181834Sroberto{ 63181834Sroberto tOptions* p = pOpts->pSavedState; 64181834Sroberto tOptDesc* pOD = pOpts->pOptDesc; 65181834Sroberto int ct = pOpts->optCt; 66181834Sroberto 67181834Sroberto /* 68181834Sroberto * Make sure that allocated stuff is only referenced in the 69181834Sroberto * archived copy of the data. 70181834Sroberto */ 71181834Sroberto for (; ct-- > 0; pOD++) { 72181834Sroberto switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { 73181834Sroberto case OPARG_TYPE_STRING: 74181834Sroberto if (pOD->fOptState & OPTST_STACKED) { 75181834Sroberto tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc); 76181834Sroberto q->optCookie = NULL; 77181834Sroberto } 78181834Sroberto if (pOD->fOptState & OPTST_ALLOC_ARG) { 79181834Sroberto tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc); 80181834Sroberto AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg"); 81181834Sroberto } 82181834Sroberto break; 83181834Sroberto 84181834Sroberto case OPARG_TYPE_HIERARCHY: 85181834Sroberto { 86181834Sroberto tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc); 87181834Sroberto q->optCookie = NULL; 88181834Sroberto } 89181834Sroberto } 90181834Sroberto } 91181834Sroberto} 92181834Sroberto 93181834Sroberto/*=export_func optionSaveState 94181834Sroberto * 95181834Sroberto * what: saves the option state to memory 96181834Sroberto * arg: tOptions*, pOpts, program options descriptor 97181834Sroberto * 98181834Sroberto * doc: 99181834Sroberto * 100181834Sroberto * This routine will allocate enough memory to save the current option 101181834Sroberto * processing state. If this routine has been called before, that memory 102181834Sroberto * will be reused. You may only save one copy of the option state. This 103181834Sroberto * routine may be called before optionProcess(3AO). If you do call it 104181834Sroberto * before the first call to optionProcess, then you may also change the 105181834Sroberto * contents of argc/argv after you call optionRestore(3AO) 106181834Sroberto * 107181834Sroberto * In fact, more strongly put: it is safest to only use this function 108181834Sroberto * before having processed any options. In particular, the saving and 109181834Sroberto * restoring of stacked string arguments and hierarchical values is 110181834Sroberto * disabled. The values are not saved. 111181834Sroberto * 112181834Sroberto * err: If it fails to allocate the memory, 113181834Sroberto * it will print a message to stderr and exit. 114181834Sroberto * Otherwise, it will always succeed. 115181834Sroberto=*/ 116181834Srobertovoid 117181834SrobertooptionSaveState(tOptions* pOpts) 118181834Sroberto{ 119181834Sroberto tOptions* p = (tOptions*)pOpts->pSavedState; 120181834Sroberto 121181834Sroberto if (p == NULL) { 122181834Sroberto size_t sz = sizeof( *pOpts ) + (pOpts->optCt * sizeof( tOptDesc )); 123181834Sroberto p = AGALOC( sz, "saved option state" ); 124181834Sroberto if (p == NULL) { 125181834Sroberto tCC* pzName = pOpts->pzProgName; 126181834Sroberto if (pzName == NULL) { 127181834Sroberto pzName = pOpts->pzPROGNAME; 128181834Sroberto if (pzName == NULL) 129181834Sroberto pzName = zNil; 130181834Sroberto } 131181834Sroberto fprintf( stderr, zCantSave, pzName, sz ); 132181834Sroberto exit( EXIT_FAILURE ); 133181834Sroberto } 134181834Sroberto 135181834Sroberto pOpts->pSavedState = p; 136181834Sroberto } 137181834Sroberto 138181834Sroberto memcpy( p, pOpts, sizeof( *p )); 139181834Sroberto memcpy( p + 1, pOpts->pOptDesc, p->optCt * sizeof( tOptDesc )); 140181834Sroberto 141181834Sroberto fixupSavedOptionArgs(pOpts); 142181834Sroberto} 143181834Sroberto 144181834Sroberto 145181834Sroberto/*=export_func optionRestore 146181834Sroberto * 147181834Sroberto * what: restore option state from memory copy 148181834Sroberto * arg: tOptions*, pOpts, program options descriptor 149181834Sroberto * 150181834Sroberto * doc: Copy back the option state from saved memory. 151181834Sroberto * The allocated memory is left intact, so this routine can be 152181834Sroberto * called repeatedly without having to call optionSaveState again. 153181834Sroberto * If you are restoring a state that was saved before the first call 154181834Sroberto * to optionProcess(3AO), then you may change the contents of the 155181834Sroberto * argc/argv parameters to optionProcess. 156181834Sroberto * 157181834Sroberto * err: If you have not called @code{optionSaveState} before, a diagnostic is 158181834Sroberto * printed to @code{stderr} and exit is called. 159181834Sroberto=*/ 160181834Srobertovoid 161181834SrobertooptionRestore( tOptions* pOpts ) 162181834Sroberto{ 163181834Sroberto tOptions* p = (tOptions*)pOpts->pSavedState; 164181834Sroberto 165181834Sroberto if (p == NULL) { 166181834Sroberto tCC* pzName = pOpts->pzProgName; 167181834Sroberto if (pzName == NULL) { 168181834Sroberto pzName = pOpts->pzPROGNAME; 169181834Sroberto if (pzName == NULL) 170181834Sroberto pzName = zNil; 171181834Sroberto } 172181834Sroberto fprintf( stderr, zNoState, pzName ); 173181834Sroberto exit( EXIT_FAILURE ); 174181834Sroberto } 175181834Sroberto 176181834Sroberto pOpts->pSavedState = NULL; 177181834Sroberto optionFree(pOpts); 178181834Sroberto 179181834Sroberto memcpy( pOpts, p, sizeof( *p )); 180181834Sroberto memcpy( pOpts->pOptDesc, p+1, p->optCt * sizeof( tOptDesc )); 181181834Sroberto pOpts->pSavedState = p; 182181834Sroberto 183181834Sroberto fixupSavedOptionArgs(pOpts); 184181834Sroberto} 185181834Sroberto 186181834Sroberto/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ 187181834Sroberto 188181834Sroberto/*=export_func optionFree 189181834Sroberto * 190181834Sroberto * what: free allocated option processing memory 191181834Sroberto * arg: tOptions*, pOpts, program options descriptor 192181834Sroberto * 193181834Sroberto * doc: AutoOpts sometimes allocates memory and puts pointers to it in the 194181834Sroberto * option state structures. This routine deallocates all such memory. 195181834Sroberto * 196181834Sroberto * err: As long as memory has not been corrupted, 197181834Sroberto * this routine is always successful. 198181834Sroberto=*/ 199181834Srobertovoid 200181834SrobertooptionFree( tOptions* pOpts ) 201181834Sroberto{ 202181834Sroberto free_saved_state: 203181834Sroberto { 204181834Sroberto tOptDesc* p = pOpts->pOptDesc; 205181834Sroberto int ct = pOpts->optCt; 206181834Sroberto do { 207181834Sroberto if (p->fOptState & OPTST_ALLOC_ARG) { 208181834Sroberto AGFREE(p->optArg.argString); 209181834Sroberto p->optArg.argString = NULL; 210181834Sroberto p->fOptState &= ~OPTST_ALLOC_ARG; 211181834Sroberto } 212181834Sroberto 213181834Sroberto switch (OPTST_GET_ARGTYPE(p->fOptState)) { 214181834Sroberto case OPARG_TYPE_STRING: 215181834Sroberto#ifdef WITH_LIBREGEX 216181834Sroberto if ( (p->fOptState & OPTST_STACKED) 217181834Sroberto && (p->optCookie != NULL)) { 218181834Sroberto p->optArg.argString = ".*"; 219181834Sroberto optionUnstackArg(pOpts, p); 220181834Sroberto } 221181834Sroberto#else 222181834Sroberto /* leak memory */; 223181834Sroberto#endif 224181834Sroberto break; 225181834Sroberto 226181834Sroberto case OPARG_TYPE_HIERARCHY: 227181834Sroberto if (p->optCookie != NULL) 228181834Sroberto unloadNestedArglist(p->optCookie); 229181834Sroberto break; 230181834Sroberto } 231181834Sroberto 232181834Sroberto p->optCookie = NULL; 233181834Sroberto } while (p++, --ct > 0); 234181834Sroberto } 235181834Sroberto if (pOpts->pSavedState != NULL) { 236181834Sroberto tOptions * p = (tOptions*)pOpts->pSavedState; 237181834Sroberto memcpy( pOpts, p, sizeof( *p )); 238181834Sroberto memcpy( pOpts->pOptDesc, p+1, p->optCt * sizeof( tOptDesc )); 239181834Sroberto AGFREE( pOpts->pSavedState ); 240181834Sroberto pOpts->pSavedState = NULL; 241181834Sroberto goto free_saved_state; 242181834Sroberto } 243181834Sroberto} 244181834Sroberto/* 245181834Sroberto * Local Variables: 246181834Sroberto * mode: C 247181834Sroberto * c-file-style: "stroustrup" 248181834Sroberto * indent-tabs-mode: nil 249181834Sroberto * End: 250181834Sroberto * end of autoopts/restore.c */ 251