xref: /freebsd/contrib/ntp/sntp/libopts/restore.c (revision ea906c4152774dff300bb26fbfc1e4188351c89a)
1ea906c41SOllivier Robert 
2ea906c41SOllivier Robert /*
3ea906c41SOllivier Robert  *  restore.c  $Id: restore.c,v 4.10 2007/02/04 17:44:12 bkorb Exp $
4ea906c41SOllivier Robert  * Time-stamp:      "2007-01-13 14:13:17 bkorb"
5ea906c41SOllivier Robert  *
6ea906c41SOllivier Robert  *  This module's routines will save the current option state to memory
7ea906c41SOllivier Robert  *  and restore it.  If saved prior to the initial optionProcess call,
8ea906c41SOllivier Robert  *  then the initial state will be restored.
9ea906c41SOllivier Robert  */
10ea906c41SOllivier Robert 
11ea906c41SOllivier Robert /*
12ea906c41SOllivier Robert  *  Automated Options copyright 1992-2007 Bruce Korb
13ea906c41SOllivier Robert  *
14ea906c41SOllivier Robert  *  Automated Options is free software.
15ea906c41SOllivier Robert  *  You may redistribute it and/or modify it under the terms of the
16ea906c41SOllivier Robert  *  GNU General Public License, as published by the Free Software
17ea906c41SOllivier Robert  *  Foundation; either version 2, or (at your option) any later version.
18ea906c41SOllivier Robert  *
19ea906c41SOllivier Robert  *  Automated Options is distributed in the hope that it will be useful,
20ea906c41SOllivier Robert  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21ea906c41SOllivier Robert  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22ea906c41SOllivier Robert  *  GNU General Public License for more details.
23ea906c41SOllivier Robert  *
24ea906c41SOllivier Robert  *  You should have received a copy of the GNU General Public License
25ea906c41SOllivier Robert  *  along with Automated Options.  See the file "COPYING".  If not,
26ea906c41SOllivier Robert  *  write to:  The Free Software Foundation, Inc.,
27ea906c41SOllivier Robert  *             51 Franklin Street, Fifth Floor,
28ea906c41SOllivier Robert  *             Boston, MA  02110-1301, USA.
29ea906c41SOllivier Robert  *
30ea906c41SOllivier Robert  * As a special exception, Bruce Korb gives permission for additional
31ea906c41SOllivier Robert  * uses of the text contained in his release of AutoOpts.
32ea906c41SOllivier Robert  *
33ea906c41SOllivier Robert  * The exception is that, if you link the AutoOpts library with other
34ea906c41SOllivier Robert  * files to produce an executable, this does not by itself cause the
35ea906c41SOllivier Robert  * resulting executable to be covered by the GNU General Public License.
36ea906c41SOllivier Robert  * Your use of that executable is in no way restricted on account of
37ea906c41SOllivier Robert  * linking the AutoOpts library code into it.
38ea906c41SOllivier Robert  *
39ea906c41SOllivier Robert  * This exception does not however invalidate any other reasons why
40ea906c41SOllivier Robert  * the executable file might be covered by the GNU General Public License.
41ea906c41SOllivier Robert  *
42ea906c41SOllivier Robert  * This exception applies only to the code released by Bruce Korb under
43ea906c41SOllivier Robert  * the name AutoOpts.  If you copy code from other sources under the
44ea906c41SOllivier Robert  * General Public License into a copy of AutoOpts, as the General Public
45ea906c41SOllivier Robert  * License permits, the exception does not apply to the code that you add
46ea906c41SOllivier Robert  * in this way.  To avoid misleading anyone as to the status of such
47ea906c41SOllivier Robert  * modified files, you must delete this exception notice from them.
48ea906c41SOllivier Robert  *
49ea906c41SOllivier Robert  * If you write modifications of your own for AutoOpts, it is your choice
50ea906c41SOllivier Robert  * whether to permit this exception to apply to your modifications.
51ea906c41SOllivier Robert  * If you do not wish that, delete this exception notice.
52ea906c41SOllivier Robert  */
53ea906c41SOllivier Robert 
54ea906c41SOllivier Robert /*
55ea906c41SOllivier Robert  *  optionFixupSavedOpts  Really, it just wipes out option state for
56ea906c41SOllivier Robert  *  options that are troublesome to copy.  viz., stacked strings and
57ea906c41SOllivier Robert  *  hierarcicaly valued option args.  We do duplicate string args that
58ea906c41SOllivier Robert  *  have been marked as allocated though.
59ea906c41SOllivier Robert  */
60ea906c41SOllivier Robert static void
61ea906c41SOllivier Robert fixupSavedOptionArgs(tOptions* pOpts)
62ea906c41SOllivier Robert {
63ea906c41SOllivier Robert     tOptions* p   = pOpts->pSavedState;
64ea906c41SOllivier Robert     tOptDesc* pOD = pOpts->pOptDesc;
65ea906c41SOllivier Robert     int       ct  = pOpts->optCt;
66ea906c41SOllivier Robert 
67ea906c41SOllivier Robert     /*
68ea906c41SOllivier Robert      *  Make sure that allocated stuff is only referenced in the
69ea906c41SOllivier Robert      *  archived copy of the data.
70ea906c41SOllivier Robert      */
71ea906c41SOllivier Robert     for (; ct-- > 0; pOD++)  {
72ea906c41SOllivier Robert         switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
73ea906c41SOllivier Robert         case OPARG_TYPE_STRING:
74ea906c41SOllivier Robert             if (pOD->fOptState & OPTST_STACKED) {
75ea906c41SOllivier Robert                 tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
76ea906c41SOllivier Robert                 q->optCookie = NULL;
77ea906c41SOllivier Robert             }
78ea906c41SOllivier Robert             if (pOD->fOptState & OPTST_ALLOC_ARG) {
79ea906c41SOllivier Robert                 tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
80ea906c41SOllivier Robert                 AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg");
81ea906c41SOllivier Robert             }
82ea906c41SOllivier Robert             break;
83ea906c41SOllivier Robert 
84ea906c41SOllivier Robert         case OPARG_TYPE_HIERARCHY:
85ea906c41SOllivier Robert         {
86ea906c41SOllivier Robert             tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
87ea906c41SOllivier Robert             q->optCookie = NULL;
88ea906c41SOllivier Robert         }
89ea906c41SOllivier Robert         }
90ea906c41SOllivier Robert     }
91ea906c41SOllivier Robert }
92ea906c41SOllivier Robert 
93ea906c41SOllivier Robert /*=export_func optionSaveState
94ea906c41SOllivier Robert  *
95ea906c41SOllivier Robert  * what:  saves the option state to memory
96ea906c41SOllivier Robert  * arg:   tOptions*, pOpts, program options descriptor
97ea906c41SOllivier Robert  *
98ea906c41SOllivier Robert  * doc:
99ea906c41SOllivier Robert  *
100ea906c41SOllivier Robert  *  This routine will allocate enough memory to save the current option
101ea906c41SOllivier Robert  *  processing state.  If this routine has been called before, that memory
102ea906c41SOllivier Robert  *  will be reused.  You may only save one copy of the option state.  This
103ea906c41SOllivier Robert  *  routine may be called before optionProcess(3AO).  If you do call it
104ea906c41SOllivier Robert  *  before the first call to optionProcess, then you may also change the
105ea906c41SOllivier Robert  *  contents of argc/argv after you call optionRestore(3AO)
106ea906c41SOllivier Robert  *
107ea906c41SOllivier Robert  *  In fact, more strongly put: it is safest to only use this function
108ea906c41SOllivier Robert  *  before having processed any options.  In particular, the saving and
109ea906c41SOllivier Robert  *  restoring of stacked string arguments and hierarchical values is
110ea906c41SOllivier Robert  *  disabled.  The values are not saved.
111ea906c41SOllivier Robert  *
112ea906c41SOllivier Robert  * err:   If it fails to allocate the memory,
113ea906c41SOllivier Robert  *        it will print a message to stderr and exit.
114ea906c41SOllivier Robert  *        Otherwise, it will always succeed.
115ea906c41SOllivier Robert =*/
116ea906c41SOllivier Robert void
117ea906c41SOllivier Robert optionSaveState(tOptions* pOpts)
118ea906c41SOllivier Robert {
119ea906c41SOllivier Robert     tOptions* p = (tOptions*)pOpts->pSavedState;
120ea906c41SOllivier Robert 
121ea906c41SOllivier Robert     if (p == NULL) {
122ea906c41SOllivier Robert         size_t sz = sizeof( *pOpts ) + (pOpts->optCt * sizeof( tOptDesc ));
123ea906c41SOllivier Robert         p = AGALOC( sz, "saved option state" );
124ea906c41SOllivier Robert         if (p == NULL) {
125ea906c41SOllivier Robert             tCC* pzName = pOpts->pzProgName;
126ea906c41SOllivier Robert             if (pzName == NULL) {
127ea906c41SOllivier Robert                 pzName = pOpts->pzPROGNAME;
128ea906c41SOllivier Robert                 if (pzName == NULL)
129ea906c41SOllivier Robert                     pzName = zNil;
130ea906c41SOllivier Robert             }
131ea906c41SOllivier Robert             fprintf( stderr, zCantSave, pzName, sz );
132ea906c41SOllivier Robert             exit( EXIT_FAILURE );
133ea906c41SOllivier Robert         }
134ea906c41SOllivier Robert 
135ea906c41SOllivier Robert         pOpts->pSavedState = p;
136ea906c41SOllivier Robert     }
137ea906c41SOllivier Robert 
138ea906c41SOllivier Robert     memcpy( p, pOpts, sizeof( *p ));
139ea906c41SOllivier Robert     memcpy( p + 1, pOpts->pOptDesc, p->optCt * sizeof( tOptDesc ));
140ea906c41SOllivier Robert 
141ea906c41SOllivier Robert     fixupSavedOptionArgs(pOpts);
142ea906c41SOllivier Robert }
143ea906c41SOllivier Robert 
144ea906c41SOllivier Robert 
145ea906c41SOllivier Robert /*=export_func optionRestore
146ea906c41SOllivier Robert  *
147ea906c41SOllivier Robert  * what:  restore option state from memory copy
148ea906c41SOllivier Robert  * arg:   tOptions*, pOpts, program options descriptor
149ea906c41SOllivier Robert  *
150ea906c41SOllivier Robert  * doc:  Copy back the option state from saved memory.
151ea906c41SOllivier Robert  *       The allocated memory is left intact, so this routine can be
152ea906c41SOllivier Robert  *       called repeatedly without having to call optionSaveState again.
153ea906c41SOllivier Robert  *       If you are restoring a state that was saved before the first call
154ea906c41SOllivier Robert  *       to optionProcess(3AO), then you may change the contents of the
155ea906c41SOllivier Robert  *       argc/argv parameters to optionProcess.
156ea906c41SOllivier Robert  *
157ea906c41SOllivier Robert  * err:  If you have not called @code{optionSaveState} before, a diagnostic is
158ea906c41SOllivier Robert  *       printed to @code{stderr} and exit is called.
159ea906c41SOllivier Robert =*/
160ea906c41SOllivier Robert void
161ea906c41SOllivier Robert optionRestore( tOptions* pOpts )
162ea906c41SOllivier Robert {
163ea906c41SOllivier Robert     tOptions* p = (tOptions*)pOpts->pSavedState;
164ea906c41SOllivier Robert 
165ea906c41SOllivier Robert     if (p == NULL) {
166ea906c41SOllivier Robert         tCC* pzName = pOpts->pzProgName;
167ea906c41SOllivier Robert         if (pzName == NULL) {
168ea906c41SOllivier Robert             pzName = pOpts->pzPROGNAME;
169ea906c41SOllivier Robert             if (pzName == NULL)
170ea906c41SOllivier Robert                 pzName = zNil;
171ea906c41SOllivier Robert         }
172ea906c41SOllivier Robert         fprintf( stderr, zNoState, pzName );
173ea906c41SOllivier Robert         exit( EXIT_FAILURE );
174ea906c41SOllivier Robert     }
175ea906c41SOllivier Robert 
176ea906c41SOllivier Robert     pOpts->pSavedState = NULL;
177ea906c41SOllivier Robert     optionFree(pOpts);
178ea906c41SOllivier Robert 
179ea906c41SOllivier Robert     memcpy( pOpts, p, sizeof( *p ));
180ea906c41SOllivier Robert     memcpy( pOpts->pOptDesc, p+1, p->optCt * sizeof( tOptDesc ));
181ea906c41SOllivier Robert     pOpts->pSavedState = p;
182ea906c41SOllivier Robert 
183ea906c41SOllivier Robert     fixupSavedOptionArgs(pOpts);
184ea906c41SOllivier Robert }
185ea906c41SOllivier Robert 
186ea906c41SOllivier Robert /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
187ea906c41SOllivier Robert 
188ea906c41SOllivier Robert /*=export_func optionFree
189ea906c41SOllivier Robert  *
190ea906c41SOllivier Robert  * what:  free allocated option processing memory
191ea906c41SOllivier Robert  * arg:   tOptions*, pOpts, program options descriptor
192ea906c41SOllivier Robert  *
193ea906c41SOllivier Robert  * doc:   AutoOpts sometimes allocates memory and puts pointers to it in the
194ea906c41SOllivier Robert  *        option state structures.  This routine deallocates all such memory.
195ea906c41SOllivier Robert  *
196ea906c41SOllivier Robert  * err:   As long as memory has not been corrupted,
197ea906c41SOllivier Robert  *        this routine is always successful.
198ea906c41SOllivier Robert =*/
199ea906c41SOllivier Robert void
200ea906c41SOllivier Robert optionFree( tOptions* pOpts )
201ea906c41SOllivier Robert {
202ea906c41SOllivier Robert  free_saved_state:
203ea906c41SOllivier Robert     {
204ea906c41SOllivier Robert         tOptDesc* p = pOpts->pOptDesc;
205ea906c41SOllivier Robert         int ct = pOpts->optCt;
206ea906c41SOllivier Robert         do  {
207ea906c41SOllivier Robert             if (p->fOptState & OPTST_ALLOC_ARG) {
208ea906c41SOllivier Robert                 AGFREE(p->optArg.argString);
209ea906c41SOllivier Robert                 p->optArg.argString = NULL;
210ea906c41SOllivier Robert                 p->fOptState &= ~OPTST_ALLOC_ARG;
211ea906c41SOllivier Robert             }
212ea906c41SOllivier Robert 
213ea906c41SOllivier Robert             switch (OPTST_GET_ARGTYPE(p->fOptState)) {
214ea906c41SOllivier Robert             case OPARG_TYPE_STRING:
215ea906c41SOllivier Robert #ifdef WITH_LIBREGEX
216ea906c41SOllivier Robert                 if (  (p->fOptState & OPTST_STACKED)
217ea906c41SOllivier Robert                    && (p->optCookie != NULL)) {
218ea906c41SOllivier Robert                     p->optArg.argString = ".*";
219ea906c41SOllivier Robert                     optionUnstackArg(pOpts, p);
220ea906c41SOllivier Robert                 }
221ea906c41SOllivier Robert #else
222ea906c41SOllivier Robert                 /* leak memory */;
223ea906c41SOllivier Robert #endif
224ea906c41SOllivier Robert                 break;
225ea906c41SOllivier Robert 
226ea906c41SOllivier Robert             case OPARG_TYPE_HIERARCHY:
227ea906c41SOllivier Robert                 if (p->optCookie != NULL)
228ea906c41SOllivier Robert                     unloadNestedArglist(p->optCookie);
229ea906c41SOllivier Robert                 break;
230ea906c41SOllivier Robert             }
231ea906c41SOllivier Robert 
232ea906c41SOllivier Robert             p->optCookie = NULL;
233ea906c41SOllivier Robert         } while (p++, --ct > 0);
234ea906c41SOllivier Robert     }
235ea906c41SOllivier Robert     if (pOpts->pSavedState != NULL) {
236ea906c41SOllivier Robert         tOptions * p = (tOptions*)pOpts->pSavedState;
237ea906c41SOllivier Robert         memcpy( pOpts, p, sizeof( *p ));
238ea906c41SOllivier Robert         memcpy( pOpts->pOptDesc, p+1, p->optCt * sizeof( tOptDesc ));
239ea906c41SOllivier Robert         AGFREE( pOpts->pSavedState );
240ea906c41SOllivier Robert         pOpts->pSavedState = NULL;
241ea906c41SOllivier Robert         goto free_saved_state;
242ea906c41SOllivier Robert     }
243ea906c41SOllivier Robert }
244ea906c41SOllivier Robert /*
245ea906c41SOllivier Robert  * Local Variables:
246ea906c41SOllivier Robert  * mode: C
247ea906c41SOllivier Robert  * c-file-style: "stroustrup"
248ea906c41SOllivier Robert  * indent-tabs-mode: nil
249ea906c41SOllivier Robert  * End:
250ea906c41SOllivier Robert  * end of autoopts/restore.c */
251