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