Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /branches/vis12/src/lib/common/input.c
ViewVC logotype

Annotation of /branches/vis12/src/lib/common/input.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3291 - (view) (download) (as text)

1 : jhr 1232 /*! \file input.c
2 :     *
3 : jhr 1301 * \author John Reppy, Gordon Kindlmann
4 : jhr 1232 */
5 :    
6 :     /*
7 : jhr 3291 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
8 :     *
9 :     * COPYRIGHT (c) 2015 The University of Chicago
10 : jhr 1232 * All rights reserved.
11 :     */
12 :     #include "Diderot/diderot.h"
13 :     #include <teem/hest.h>
14 :    
15 : jhr 1301 //! Option type tags
16 :     typedef enum {
17 : jhr 3254 optTypeUnknown, // 0
18 :     optTypeFlag, // 1
19 :     optTypeBool, // 2
20 :     optTypeInt, // 3
21 :     optTypeUInt, // 4
22 :     optTypeReal, // 5
23 :     optTypeReal2, // 6
24 :     optTypeReal3, // 7
25 :     optTypeReal4, // 8
26 :     optTypeString // 9
27 : jhr 1301 } opt_type_t;
28 :    
29 :     /*! The struct containing the definition of *one* option, and storage
30 :     * for its value once parsed
31 :     */
32 :     typedef struct {
33 :     char *name; //!< option name
34 :     char *desc; //!< option description (a phrase or sentence)
35 :     opt_type_t ty; //!< option type
36 :     union { //! storage that is passed into hest
37 :     int b; //!< storage for boolean-valued options
38 :     double r[4]; //!< storage for real-valued options
39 :     int64_t i[4]; //!< storage for integer-valued options
40 : jhr 3254 uint64_t u[1]; //!< storage for unsigned integer-valued options
41 : jhr 1301 char *s; //!< storage for string-valued options
42 :     } hval;
43 :     void *valp; //!< pointer to Diderot global variable being set
44 :     } opt_def_t;
45 :    
46 : jhr 1671 /*! container for *all* options, the machinery for parsing them,
47 : jhr 1301 * and means of managing their allocation. There is an opaque typedef
48 :     * around this in src/include/Diderot/options.h.
49 :     *
50 :     * The "airArray *mop" is the primary means of managing the things that
51 :     * are dynamically allocated; anything that is allocated is registered
52 :     * in the mop so that it can be freed from a single place later (look
53 :     * for calls to airMopAdd)
54 :     *
55 :     * Note that "odef" is a dynamically re-allocated array (managed by
56 :     * "odefArr"), and it is an array of opt_def_t pointers, and not an
57 :     * array of opt_def_t's, which is necessary: the values that hest sets
58 :     * are set via a pointer, and those values are stored in the opt_def_t,
59 :     * so the memory location of the opt_def_t cannot change, so these are
60 :     * allocated individually once. If odef was an array of opt_def_t's,
61 :     * then the location of the individual op_def_t would change if odef
62 :     * was reallocated for a different length.
63 :     */
64 :     struct Diderot_struct_options {
65 : jhr 1671 char *progInfo; //!< documentation string for describing whole
66 :     //! program, intended to be one or more sentences
67 : jhr 1301 hestOpt *hopt; //!< dynamically managed hest options
68 :     hestParm *hparm; //!< hest parameters
69 :     opt_def_t **odef; //!< dynamically reallocated via odefArr
70 :     unsigned int odefNum; //!< length of meaningful values in odef[]
71 :     airArray *odefArr; //!< manages odef and odefNum;
72 :     airArray *mop; //!< manages hopt, hparm, and odefArr
73 :     };
74 :    
75 :     static void *OptDefNew ()
76 : jhr 1232 {
77 : jhr 1301 opt_def_t *odef = AIR_CALLOC(1, opt_def_t);
78 :     odef->name = odef->desc = 0;
79 :     odef->ty = optTypeUnknown;
80 :     odef->valp = 0;
81 :     return odef;
82 : jhr 1232 }
83 :    
84 : jhr 1301 /*! free an opt_def_t. This doesn't need to be called directly; it will
85 : jhr 1671 * be used by the airArray to manage "odef" and what it points to.
86 : jhr 1301 */
87 :     static void *optDefNix (void *_odef)
88 : jhr 1232 {
89 : jhr 1301 opt_def_t *odef = (opt_def_t *)_odef;
90 :     airFree(odef->name);
91 :     airFree(odef->desc);
92 :     if (optTypeString == odef->ty) {
93 :     airFree(odef->hval.s);
94 :     }
95 :     airFree(odef);
96 :     return 0;
97 :     }
98 : jhr 1232
99 : jhr 1671 /*! create the container for all option information and register standard
100 :     * command-line options.
101 : jhr 1301 */
102 :     Diderot_Options_t *Diderot_OptNew ()
103 :     {
104 :     static const char *me = "Diderot_Options_New";
105 : jhr 1671 Diderot_Options_t *opts = AIR_CALLOC(1, Diderot_Options_t);
106 :     if (opts == 0) {
107 : jhr 1301 fprintf(stderr, "%s: unable to allocate output\n", me);
108 :     exit(1);
109 :     }
110 : jhr 1671 opts->progInfo = 0;
111 :     opts->mop = airMopNew();
112 :     opts->hopt = 0;
113 :     opts->hparm = hestParmNew();
114 :     opts->hparm->noArgsIsNoProblem = AIR_TRUE;
115 :     airMopAdd (opts->mop, opts->hparm, (airMopper)hestParmFree, airMopAlways);
116 :     opts->odef = 0;
117 :     opts->odefNum = 0;
118 : jhr 1301 /*
119 :     ** the airArray odefArr manages the allocation of odef, and as a
120 :     ** convenience also sets odefNum to the number of values reliably
121 :     ** set in odef
122 :     */
123 : jhr 1671 opts->odefArr = airArrayNew (
124 :     (void**)(&opts->odef),
125 :     &opts->odefNum,
126 :     sizeof(opt_def_t *),
127 : jhr 1301 8 /* allocation increment */);
128 : jhr 1232
129 : jhr 1671 if (opts->odefArr == 0) {
130 : jhr 1301 fprintf(stderr, "%s: unable to allocate option array\n", me);
131 :     exit(1);
132 : jhr 1232 }
133 : jhr 1301 /*
134 :     ** the airArray will set odef[I] = OptDefNew for newly allocated
135 :     ** elements I of odef, and will call optDefNix(odef[I]) for
136 :     ** elements of odef that are about to be freed
137 :     */
138 : jhr 1671 airArrayPointerCB (opts->odefArr, OptDefNew, optDefNix);
139 :     airMopAdd (opts->mop, opts->odefArr, (airMopper)airArrayNuke, airMopAlways);
140 :    
141 :     return opts;
142 : jhr 1301 }
143 : jhr 1232
144 : jhr 1301 /*! free everything associated with a Diderot_Options_t
145 :     */
146 :     void Diderot_OptFree (Diderot_Options_t *dopts)
147 :     {
148 :     if (dopts != 0) {
149 :     airFree(dopts->progInfo);
150 :     /* frees everything connected to the mop, and the mop itself */
151 :     airMopOkay(dopts->mop);
152 :     free(dopts);
153 :     }
154 :     return;
155 : jhr 1232 }
156 :    
157 : jhr 1301 /*! sets the one piece of information in the Diderot_Options_t
158 :     * which is not really for the options; "progInfo" is to describe the
159 :     * whole program.
160 :     */
161 :     void Diderot_OptProgramInfoSet (
162 :     Diderot_Options_t *dopts,
163 :     const char *progInfo)
164 : jhr 1232 {
165 : jhr 1301 static const char *me = "Diderot_OptProgramInfoSet";
166 : jhr 1232
167 : jhr 1301 if (progInfo) {
168 :     if (!( dopts->progInfo = airStrdup(progInfo) )) {
169 :     fprintf(stderr, "%s: unable to copy program info", me);
170 :     exit(1);
171 :     }
172 :     }
173 :     }
174 : jhr 1232
175 : jhr 1301 /*! main function for adding options to a Diderot_Options_t.
176 :     */
177 :     static opt_def_t *OptAdd (
178 :     Diderot_Options_t *dopts,
179 :     const char *name,
180 :     const char *desc,
181 :     void *valp,
182 :     opt_type_t ty)
183 :     {
184 :     static const char *me = "OptAdd";
185 :     unsigned int nidx;
186 :    
187 :     if ((name == 0) || (desc == 0)) {
188 :     fprintf(stderr, "%s: need both name (%p) and desc (%p) non-NULL\n",
189 :     me, (void *)name, (void *)desc);
190 :     exit(1);
191 : jhr 1232 }
192 : jhr 1301 /* calling airArrayLenIncr may trigger re-allocation of odef;
193 :     * nidx is the index of the newly reserved element, odef[nidx]
194 :     */
195 :     nidx = airArrayLenIncr(dopts->odefArr, 1);
196 :     if (dopts->odef == 0) {
197 :     fprintf(stderr, "%s: unable to reallocate option array\n", me);
198 :     exit(1);
199 :     }
200 :     /* code here uses "odf" to copy one value of odef[] */
201 :     opt_def_t *odf = dopts->odef[nidx];
202 :     odf->name = airStrdup(name);
203 :     odf->desc = airStrdup(desc);
204 :     if ((odf->name == 0) || (odf->desc == 0)) {
205 :     fprintf(stderr, "%s: unable to allocate strings (%p, %p)\n",
206 :     me, (void *)odf->name,(void *) odf->desc);
207 :     exit(1);
208 :     }
209 :     odf->valp = valp;
210 :     odf->ty = ty;
211 :    
212 :     return odf;
213 :     }
214 : jhr 1232
215 : jhr 1301 void Diderot_OptAddFlag (
216 :     Diderot_Options_t *dopts,
217 :     const char *name, const char *desc,
218 :     bool *flg)
219 :     {
220 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)flg, optTypeFlag);
221 :     hestOptAdd (
222 :     &dopts->hopt, name, NULL, airTypeInt, 0, 0, &odf->hval.b,
223 :     NULL, desc);
224 : jhr 1232 }
225 :    
226 : jhr 1301 /*! \brief add a boolean-valued option to the list of options.
227 :     * \param dopts the list of options
228 :     * \param name the name of the option
229 :     * \param desc a short description string
230 :     * \param v a pointer to the location where the value gets stored
231 :     * \param hasDflt true if there is an initial value
232 :     */
233 :     void Diderot_OptAddBool (
234 :     Diderot_Options_t *dopts,
235 :     const char *name, const char *desc,
236 :     bool *v, bool hasDflt)
237 : jhr 1232 {
238 : jhr 1301 opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeBool);
239 :     hestOptAdd (
240 :     &dopts->hopt, name, "bool", airTypeBool, 1, 1, &odf->hval.b,
241 :     hasDflt ? (*v ? "true" : "false") : NULL, desc);
242 :     }
243 : jhr 1232
244 : jhr 1301 /*
245 :     ** On the use of AIR_STRLEN_HUGE below: default values for
246 :     ** command-line options are communicated to hest by a *string*, but
247 :     ** the actual default value comes to us in Diderot global. So these
248 :     ** functions have to convert the value from the Diderot variable into
249 :     ** a string.
250 :     **
251 :     ** The problem is that we don't know how long string will have to be,
252 :     ** and there are few good functions for dealing with this. snprintf
253 :     ** is good for making sure you don't over-write a buffer of fixed
254 :     ** size, but you still have to allocate the buffer. asprintf allocates
255 :     ** as needed, but GLK didn't want to assume it was available (perhaps
256 :     ** this should be revisited)
257 :     **
258 :     ** So instead, we just use a huge buffer, and assume that it will be
259 :     ** more than big enough. Feel free to fix this.
260 :     */
261 : jhr 1232
262 : jhr 1301 /*! \brief add an integer option to the list of options.
263 :     * \param dopts the list of options
264 :     * \param name the name of the option
265 :     * \param desc a short description string
266 :     * \param v a pointer to the location where the value gets stored
267 :     * \param hasDflt true if there is an initial value
268 :     */
269 :     void Diderot_OptAddInt (
270 :     Diderot_Options_t *dopts,
271 :     const char *name, const char *desc, Diderot_int_t *v, bool hasDflt)
272 :     {
273 :     char buf[AIR_STRLEN_HUGE] = "";
274 :     if (hasDflt) {
275 : jhr 1671 snprintf(buf, sizeof(buf), "%ld", (long)*v);
276 : jhr 1232 }
277 : jhr 1301 opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeInt);
278 :     hestOptAdd (
279 :     &dopts->hopt, name, "int", airTypeLongInt, 1, 1, odf->hval.i,
280 :     hasDflt ? buf : NULL, desc);
281 :     }
282 : jhr 1232
283 : jhr 1831 /*! \brief add an unsigned integer option to the list of options.
284 :     * \param dopts the list of options
285 :     * \param name the name of the option
286 :     * \param desc a short description string
287 :     * \param v a pointer to the location where the value gets stored
288 :     * \param hasDflt true if there is an initial value
289 :     */
290 :     void Diderot_OptAddUInt (
291 :     Diderot_Options_t *dopts,
292 :     const char *name, const char *desc, Diderot_uint_t *v, bool hasDflt)
293 :     {
294 :     char buf[AIR_STRLEN_HUGE] = "";
295 :     if (hasDflt) {
296 :     snprintf(buf, sizeof(buf), "%ld", (unsigned long)*v);
297 :     }
298 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeUInt);
299 :     hestOptAdd (
300 :     &dopts->hopt, name, "int", airTypeULongInt, 1, 1, odf->hval.u,
301 :     hasDflt ? buf : NULL, desc);
302 :     }
303 :    
304 : jhr 1301 /*! \brief add a real-valued option to the list of options.
305 :     * \param dopts the list of options
306 :     * \param name the name of the option
307 :     * \param desc a short description string
308 :     * \param v a pointer to the location where the value gets stored
309 :     * \param hasDflt true if there is an initial value
310 :     */
311 :     void Diderot_OptAddReal (
312 :     Diderot_Options_t *dopts,
313 :     const char *name, const char *desc, Diderot_real_t *v, bool hasDflt)
314 :     {
315 :     char buf[AIR_STRLEN_HUGE] = "";
316 :     if (hasDflt) {
317 : jhr 1671 snprintf(buf, sizeof(buf), "%lf", (double)*v);
318 : jhr 1301 }
319 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeReal);
320 :     hestOptAdd (
321 :     &dopts->hopt, name, "val", airTypeDouble, 1, 1, odf->hval.r,
322 :     hasDflt ? buf : NULL, desc);
323 : jhr 1232 }
324 : jhr 1301
325 :     /*! \brief add a 2-element vector option to the list of options.
326 :     * \param dopts the list of options
327 :     * \param name the name of the option
328 :     * \param desc a short description string
329 :     * \param v a pointer to the location where the value gets stored
330 :     * \param hasDflt true if there is an initial value
331 :     */
332 :     void Diderot_OptAddReal2 (
333 :     Diderot_Options_t *dopts,
334 : jhr 2118 const char *name, const char *desc, Diderot_real_t v[2], bool hasDflt)
335 : jhr 1301 {
336 :     char buf[AIR_STRLEN_HUGE] = "";
337 :    
338 :     if (hasDflt) {
339 : jhr 2118 snprintf(buf, sizeof(buf), "%lf %lf", (double)(v[0]), (double)(v[1]));
340 : jhr 1301 }
341 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeReal2);
342 :     hestOptAdd (
343 :     &dopts->hopt, name, "x y", airTypeDouble, 2, 2, odf->hval.r,
344 :     hasDflt ? buf : NULL, desc);
345 :     }
346 :    
347 :     /*! \brief add a 3-element vector option to the list of options.
348 :     * \param dopts the list of options
349 :     * \param name the name of the option
350 :     * \param desc a short description string
351 :     * \param v a pointer to the location where the value gets stored
352 :     * \param hasDflt true if there is an initial value
353 :     */
354 :     void Diderot_OptAddReal3 (
355 :     Diderot_Options_t *dopts,
356 : jhr 2118 const char *name, const char *desc, Diderot_real_t v[3], bool hasDflt)
357 : jhr 1301 {
358 :     char buf[AIR_STRLEN_HUGE] = "";
359 :    
360 :     if (hasDflt) {
361 : jhr 1671 snprintf(buf, sizeof(buf), "%lf %lf %lf",
362 : jhr 2118 (double)(v[0]), (double)(v[1]), (double)(v[2]));
363 : jhr 1301 }
364 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeReal3);
365 :     hestOptAdd (
366 :     &dopts->hopt, name, "x y z", airTypeDouble, 3, 3, odf->hval.r,
367 :     hasDflt ? buf : NULL, desc);
368 :     }
369 :    
370 :     /*! \brief add a 4-element vector option to the list of options.
371 :     * \param dopts the list of options
372 :     * \param name the name of the option
373 :     * \param desc a short description string
374 :     * \param v a pointer to the location where the value gets stored
375 :     * \param hasDflt true if there is an initial value
376 :     */
377 :     void Diderot_OptAddReal4 (
378 :     Diderot_Options_t *dopts,
379 :     const char *name, const char *desc,
380 : jhr 2118 Diderot_real_t v[4], bool hasDflt)
381 : jhr 1301 {
382 :     char buf[AIR_STRLEN_HUGE] = "";
383 :    
384 :     if (hasDflt) {
385 : jhr 1671 snprintf(buf, sizeof(buf), "%lf %lf %lf %lf",
386 : jhr 2118 (double)(v[0]), (double)(v[1]),
387 :     (double)(v[2]), (double)(v[3]));
388 : jhr 1301 }
389 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeReal4);
390 :     hestOptAdd (
391 :     &dopts->hopt, name, "x y z w", airTypeDouble, 4, 4, odf->hval.r,
392 :     hasDflt ? buf : NULL, desc);
393 :     }
394 :    
395 :     /*! \brief add a string-vauled option to the list of options.
396 :     * \param dopts the list of options
397 :     * \param name the name of the option
398 :     * \param desc a short description string
399 :     * \param v a pointer to the location where the value gets stored
400 :     * \param hasDflt true if there is an initial value
401 :     */
402 :     void Diderot_OptAddString (
403 :     Diderot_Options_t *dopts,
404 :     const char *name, const char *desc,
405 :     char **v, bool hasDflt)
406 :     {
407 :     opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeString);
408 :     hestOptAdd (
409 :     &dopts->hopt, name, "str", airTypeString, 1, 1, &odf->hval.s,
410 :     hasDflt ? *v : NULL, desc);
411 :     }
412 :    
413 :     /*! given argc/argv, learn values for all options and set them
414 :     */
415 :     void Diderot_OptProcess (Diderot_Options_t *dopts, int argc, const char **argv)
416 :     {
417 :     static const char *me = "Diderot_ProcessOptions";
418 :    
419 :     hestParseOrDie (
420 :     dopts->hopt, argc-1, argv+1, dopts->hparm, argv[0],
421 :     dopts->progInfo ? dopts->progInfo : "(no program info set)",
422 :     AIR_TRUE, AIR_TRUE, AIR_TRUE);
423 :     airMopAdd(dopts->mop, dopts->hopt, (airMopper)hestOptFree, airMopAlways);
424 :     airMopAdd(dopts->mop, dopts->hopt, (airMopper)hestParseFree, airMopAlways);
425 :    
426 :     // convert values learned by hest to their Diderot representations
427 :     for (int i = 0; i < dopts->odefNum; i++) {
428 :     opt_def_t *odf = dopts->odef[i];
429 :     switch (odf->ty) {
430 :     case optTypeFlag:
431 :     case optTypeBool:
432 :     *(bool*)(odf->valp) = odf->hval.b ? true : false;
433 :     break;
434 :     case optTypeInt:
435 :     *(Diderot_int_t *)(odf->valp) = (Diderot_int_t)(odf->hval.i[0]);
436 :     break;
437 : jhr 1831 case optTypeUInt:
438 :     *(Diderot_uint_t *)(odf->valp) = (Diderot_uint_t)(odf->hval.u[0]);
439 :     break;
440 : jhr 1301 case optTypeReal:
441 :     *(Diderot_real_t *)(odf->valp) = (Diderot_real_t)(odf->hval.r[0]);
442 :     break;
443 :     case optTypeReal2:
444 : jhr 3254 ((Diderot_real_t *)(odf->valp))[0] = (Diderot_real_t)(odf->hval.r[0]);
445 :     ((Diderot_real_t *)(odf->valp))[1] = (Diderot_real_t)(odf->hval.r[1]);
446 : jhr 1301 break;
447 :     case optTypeReal3:
448 : jhr 3254 ((Diderot_real_t *)(odf->valp))[0] = (Diderot_real_t)(odf->hval.r[0]);
449 :     ((Diderot_real_t *)(odf->valp))[1] = (Diderot_real_t)(odf->hval.r[1]);
450 :     ((Diderot_real_t *)(odf->valp))[2] = (Diderot_real_t)(odf->hval.r[2]);
451 : jhr 2118 break;
452 : jhr 1301 case optTypeReal4:
453 : jhr 3254 ((Diderot_real_t *)(odf->valp))[0] = (Diderot_real_t)(odf->hval.r[0]);
454 :     ((Diderot_real_t *)(odf->valp))[1] = (Diderot_real_t)(odf->hval.r[1]);
455 :     ((Diderot_real_t *)(odf->valp))[2] = (Diderot_real_t)(odf->hval.r[2]);
456 :     ((Diderot_real_t *)(odf->valp))[3] = (Diderot_real_t)(odf->hval.r[3]);
457 : jhr 2118 break;
458 : jhr 1301 case optTypeString: {
459 :     char *s = airStrdup(odf->hval.s);
460 :     if (s == 0) {
461 :     fprintf(stderr, "%s: unable to allocate string copy\n", me);
462 :     exit(1);
463 :     }
464 :     *(char **)(odf->valp) = s;
465 :     } break;
466 :     default:
467 :     fprintf(stderr, "%s: unknown option type %d\n", me, odf->ty);
468 :     exit(1);
469 :     } /* switch */
470 :     }
471 :     }

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0