1181834Sroberto 2181834Sroberto/* 3290001Sglebius * \file restore.c 4181834Sroberto * 5181834Sroberto * This module's routines will save the current option state to memory 6181834Sroberto * and restore it. If saved prior to the initial optionProcess call, 7181834Sroberto * then the initial state will be restored. 8290001Sglebius * 9290001Sglebius * @addtogroup autoopts 10290001Sglebius * @{ 11181834Sroberto */ 12181834Sroberto/* 13290001Sglebius * This file is part of AutoOpts, a companion to AutoGen. 14290001Sglebius * AutoOpts is free software. 15290001Sglebius * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 16181834Sroberto * 17290001Sglebius * AutoOpts is available under any one of two licenses. The license 18290001Sglebius * in use must be one of these two and the choice is under the control 19290001Sglebius * of the user of the license. 20181834Sroberto * 21290001Sglebius * The GNU Lesser General Public License, version 3 or later 22290001Sglebius * See the files "COPYING.lgplv3" and "COPYING.gplv3" 23181834Sroberto * 24290001Sglebius * The Modified Berkeley Software Distribution License 25290001Sglebius * See the file "COPYING.mbsd" 26181834Sroberto * 27290001Sglebius * These files have the following sha256 sums: 28181834Sroberto * 29290001Sglebius * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 30290001Sglebius * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 31290001Sglebius * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 32181834Sroberto */ 33181834Sroberto 34181834Sroberto/* 35181834Sroberto * optionFixupSavedOpts Really, it just wipes out option state for 36181834Sroberto * options that are troublesome to copy. viz., stacked strings and 37181834Sroberto * hierarcicaly valued option args. We do duplicate string args that 38181834Sroberto * have been marked as allocated though. 39181834Sroberto */ 40181834Srobertostatic void 41290001SglebiusfixupSavedOptionArgs(tOptions * pOpts) 42181834Sroberto{ 43290001Sglebius tOptions * p = pOpts->pSavedState; 44290001Sglebius tOptDesc * pOD = pOpts->pOptDesc; 45290001Sglebius int ct = pOpts->optCt; 46181834Sroberto 47181834Sroberto /* 48181834Sroberto * Make sure that allocated stuff is only referenced in the 49181834Sroberto * archived copy of the data. 50181834Sroberto */ 51181834Sroberto for (; ct-- > 0; pOD++) { 52181834Sroberto switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { 53181834Sroberto case OPARG_TYPE_STRING: 54181834Sroberto if (pOD->fOptState & OPTST_STACKED) { 55290001Sglebius tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc); 56181834Sroberto q->optCookie = NULL; 57181834Sroberto } 58181834Sroberto if (pOD->fOptState & OPTST_ALLOC_ARG) { 59290001Sglebius tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc); 60181834Sroberto AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg"); 61181834Sroberto } 62181834Sroberto break; 63181834Sroberto 64181834Sroberto case OPARG_TYPE_HIERARCHY: 65181834Sroberto { 66290001Sglebius tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc); 67181834Sroberto q->optCookie = NULL; 68181834Sroberto } 69181834Sroberto } 70181834Sroberto } 71181834Sroberto} 72181834Sroberto 73181834Sroberto/*=export_func optionSaveState 74181834Sroberto * 75181834Sroberto * what: saves the option state to memory 76290001Sglebius * arg: tOptions *, pOpts, program options descriptor 77181834Sroberto * 78181834Sroberto * doc: 79181834Sroberto * 80181834Sroberto * This routine will allocate enough memory to save the current option 81181834Sroberto * processing state. If this routine has been called before, that memory 82181834Sroberto * will be reused. You may only save one copy of the option state. This 83181834Sroberto * routine may be called before optionProcess(3AO). If you do call it 84181834Sroberto * before the first call to optionProcess, then you may also change the 85181834Sroberto * contents of argc/argv after you call optionRestore(3AO) 86181834Sroberto * 87181834Sroberto * In fact, more strongly put: it is safest to only use this function 88181834Sroberto * before having processed any options. In particular, the saving and 89181834Sroberto * restoring of stacked string arguments and hierarchical values is 90181834Sroberto * disabled. The values are not saved. 91181834Sroberto * 92181834Sroberto * err: If it fails to allocate the memory, 93181834Sroberto * it will print a message to stderr and exit. 94181834Sroberto * Otherwise, it will always succeed. 95181834Sroberto=*/ 96181834Srobertovoid 97290001SglebiusoptionSaveState(tOptions * pOpts) 98181834Sroberto{ 99290001Sglebius tOptions * p = (tOptions *)pOpts->pSavedState; 100181834Sroberto 101181834Sroberto if (p == NULL) { 102290001Sglebius size_t sz = sizeof(*pOpts) 103290001Sglebius + ((size_t)pOpts->optCt * sizeof(tOptDesc)); 104290001Sglebius p = AGALOC(sz, "saved option state"); 105181834Sroberto 106181834Sroberto pOpts->pSavedState = p; 107181834Sroberto } 108181834Sroberto 109290001Sglebius memcpy(p, pOpts, sizeof(*p)); 110290001Sglebius memcpy(p + 1, pOpts->pOptDesc, (size_t)p->optCt * sizeof(tOptDesc)); 111181834Sroberto 112181834Sroberto fixupSavedOptionArgs(pOpts); 113181834Sroberto} 114181834Sroberto 115181834Sroberto 116181834Sroberto/*=export_func optionRestore 117181834Sroberto * 118181834Sroberto * what: restore option state from memory copy 119290001Sglebius * arg: tOptions *, pOpts, program options descriptor 120181834Sroberto * 121181834Sroberto * doc: Copy back the option state from saved memory. 122181834Sroberto * The allocated memory is left intact, so this routine can be 123181834Sroberto * called repeatedly without having to call optionSaveState again. 124181834Sroberto * If you are restoring a state that was saved before the first call 125181834Sroberto * to optionProcess(3AO), then you may change the contents of the 126181834Sroberto * argc/argv parameters to optionProcess. 127181834Sroberto * 128181834Sroberto * err: If you have not called @code{optionSaveState} before, a diagnostic is 129181834Sroberto * printed to @code{stderr} and exit is called. 130181834Sroberto=*/ 131181834Srobertovoid 132290001SglebiusoptionRestore(tOptions * pOpts) 133181834Sroberto{ 134290001Sglebius tOptions * p = (tOptions *)pOpts->pSavedState; 135181834Sroberto 136181834Sroberto if (p == NULL) { 137290001Sglebius char const * pzName = pOpts->pzProgName; 138181834Sroberto if (pzName == NULL) { 139181834Sroberto pzName = pOpts->pzPROGNAME; 140181834Sroberto if (pzName == NULL) 141181834Sroberto pzName = zNil; 142181834Sroberto } 143290001Sglebius fprintf(stderr, zNoState, pzName); 144290001Sglebius option_exits(EXIT_FAILURE); 145181834Sroberto } 146181834Sroberto 147181834Sroberto pOpts->pSavedState = NULL; 148181834Sroberto optionFree(pOpts); 149181834Sroberto 150290001Sglebius memcpy(pOpts, p, sizeof(*p)); 151290001Sglebius memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc)); 152181834Sroberto pOpts->pSavedState = p; 153181834Sroberto 154181834Sroberto fixupSavedOptionArgs(pOpts); 155181834Sroberto} 156181834Sroberto 157181834Sroberto/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ 158181834Sroberto 159181834Sroberto/*=export_func optionFree 160181834Sroberto * 161181834Sroberto * what: free allocated option processing memory 162290001Sglebius * arg: tOptions *, pOpts, program options descriptor 163181834Sroberto * 164181834Sroberto * doc: AutoOpts sometimes allocates memory and puts pointers to it in the 165181834Sroberto * option state structures. This routine deallocates all such memory. 166181834Sroberto * 167181834Sroberto * err: As long as memory has not been corrupted, 168181834Sroberto * this routine is always successful. 169181834Sroberto=*/ 170181834Srobertovoid 171290001SglebiusoptionFree(tOptions * pOpts) 172181834Sroberto{ 173181834Sroberto free_saved_state: 174181834Sroberto { 175290001Sglebius tOptDesc * p = pOpts->pOptDesc; 176181834Sroberto int ct = pOpts->optCt; 177181834Sroberto do { 178181834Sroberto if (p->fOptState & OPTST_ALLOC_ARG) { 179181834Sroberto AGFREE(p->optArg.argString); 180181834Sroberto p->optArg.argString = NULL; 181181834Sroberto p->fOptState &= ~OPTST_ALLOC_ARG; 182181834Sroberto } 183181834Sroberto 184181834Sroberto switch (OPTST_GET_ARGTYPE(p->fOptState)) { 185181834Sroberto case OPARG_TYPE_STRING: 186181834Sroberto#ifdef WITH_LIBREGEX 187181834Sroberto if ( (p->fOptState & OPTST_STACKED) 188181834Sroberto && (p->optCookie != NULL)) { 189181834Sroberto p->optArg.argString = ".*"; 190181834Sroberto optionUnstackArg(pOpts, p); 191181834Sroberto } 192181834Sroberto#else 193181834Sroberto /* leak memory */; 194181834Sroberto#endif 195181834Sroberto break; 196181834Sroberto 197181834Sroberto case OPARG_TYPE_HIERARCHY: 198181834Sroberto if (p->optCookie != NULL) 199290001Sglebius unload_arg_list(p->optCookie); 200181834Sroberto break; 201181834Sroberto } 202181834Sroberto 203181834Sroberto p->optCookie = NULL; 204181834Sroberto } while (p++, --ct > 0); 205181834Sroberto } 206181834Sroberto if (pOpts->pSavedState != NULL) { 207290001Sglebius tOptions * p = (tOptions *)pOpts->pSavedState; 208290001Sglebius memcpy(pOpts, p, sizeof(*p)); 209290001Sglebius memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc)); 210290001Sglebius AGFREE(pOpts->pSavedState); 211181834Sroberto pOpts->pSavedState = NULL; 212181834Sroberto goto free_saved_state; 213181834Sroberto } 214181834Sroberto} 215290001Sglebius 216290001Sglebius/** @} 217290001Sglebius * 218181834Sroberto * Local Variables: 219181834Sroberto * mode: C 220181834Sroberto * c-file-style: "stroustrup" 221181834Sroberto * indent-tabs-mode: nil 222181834Sroberto * End: 223181834Sroberto * end of autoopts/restore.c */ 224