LAL 7.6.1.1-4859cae
UserInput.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016 Karl Wette
3 * Copyright (C) 2015 Reinhard Prix
4 * Copyright (C) 2010 Reinhard Prix (xlalified)
5 * Copyright (C) 2004, 2005, 2015 Reinhard Prix
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with with program; see the file COPYING. If not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301 USA
21 */
22
23// ---------- local includes ----------
24#include <config.h>
25#include <stdio.h>
26#include <ctype.h>
27#include <limits.h>
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31#ifdef HAVE_SYS_IOCTL_H
32#include <sys/ioctl.h>
33#endif
34
35#include <lal/LALStdio.h>
36#include <lal/LALgetopt.h>
37#include <lal/LogPrintf.h>
38#include <lal/LALString.h>
39#include <lal/Date.h>
40#include <lal/StringVector.h>
41#include <lal/AVFactories.h>
42
43#include <lal/UserInputParse.h>
44#include <lal/UserInputPrint.h>
45
46#include <lal/UserInput.h>
47// ---------- local defines ----------
48#define TRUE (1==1)
49#define FALSE (1==0)
50
51
52// ---------- local Macro definitions ----------
53
54// ----- macro template for defining registration functions for UserInput variables
55#define DEFN_REGISTER_UVAR(UTYPE,CTYPE) \
56 DEFN_REGISTER_UVAR_AUX_DATA(UTYPE,CTYPE,void)
57#define DEFN_REGISTER_UVAR_AUX_DATA(UTYPE,CTYPE,DTYPE) \
58int XLALRegister ##UTYPE## UserVar ( CTYPE *cvar, const DTYPE *cdata, const CHAR *name, CHAR optchar, UserVarCategory category, const CHAR *fmt, ... ) \
59{ \
60 char helpstr[2048]; \
61 va_list ap; \
62 va_start(ap, fmt); \
63 vsnprintf(helpstr, sizeof(helpstr), fmt, ap); \
64 va_end(ap); \
65 return XLALRegisterUserVar (cvar, (const void*)cdata, name, UVAR_TYPE_ ## UTYPE, optchar, category, helpstr); \
66}
67
68// ---------- local type definitions ----------
69
70// Define the type of a "user-variable": bool, int, real or string, ...
71typedef enum {
72 UVAR_TYPE_START=0, // internal start marker for range checking
73
75 UVAR_TYPE_INT4, // 4-byte signed integer
76 UVAR_TYPE_INT8, // 8-byte signed integer
77 UVAR_TYPE_UINT4, // 4-byte unsigned integer
78 UVAR_TYPE_UINT8, // 8-byte unsigned integer
79 UVAR_TYPE_REAL8, // 8-byte float
80 UVAR_TYPE_EPOCH, // time 'epoch', specified in either GPS or MJD(TT) format, translated into GPS
81 UVAR_TYPE_RAJ, // sky equatorial longitude (aka right-ascencion or RA), in either radians or hours:minutes:seconds format, translated into radians
82 UVAR_TYPE_DECJ, // sky equatorial latitude (aka declination or DEC), in either radians or degrees:minutes:seconds format, translated into radians
83 UVAR_TYPE_STRING, // normal string
84
85 UVAR_TYPE_INT4Range, // range of INT4 values
86 UVAR_TYPE_REAL8Range, // range of REAL8 values
87 UVAR_TYPE_EPOCHRange, // range of LIGOTimeGPS values
88 UVAR_TYPE_RAJRange, // range of RAJ values
89 UVAR_TYPE_DECJRange, // range of DECJ values
90
91 UVAR_TYPE_UserEnum, // user selection of an enumeration value
92 UVAR_TYPE_UserFlag, // user selection of a set of bitflags
93
94 UVAR_TYPE_INT4Vector, // list of comma-separated INT4's
95 UVAR_TYPE_UINT4Vector, // list of comma-separated UINT4's
96 UVAR_TYPE_REAL8Vector, // list of comma-separated REAL8's
97 UVAR_TYPE_STRINGVector, // list of comma-separated strings
98
99 UVAR_TYPE_END // internal end marker for range checking
101
102//
103// Linked list to hold the complete information about the user-variables.
104//
105typedef struct tagLALUserVariable {
106 CHAR name[64]; // full name
107 UserVarType type; // variable type: BOOLEAN, INT4, REAL8, ...
108 CHAR optchar; // cmd-line character
109 const CHAR* subsection; // optional subsection heading under OPTIONS
110 CHAR help[2048]; // help-string
111 void *cvar; // pointer to the actual C-variable
112 const void *cdata; // pointer to auxilliary data needed to parse the C-variable
113 UserVarCategory category; // category (optional, required, developer, ... )
114 BOOLEAN was_set; // was this set by the user: 0=no, 1=via cfg-file, 2=via cmdline
115 struct tagLALUserVariable *next; // linked list
117
118// ---------- local prototypes ----------
119int XLALRegisterUserVar (void *cvar, const void *cdata, const CHAR *name, UserVarType type, CHAR optchar, UserVarCategory category, const CHAR *help);
120int XLALUserVarPrintUsage ( FILE *file );
121int XLALUserVarPrintHelp ( FILE *file );
122static void format_user_var_names( char *s );
123static void fprint_wrapped( FILE *f, int line_width, const char *prefix, char *text );
124
125// ----- define templated registration functions for all supported UVAR_TYPE_ 'UTYPES'
136
142
145
150
151// ----- define helper types for casting
152typedef void (*destructorT)(void *cvar);
153typedef int (*parserT)(void *cvar, const char *valstr);
154typedef char *(*printerT)(const void *cvar);
155typedef int (*parser_cdataT)(void *cvar, const void *cdata, const char *valstr);
156typedef char *(*printer_cdataT)(const void *cvar, const void *cdata);
157typedef char *(*format_help_cdataT)(const void *cdata);
158
159// ----- handy macro to simplify adding 'regular' entries for new UTYPES into UserVarTypeMap
160#define REGULAR_MAP_ENTRY(UTYPE,DESTRUCTOR,FORMATHELP) \
161 [UVAR_TYPE_##UTYPE] = { \
162 .name = #UTYPE, \
163 .destructor = (destructorT)DESTRUCTOR, \
164 .parser = (parserT)XLALParseStringValueAs##UTYPE, \
165 .printer = (printerT)XLALPrintStringValueOf##UTYPE, \
166 .format_help_str = FORMATHELP, \
167 }
168#define REGULAR_MAP_ENTRY_AUX_DATA(UTYPE,DESTRUCTOR,DTYPE) \
169 [UVAR_TYPE_##UTYPE] = { \
170 .name = #UTYPE, \
171 .destructor = (destructorT)DESTRUCTOR, \
172 .parser_cdata = (parser_cdataT)XLALParseStringValueAs##UTYPE, \
173 .printer_cdata = (printer_cdataT)XLALPrintStringValueOf##UTYPE, \
174 .format_help_cdata = (format_help_cdataT)XLALFormatHelpStringOf##UTYPE, \
175 }
176
177// ---------- HOWTO add new UserInput variable types ----------
178// In order to add a new type <UTYPE> to be handled by the UserInput module, you just need to
179// 1) add an entry 'UVAR_TYPE_<UTYPE>' in the UserVarType enum
180// 2) provide
181// a) a parser function XLALParseStringValueAs<UTYPE>() (recommended to be added in \ref UserInputParse_h)
182// b) a printer function XLALPrintStringValueOf<UTYPE>() (recommended to be added in \ref UserInputPrint_h)
183// c) a unit test for the new parser+printer, ideally checking identity of print(parse(x)) or parse(print(x))
184// 3) generate a corresponding registration function declaration + definition using the macro-templates
185// DECL_REGISTER_UVAR_AS<VALUE|POINTER>() and DEFN_REGISTER_UVAR_AS<VALUE|POINTER>(),
186// 4) add an entry in the master map 'UserInputTypeMap', specifying the parser, printer and (if required) a destructor
187// If these follow the standard naming and API, the template macro REGULAR_MAP_ENTRY() can be used for that.
188//
189// ---------- Master 'map' defining all UserInput types and how to handle them ----------
190// in particular, lists their name, and how to parse and print them, and (if required) how to destroy them
191static const struct
192{
193 const char *const name; ///< type name
194 destructorT destructor; ///< destructor for this variable type, NULL if none required
195 parserT parser; ///< parser function to parse string as this type
196 printerT printer; ///< 'printer' function returning string value for given type
197 const char *const format_help_str; ///< help string describing format of user variable
198 parser_cdataT parser_cdata; ///< parser function (with auxilliary data) to parse string as this type
199 printer_cdataT printer_cdata; ///< 'printer' function (with auxilliary data) returning string value for given type
200 format_help_cdataT format_help_cdata; ///< function returning describing format of user variable (with auxilliary data)
202= {
203 // either use 'manual' entries of the form
204 // [UVAR_TYPE_<UTYPE>] = {
205 // .name = "<UTYPE>", .destructor = (destructorT)XLALDestroy<UTYPE>, .format_help_str = "=help string for <UTYPE>",
206 // .parser = (parserT)XLALParseStringValueAs<UTYPE>, .printer = (printerT)XLALPrintStringValueOf<UTYPE>,
207 // },
208 // or the convenience macro for cases using 'standard' function names and API
209 // REGULAR_MAP_ENTRY ( <UTYPE>, XLALDestroy<UTYPE>, "=help string for <UTYPE>" ),
210 // REGULAR_MAP_ENTRY_AUX_DATA ( <UTYPE>, XLALDestroy<UTYPE>, XLALFormatHelpStringOf<UTYPE> ),
211
212 REGULAR_MAP_ENTRY ( BOOLEAN, NULL, "[=(TRUE|FALSE)|(YES|NO)|(1|0)]" ),
213 REGULAR_MAP_ENTRY ( INT4, NULL, "=<4-byte signed integer>" ),
214 REGULAR_MAP_ENTRY ( INT8, NULL, "=<8-byte signed integer>" ),
215 REGULAR_MAP_ENTRY ( UINT4, NULL, "=<4-byte unsigned integer>" ),
216 REGULAR_MAP_ENTRY ( UINT8, NULL, "=<8-byte unsigned integer>" ),
217 REGULAR_MAP_ENTRY ( REAL8, NULL, "=<8-byte real>" ),
218 REGULAR_MAP_ENTRY ( STRING, XLALFree, "=<string>" ),
219 REGULAR_MAP_ENTRY ( EPOCH, NULL, "=<seconds>[.<frac-seconds>][GPS] | <days>[.<frac-days>]MJD" ),
220 REGULAR_MAP_ENTRY ( RAJ, NULL, "=<radians>|<hours>:<minutes>:<seconds>" ),
221 REGULAR_MAP_ENTRY ( DECJ, NULL, "=<radians>|<degrees>:<minutes>:<seconds>" ),
222
223 REGULAR_MAP_ENTRY ( INT4Range, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<4-byte signed integer>" ),
224 REGULAR_MAP_ENTRY ( REAL8Range, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<8-byte real>" ),
225 REGULAR_MAP_ENTRY ( EPOCHRange, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<seconds>[.<frac-seconds>][GPS] | <days>[.<frac-days>]MJD" ),
226 REGULAR_MAP_ENTRY ( RAJRange, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<radians>|<hours>:<minutes>:<seconds>" ),
227 REGULAR_MAP_ENTRY ( DECJRange, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<radians>|<degrees>:<minutes>:<seconds>" ),
228
229 REGULAR_MAP_ENTRY_AUX_DATA ( UserEnum, NULL, UserChoices ),
230 REGULAR_MAP_ENTRY_AUX_DATA ( UserFlag, NULL, UserChoices ),
231
232 REGULAR_MAP_ENTRY ( INT4Vector, XLALDestroyINT4Vector, "=<4-byte signed integer>,..." ),
233 REGULAR_MAP_ENTRY ( UINT4Vector, XLALDestroyUINT4Vector, "=<4-byte unsigned integer>,..." ),
234 REGULAR_MAP_ENTRY ( REAL8Vector, XLALDestroyREAL8Vector, "=<8-byte real>,..." ),
235 REGULAR_MAP_ENTRY ( STRINGVector, XLALDestroyStringVector, "=<string>,..." ),
237
238
239// ---------- The module-local linked list to hold the user-variables
240static LALUserVariable UVAR_vars; // empty head
241static CHAR *program_path = NULL; // keep a pointer to the program path
242static CHAR *program_name = NULL; // keep a pointer to the program name
243
244
245/**
246 * An optional brief description of the program, printed after its name as part of the help page.
247 */
248const char *lalUserVarHelpBrief = NULL;
249
250/**
251 * An optional longer description of the program, printed in its own section as part of the help page.
252 */
253const char *lalUserVarHelpDescription = NULL;
254
255/**
256 * An optional subsection heading under \e OPTIONS, under which all subsequently-defined user variables are printed as part of the help page.
257 */
259
260
261// ==================== Function definitions ====================
262
263/**
264 * \ingroup UserInput_h
265 * Internal function: Register a user-variable with the module.
266 * Effectively put an appropriate entry into UVAR_vars
267 *
268 * Checks that long- and short-options are unique, an error is returned
269 * if a previous option name collides.
270 *
271 * \note don't use this function directly, as it is not type-safe!!
272 * ==> use the type-safe macro XLALRegisterUvarMember(name,type,option,category,help) instead!
273 */
274int
275XLALRegisterUserVar ( void *cvar, /**< pointer to the actual C-variable to link to this user-variable */
276 const void *cdata, /**< pointer to auxilliary data needed to parse the C-variable */
277 const CHAR *name, /**< name of user-variable to register */
278 UserVarType type, /**< variable type (int,bool,string,real) */
279 CHAR optchar, /**< optional short-option character */
280 UserVarCategory category, /**< sets category to this */
281 const CHAR *help /**< help-string explaining this input-variable */
282 )
283{
284 XLAL_CHECK ( cvar != NULL || category == UVAR_CATEGORY_DEFUNCT, XLAL_EINVAL );
285 XLAL_CHECK ( name != NULL, XLAL_EINVAL );
286 XLAL_CHECK ( strlen(name) < sizeof(UVAR_vars.name), XLAL_EINVAL, "User-variable name '%s' is too long", name );
287 XLAL_CHECK ( (category > UVAR_CATEGORY_START) && (category < UVAR_CATEGORY_END), XLAL_EINVAL );
288 XLAL_CHECK ( help != NULL, XLAL_EINVAL );
289 XLAL_CHECK ( strlen(help) < sizeof(UVAR_vars.help), XLAL_EINVAL, "User-variable help '%s' is too long", help );
290
291 // check that UserVarTypeMap entry is correct
292 XLAL_CHECK ( ( cdata != NULL ? (const void*)UserVarTypeMap [ type ].parser_cdata : (const void*)UserVarTypeMap [ type ].parser ) != NULL, XLAL_EERR );
293 XLAL_CHECK ( ( cdata != NULL ? (const void*)UserVarTypeMap [ type ].printer_cdata : (const void*)UserVarTypeMap [ type ].printer ) != NULL, XLAL_EERR );
294 XLAL_CHECK ( ( cdata != NULL ? (const void*)UserVarTypeMap [ type ].format_help_cdata : (const void*)UserVarTypeMap [ type ].format_help_str ) != NULL, XLAL_EERR );
295
296 // check that neither short- nor long-option are used by help
297 XLAL_CHECK ( strcmp ( name, "help" ) != 0, XLAL_EINVAL, "Long-option name '--%s' is reserved for help!\n", name );
298 XLAL_CHECK ( optchar != 'h', XLAL_EINVAL, "Short-option '-%c' is reserved for help!\n", optchar );
299
300 // check that neither short- nor long-option are used by version
301 XLAL_CHECK ( strcmp ( name, "version" ) != 0, XLAL_EINVAL, "Long-option name '--%s' is reserved for version!\n", name );
302 XLAL_CHECK ( optchar != 'v', XLAL_EINVAL, "Short-option '-%c' is reserved for version!\n", optchar );
303
304 // find end of uvar-list && check that neither short- nor long-option are taken already
306 while ( ptr->next != NULL )
307 {
308 ptr = ptr->next;
309
310 // long-option name taken already?
311 XLAL_CHECK ( strcmp ( name, ptr->name ) != 0, XLAL_EINVAL, "Long-option name '--%s' already taken!\n", name );
312 // short-option character taken already?
313 XLAL_CHECK ( (optchar == 0) || (ptr->optchar == 0) || (optchar != ptr->optchar), XLAL_EINVAL, "Short-option '-%c' already taken (by '--%s')!\n", optchar, ptr->name );
314
315 } // while ptr->next
316
317 // append new entry at the end
318 XLAL_CHECK ( (ptr->next = XLALCalloc (1, sizeof(LALUserVariable))) != NULL, XLAL_ENOMEM );
319
320 // set pointer to newly created entry
321 ptr = ptr->next;
322
323 // copy entry name, replacing '_' with '-' so that
324 // e.g. uvar->a_long_option maps to --a-long-option
325 XLALStringReplaceChar( strncpy( ptr->name, name, sizeof(ptr->name) - 1 ), '_', '-' );
326
327 // copy current subsection heading
329
330 // copy entry help string
331 strncpy( ptr->help, help, sizeof(ptr->help) - 1 );
333
334 // fill in entry values
335 ptr->type = type;
336 ptr->optchar = optchar;
337 ptr->cvar = category == UVAR_CATEGORY_DEFUNCT ? NULL : cvar;
338 ptr->cdata = cdata;
339 ptr->category = category;
340
341 return XLAL_SUCCESS;
342
343} // XLALRegisterUserVar()
344
345/**
346 * Free all memory associated with user-variable linked list
347 */
348void
350{
351 LALUserVariable *ptr = &(UVAR_vars);
352 LALUserVariable *lastptr = NULL;
353
354 // step through user-variables: free list-entries and all allocated strings
355 while ( (ptr=ptr->next) != NULL )
356 {
357 XLAL_CHECK_VOID ( (ptr->type > UVAR_TYPE_START) && (ptr->type < UVAR_TYPE_END), XLAL_EFAILED, "Invalid UVAR_TYPE '%d' outside of [%d,%d]\n", ptr->type, UVAR_TYPE_START+1, UVAR_TYPE_END-1 );
358
359 // is there a destructor function registered for this type?
360 if ( UserVarTypeMap [ ptr->type ].destructor != NULL )
361 if ( ptr->cvar ) {
362 UserVarTypeMap [ ptr->type ].destructor ( *(CHAR**)ptr->cvar );
363 *(CHAR**)ptr->cvar = NULL;
364 }
365
366 /* free list-entry behind us (except for the head) */
367 if ( lastptr != NULL ) {
368 XLALFree ( lastptr );
369 }
370
371 lastptr = ptr;
372
373 } // while ptr->next
374
375 if ( lastptr != NULL ) {
376 XLALFree ( lastptr );
377 }
378
379 // clean head
380 memset (&UVAR_vars, 0, sizeof(UVAR_vars));
381
382 return;
383
384} /* XLALDestroyUserVars() */
385
386
387/**
388 * Parse command-line into UserVariable array
389 *
390 * If \p *should_exit is TRUE when this function returns, the
391 * caller should exit immediately.
392 */
393int
394XLALUserVarReadCmdline ( BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list )
395{
396 XLAL_CHECK ( should_exit != NULL, XLAL_EFAULT );
397 XLAL_CHECK ( argv != NULL, XLAL_EINVAL, "Input error, NULL argv[] pointer passed.\n" );
398 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "Internal error, no UVAR memory allocated. Did you register any user-variables?" );
399
400 *should_exit = 0;
401
402 LALUserVariable *ptr;
403 UINT4 pos;
404
405 // ---------- build optstring of short-options
406 UINT4 numvars = 0;
407 char optstring[512] = "\0"; // string of short-options
408 pos = 0;
409
410 // add special version option
411 optstring[pos++] = 'v';
412 optstring[pos++] = ':';
413 optstring[pos++] = ':';
414
415 // add user-specified options
416 ptr = &UVAR_vars; // set to empty head
417 while ( (ptr = ptr->next) != NULL )
418 {
419 numvars ++; /* counter number of user-variables */
420 if (ptr->optchar == 0) { /* if no short-option given, ignore */
421 continue;
422 }
423 optstring[pos++] = ptr->optchar;
424 optstring[pos++] = ':'; /* everything but bool takes an argument */
425 if (ptr->type == UVAR_TYPE_BOOLEAN) { /* but for BOOL its optional */
426 optstring[pos++] = ':';
427 }
428 } // while ptr->next
429
430 // null-terminate array
431 optstring[pos] = '\0';
432
433 // ---------- fill option-struct for long-options
434 struct LALoption *long_options = LALCalloc (1, (numvars+2) * sizeof(struct LALoption));
435 pos = 0;
436
437 // add special version option
438 long_options[pos].name = "version";
439 long_options[pos].has_arg = optional_argument;
440 long_options[pos].flag = NULL;
441 long_options[pos].val = 0;
442 pos ++;
443
444 // add user-specified options
445 ptr = &UVAR_vars; // start again from beginning: empty head
446 while ( (ptr= ptr->next) != NULL)
447 {
448 long_options[pos].name = ptr->name;
449 long_options[pos].has_arg = (ptr->type == UVAR_TYPE_BOOLEAN) ? optional_argument : required_argument;
450 long_options[pos].flag = NULL; // get val returned from LALgetopt_long()
451 long_options[pos].val = 0; // we use longindex to find long-options
452 pos ++;
453 } // while ptr->next
454
455 // null-terminate array
456 long_options[pos].name = 0;
457 long_options[pos].has_arg = 0;
458 long_options[pos].flag = 0;
459 long_options[pos].val = 0;
460
461 /* NOTE: in case we get called several times, we have to make sure here that getopt() gets
462 * properly reset/initialized. We do this using the (undocumented) feature of GNU getopt
463 * of setting optind to 0. As we're linking our private version of GNU getopt, this should be
464 * guaranteed to work.
465 *
466 * Bruce's notes: read LALgetopt_long() source code, and in particular
467 * _getopt_internal() to see what is initialized.
468 */
469 LALoptind = 0; // reset our local LALgetopt(), LALgetopt_long()
470
471 // ---------- parse the command-line
472 while ( 1 )
473 {
474
475 // call LALgetopt_long()
476 char *old_argv0 = argv[0];
477 argv[0] = program_name; // use program_name for LALgetopt_long() error messages
478 int longindex = -1;
479 int c = LALgetopt_long(argc, argv, optstring, long_options, &longindex);
480 argv[0] = old_argv0;
481 if ( c == -1 ) { // LALgetopt_long() is done
482 break;
483 }
484 if ( c == '?' || c == ':' ) { // LALgetopt_long() returned an error
486 *should_exit = 1;
487 return XLAL_SUCCESS;
488 }
489
490 // handle special version option
491 if ( (c != 0) ? (c == 'v') : !strcmp(long_options[longindex].name, "version") )
492 {
493 int verbose = 0;
494 if ( LALoptarg != NULL )
495 {
496 if ( !strcmp(LALoptarg, "verbose") )
497 {
498 verbose = 1;
499 }
500 else
501 {
502 XLALPrintError( "\n%s: invalid value '%s' given to option " UVAR_FMT "\n\n", program_name, LALoptarg, "version" );
503 *should_exit = 1;
504 return XLAL_SUCCESS;
505 }
506 }
507 char *str = XLALVCSInfoString( vcs_list, verbose, NULL );
508 XLAL_CHECK( str != NULL, XLAL_EFUNC );
509 printf( "%s", str );
510 XLALFree( str );
511 *should_exit = 1;
512 return XLAL_SUCCESS;
513 }
514
515 if (c != 0) // find short-option character
516 {
517 ptr = &UVAR_vars;
518 do {
519 if (c == ptr->optchar) {
520 break;
521 }
522 } while ( (ptr=ptr->next) != NULL);
523 } // end: if short-option given
524 else // find long-option: returned in longindex
525 {
526 ptr = &UVAR_vars;
527 while ( (ptr=ptr->next) != NULL) {
528 if ( !strcmp (long_options[longindex].name, ptr->name) ) {
529 break;
530 }
531 }
532 } // end: if long-option
533
534 XLAL_CHECK ( ptr != NULL, XLAL_EFAILED, "ERROR: failed to find matching option ... this points to a coding-error!\n" );
535 XLAL_CHECK ( (ptr->type > UVAR_TYPE_START) && (ptr->type < UVAR_TYPE_END), XLAL_EFAILED, "Invalid UVAR_TYPE '%d' outside of [%d,%d]\n", ptr->type, UVAR_TYPE_START+1, UVAR_TYPE_END-1 );
536
537 switch (ptr->type)
538 {
540 // subtlety with optional arguments: it's not necessarily found in the *same* argv-entry
541 // eg, if no '=' was used, so we have to check for that case by hand:
542 // if the next entry is not an option, take it as an argument
543 if ( (LALoptarg == NULL) && (LALoptind < argc) && (argv[LALoptind][0] != '-') && (argv[LALoptind][0] != '@') )
544 {
545 LALoptarg = argv[LALoptind];
546 LALoptind ++;
547 }
548
549 if ( LALoptarg == NULL ) { // if no argument given, defaults to TRUE
550 if ( ptr->cvar ) {
551 *(BOOLEAN*)(ptr->cvar) = TRUE;
552 }
553 } else {
554 if ( LALoptarg == NULL || strlen(LALoptarg) == 0 )
555 {
556 XLALPrintError( "\n%s: no value given to option " UVAR_FMT "\n\n", program_name, ptr->name );
557 *should_exit = 1;
558 return XLAL_SUCCESS;
559 }
560 if ( ptr->cvar )
561 {
562 int retn = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].parser_cdata( ptr->cvar, ptr->cdata, LALoptarg ) : UserVarTypeMap [ ptr->type ].parser( ptr->cvar, LALoptarg );
563 if ( retn != XLAL_SUCCESS )
564 {
565 XLALPrintError( "\n%s: could not parse value '%s' given to option " UVAR_FMT "\n\n", program_name, LALoptarg, ptr->name );
566 *should_exit = 1;
567 return XLAL_SUCCESS;
568 }
569 }
570 }
571 break;
572
573 default:
574 // all other UVAR_TYPE_ types can be handled canonically: first destroy previous value, the parse new one
575 if ( UserVarTypeMap [ ptr->type ].destructor != NULL )
576 if ( ptr->cvar ) {
577 UserVarTypeMap [ ptr->type ].destructor( *(char**)ptr->cvar );
578 *(char**)ptr->cvar = NULL;
579 } // if a destructor was registered
580 if ( LALoptarg == NULL || strlen(LALoptarg) == 0 )
581 {
582 XLALPrintError( "\n%s: no value given to option " UVAR_FMT "\n\n", program_name, ptr->name );
583 *should_exit = 1;
584 return XLAL_SUCCESS;
585 }
586 if ( ptr->cvar )
587 {
588 int retn = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].parser_cdata( ptr->cvar, ptr->cdata, LALoptarg ) : UserVarTypeMap [ ptr->type ].parser( ptr->cvar, LALoptarg );
589 if ( retn != XLAL_SUCCESS )
590 {
591 XLALPrintError( "\n%s: could not parse value '%s' given to option " UVAR_FMT "\n\n", program_name, LALoptarg, ptr->name );
592 *should_exit = 1;
593 return XLAL_SUCCESS;
594 }
595 }
596 break;
597
598 } // switch ptr->type
599
600 switch ( ptr->was_set ) {
601 case 0: // this variable has not been set; mark as set on command line
602 ptr->was_set = 2;
603 break;
604 case 1: // this variable has been set in configuration file; print warning
605 XLALPrintError ( "\n%s: option " UVAR_FMT " is overriding value set in configuration file!\n\n", program_name, ptr->name );
606 break;
607 default: // this variable has been set before; error
608 XLALUserVarCheck( should_exit, 0, "option " UVAR_FMT " was set more than once!", ptr->name );
609 return XLAL_SUCCESS;
610 }
611
612 } // while LALgetopt_long()
613
614 // ---------- check if there's any non-option strings left (except for a config-file specification '@file')
615 if ( (LALoptind == argc - 1) && (argv[LALoptind][0] == '@' ) ) {
616 LALoptind ++; // advance counter in case of one config-file specification (only one allowed)
617 }
618 if ( LALoptind < argc ) // still stuff left? ==> error
619 {
620 XLALPrintError ( "\nGot non-option ARGV-elements: [ ");
621 while (LALoptind < argc) {
622 if ( argv[LALoptind][0] == '@' ) { LALoptind ++; continue; } // don't list config-file entries here
623 XLALPrintError ("%s ", argv[LALoptind++]);
624 }
625 XLALPrintError(" ]\n");
626 *should_exit = 1;
627 return XLAL_SUCCESS;
628 } // trailing non-option arguments found
629
630 XLALFree (long_options);
631 long_options=NULL;
632
633 return XLAL_SUCCESS;
634
635} // XLALUserVarReadCmdline()
636
637
638/**
639 * Read config-variables from cfgfile and parse into input-structure.
640 * An error is reported if the config-file reading fails, but the
641 * individual variable-reads are treated as optional
642 *
643 * If \p *should_exit is TRUE when this function returns, the
644 * caller should exit immediately.
645 */
646int
647XLALUserVarReadCfgfile ( BOOLEAN *should_exit, const CHAR *cfgfile )
648{
649 XLAL_CHECK ( should_exit != NULL, XLAL_EFAULT );
650 XLAL_CHECK ( cfgfile != NULL, XLAL_EINVAL );
651 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No memory allocated in UVAR_vars.next, did you register any user-variables?\n" );
652
653 *should_exit = 0;
654
655 LALParsedDataFile *cfg = NULL;
656 XLAL_CHECK ( XLALParseDataFile ( &cfg, cfgfile ) == XLAL_SUCCESS, XLAL_EFUNC );
657
658 // step through all user-variable: read those with names from config-file
660 while ( (ptr=ptr->next) != NULL)
661 {
662
663 XLAL_CHECK ( (ptr->type > UVAR_TYPE_START) && (ptr->type < UVAR_TYPE_END), XLAL_EFAILED, "Invalid UVAR_TYPE '%d' outside of [%d,%d]\n", ptr->type, UVAR_TYPE_START+1, UVAR_TYPE_END-1 );
664
665 BOOLEAN wasRead;
666 CHAR *valString = NULL; // first read the value as a string
667 XLAL_CHECK ( XLALReadConfigSTRINGVariable ( &valString, cfg, NULL, ptr->name, &wasRead ) == XLAL_SUCCESS, XLAL_EFUNC );
668 if ( wasRead ) // if successful, parse this as the desired type
669 {
670 // destroy previous value, is applicable, then parse new one
671 if ( UserVarTypeMap [ ptr->type ].destructor != NULL )
672 if ( ptr->cvar ) {
673 UserVarTypeMap [ ptr->type ].destructor( *(char**)ptr->cvar );
674 *(char**)ptr->cvar = NULL;
675 } // if a destructor was registered
676 if ( valString == NULL || strlen(valString) == 0 )
677 {
678 XLALPrintError( "\n%s: no value given to option " UVAR_FMT "\n\n", program_name, ptr->name );
679 *should_exit = 1;
680 return XLAL_SUCCESS;
681 }
682 if ( ptr->cvar )
683 {
684 int retn = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].parser_cdata( ptr->cvar, ptr->cdata, valString ) : UserVarTypeMap [ ptr->type ].parser( ptr->cvar, valString );
685 if ( retn != XLAL_SUCCESS )
686 {
687 XLALPrintError( "\n%s: could not parse value '%s' given to option " UVAR_FMT "\n\n", program_name, valString, ptr->name );
688 *should_exit = 1;
689 return XLAL_SUCCESS;
690 }
691 }
692 XLALFree (valString);
693
694 switch ( ptr->was_set ) {
695 case 0: // this variable has not been set; mark as set in configuration file
696 ptr->was_set = 1;
697 break;
698 default: // this variable has been set before; error
699 XLALUserVarCheck( should_exit, 0, "configuration option `%s' was set more than once!", ptr->name );
700 return XLAL_SUCCESS;
701 }
702
703 } // if wasRead
704
705 } // while ptr->next
706
707 // ok, that should be it: check if there were more definitions we did not read
709 XLAL_CHECK ( xlalErrno == 0, XLAL_EFUNC, "XLALConfigFileGetUnreadEntries() failed\n");
710 if ( unread != NULL )
711 {
712 XLALPrintWarning ("The following entries in config-file '%s' have not been parsed:\n", cfgfile );
713 for ( UINT4 i = 0; i < unread->length; i ++ ) {
714 XLALPrintWarning ("%s\n", cfg->lines->tokens[ unread->data[i] ] );
715 }
716 XLALDestroyUINT4Vector ( unread );
717 }
718
720
721 return XLAL_SUCCESS;
722
723} // XLALUserVarReadCfgfile()
724
725/**
726 * Print a one-line usage string
727 */
728int
730{
731
732 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
733
734 /* Print usage: only required and regular arguments are printed */
735 fprintf( file, "\nUsage: %s [-h|--help] [-v|--version] [@<config-file>]", program_name );
736 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
737 {
738 switch ( ptr->category )
739 {
743 continue;
744 default:
745 break;
746 }
747 fprintf( file, " " );
748 if ( ptr->category != UVAR_CATEGORY_REQUIRED ) {
749 fprintf( file, "[" );
750 }
751 if ( ptr->optchar != 0 ) {
752 fprintf( file, "-%c|", ptr->optchar );
753 }
754 fprintf( file,"--%s", ptr->name);
755 if ( ptr->category != UVAR_CATEGORY_REQUIRED ) {
756 fprintf( file, "]" );
757 }
758 }
759 fprintf( file,"\n\n");
760
761 return XLAL_SUCCESS;
762
763} // XLALUserVarPrintUsage()
764
765/*
766 * Format strings so that `--user_variables` have '_' replaced with '-'
767 */
768void
770{
771 while ( ( s = strchr( s, '`' ) ) != NULL )
772 {
773 while ( *s != '\0' && *s != '\'' )
774 {
775 if ( *s == '_' ) *s = '-';
776 ++s;
777 }
778 }
779}
780
781/*
782 * Print text wrapped to a given line width
783 */
784void
785fprint_wrapped( FILE *file, int line_width, const char *prefix, char *text )
786{
787
788 /* Adjust line width */
789 line_width -= strlen(prefix) + 1;
790
791 /* If line width is too short, just assume very long lines */
792 if ( line_width < 1 ) {
793 line_width = INT_MAX;
794 }
795
796 /* Iterate over text */
797 char *pstart = text, *pline = text, *pbreak = NULL;
798 char empty_line[2] = "";
799 char list_indent[16] = "";
800 for ( char *pend = text; *pend != '\0'; ++pend )
801 {
802
803 /* Record position of last space, in order to break line */
804 if ( isspace( *pend ) ) {
805 pbreak = pend;
806 }
807
808 /* Determine indent for lists (lines with start with spaces/dashes) */
809 strcpy( list_indent, "" );
810 if ( pline != pstart ) {
811 for ( size_t i = 0; i + 1 < XLAL_NUM_ELEM( list_indent ) && strchr( " -", pline[i] ) != NULL; ++i ) {
812 list_indent[i] = ' ';
813 }
814 }
815
816 /* If at end of line, or encountered a newline */
817 int indented_line_width = line_width - strlen( list_indent );
818 if ( ( pend - pstart ) == indented_line_width || *pend == '\n' ) {
819
820 /* Save beginning of line for determining list indent */
821 if ( *pend == '\n' ) {
822 pline = pend + 1;
823 }
824
825 if ( pbreak != NULL ) { /* If we have a space character */
826
827 /* Print text up to before last space character */
828 const char old_pbreak = *pbreak;
829 *pbreak = '\0';
830 fprintf( file, "%s%s%s%s\n", empty_line, prefix, list_indent, pstart );
831 strcpy( empty_line, "" );
832 *pbreak = old_pbreak;
833
834 /* Save an empty line for the next time a non-empty line is printed */
835 for ( pend = pbreak + 1; *pend != '\0' && *pend == '\n'; ++pend ) {
836 strcpy( empty_line, "\n" );
837 pline = pend + 1;
838 }
839
840 /* Start from next non-printed character */
841 pstart = pend;
842
843 /* Reset space character */
844 pbreak = NULL;
845
846 } else {
847
848 /* Print unbroken line, ending with hyphen */
849 const char old_pend = *pend;
850 *pend = '\0';
851 fprintf( file, "%s%s%s%s-\n", empty_line, prefix, list_indent, pstart );
852 strcpy( empty_line, "" );
853 *pend = old_pend;
854
855 /* Start from next non-printed character */
856 pstart = pend;
857
858 }
859 }
860
861 }
862
863 /* Print remaining text */
864 if ( strlen( pstart ) > 0 ) {
865 fprintf( file, "%s%s%s%s\n", empty_line, prefix, list_indent, pstart );
866 strcpy( empty_line, "" );
867 }
868
869}
870
871/**
872 * Print help page
873 */
874int
876{
877 int retn = XLAL_FAILURE;
878 FILE *f = file;
879 int line_width = 0;
880
881 XLAL_CHECK_FAIL ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
882
883 /* Determine terminal line width, or set to zero otherwise */
884#if defined(HAVE_ISATTY) && defined(HAVE_FILENO) && defined(HAVE_IOCTL)
885#if HAVE_DECL_TIOCGWINSZ && HAVE_STRUCT_WINSIZE_WS_COL
886 if ( isatty( fileno( file ) ) ) {
887 struct winsize w;
888 ioctl( fileno( file ), TIOCGWINSZ, &w );
889 line_width = w.ws_col;
890 }
891#endif
892#endif
893
894 /* Pipe output through pager if possible */
895#if defined(PAGER) && defined(HAVE_POPEN) && defined(HAVE_PCLOSE)
896 f = popen(PAGER, "w");
897 if ( f == NULL ) {
898 f = file;
899 }
900#endif
901 fflush( f );
902
903 /* Print program name and synopsis of command line syntax */
904 fprintf( f, "\nNAME\n" );
905 fprintf( f, " %s", program_name );
906 if ( lalUserVarHelpBrief != NULL ) {
907 fprintf( f, " - %s", lalUserVarHelpBrief );
908 }
909 fprintf( f, "\n" );
910 fprintf( f, "\nSYNOPSIS\n" );
911 {
912 fprintf( f, " %s --help\n", program_name );
913 CHAR help_str[] = "Display this help page.";
914 fprint_wrapped( f, line_width, " ", help_str );
915 }
916 fprintf( f, "\n" );
917 {
918 fprintf( f, " %s -h\n", program_name );
919 CHAR help_str[] = "Display a short usage string of available options.";
920 fprint_wrapped( f, line_width, " ", help_str );
921 }
922 fprintf( f, "\n" );
923 {
924 fprintf( f, " %s -v|--version[=verbose]\n", program_name );
925 CHAR help_str[] = "Display (verbose) version information.";
926 fprint_wrapped( f, line_width, " ", help_str );
927 }
928 fprintf( f, "\n" );
929 {
930 fprintf( f, " %s [@<config-file>] [<options>...]\n", program_name );
931 CHAR help_str[] = "Run the program. Options are parsed from, if given:\n- Configuration file <config-file>: format is INI file style, one <option>=<value> pair per line.\n- Command line <options>: format is --<option>=<value>, --<option> <value>, or -<short-option> <value>.";
932 fprint_wrapped( f, line_width, " ", help_str );
933 }
934 if ( lalUserVarHelpDescription != NULL ) {
937 fprintf( f, "\nDESCRIPTION\n" );
938 fprint_wrapped( f, line_width, " ", description );
940 }
941 fprintf( f, "\n" );
942
943 /* Print options in sections */
944 const char* section_headers[] = { "OPTIONS", "DEVELOPER OPTIONS", "DEPRECATED OPTIONS" };
945 for ( size_t section = 0; section < XLAL_NUM_ELEM(section_headers); ++section )
946 {
947 BOOLEAN print_section_header = 1;
948
949 /* Go through all user variables */
950 const char *subsection = NULL;
951 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
952 {
953
954 /* Decide what section to print option in, and with what formatting */
955 size_t print_section = 0;
956 BOOLEAN print_format_help = 1, print_default_value = 1;
957 switch ( ptr->category )
958 {
960 print_section = 1;
961 break;
963 print_section = 2;
964 print_format_help = print_default_value = 0;
965 break;
967 continue;
968 default:
969 break;
970 }
971 XLAL_CHECK_FAIL( print_section < XLAL_NUM_ELEM(section_headers), XLAL_EFAILED );
972
973 if ( print_section == section )
974 {
975
976 /* Print section (and possibly subsection) headers */
977 if ( print_section_header )
978 {
979 fprintf( f, "%s\n", section_headers[section] );
980 print_section_header = 0;
981 }
982 if ( ptr->subsection != NULL && ( subsection == NULL || strcmp( ptr->subsection, subsection ) != 0 ) )
983 {
984 fprintf( f, " %s\n", ptr->subsection );
985 subsection = ptr->subsection;
986 }
987
988 /* Print option, format help, and default value */
989 fprintf( f, " " );
990 if ( ptr->optchar != 0 )
991 {
992 fprintf( f, "-%c, ", ptr->optchar );
993 }
994 fprintf( f, "--%s", ptr->name );
995 if ( print_format_help )
996 {
997 if ( ptr->cdata != NULL )
998 {
999 CHAR *format_help_str = UserVarTypeMap [ ptr->type ].format_help_cdata( ptr->cdata );
1001 fprintf( f, "%s", format_help_str );
1003 }
1004 else
1005 {
1006 fprintf( f, "%s", UserVarTypeMap [ ptr->type ].format_help_str );
1007 }
1008 }
1009 if ( print_default_value )
1010 {
1011 if ( ptr->category == UVAR_CATEGORY_REQUIRED )
1012 {
1013 fprintf( f, " [required]" );
1014 }
1015 else if ( ptr->category == UVAR_CATEGORY_NODEFAULT )
1016 {
1017 fprintf( f, " [optional]" );
1018 }
1019 else if ( ptr->cvar )
1020 {
1021 CHAR *valstr = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].printer_cdata( ptr->cvar, ptr->cdata ) : UserVarTypeMap [ ptr->type ].printer( ptr->cvar );
1022 XLAL_CHECK_FAIL( valstr != NULL, XLAL_EFUNC );
1023 fprintf( f, " [default: %s]", valstr );
1024 XLALFree( valstr );
1025 }
1026 }
1027 fprintf( f, "\n" );
1028
1029 /* Print option help string */
1030 fprint_wrapped( f, line_width, " ", ptr->help );
1031 fprintf( f, "\n" );
1032
1033 }
1034
1035 }
1036
1037 }
1038
1039 retn = XLAL_SUCCESS;
1040XLAL_FAIL:
1041
1042 /* Close pipe to pager if used */
1043 fflush( f );
1044#if defined(PAGER) && defined(HAVE_POPEN) && defined(HAVE_PCLOSE)
1045 if ( f != file ) {
1046 pclose( f );
1047 }
1048#endif
1049
1050 return retn;
1051
1052} // XLALUserVarPrintHelp()
1053
1054
1055/**
1056 * Put all the pieces together, and basically does everything:
1057 * print help (if requested), get config-filename from cmd-line (if found),
1058 * then interpret config-file and then the command-line
1059 *
1060 * If \p *should_exit is TRUE when this function returns, the
1061 * program should exit immediately with a non-zero status.
1062 */
1063int
1064XLALUserVarReadAllInput ( BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list )
1065{
1066 XLAL_CHECK ( should_exit != NULL, XLAL_EFAULT );
1067 XLAL_CHECK ( argc > 0, XLAL_EINVAL );
1068 XLAL_CHECK ( argv != NULL, XLAL_EINVAL );
1069 XLAL_CHECK ( argv[0] != NULL, XLAL_EINVAL );
1070 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
1071
1072 *should_exit = 0;
1073
1074 // keep a module-local pointer to the executable path/name
1075 program_path = argv[0];
1076 program_name = strrchr( program_path, '/' );
1077 if ( program_name == NULL ) {
1079 } else {
1080 ++program_name;
1081 }
1082
1083 // ---------- manually parse command-line for help/usage arguments
1084 for ( INT4 i = 1; i < argc; i++ )
1085 {
1086 XLAL_CHECK( argv[i] != NULL, XLAL_EINVAL, "argc = %d, but argv[%d] == NULL!\n", argc, i );
1087 if ( strcmp( argv[i], "-h" ) == 0 )
1088 {
1090 *should_exit = 1;
1091 return XLAL_SUCCESS;
1092 }
1093 else if ( strcmp( argv[i], "--help" ) == 0 || strcmp( argv[i], "-help" ) == 0 )
1094 {
1096 *should_exit = 1;
1097 return XLAL_SUCCESS;
1098 }
1099 }
1100
1101 // ---------- pre-process command-line: have we got a config-file ?
1102 CHAR* cfgfile_name = NULL;
1103 for ( INT4 i = 1; i < argc; i++ )
1104 {
1105 char *argi = argv[i];
1106 XLAL_CHECK ( argi != NULL, XLAL_EINVAL, "argc = %d, but argv[%d] == NULL!\n", argc, i );
1107
1108 if ( argi[0] == '@' )
1109 {
1110 XLAL_CHECK ( cfgfile_name == NULL, XLAL_EINVAL, "Can only handle *one* config-file passed on commandline!\n" );
1111 argi ++;
1112 XLAL_CHECK ( (cfgfile_name = XLALStringDuplicate ( argi )) != NULL, XLAL_EFUNC );
1113 } // if argument starts with '@' -> config-file
1114
1115 } // for i < argc
1116
1117 // ---------- if config-file specified, read from that first
1118 if ( cfgfile_name != NULL )
1119 {
1120 XLAL_CHECK ( XLALUserVarReadCfgfile ( should_exit, cfgfile_name ) == XLAL_SUCCESS, XLAL_EFUNC );
1121 if ( *should_exit ) {
1122 return XLAL_SUCCESS;
1123 }
1124 XLALFree (cfgfile_name);
1125 }
1126
1127 // ---------- now parse cmdline: overloads previous config-file settings
1128 XLAL_CHECK ( XLALUserVarReadCmdline ( should_exit, argc, argv, vcs_list ) == XLAL_SUCCESS, XLAL_EFUNC );
1129 if ( *should_exit ) {
1130 return XLAL_SUCCESS;
1131 }
1132
1133 // ---------- handle special options that need some action ----------
1134 BOOLEAN skipCheckRequired = FALSE;
1135 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
1136 {
1137
1138 // handle DEPRECATED options by outputting a warning (on error-level to make this very noticeable!)
1139 if ( ptr->category == UVAR_CATEGORY_DEPRECATED && ptr->was_set ) {
1140 XLALPrintError ("\n%s: option " UVAR_FMT " is DEPRECATED: %s\n\n", program_name, ptr->name, ptr->help );
1141 }
1142
1143 // handle DEFUNCT options by throwing an error:
1144 XLALUserVarCheck( should_exit, ptr->category != UVAR_CATEGORY_DEFUNCT || !ptr->was_set, "option " UVAR_FMT " is DEFUNCT: %s", ptr->name, ptr->help );
1145 if ( *should_exit ) {
1146 return XLAL_SUCCESS;
1147 }
1148
1149 } // while ptr = ptr->next
1150
1151 // check that all required input-variables have been specified
1152 if ( !skipCheckRequired ) {
1153
1154 // go through list of uvars
1155 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
1156 {
1157 XLALUserVarCheck( should_exit, ptr->category != UVAR_CATEGORY_REQUIRED || ptr->was_set, "required option " UVAR_FMT " has not been specified!", ptr->name );
1158 if ( *should_exit ) {
1159 return XLAL_SUCCESS;
1160 }
1161 }
1162
1163 }
1164
1165 return XLAL_SUCCESS;
1166
1167} // XLALUserVarReadAllInput()
1168
1169
1170/**
1171 * Has this user-variable been set by the user?
1172 * returns 1 (=TRUE) or 0 (=FALSE) on success, error-code otherwise
1173 */
1174int
1175XLALUserVarWasSet ( const void *cvar )
1176{
1177 XLAL_CHECK ( cvar != NULL, XLAL_EINVAL );
1178 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
1179
1180 // find this variable name in the list of registered user-variables
1181 LALUserVariable *ptr = &UVAR_vars;
1182 while ( (ptr = ptr->next) != NULL )
1183 {
1184 if ( ptr->cvar != NULL && ptr->cvar == cvar) {
1185 break;
1186 }
1187 } // while ptr = ptr->next
1188
1189 XLAL_CHECK ( ptr != NULL, XLAL_EINVAL, "Variable pointer passed UVARwasSet is not a registered User-variable\n" );
1190
1191 // we found it: has it been set by user?
1192 if ( ptr->was_set ) {
1193 return 1;
1194 } else {
1195 return 0;
1196 }
1197
1198} // XLALUserVarWasSet()
1199
1200
1201/**
1202 * If \p assertion is false, print the given error message, then the help usage;
1203 * \p should_exit is then set to true.
1204 */
1205void
1206XLALUserVarCheck( BOOLEAN *should_exit, const int assertion, const CHAR *fmt, ... )
1207{
1208 if ( !( *should_exit ) && !assertion ) {
1209 char buf[2048];
1210 va_list ap;
1211 va_start( ap, fmt );
1212 vsnprintf( buf, sizeof( buf ), fmt, ap );
1213 va_end( ap );
1214 format_user_var_names( buf );
1215 fprintf( stderr, "\n%s: %s\n", program_name, buf );
1217 fflush( stderr );
1218 *should_exit = 1;
1219 }
1220} // XLALUserVarCheck()
1221
1222/**
1223 * Return a log-string representing the <em>complete</em> user-input.
1224 * <em>NOTE:</em> we only record user-variables that have been set
1225 * by the user.
1226 */
1227CHAR *
1228XLALUserVarGetLog ( UserVarLogFormat format /**< output format: return as config-file or command-line */
1229 )
1230{
1231 return XLALUserVarGetLogEx ( format, 1 );
1232}
1233
1234/**
1235 * Return a log-string representing the <em>complete</em> user-input.
1236 */
1237CHAR *
1238XLALUserVarGetLogEx ( UserVarLogFormat format, /**< output format: return as config-file or command-line */
1239 const BOOLEAN skip_unset /**< if true, do not include unset variables in output */
1240 )
1241{
1242 XLAL_CHECK_NULL ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
1244
1245 CHAR *record = NULL;
1246
1247 switch (format)
1248 {
1251 XLAL_CHECK_NULL ( ( record = XLALStringAppend ( record, program_path ) ) != NULL, XLAL_EFUNC );
1252 break;
1253
1254 default:
1255 break;
1256 }
1257
1258 LALUserVariable *ptr = &UVAR_vars;
1259 while ( (ptr = ptr->next) )
1260 {
1261 if ( skip_unset && ! ptr->was_set ) { // skip unset variables
1262 continue;
1263 }
1264 if ( ! ptr->cvar ) { // skip defunct variables
1265 continue;
1266 }
1267
1268 CHAR *valstr = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].printer_cdata( ptr->cvar, ptr->cdata ) : UserVarTypeMap [ ptr->type ].printer( ptr->cvar );
1269 XLAL_CHECK_NULL ( valstr != NULL, XLAL_EFUNC );
1270
1271 switch (format)
1272 {
1274 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "\n%s\t%s", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1275 break;
1276
1278 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "%s = %s;\n", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1279 break;
1280
1282 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, " --%s=%s", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1283 break;
1284
1286 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "--%s = %s :%s;", ptr->name, valstr, UserVarTypeMap[ptr->type].name ) ) != NULL, XLAL_EFUNC );
1287 break;
1288
1289 default:
1290 XLAL_ERROR_NULL ( XLAL_EINVAL, "Unknown format for recording user-input: '%i'\n", format );
1291 break;
1292 } // switch (format)
1293
1294 XLALFree (valstr);
1295 } // while ptr=ptr->next
1296
1297 return record;
1298
1299} // XLALUserVarGetLog()
int XLALReadConfigSTRINGVariable(CHAR **varp, LALParsedDataFile *cfgdata, const CHAR *secName, const CHAR *varName, BOOLEAN *wasRead)
String parser for config-file: can read config-variables of the form VARIABLE [=:] VALUE.
Definition: ConfigFile.c:277
static const size_t prefix
Definition: LALMalloc.c:256
#define LALCalloc(m, n)
Definition: LALMalloc.h:94
char * XLALStringAppendFmt(char *s, const char *fmt,...)
Append the formatted string 'fmt' to the string 's', which is reallocated with XLALRealloc() to the r...
Definition: LALString.c:69
int LALgetopt_long(int argc, char *const *argv, const char *options, const struct LALoption *long_options, int *opt_index)
Definition: LALgetopt.c:178
int LALoptind
Definition: LALgetopt.c:79
char * LALoptarg
Definition: LALgetopt.c:64
#define required_argument
Definition: LALgetopt.h:101
#define optional_argument
Definition: LALgetopt.h:102
#define STRING(a)
Definition: PrintVector.c:12
#define fprintf
#define REGULAR_MAP_ENTRY(UTYPE, DESTRUCTOR, FORMATHELP)
Definition: UserInput.c:160
int XLALUserVarPrintHelp(FILE *file)
Print help page.
Definition: UserInput.c:875
format_help_cdataT format_help_cdata
function returning describing format of user variable (with auxilliary data)
Definition: UserInput.c:200
static CHAR * program_name
Definition: UserInput.c:242
static const struct @12 UserVarTypeMap[UVAR_TYPE_END]
int(* parser_cdataT)(void *cvar, const void *cdata, const char *valstr)
Definition: UserInput.c:155
char *(* printerT)(const void *cvar)
Definition: UserInput.c:154
printerT printer
'printer' function returning string value for given type
Definition: UserInput.c:196
char *(* printer_cdataT)(const void *cvar, const void *cdata)
Definition: UserInput.c:156
void XLALUserVarCheck(BOOLEAN *should_exit, const int assertion, const CHAR *fmt,...)
If assertion is false, print the given error message, then the help usage; should_exit is then set to...
Definition: UserInput.c:1206
static LALUserVariable UVAR_vars
Definition: UserInput.c:240
static CHAR * program_path
Definition: UserInput.c:241
destructorT destructor
destructor for this variable type, NULL if none required
Definition: UserInput.c:194
parserT parser
parser function to parse string as this type
Definition: UserInput.c:195
#define DEFN_REGISTER_UVAR(UTYPE, CTYPE)
Definition: UserInput.c:55
int(* parserT)(void *cvar, const char *valstr)
Definition: UserInput.c:153
void(* destructorT)(void *cvar)
Definition: UserInput.c:152
static void format_user_var_names(char *s)
Definition: UserInput.c:769
UserVarType
Definition: UserInput.c:71
@ UVAR_TYPE_REAL8Vector
Definition: UserInput.c:96
@ UVAR_TYPE_DECJRange
Definition: UserInput.c:89
@ UVAR_TYPE_UINT4Vector
Definition: UserInput.c:95
@ UVAR_TYPE_UserFlag
Definition: UserInput.c:92
@ UVAR_TYPE_UINT8
Definition: UserInput.c:78
@ UVAR_TYPE_EPOCHRange
Definition: UserInput.c:87
@ UVAR_TYPE_REAL8
Definition: UserInput.c:79
@ UVAR_TYPE_STRINGVector
Definition: UserInput.c:97
@ UVAR_TYPE_INT8
Definition: UserInput.c:76
@ UVAR_TYPE_DECJ
Definition: UserInput.c:82
@ UVAR_TYPE_EPOCH
Definition: UserInput.c:80
@ UVAR_TYPE_START
Definition: UserInput.c:72
@ UVAR_TYPE_END
Definition: UserInput.c:99
@ UVAR_TYPE_STRING
Definition: UserInput.c:83
@ UVAR_TYPE_INT4Vector
Definition: UserInput.c:94
@ UVAR_TYPE_UINT4
Definition: UserInput.c:77
@ UVAR_TYPE_RAJRange
Definition: UserInput.c:88
@ UVAR_TYPE_UserEnum
Definition: UserInput.c:91
@ UVAR_TYPE_INT4
Definition: UserInput.c:75
@ UVAR_TYPE_REAL8Range
Definition: UserInput.c:86
@ UVAR_TYPE_INT4Range
Definition: UserInput.c:85
@ UVAR_TYPE_RAJ
Definition: UserInput.c:81
@ UVAR_TYPE_BOOLEAN
Definition: UserInput.c:74
char *(* format_help_cdataT)(const void *cdata)
Definition: UserInput.c:157
#define DEFN_REGISTER_UVAR_AUX_DATA(UTYPE, CTYPE, DTYPE)
Definition: UserInput.c:57
const char *const format_help_str
help string describing format of user variable
Definition: UserInput.c:197
#define TRUE
Definition: UserInput.c:48
#define FALSE
Definition: UserInput.c:49
int XLALUserVarPrintUsage(FILE *file)
Print a one-line usage string.
Definition: UserInput.c:729
printer_cdataT printer_cdata
'printer' function (with auxilliary data) returning string value for given type
Definition: UserInput.c:199
const char *const name
type name
Definition: UserInput.c:193
static void fprint_wrapped(FILE *f, int line_width, const char *prefix, char *text)
Definition: UserInput.c:785
parser_cdataT parser_cdata
parser function (with auxilliary data) to parse string as this type
Definition: UserInput.c:198
#define REGULAR_MAP_ENTRY_AUX_DATA(UTYPE, DESTRUCTOR, DTYPE)
Definition: UserInput.c:168
int XLALPrintWarning(const char *fmt,...)
Definition: XLALError.c:79
int XLALPrintError(const char *fmt,...)
Definition: XLALError.c:68
static double f(double theta, double y, double xi)
Definition: XLALMarcumQ.c:258
int XLALParseDataFile(LALParsedDataFile **cfgdata, const CHAR *path)
Parse an ASCII data-file into a pre-cleaned array of lines.
Definition: ConfigFile.c:65
UINT4Vector * XLALConfigFileGetUnreadEntries(const LALParsedDataFile *cfgdata)
Return a list of unread config-file entries, NULL if none found (without error).
Definition: ConfigFile.c:398
void XLALDestroyParsedDataFile(LALParsedDataFile *cfgdata)
Free memory associated with a LALParsedDataFile structure.
Definition: ConfigFile.c:147
unsigned char BOOLEAN
Boolean logical type, see Headers LAL(Atomic)Datatypes.h for more details.
#define XLAL_NUM_ELEM(x)
MACRO which gives the number of elements in a fixed-size array.
uint64_t UINT8
Eight-byte unsigned integer; on some platforms this is equivalent to unsigned long int instead.
double REAL8
Double precision real floating-point number (8 bytes).
int64_t INT8
Eight-byte signed integer; on some platforms this is equivalent to long int instead.
char CHAR
One-byte signed integer, see Headers LAL(Atomic)Datatypes.h for more details.
uint32_t UINT4
Four-byte unsigned integer.
int32_t INT4
Four-byte signed integer.
#define XLALCalloc(m, n)
Definition: LALMalloc.h:45
#define XLALFree(p)
Definition: LALMalloc.h:47
char * XLALStringDuplicate(const char *s)
Like strdup but uses LAL allocation routines (free with LALFree).
Definition: LALString.c:89
char * XLALStringAppend(char *s, const char *append)
Like strcat but dynamically reallocates string with LALRealloc.
Definition: LALString.c:50
char * XLALStringReplaceChar(char *s, const int from, const int to)
Return the string 's' with all characters 'from' replaced with 'to'.
Definition: LALString.c:382
char * XLALVCSInfoString(const LALVCSInfoList vcs_list, const int verbose, const char *prefix)
Generate a multi-line string containing VCS and build information for a library and its dependencies,...
const LALVCSInfo *const LALVCSInfoList[16]
NULL-terminated list of VCS and build information structures
void XLALDestroyStringVector(LALStringVector *vect)
XLAL-interface: Free a string-vector ;)
Definition: StringVector.c:204
const char * lalUserVarHelpOptionSubsection
An optional subsection heading under OPTIONS, under which all subsequently-defined user variables are...
Definition: UserInput.c:258
const char * lalUserVarHelpBrief
An optional brief description of the program, printed after its name as part of the help page.
Definition: UserInput.c:248
#define UVAR_FMT
Definition: UserInput.h:264
UserVarLogFormat
Format for logging User-input: configFile- or cmdLine-style.
Definition: UserInput.h:201
int XLALUserVarReadAllInput(BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list)
Put all the pieces together, and basically does everything: print help (if requested),...
Definition: UserInput.c:1064
void XLALDestroyUserVars(void)
Free all memory associated with user-variable linked list.
Definition: UserInput.c:349
int XLALRegisterUserVar(void *cvar, const void *cdata, const CHAR *name, UserVarType type, CHAR optchar, UserVarCategory category, const CHAR *help)
Internal function: Register a user-variable with the module.
Definition: UserInput.c:275
CHAR * XLALUserVarGetLogEx(UserVarLogFormat format, const BOOLEAN skip_unset)
Return a log-string representing the complete user-input.
Definition: UserInput.c:1238
UserVarCategory
Mutually-exclusive user variable categories: optional, required, help, developer, ....
Definition: UserInput.h:185
int XLALUserVarReadCmdline(BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list)
Parse command-line into UserVariable array.
Definition: UserInput.c:394
CHAR * XLALUserVarGetLog(UserVarLogFormat format)
Return a log-string representing the complete user-input.
Definition: UserInput.c:1228
const char * lalUserVarHelpDescription
An optional longer description of the program, printed in its own section as part of the help page.
Definition: UserInput.c:253
int XLALUserVarWasSet(const void *cvar)
Has this user-variable been set by the user? returns 1 (=TRUE) or 0 (=FALSE) on success,...
Definition: UserInput.c:1175
int XLALUserVarReadCfgfile(BOOLEAN *should_exit, const CHAR *cfgfile)
Read config-variables from cfgfile and parse into input-structure.
Definition: UserInput.c:647
@ UVAR_LOGFMT_RAWFORM
return UserVars in a raw format suitable for further parsing
Definition: UserInput.h:202
@ UVAR_LOGFMT_CMDLINE
return UserVars as a command-line
Definition: UserInput.h:204
@ UVAR_LOGFMT_LAST
Definition: UserInput.h:206
@ UVAR_LOGFMT_PROCPARAMS
return UserVars suitable for filling in process-params struct
Definition: UserInput.h:205
@ UVAR_LOGFMT_CFGFILE
return UserVars as a config-file
Definition: UserInput.h:203
@ UVAR_CATEGORY_START
internal start marker for range checking
Definition: UserInput.h:186
@ UVAR_CATEGORY_REQUIRED
required
Definition: UserInput.h:189
@ UVAR_CATEGORY_DEFUNCT
hidden completely from help output; not supported, will output error + help-string if used
Definition: UserInput.h:192
@ UVAR_CATEGORY_NODEFAULT
optional and supresses printing the default value in the help, where it doesn't make sense
Definition: UserInput.h:193
@ UVAR_CATEGORY_DEVELOPER
optional and hidden in help-output until lalDebugLevel>=warning
Definition: UserInput.h:190
@ UVAR_CATEGORY_DEPRECATED
optional and hidden until lalDebugLevel>=info; still supported but output warning if used
Definition: UserInput.h:191
@ UVAR_CATEGORY_END
internal end marker for range checking
Definition: UserInput.h:194
LIGOTimeGPS LIGOTimeGPSRange[2]
A range of GPS times; first element is minimum, second element is maximum of range.
REAL8 REAL8Range[2]
A range of REAL8 values; first element is minimum, second element is maximum of range.
INT4 INT4Range[2]
A range of INT4 values; first element is minimum, second element is maximum of range.
void XLALDestroyUINT4Vector(UINT4Vector *vector)
void XLALDestroyINT4Vector(INT4Vector *vector)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
#define XLAL_ERROR_NULL(...)
Macro to invoke a failure from a XLAL routine returning a pointer.
Definition: XLALError.h:713
#define xlalErrno
Modifiable lvalue containing the XLAL error number.
Definition: XLALError.h:571
#define XLAL_CHECK(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns an integ...
Definition: XLALError.h:810
#define XLAL_CHECK_VOID(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns void.
Definition: XLALError.h:840
#define XLAL_CHECK_FAIL(assertion,...)
Macro to test an assertion and invoke a failure if it is not true by jumping to a XLAL_FAIL label.
Definition: XLALError.h:900
#define XLAL_CHECK_NULL(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns a pointe...
Definition: XLALError.h:825
@ XLAL_ENOMEM
Memory allocation error.
Definition: XLALError.h:407
@ XLAL_SUCCESS
Success return value (not an error number)
Definition: XLALError.h:401
@ XLAL_EFAULT
Invalid pointer.
Definition: XLALError.h:408
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
@ XLAL_EERR
Internal error.
Definition: XLALError.h:443
@ XLAL_EINVAL
Invalid argument.
Definition: XLALError.h:409
@ XLAL_EFAILED
Generic failure.
Definition: XLALError.h:418
@ XLAL_FAILURE
Failure return value (not an error number)
Definition: XLALError.h:402
Vector of type INT4, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:109
This structure is returned by XLALParseDataFile() and holds the contents of an ASCII data-file in a p...
Definition: ConfigFile.h:107
TokenList * lines
list of pre-parsed data-file lines
Definition: ConfigFile.h:108
Vector of type CHAR*, ie 'strings', see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:82
BOOLEAN was_set
Definition: UserInput.c:114
CHAR name[64]
Definition: UserInput.c:106
const void * cdata
Definition: UserInput.c:112
UserVarCategory category
Definition: UserInput.c:113
UserVarType type
Definition: UserInput.c:107
const CHAR * subsection
Definition: UserInput.c:109
CHAR help[2048]
Definition: UserInput.c:110
struct tagLALUserVariable * next
Definition: UserInput.c:115
int has_arg
Definition: LALgetopt.h:89
int val
Definition: LALgetopt.h:91
const char * name
Definition: LALgetopt.h:86
int * flag
Definition: LALgetopt.h:90
Epoch relative to GPS epoch, see LIGOTimeGPS type for more details.
Definition: LALDatatypes.h:458
Vector of type REAL8, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:154
CHAR ** tokens
A list of pointers to the individual tokens; the elements tokens[0..nTokens-1] point to tokens,...
Definition: StringInput.h:137
Vector of type UINT4, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:118
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:122
UINT4 * data
Pointer to the data array.
Definition: LALDatatypes.h:123
Possible choices the user may select for an enumeration or bitflag.
int verbose
Definition: tconvert.c:103