xref: /freebsd/contrib/ntp/sntp/libopts/restore.c (revision a466cc55)
1ea906c41SOllivier Robert 
2ea906c41SOllivier Robert /*
32b15cb3dSCy Schubert  * \file restore.c
4ea906c41SOllivier Robert  *
5ea906c41SOllivier Robert  *  This module's routines will save the current option state to memory
6ea906c41SOllivier Robert  *  and restore it.  If saved prior to the initial optionProcess call,
7ea906c41SOllivier Robert  *  then the initial state will be restored.
82b15cb3dSCy Schubert  *
92b15cb3dSCy Schubert  * @addtogroup autoopts
102b15cb3dSCy Schubert  * @{
11ea906c41SOllivier Robert  */
12ea906c41SOllivier Robert /*
132b15cb3dSCy Schubert  *  This file is part of AutoOpts, a companion to AutoGen.
142b15cb3dSCy Schubert  *  AutoOpts is free software.
15*a466cc55SCy Schubert  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
16ea906c41SOllivier Robert  *
172b15cb3dSCy Schubert  *  AutoOpts is available under any one of two licenses.  The license
182b15cb3dSCy Schubert  *  in use must be one of these two and the choice is under the control
192b15cb3dSCy Schubert  *  of the user of the license.
20ea906c41SOllivier Robert  *
212b15cb3dSCy Schubert  *   The GNU Lesser General Public License, version 3 or later
222b15cb3dSCy Schubert  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
23ea906c41SOllivier Robert  *
242b15cb3dSCy Schubert  *   The Modified Berkeley Software Distribution License
252b15cb3dSCy Schubert  *      See the file "COPYING.mbsd"
26ea906c41SOllivier Robert  *
272b15cb3dSCy Schubert  *  These files have the following sha256 sums:
28ea906c41SOllivier Robert  *
292b15cb3dSCy Schubert  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
302b15cb3dSCy Schubert  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
312b15cb3dSCy Schubert  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
32ea906c41SOllivier Robert  */
33ea906c41SOllivier Robert 
34ea906c41SOllivier Robert /*
35ea906c41SOllivier Robert  *  optionFixupSavedOpts  Really, it just wipes out option state for
36ea906c41SOllivier Robert  *  options that are troublesome to copy.  viz., stacked strings and
37ea906c41SOllivier Robert  *  hierarcicaly valued option args.  We do duplicate string args that
38ea906c41SOllivier Robert  *  have been marked as allocated though.
39ea906c41SOllivier Robert  */
40ea906c41SOllivier Robert static void
fixupSavedOptionArgs(tOptions * pOpts)41ea906c41SOllivier Robert fixupSavedOptionArgs(tOptions * pOpts)
42ea906c41SOllivier Robert {
43ea906c41SOllivier Robert     tOptions * p   = pOpts->pSavedState;
44ea906c41SOllivier Robert     tOptDesc * pOD = pOpts->pOptDesc;
45ea906c41SOllivier Robert     int        ct  = pOpts->optCt;
46ea906c41SOllivier Robert 
47ea906c41SOllivier Robert     /*
48ea906c41SOllivier Robert      *  Make sure that allocated stuff is only referenced in the
49ea906c41SOllivier Robert      *  archived copy of the data.
50ea906c41SOllivier Robert      */
51ea906c41SOllivier Robert     for (; ct-- > 0; pOD++)  {
52ea906c41SOllivier Robert         switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
53ea906c41SOllivier Robert         case OPARG_TYPE_STRING:
54ea906c41SOllivier Robert             if (pOD->fOptState & OPTST_STACKED) {
55ea906c41SOllivier Robert                 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc);
56ea906c41SOllivier Robert                 q->optCookie = NULL;
57ea906c41SOllivier Robert             }
58ea906c41SOllivier Robert             if (pOD->fOptState & OPTST_ALLOC_ARG) {
59ea906c41SOllivier Robert                 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc);
60ea906c41SOllivier Robert                 AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg");
61ea906c41SOllivier Robert             }
62ea906c41SOllivier Robert             break;
63ea906c41SOllivier Robert 
64ea906c41SOllivier Robert         case OPARG_TYPE_HIERARCHY:
65ea906c41SOllivier Robert         {
66ea906c41SOllivier Robert             tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc);
67ea906c41SOllivier Robert             q->optCookie = NULL;
68ea906c41SOllivier Robert         }
69ea906c41SOllivier Robert         }
70ea906c41SOllivier Robert     }
71ea906c41SOllivier Robert }
72ea906c41SOllivier Robert 
73ea906c41SOllivier Robert /*=export_func optionSaveState
74ea906c41SOllivier Robert  *
75ea906c41SOllivier Robert  * what:  saves the option state to memory
76ea906c41SOllivier Robert  * arg:   tOptions *, pOpts, program options descriptor
77ea906c41SOllivier Robert  *
78ea906c41SOllivier Robert  * doc:
79ea906c41SOllivier Robert  *
80ea906c41SOllivier Robert  *  This routine will allocate enough memory to save the current option
81ea906c41SOllivier Robert  *  processing state.  If this routine has been called before, that memory
82ea906c41SOllivier Robert  *  will be reused.  You may only save one copy of the option state.  This
83ea906c41SOllivier Robert  *  routine may be called before optionProcess(3AO).  If you do call it
84ea906c41SOllivier Robert  *  before the first call to optionProcess, then you may also change the
85ea906c41SOllivier Robert  *  contents of argc/argv after you call optionRestore(3AO)
86ea906c41SOllivier Robert  *
87ea906c41SOllivier Robert  *  In fact, more strongly put: it is safest to only use this function
88ea906c41SOllivier Robert  *  before having processed any options.  In particular, the saving and
89ea906c41SOllivier Robert  *  restoring of stacked string arguments and hierarchical values is
90ea906c41SOllivier Robert  *  disabled.  The values are not saved.
91ea906c41SOllivier Robert  *
92ea906c41SOllivier Robert  * err:   If it fails to allocate the memory,
93ea906c41SOllivier Robert  *        it will print a message to stderr and exit.
94ea906c41SOllivier Robert  *        Otherwise, it will always succeed.
95ea906c41SOllivier Robert =*/
96ea906c41SOllivier Robert void
optionSaveState(tOptions * pOpts)97ea906c41SOllivier Robert optionSaveState(tOptions * pOpts)
98ea906c41SOllivier Robert {
99ea906c41SOllivier Robert     tOptions * p = (tOptions *)pOpts->pSavedState;
100ea906c41SOllivier Robert 
101ea906c41SOllivier Robert     if (p == NULL) {
1022b15cb3dSCy Schubert         size_t sz = sizeof(*pOpts)
1032b15cb3dSCy Schubert             + ((size_t)pOpts->optCt * sizeof(tOptDesc));
104ea906c41SOllivier Robert         p = AGALOC(sz, "saved option state");
105ea906c41SOllivier Robert 
106ea906c41SOllivier Robert         pOpts->pSavedState = p;
107ea906c41SOllivier Robert     }
108ea906c41SOllivier Robert 
109ea906c41SOllivier Robert     memcpy(p, pOpts, sizeof(*p));
1102b15cb3dSCy Schubert     memcpy(p + 1, pOpts->pOptDesc, (size_t)p->optCt * sizeof(tOptDesc));
111ea906c41SOllivier Robert 
112ea906c41SOllivier Robert     fixupSavedOptionArgs(pOpts);
113ea906c41SOllivier Robert }
114ea906c41SOllivier Robert 
115ea906c41SOllivier Robert 
116ea906c41SOllivier Robert /*=export_func optionRestore
117ea906c41SOllivier Robert  *
118ea906c41SOllivier Robert  * what:  restore option state from memory copy
119ea906c41SOllivier Robert  * arg:   tOptions *, pOpts, program options descriptor
120ea906c41SOllivier Robert  *
121ea906c41SOllivier Robert  * doc:  Copy back the option state from saved memory.
122ea906c41SOllivier Robert  *       The allocated memory is left intact, so this routine can be
123ea906c41SOllivier Robert  *       called repeatedly without having to call optionSaveState again.
124ea906c41SOllivier Robert  *       If you are restoring a state that was saved before the first call
125ea906c41SOllivier Robert  *       to optionProcess(3AO), then you may change the contents of the
126ea906c41SOllivier Robert  *       argc/argv parameters to optionProcess.
127ea906c41SOllivier Robert  *
128ea906c41SOllivier Robert  * err:  If you have not called @code{optionSaveState} before, a diagnostic is
129ea906c41SOllivier Robert  *       printed to @code{stderr} and exit is called.
130ea906c41SOllivier Robert =*/
131ea906c41SOllivier Robert void
optionRestore(tOptions * pOpts)132ea906c41SOllivier Robert optionRestore(tOptions * pOpts)
133ea906c41SOllivier Robert {
134ea906c41SOllivier Robert     tOptions * p = (tOptions *)pOpts->pSavedState;
135ea906c41SOllivier Robert 
136ea906c41SOllivier Robert     if (p == NULL) {
1372b15cb3dSCy Schubert         char const * pzName = pOpts->pzProgName;
138ea906c41SOllivier Robert         if (pzName == NULL) {
139ea906c41SOllivier Robert             pzName = pOpts->pzPROGNAME;
140ea906c41SOllivier Robert             if (pzName == NULL)
141ea906c41SOllivier Robert                 pzName = zNil;
142ea906c41SOllivier Robert         }
143ea906c41SOllivier Robert         fprintf(stderr, zNoState, pzName);
1442b15cb3dSCy Schubert         option_exits(EXIT_FAILURE);
145ea906c41SOllivier Robert     }
146ea906c41SOllivier Robert 
147ea906c41SOllivier Robert     pOpts->pSavedState = NULL;
148ea906c41SOllivier Robert     optionFree(pOpts);
149ea906c41SOllivier Robert 
150ea906c41SOllivier Robert     memcpy(pOpts, p, sizeof(*p));
1512b15cb3dSCy Schubert     memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc));
152ea906c41SOllivier Robert     pOpts->pSavedState = p;
153ea906c41SOllivier Robert 
154ea906c41SOllivier Robert     fixupSavedOptionArgs(pOpts);
155ea906c41SOllivier Robert }
156ea906c41SOllivier Robert 
157ea906c41SOllivier Robert /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
158ea906c41SOllivier Robert 
159ea906c41SOllivier Robert /*=export_func optionFree
160ea906c41SOllivier Robert  *
161ea906c41SOllivier Robert  * what:  free allocated option processing memory
162ea906c41SOllivier Robert  * arg:   tOptions *, pOpts, program options descriptor
163ea906c41SOllivier Robert  *
164ea906c41SOllivier Robert  * doc:   AutoOpts sometimes allocates memory and puts pointers to it in the
165ea906c41SOllivier Robert  *        option state structures.  This routine deallocates all such memory.
166ea906c41SOllivier Robert  *
167ea906c41SOllivier Robert  * err:   As long as memory has not been corrupted,
168ea906c41SOllivier Robert  *        this routine is always successful.
169ea906c41SOllivier Robert =*/
170ea906c41SOllivier Robert void
optionFree(tOptions * pOpts)171ea906c41SOllivier Robert optionFree(tOptions * pOpts)
172ea906c41SOllivier Robert {
173ea906c41SOllivier Robert  free_saved_state:
174ea906c41SOllivier Robert     {
175ea906c41SOllivier Robert         tOptDesc * p = pOpts->pOptDesc;
176ea906c41SOllivier Robert         int ct = pOpts->optCt;
177ea906c41SOllivier Robert         do  {
178ea906c41SOllivier Robert             if (p->fOptState & OPTST_ALLOC_ARG) {
179ea906c41SOllivier Robert                 AGFREE(p->optArg.argString);
180ea906c41SOllivier Robert                 p->optArg.argString = NULL;
181ea906c41SOllivier Robert                 p->fOptState &= ~OPTST_ALLOC_ARG;
182ea906c41SOllivier Robert             }
183ea906c41SOllivier Robert 
184ea906c41SOllivier Robert             switch (OPTST_GET_ARGTYPE(p->fOptState)) {
185ea906c41SOllivier Robert             case OPARG_TYPE_STRING:
186ea906c41SOllivier Robert #ifdef WITH_LIBREGEX
187ea906c41SOllivier Robert                 if (  (p->fOptState & OPTST_STACKED)
188ea906c41SOllivier Robert                    && (p->optCookie != NULL)) {
189ea906c41SOllivier Robert                     p->optArg.argString = ".*";
190ea906c41SOllivier Robert                     optionUnstackArg(pOpts, p);
191ea906c41SOllivier Robert                 }
192ea906c41SOllivier Robert #else
193ea906c41SOllivier Robert                 /* leak memory */;
194ea906c41SOllivier Robert #endif
195ea906c41SOllivier Robert                 break;
196ea906c41SOllivier Robert 
197ea906c41SOllivier Robert             case OPARG_TYPE_HIERARCHY:
198ea906c41SOllivier Robert                 if (p->optCookie != NULL)
1992b15cb3dSCy Schubert                     unload_arg_list(p->optCookie);
200ea906c41SOllivier Robert                 break;
201ea906c41SOllivier Robert             }
202ea906c41SOllivier Robert 
203ea906c41SOllivier Robert             p->optCookie = NULL;
204ea906c41SOllivier Robert         } while (p++, --ct > 0);
205ea906c41SOllivier Robert     }
206ea906c41SOllivier Robert     if (pOpts->pSavedState != NULL) {
207ea906c41SOllivier Robert         tOptions * p = (tOptions *)pOpts->pSavedState;
208ea906c41SOllivier Robert         memcpy(pOpts, p, sizeof(*p));
2092b15cb3dSCy Schubert         memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc));
210ea906c41SOllivier Robert         AGFREE(pOpts->pSavedState);
211ea906c41SOllivier Robert         pOpts->pSavedState = NULL;
212ea906c41SOllivier Robert         goto free_saved_state;
213ea906c41SOllivier Robert     }
214ea906c41SOllivier Robert }
2152b15cb3dSCy Schubert 
2162b15cb3dSCy Schubert /** @}
2172b15cb3dSCy Schubert  *
218ea906c41SOllivier Robert  * Local Variables:
219ea906c41SOllivier Robert  * mode: C
220ea906c41SOllivier Robert  * c-file-style: "stroustrup"
221ea906c41SOllivier Robert  * indent-tabs-mode: nil
222ea906c41SOllivier Robert  * End:
223ea906c41SOllivier Robert  * end of autoopts/restore.c */
224