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