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