restore.c revision 290001
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-2015 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 */
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)
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=*/
131void
132optionRestore(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=*/
170void
171optionFree(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