LAL 7.7.0.1-eeff03c
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; use the pattern
185// int XLALRegister<UTYPE>UserVar ( <CTYPE> *cvar, const <DTYPE> *cdata, const CHAR *name, CHAR optchar, UserVarCategory category, const CHAR *fmt, ... ) _LAL_GCC_PRINTF_FORMAT_(6,7)
186// where
187// CTYPE is the C type of the user variable,
188// DTYPE is either
189// void - for normal user variables, where the value of the command line argumet is used directly
190// UserChoices - for enum user variables, where the value of the command line argument is used to select a named enum value from a list
191// 4) add an entry in the master map 'UserInputTypeMap', specifying the parser, printer and (if required) a destructor
192// If these follow the standard naming and API, the template macro REGULAR_MAP_ENTRY() can be used for that.
193//
194// ---------- Master 'map' defining all UserInput types and how to handle them ----------
195// in particular, lists their name, and how to parse and print them, and (if required) how to destroy them
196static const struct
197{
198 const char *const name; ///< type name
199 destructorT destructor; ///< destructor for this variable type, NULL if none required
200 parserT parser; ///< parser function to parse string as this type
201 printerT printer; ///< 'printer' function returning string value for given type
202 const char *const format_help_str; ///< help string describing format of user variable
203 parser_cdataT parser_cdata; ///< parser function (with auxilliary data) to parse string as this type
204 printer_cdataT printer_cdata; ///< 'printer' function (with auxilliary data) returning string value for given type
205 format_help_cdataT format_help_cdata; ///< function returning describing format of user variable (with auxilliary data)
207= {
208 // either use 'manual' entries of the form
209 // [UVAR_TYPE_<UTYPE>] = {
210 // .name = "<UTYPE>", .destructor = (destructorT)XLALDestroy<UTYPE>, .format_help_str = "=help string for <UTYPE>",
211 // .parser = (parserT)XLALParseStringValueAs<UTYPE>, .printer = (printerT)XLALPrintStringValueOf<UTYPE>,
212 // },
213 // or the convenience macro for cases using 'standard' function names and API
214 // REGULAR_MAP_ENTRY ( <UTYPE>, XLALDestroy<UTYPE>, "=help string for <UTYPE>" ),
215 // REGULAR_MAP_ENTRY_AUX_DATA ( <UTYPE>, XLALDestroy<UTYPE>, XLALFormatHelpStringOf<UTYPE> ),
216
217 REGULAR_MAP_ENTRY ( BOOLEAN, NULL, "[=(TRUE|FALSE)|(YES|NO)|(1|0)]" ),
218 REGULAR_MAP_ENTRY ( INT4, NULL, "=<4-byte signed integer>" ),
219 REGULAR_MAP_ENTRY ( INT8, NULL, "=<8-byte signed integer>" ),
220 REGULAR_MAP_ENTRY ( UINT4, NULL, "=<4-byte unsigned integer>" ),
221 REGULAR_MAP_ENTRY ( UINT8, NULL, "=<8-byte unsigned integer>" ),
222 REGULAR_MAP_ENTRY ( REAL8, NULL, "=<8-byte real>" ),
223 REGULAR_MAP_ENTRY ( STRING, XLALFree, "=<string>" ),
224 REGULAR_MAP_ENTRY ( EPOCH, NULL, "=<seconds>[.<frac-seconds>][GPS] | <days>[.<frac-days>]MJD" ),
225 REGULAR_MAP_ENTRY ( RAJ, NULL, "=<radians>|<hours>:<minutes>:<seconds>" ),
226 REGULAR_MAP_ENTRY ( DECJ, NULL, "=<radians>|<degrees>:<minutes>:<seconds>" ),
227
228 REGULAR_MAP_ENTRY ( INT4Range, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<4-byte signed integer>" ),
229 REGULAR_MAP_ENTRY ( REAL8Range, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<8-byte real>" ),
230 REGULAR_MAP_ENTRY ( EPOCHRange, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<seconds>[.<frac-seconds>][GPS] | <days>[.<frac-days>]MJD" ),
231 REGULAR_MAP_ENTRY ( RAJRange, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<radians>|<hours>:<minutes>:<seconds>" ),
232 REGULAR_MAP_ENTRY ( DECJRange, NULL, "=<start>[,<end>|/<band>|~<plus-minus>] where <>=<radians>|<degrees>:<minutes>:<seconds>" ),
233
234 REGULAR_MAP_ENTRY_AUX_DATA ( UserEnum, NULL, UserChoices ),
235 REGULAR_MAP_ENTRY_AUX_DATA ( UserFlag, NULL, UserChoices ),
236
237 REGULAR_MAP_ENTRY ( INT4Vector, XLALDestroyINT4Vector, "=<4-byte signed integer>,..." ),
238 REGULAR_MAP_ENTRY ( UINT4Vector, XLALDestroyUINT4Vector, "=<4-byte unsigned integer>,..." ),
239 REGULAR_MAP_ENTRY ( REAL8Vector, XLALDestroyREAL8Vector, "=<8-byte real>,..." ),
240 REGULAR_MAP_ENTRY ( STRINGVector, XLALDestroyStringVector, "=<string>,..." ),
242
243
244// ---------- The module-local linked list to hold the user-variables
245static LALUserVariable UVAR_vars; // empty head
246static CHAR *program_path = NULL; // keep a pointer to the program path
247static CHAR *program_name = NULL; // keep a pointer to the program name
248
249
250/**
251 * An optional brief description of the program, printed after its name as part of the help page.
252 */
253const char *lalUserVarHelpBrief = NULL;
254
255/**
256 * An optional longer description of the program, printed in its own section as part of the help page.
257 */
258const char *lalUserVarHelpDescription = NULL;
259
260/**
261 * An optional subsection heading under \e OPTIONS, under which all subsequently-defined user variables are printed as part of the help page.
262 */
264
265
266// ==================== Function definitions ====================
267
268/**
269 * \ingroup UserInput_h
270 * Internal function: Register a user-variable with the module.
271 * Effectively put an appropriate entry into UVAR_vars
272 *
273 * Checks that long- and short-options are unique, an error is returned
274 * if a previous option name collides.
275 *
276 * \note don't use this function directly, as it is not type-safe!!
277 * ==> use the type-safe macro XLALRegisterUvarMember(name,type,option,category,help) instead!
278 */
279int
280XLALRegisterUserVar ( void *cvar, /**< pointer to the actual C-variable to link to this user-variable */
281 const void *cdata, /**< pointer to auxilliary data needed to parse the C-variable */
282 const CHAR *name, /**< name of user-variable to register */
283 UserVarType type, /**< variable type (int,bool,string,real) */
284 CHAR optchar, /**< optional short-option character */
285 UserVarCategory category, /**< sets category to this */
286 const CHAR *help /**< help-string explaining this input-variable */
287 )
288{
289 XLAL_CHECK ( cvar != NULL || category == UVAR_CATEGORY_DEFUNCT, XLAL_EINVAL );
290 XLAL_CHECK ( name != NULL, XLAL_EINVAL );
291 XLAL_CHECK ( strlen(name) < sizeof(UVAR_vars.name), XLAL_EINVAL, "User-variable name '%s' is too long", name );
292 XLAL_CHECK ( (category > UVAR_CATEGORY_START) && (category < UVAR_CATEGORY_END), XLAL_EINVAL );
293 XLAL_CHECK ( help != NULL, XLAL_EINVAL );
294 XLAL_CHECK ( strlen(help) < sizeof(UVAR_vars.help), XLAL_EINVAL, "User-variable help '%s' is too long", help );
295
296 // check that UserVarTypeMap entry is correct
297 XLAL_CHECK ( ( cdata != NULL ? (const void*)UserVarTypeMap [ type ].parser_cdata : (const void*)UserVarTypeMap [ type ].parser ) != NULL, XLAL_EERR );
298 XLAL_CHECK ( ( cdata != NULL ? (const void*)UserVarTypeMap [ type ].printer_cdata : (const void*)UserVarTypeMap [ type ].printer ) != NULL, XLAL_EERR );
299 XLAL_CHECK ( ( cdata != NULL ? (const void*)UserVarTypeMap [ type ].format_help_cdata : (const void*)UserVarTypeMap [ type ].format_help_str ) != NULL, XLAL_EERR );
300
301 // check that neither short- nor long-option are used by help
302 XLAL_CHECK ( strcmp ( name, "help" ) != 0, XLAL_EINVAL, "Long-option name '--%s' is reserved for help!\n", name );
303 XLAL_CHECK ( optchar != 'h', XLAL_EINVAL, "Short-option '-%c' is reserved for help!\n", optchar );
304
305 // check that neither short- nor long-option are used by version
306 XLAL_CHECK ( strcmp ( name, "version" ) != 0, XLAL_EINVAL, "Long-option name '--%s' is reserved for version!\n", name );
307 XLAL_CHECK ( optchar != 'v', XLAL_EINVAL, "Short-option '-%c' is reserved for version!\n", optchar );
308
309 // find end of uvar-list && check that neither short- nor long-option are taken already
311 while ( ptr->next != NULL )
312 {
313 ptr = ptr->next;
314
315 // long-option name taken already?
316 XLAL_CHECK ( strcmp ( name, ptr->name ) != 0, XLAL_EINVAL, "Long-option name '--%s' already taken!\n", name );
317 // short-option character taken already?
318 XLAL_CHECK ( (optchar == 0) || (ptr->optchar == 0) || (optchar != ptr->optchar), XLAL_EINVAL, "Short-option '-%c' already taken (by '--%s')!\n", optchar, ptr->name );
319
320 } // while ptr->next
321
322 // append new entry at the end
323 XLAL_CHECK ( (ptr->next = XLALCalloc (1, sizeof(LALUserVariable))) != NULL, XLAL_ENOMEM );
324
325 // set pointer to newly created entry
326 ptr = ptr->next;
327
328 // copy entry name, replacing '_' with '-' so that
329 // e.g. uvar->a_long_option maps to --a-long-option
330 XLALStringReplaceChar( strncpy( ptr->name, name, sizeof(ptr->name) - 1 ), '_', '-' );
331
332 // copy current subsection heading
334
335 // copy entry help string
336 strncpy( ptr->help, help, sizeof(ptr->help) - 1 );
338
339 // fill in entry values
340 ptr->type = type;
341 ptr->optchar = optchar;
342 ptr->cvar = category == UVAR_CATEGORY_DEFUNCT ? NULL : cvar;
343 ptr->cdata = cdata;
344 ptr->category = category;
345
346 return XLAL_SUCCESS;
347
348} // XLALRegisterUserVar()
349
350/**
351 * Free all memory associated with user-variable linked list
352 */
353void
355{
356 LALUserVariable *ptr = &(UVAR_vars);
357 LALUserVariable *lastptr = NULL;
358
359 // step through user-variables: free list-entries and all allocated strings
360 while ( (ptr=ptr->next) != NULL )
361 {
362 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 );
363
364 // is there a destructor function registered for this type?
365 if ( UserVarTypeMap [ ptr->type ].destructor != NULL )
366 if ( ptr->cvar ) {
367 UserVarTypeMap [ ptr->type ].destructor ( *(CHAR**)ptr->cvar );
368 *(CHAR**)ptr->cvar = NULL;
369 }
370
371 /* free list-entry behind us (except for the head) */
372 if ( lastptr != NULL ) {
373 XLALFree ( lastptr );
374 }
375
376 lastptr = ptr;
377
378 } // while ptr->next
379
380 if ( lastptr != NULL ) {
381 XLALFree ( lastptr );
382 }
383
384 // clean head
385 memset (&UVAR_vars, 0, sizeof(UVAR_vars));
386
387 return;
388
389} /* XLALDestroyUserVars() */
390
391
392/**
393 * Parse command-line into UserVariable array
394 *
395 * If \p *should_exit is TRUE when this function returns, the
396 * caller should exit immediately.
397 */
398int
399XLALUserVarReadCmdline ( BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list )
400{
401 XLAL_CHECK ( should_exit != NULL, XLAL_EFAULT );
402 XLAL_CHECK ( argv != NULL, XLAL_EINVAL, "Input error, NULL argv[] pointer passed.\n" );
403 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "Internal error, no UVAR memory allocated. Did you register any user-variables?" );
404
405 *should_exit = 0;
406
407 LALUserVariable *ptr;
408 UINT4 pos;
409
410 // ---------- build optstring of short-options
411 UINT4 numvars = 0;
412 char optstring[512] = "\0"; // string of short-options
413 pos = 0;
414
415 // add special version option
416 optstring[pos++] = 'v';
417 optstring[pos++] = ':';
418 optstring[pos++] = ':';
419
420 // add user-specified options
421 ptr = &UVAR_vars; // set to empty head
422 while ( (ptr = ptr->next) != NULL )
423 {
424 numvars ++; /* counter number of user-variables */
425 if (ptr->optchar == 0) { /* if no short-option given, ignore */
426 continue;
427 }
428 optstring[pos++] = ptr->optchar;
429 optstring[pos++] = ':'; /* everything but bool takes an argument */
430 if (ptr->type == UVAR_TYPE_BOOLEAN) { /* but for BOOL its optional */
431 optstring[pos++] = ':';
432 }
433 } // while ptr->next
434
435 // null-terminate array
436 optstring[pos] = '\0';
437
438 // ---------- fill option-struct for long-options
439 struct LALoption *long_options = LALCalloc (1, (numvars+2) * sizeof(struct LALoption));
440 pos = 0;
441
442 // add special version option
443 long_options[pos].name = "version";
444 long_options[pos].has_arg = optional_argument;
445 long_options[pos].flag = NULL;
446 long_options[pos].val = 0;
447 pos ++;
448
449 // add user-specified options
450 ptr = &UVAR_vars; // start again from beginning: empty head
451 while ( (ptr= ptr->next) != NULL)
452 {
453 long_options[pos].name = ptr->name;
454 long_options[pos].has_arg = (ptr->type == UVAR_TYPE_BOOLEAN) ? optional_argument : required_argument;
455 long_options[pos].flag = NULL; // get val returned from LALgetopt_long()
456 long_options[pos].val = 0; // we use longindex to find long-options
457 pos ++;
458 } // while ptr->next
459
460 // null-terminate array
461 long_options[pos].name = 0;
462 long_options[pos].has_arg = 0;
463 long_options[pos].flag = 0;
464 long_options[pos].val = 0;
465
466 /* NOTE: in case we get called several times, we have to make sure here that getopt() gets
467 * properly reset/initialized. We do this using the (undocumented) feature of GNU getopt
468 * of setting optind to 0. As we're linking our private version of GNU getopt, this should be
469 * guaranteed to work.
470 *
471 * Bruce's notes: read LALgetopt_long() source code, and in particular
472 * _getopt_internal() to see what is initialized.
473 */
474 LALoptind = 0; // reset our local LALgetopt(), LALgetopt_long()
475
476 // ---------- parse the command-line
477 while ( 1 )
478 {
479
480 // call LALgetopt_long()
481 char *old_argv0 = argv[0];
482 argv[0] = program_name; // use program_name for LALgetopt_long() error messages
483 int longindex = -1;
484 int c = LALgetopt_long(argc, argv, optstring, long_options, &longindex);
485 argv[0] = old_argv0;
486 if ( c == -1 ) { // LALgetopt_long() is done
487 break;
488 }
489 if ( c == '?' || c == ':' ) { // LALgetopt_long() returned an error
491 *should_exit = 1;
492 return XLAL_SUCCESS;
493 }
494
495 // handle special version option
496 if ( (c != 0) ? (c == 'v') : !strcmp(long_options[longindex].name, "version") )
497 {
498 int verbose = 0;
499 if ( LALoptarg != NULL )
500 {
501 if ( !strcmp(LALoptarg, "verbose") )
502 {
503 verbose = 1;
504 }
505 else
506 {
507 XLALPrintError( "\n%s: invalid value '%s' given to option " UVAR_FMT "\n\n", program_name, LALoptarg, "version" );
508 *should_exit = 1;
509 return XLAL_SUCCESS;
510 }
511 }
512 char *str = XLALVCSInfoString( vcs_list, verbose, NULL );
513 XLAL_CHECK( str != NULL, XLAL_EFUNC );
514 printf( "%s", str );
515 XLALFree( str );
516 *should_exit = 1;
517 return XLAL_SUCCESS;
518 }
519
520 if (c != 0) // find short-option character
521 {
522 ptr = &UVAR_vars;
523 do {
524 if (c == ptr->optchar) {
525 break;
526 }
527 } while ( (ptr=ptr->next) != NULL);
528 } // end: if short-option given
529 else // find long-option: returned in longindex
530 {
531 ptr = &UVAR_vars;
532 while ( (ptr=ptr->next) != NULL) {
533 if ( !strcmp (long_options[longindex].name, ptr->name) ) {
534 break;
535 }
536 }
537 } // end: if long-option
538
539 XLAL_CHECK ( ptr != NULL, XLAL_EFAILED, "ERROR: failed to find matching option ... this points to a coding-error!\n" );
540 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 );
541
542 switch (ptr->type)
543 {
545 // subtlety with optional arguments: it's not necessarily found in the *same* argv-entry
546 // eg, if no '=' was used, so we have to check for that case by hand:
547 // if the next entry is not an option, take it as an argument
548 if ( (LALoptarg == NULL) && (LALoptind < argc) && (argv[LALoptind][0] != '-') && (argv[LALoptind][0] != '@') )
549 {
550 LALoptarg = argv[LALoptind];
551 LALoptind ++;
552 }
553
554 if ( LALoptarg == NULL ) { // if no argument given, defaults to TRUE
555 if ( ptr->cvar ) {
556 *(BOOLEAN*)(ptr->cvar) = TRUE;
557 }
558 } else {
559 if ( LALoptarg == NULL || strlen(LALoptarg) == 0 )
560 {
561 XLALPrintError( "\n%s: no value given to option " UVAR_FMT "\n\n", program_name, ptr->name );
562 *should_exit = 1;
563 return XLAL_SUCCESS;
564 }
565 if ( ptr->cvar )
566 {
567 int retn = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].parser_cdata( ptr->cvar, ptr->cdata, LALoptarg ) : UserVarTypeMap [ ptr->type ].parser( ptr->cvar, LALoptarg );
568 if ( retn != XLAL_SUCCESS )
569 {
570 XLALPrintError( "\n%s: could not parse value '%s' given to option " UVAR_FMT "\n\n", program_name, LALoptarg, ptr->name );
571 *should_exit = 1;
572 return XLAL_SUCCESS;
573 }
574 }
575 }
576 break;
577
578 default:
579 // all other UVAR_TYPE_ types can be handled canonically: first destroy previous value, the parse new one
580 if ( UserVarTypeMap [ ptr->type ].destructor != NULL )
581 if ( ptr->cvar ) {
582 UserVarTypeMap [ ptr->type ].destructor( *(char**)ptr->cvar );
583 *(char**)ptr->cvar = NULL;
584 } // if a destructor was registered
585 if ( LALoptarg == NULL || strlen(LALoptarg) == 0 )
586 {
587 XLALPrintError( "\n%s: no value given to option " UVAR_FMT "\n\n", program_name, ptr->name );
588 *should_exit = 1;
589 return XLAL_SUCCESS;
590 }
591 if ( ptr->cvar )
592 {
593 int retn = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].parser_cdata( ptr->cvar, ptr->cdata, LALoptarg ) : UserVarTypeMap [ ptr->type ].parser( ptr->cvar, LALoptarg );
594 if ( retn != XLAL_SUCCESS )
595 {
596 XLALPrintError( "\n%s: could not parse value '%s' given to option " UVAR_FMT "\n\n", program_name, LALoptarg, ptr->name );
597 *should_exit = 1;
598 return XLAL_SUCCESS;
599 }
600 }
601 break;
602
603 } // switch ptr->type
604
605 switch ( ptr->was_set ) {
606 case 0: // this variable has not been set; mark as set on command line
607 ptr->was_set = 2;
608 break;
609 case 1: // this variable has been set in configuration file; print warning
610 XLALPrintError ( "\n%s: option " UVAR_FMT " is overriding value set in configuration file!\n\n", program_name, ptr->name );
611 break;
612 default: // this variable has been set before; error
613 XLALUserVarCheck( should_exit, 0, "option " UVAR_FMT " was set more than once!", ptr->name );
614 return XLAL_SUCCESS;
615 }
616
617 } // while LALgetopt_long()
618
619 // ---------- check if there's any non-option strings left (except for a config-file specification '@file')
620 if ( (LALoptind == argc - 1) && (argv[LALoptind][0] == '@' ) ) {
621 LALoptind ++; // advance counter in case of one config-file specification (only one allowed)
622 }
623 if ( LALoptind < argc ) // still stuff left? ==> error
624 {
625 XLALPrintError ( "\nGot non-option ARGV-elements: [ ");
626 while (LALoptind < argc) {
627 if ( argv[LALoptind][0] == '@' ) { LALoptind ++; continue; } // don't list config-file entries here
628 XLALPrintError ("%s ", argv[LALoptind++]);
629 }
630 XLALPrintError(" ]\n");
631 *should_exit = 1;
632 return XLAL_SUCCESS;
633 } // trailing non-option arguments found
634
635 XLALFree (long_options);
636 long_options=NULL;
637
638 return XLAL_SUCCESS;
639
640} // XLALUserVarReadCmdline()
641
642
643/**
644 * Read config-variables from cfgfile and parse into input-structure.
645 * An error is reported if the config-file reading fails, but the
646 * individual variable-reads are treated as optional
647 *
648 * If \p *should_exit is TRUE when this function returns, the
649 * caller should exit immediately.
650 */
651int
652XLALUserVarReadCfgfile ( BOOLEAN *should_exit, const CHAR *cfgfile )
653{
654 XLAL_CHECK ( should_exit != NULL, XLAL_EFAULT );
655 XLAL_CHECK ( cfgfile != NULL, XLAL_EINVAL );
656 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No memory allocated in UVAR_vars.next, did you register any user-variables?\n" );
657
658 *should_exit = 0;
659
660 LALParsedDataFile *cfg = NULL;
661 XLAL_CHECK ( XLALParseDataFile ( &cfg, cfgfile ) == XLAL_SUCCESS, XLAL_EFUNC );
662
663 // step through all user-variable: read those with names from config-file
665 while ( (ptr=ptr->next) != NULL)
666 {
667
668 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 );
669
670 BOOLEAN wasRead;
671 CHAR *valString = NULL; // first read the value as a string
672 XLAL_CHECK ( XLALReadConfigSTRINGVariable ( &valString, cfg, NULL, ptr->name, &wasRead ) == XLAL_SUCCESS, XLAL_EFUNC );
673 if ( wasRead ) // if successful, parse this as the desired type
674 {
675 // destroy previous value, is applicable, then parse new one
676 if ( UserVarTypeMap [ ptr->type ].destructor != NULL )
677 if ( ptr->cvar ) {
678 UserVarTypeMap [ ptr->type ].destructor( *(char**)ptr->cvar );
679 *(char**)ptr->cvar = NULL;
680 } // if a destructor was registered
681 if ( valString == NULL || strlen(valString) == 0 )
682 {
683 XLALPrintError( "\n%s: no value given to option " UVAR_FMT "\n\n", program_name, ptr->name );
684 *should_exit = 1;
685 return XLAL_SUCCESS;
686 }
687 if ( ptr->cvar )
688 {
689 int retn = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].parser_cdata( ptr->cvar, ptr->cdata, valString ) : UserVarTypeMap [ ptr->type ].parser( ptr->cvar, valString );
690 if ( retn != XLAL_SUCCESS )
691 {
692 XLALPrintError( "\n%s: could not parse value '%s' given to option " UVAR_FMT "\n\n", program_name, valString, ptr->name );
693 *should_exit = 1;
694 return XLAL_SUCCESS;
695 }
696 }
697 XLALFree (valString);
698
699 switch ( ptr->was_set ) {
700 case 0: // this variable has not been set; mark as set in configuration file
701 ptr->was_set = 1;
702 break;
703 default: // this variable has been set before; error
704 XLALUserVarCheck( should_exit, 0, "configuration option `%s' was set more than once!", ptr->name );
705 return XLAL_SUCCESS;
706 }
707
708 } // if wasRead
709
710 } // while ptr->next
711
712 // ok, that should be it: check if there were more definitions we did not read
714 XLAL_CHECK ( xlalErrno == 0, XLAL_EFUNC, "XLALConfigFileGetUnreadEntries() failed\n");
715 if ( unread != NULL )
716 {
717 XLALPrintWarning ("The following entries in config-file '%s' have not been parsed:\n", cfgfile );
718 for ( UINT4 i = 0; i < unread->length; i ++ ) {
719 XLALPrintWarning ("%s\n", cfg->lines->tokens[ unread->data[i] ] );
720 }
721 XLALDestroyUINT4Vector ( unread );
722 }
723
725
726 return XLAL_SUCCESS;
727
728} // XLALUserVarReadCfgfile()
729
730/**
731 * Print a one-line usage string
732 */
733int
735{
736
737 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
738
739 /* Print usage: only required and regular arguments are printed */
740 fprintf( file, "\nUsage: %s [-h|--help] [-v|--version] [@<config-file>]", program_name );
741 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
742 {
743 switch ( ptr->category )
744 {
748 continue;
749 default:
750 break;
751 }
752 fprintf( file, " " );
753 if ( ptr->category != UVAR_CATEGORY_REQUIRED ) {
754 fprintf( file, "[" );
755 }
756 if ( ptr->optchar != 0 ) {
757 fprintf( file, "-%c|", ptr->optchar );
758 }
759 fprintf( file,"--%s", ptr->name);
760 if ( ptr->category != UVAR_CATEGORY_REQUIRED ) {
761 fprintf( file, "]" );
762 }
763 }
764 fprintf( file,"\n\n");
765
766 return XLAL_SUCCESS;
767
768} // XLALUserVarPrintUsage()
769
770/*
771 * Format strings so that `--user_variables` have '_' replaced with '-'
772 */
773void
775{
776 while ( ( s = strchr( s, '`' ) ) != NULL )
777 {
778 while ( *s != '\0' && *s != '\'' )
779 {
780 if ( *s == '_' ) *s = '-';
781 ++s;
782 }
783 }
784}
785
786/*
787 * Print text wrapped to a given line width
788 */
789void
790fprint_wrapped( FILE *file, int line_width, const char *prefix, char *text )
791{
792
793 /* Adjust line width */
794 line_width -= strlen(prefix) + 1;
795
796 /* If line width is too short, just assume very long lines */
797 if ( line_width < 1 ) {
798 line_width = INT_MAX;
799 }
800
801 /* Iterate over text */
802 char *pstart = text, *pline = text, *pbreak = NULL;
803 char empty_line[2] = "";
804 char list_indent[16] = "";
805 for ( char *pend = text; *pend != '\0'; ++pend )
806 {
807
808 /* Record position of last space, in order to break line */
809 if ( isspace( *pend ) ) {
810 pbreak = pend;
811 }
812
813 /* Determine indent for lists (lines with start with spaces/dashes) */
814 strcpy( list_indent, "" );
815 if ( pline != pstart ) {
816 for ( size_t i = 0; i + 1 < XLAL_NUM_ELEM( list_indent ) && strchr( " -", pline[i] ) != NULL; ++i ) {
817 list_indent[i] = ' ';
818 }
819 }
820
821 /* If at end of line, or encountered a newline */
822 int indented_line_width = line_width - strlen( list_indent );
823 if ( ( pend - pstart ) == indented_line_width || *pend == '\n' ) {
824
825 /* Save beginning of line for determining list indent */
826 if ( *pend == '\n' ) {
827 pline = pend + 1;
828 }
829
830 if ( pbreak != NULL ) { /* If we have a space character */
831
832 /* Print text up to before last space character */
833 const char old_pbreak = *pbreak;
834 *pbreak = '\0';
835 fprintf( file, "%s%s%s%s\n", empty_line, prefix, list_indent, pstart );
836 strcpy( empty_line, "" );
837 *pbreak = old_pbreak;
838
839 /* Save an empty line for the next time a non-empty line is printed */
840 for ( pend = pbreak + 1; *pend != '\0' && *pend == '\n'; ++pend ) {
841 strcpy( empty_line, "\n" );
842 pline = pend + 1;
843 }
844
845 /* Start from next non-printed character */
846 pstart = pend;
847
848 /* Reset space character */
849 pbreak = NULL;
850
851 } else {
852
853 /* Print unbroken line, ending with hyphen */
854 const char old_pend = *pend;
855 *pend = '\0';
856 fprintf( file, "%s%s%s%s-\n", empty_line, prefix, list_indent, pstart );
857 strcpy( empty_line, "" );
858 *pend = old_pend;
859
860 /* Start from next non-printed character */
861 pstart = pend;
862
863 }
864 }
865
866 }
867
868 /* Print remaining text */
869 if ( strlen( pstart ) > 0 ) {
870 fprintf( file, "%s%s%s%s\n", empty_line, prefix, list_indent, pstart );
871 strcpy( empty_line, "" );
872 }
873
874}
875
876/**
877 * Print help page
878 */
879int
881{
882 int retn = XLAL_FAILURE;
883 FILE *f = file;
884 int line_width = 0;
885
886 XLAL_CHECK_FAIL ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
887
888 /* Determine terminal line width, or set to zero otherwise */
889#if defined(HAVE_ISATTY) && defined(HAVE_FILENO) && defined(HAVE_IOCTL)
890#if HAVE_DECL_TIOCGWINSZ && HAVE_STRUCT_WINSIZE_WS_COL
891 if ( isatty( fileno( file ) ) ) {
892 struct winsize w;
893 ioctl( fileno( file ), TIOCGWINSZ, &w );
894 line_width = w.ws_col;
895 }
896#endif
897#endif
898
899 /* Pipe output through pager if possible */
900#if defined(PAGER) && defined(HAVE_POPEN) && defined(HAVE_PCLOSE)
901 f = popen(PAGER, "w");
902 if ( f == NULL ) {
903 f = file;
904 }
905#endif
906 fflush( f );
907
908 /* Print program name and synopsis of command line syntax */
909 fprintf( f, "\n*NAME*\n" );
910 fprintf( f, " %s", program_name );
911 if ( lalUserVarHelpBrief != NULL ) {
912 fprintf( f, " - %s", lalUserVarHelpBrief );
913 }
914 fprintf( f, "\n" );
915 fprintf( f, "\n*SYNOPSIS*\n" );
916 {
917 fprintf( f, " %s --help\n", program_name );
918 CHAR help_str[] = "Display this help page.";
919 fprint_wrapped( f, line_width, " ", help_str );
920 }
921 fprintf( f, "\n" );
922 {
923 fprintf( f, " %s -h\n", program_name );
924 CHAR help_str[] = "Display a short usage string of available options.";
925 fprint_wrapped( f, line_width, " ", help_str );
926 }
927 fprintf( f, "\n" );
928 {
929 fprintf( f, " %s -v|--version[=verbose]\n", program_name );
930 CHAR help_str[] = "Display (verbose) version information.";
931 fprint_wrapped( f, line_width, " ", help_str );
932 }
933 fprintf( f, "\n" );
934 {
935 fprintf( f, " %s [@<config-file>] [<options>...]\n", program_name );
936 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>.";
937 fprint_wrapped( f, line_width, " ", help_str );
938 }
939 if ( lalUserVarHelpDescription != NULL ) {
942 fprintf( f, "\n*DESCRIPTION*\n" );
943 fprint_wrapped( f, line_width, " ", description );
945 }
946 fprintf( f, "\n" );
947
948 /* Print options in sections */
949 const char* section_headers[] = { "OPTIONS", "DEVELOPER OPTIONS", "DEPRECATED OPTIONS" };
950 for ( size_t section = 0; section < XLAL_NUM_ELEM(section_headers); ++section )
951 {
952 BOOLEAN print_section_header = 1;
953
954 /* Go through all user variables */
955 const char *subsection = NULL;
956 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
957 {
958
959 /* Decide what section to print option in, and with what formatting */
960 size_t print_section = 0;
961 BOOLEAN print_format_help = 1, print_default_value = 1;
962 switch ( ptr->category )
963 {
965 print_section = 1;
966 break;
968 print_section = 2;
969 print_format_help = print_default_value = 0;
970 break;
972 continue;
973 default:
974 break;
975 }
976 XLAL_CHECK_FAIL( print_section < XLAL_NUM_ELEM(section_headers), XLAL_EFAILED );
977
978 if ( print_section == section )
979 {
980
981 /* Print section (and possibly subsection) headers */
982 if ( print_section_header )
983 {
984 fprintf( f, "*%s*\n", section_headers[section] );
985 print_section_header = 0;
986 }
987 if ( ptr->subsection != NULL && ( subsection == NULL || strcmp( ptr->subsection, subsection ) != 0 ) )
988 {
989 fprintf( f, "%s:\n", ptr->subsection );
990 subsection = ptr->subsection;
991 }
992
993 /* Print option, format help, and default value */
994 fprintf( f, " " );
995 if ( ptr->optchar != 0 )
996 {
997 fprintf( f, "-%c, ", ptr->optchar );
998 }
999 fprintf( f, "--%s", ptr->name );
1000 if ( print_format_help )
1001 {
1002 if ( ptr->cdata != NULL )
1003 {
1004 CHAR *format_help_str = UserVarTypeMap [ ptr->type ].format_help_cdata( ptr->cdata );
1006 fprintf( f, "%s", format_help_str );
1008 }
1009 else
1010 {
1011 fprintf( f, "%s", UserVarTypeMap [ ptr->type ].format_help_str );
1012 }
1013 }
1014 if ( print_default_value )
1015 {
1016 if ( ptr->category == UVAR_CATEGORY_REQUIRED )
1017 {
1018 fprintf( f, " [required]" );
1019 }
1020 else if ( ptr->category == UVAR_CATEGORY_NODEFAULT )
1021 {
1022 fprintf( f, " [optional]" );
1023 }
1024 else if ( ptr->cvar )
1025 {
1026 CHAR *valstr = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].printer_cdata( ptr->cvar, ptr->cdata ) : UserVarTypeMap [ ptr->type ].printer( ptr->cvar );
1027 XLAL_CHECK_FAIL( valstr != NULL, XLAL_EFUNC );
1028 fprintf( f, " [default: %s]", valstr );
1029 XLALFree( valstr );
1030 }
1031 }
1032 fprintf( f, "\n" );
1033
1034 /* Print option help string */
1035 fprint_wrapped( f, line_width, " ", ptr->help );
1036 fprintf( f, "\n" );
1037
1038 }
1039
1040 }
1041
1042 }
1043
1044 retn = XLAL_SUCCESS;
1045XLAL_FAIL:
1046
1047 /* Close pipe to pager if used */
1048 fflush( f );
1049#if defined(PAGER) && defined(HAVE_POPEN) && defined(HAVE_PCLOSE)
1050 if ( f != file ) {
1051 pclose( f );
1052 }
1053#endif
1054
1055 return retn;
1056
1057} // XLALUserVarPrintHelp()
1058
1059
1060/**
1061 * Put all the pieces together, and basically does everything:
1062 * print help (if requested), get config-filename from cmd-line (if found),
1063 * then interpret config-file and then the command-line
1064 *
1065 * If \p *should_exit is TRUE when this function returns, the
1066 * program should exit immediately with a non-zero status.
1067 */
1068int
1069XLALUserVarReadAllInput ( BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list )
1070{
1071 XLAL_CHECK ( should_exit != NULL, XLAL_EFAULT );
1072 XLAL_CHECK ( argc > 0, XLAL_EINVAL );
1073 XLAL_CHECK ( argv != NULL, XLAL_EINVAL );
1074 XLAL_CHECK ( argv[0] != NULL, XLAL_EINVAL );
1075 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
1076
1077 *should_exit = 0;
1078
1079 // keep a module-local pointer to the executable path/name
1080 program_path = argv[0];
1081 program_name = strrchr( program_path, '/' );
1082 if ( program_name == NULL ) {
1084 } else {
1085 ++program_name;
1086 }
1087
1088 // ---------- manually parse command-line for help/usage arguments
1089 for ( INT4 i = 1; i < argc; i++ )
1090 {
1091 XLAL_CHECK( argv[i] != NULL, XLAL_EINVAL, "argc = %d, but argv[%d] == NULL!\n", argc, i );
1092 if ( strcmp( argv[i], "-h" ) == 0 )
1093 {
1095 *should_exit = 1;
1096 return XLAL_SUCCESS;
1097 }
1098 else if ( strcmp( argv[i], "--help" ) == 0 || strcmp( argv[i], "-help" ) == 0 )
1099 {
1101 *should_exit = 1;
1102 return XLAL_SUCCESS;
1103 }
1104 }
1105
1106 // ---------- pre-process command-line: have we got a config-file ?
1107 CHAR* cfgfile_name = NULL;
1108 for ( INT4 i = 1; i < argc; i++ )
1109 {
1110 char *argi = argv[i];
1111 XLAL_CHECK ( argi != NULL, XLAL_EINVAL, "argc = %d, but argv[%d] == NULL!\n", argc, i );
1112
1113 if ( argi[0] == '@' )
1114 {
1115 XLAL_CHECK ( cfgfile_name == NULL, XLAL_EINVAL, "Can only handle *one* config-file passed on commandline!\n" );
1116 argi ++;
1117 XLAL_CHECK ( (cfgfile_name = XLALStringDuplicate ( argi )) != NULL, XLAL_EFUNC );
1118 } // if argument starts with '@' -> config-file
1119
1120 } // for i < argc
1121
1122 // ---------- if config-file specified, read from that first
1123 if ( cfgfile_name != NULL )
1124 {
1125 XLAL_CHECK ( XLALUserVarReadCfgfile ( should_exit, cfgfile_name ) == XLAL_SUCCESS, XLAL_EFUNC );
1126 if ( *should_exit ) {
1127 return XLAL_SUCCESS;
1128 }
1129 XLALFree (cfgfile_name);
1130 }
1131
1132 // ---------- now parse cmdline: overloads previous config-file settings
1133 XLAL_CHECK ( XLALUserVarReadCmdline ( should_exit, argc, argv, vcs_list ) == XLAL_SUCCESS, XLAL_EFUNC );
1134 if ( *should_exit ) {
1135 return XLAL_SUCCESS;
1136 }
1137
1138 // ---------- handle special options that need some action ----------
1139 BOOLEAN skipCheckRequired = FALSE;
1140 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
1141 {
1142
1143 // handle DEPRECATED options by outputting a warning (on error-level to make this very noticeable!)
1144 if ( ptr->category == UVAR_CATEGORY_DEPRECATED && ptr->was_set ) {
1145 XLALPrintError ("\n%s: option " UVAR_FMT " is DEPRECATED: %s\n\n", program_name, ptr->name, ptr->help );
1146 }
1147
1148 // handle DEFUNCT options by throwing an error:
1149 XLALUserVarCheck( should_exit, ptr->category != UVAR_CATEGORY_DEFUNCT || !ptr->was_set, "option " UVAR_FMT " is DEFUNCT: %s", ptr->name, ptr->help );
1150 if ( *should_exit ) {
1151 return XLAL_SUCCESS;
1152 }
1153
1154 } // while ptr = ptr->next
1155
1156 // check that all required input-variables have been specified
1157 if ( !skipCheckRequired ) {
1158
1159 // go through list of uvars
1160 for ( LALUserVariable *ptr = &UVAR_vars; (ptr=ptr->next) != NULL; )
1161 {
1162 XLALUserVarCheck( should_exit, ptr->category != UVAR_CATEGORY_REQUIRED || ptr->was_set, "required option " UVAR_FMT " has not been specified!", ptr->name );
1163 if ( *should_exit ) {
1164 return XLAL_SUCCESS;
1165 }
1166 }
1167
1168 }
1169
1170 return XLAL_SUCCESS;
1171
1172} // XLALUserVarReadAllInput()
1173
1174
1175/**
1176 * Has this user-variable been set by the user?
1177 * returns 1 (=TRUE) or 0 (=FALSE) on success, error-code otherwise
1178 */
1179int
1180XLALUserVarWasSet ( const void *cvar )
1181{
1182 XLAL_CHECK ( cvar != NULL, XLAL_EINVAL );
1183 XLAL_CHECK ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
1184
1185 // find this variable name in the list of registered user-variables
1186 LALUserVariable *ptr = &UVAR_vars;
1187 while ( (ptr = ptr->next) != NULL )
1188 {
1189 if ( ptr->cvar != NULL && ptr->cvar == cvar) {
1190 break;
1191 }
1192 } // while ptr = ptr->next
1193
1194 XLAL_CHECK ( ptr != NULL, XLAL_EINVAL, "Variable pointer passed UVARwasSet is not a registered User-variable\n" );
1195
1196 // we found it: has it been set by user?
1197 if ( ptr->was_set ) {
1198 return 1;
1199 } else {
1200 return 0;
1201 }
1202
1203} // XLALUserVarWasSet()
1204
1205
1206/**
1207 * If \p assertion is false, print the given error message, then the help usage;
1208 * \p should_exit is then set to true.
1209 */
1210void
1211XLALUserVarCheck( BOOLEAN *should_exit, const int assertion, const CHAR *fmt, ... )
1212{
1213 if ( !( *should_exit ) && !assertion ) {
1214 char buf[2048];
1215 va_list ap;
1216 va_start( ap, fmt );
1217 vsnprintf( buf, sizeof( buf ), fmt, ap );
1218 va_end( ap );
1219 format_user_var_names( buf );
1220 fprintf( stderr, "\n%s: %s\n", program_name, buf );
1222 fflush( stderr );
1223 *should_exit = 1;
1224 }
1225} // XLALUserVarCheck()
1226
1227/**
1228 * Return a log-string representing the <em>complete</em> user-input.
1229 * <em>NOTE:</em> we only record user-variables that have been set
1230 * by the user.
1231 */
1232CHAR *
1233XLALUserVarGetLog ( UserVarLogFormat format /**< output format: return as config-file or command-line */
1234 )
1235{
1236 return XLALUserVarGetLogEx ( format, 1 );
1237}
1238
1239/**
1240 * Return a log-string representing the <em>complete</em> user-input.
1241 */
1242CHAR *
1243XLALUserVarGetLogEx ( UserVarLogFormat format, /**< output format: return as config-file or command-line */
1244 const BOOLEAN skip_unset /**< if true, do not include unset variables in output */
1245 )
1246{
1247 XLAL_CHECK_NULL ( UVAR_vars.next != NULL, XLAL_EINVAL, "No UVAR memory allocated. Did you register any user-variables?" );
1249
1250 CHAR *record = NULL;
1251
1252 switch (format)
1253 {
1256 XLAL_CHECK_NULL ( ( record = XLALStringAppend ( record, program_path ) ) != NULL, XLAL_EFUNC );
1257 break;
1258
1259 default:
1260 break;
1261 }
1262
1263 LALUserVariable *ptr = &UVAR_vars;
1264 while ( (ptr = ptr->next) )
1265 {
1266 if ( skip_unset && ! ptr->was_set ) { // skip unset variables
1267 continue;
1268 }
1269 if ( ! ptr->cvar ) { // skip defunct variables
1270 continue;
1271 }
1272
1273 CHAR *valstr = ptr->cdata != NULL ? UserVarTypeMap [ ptr->type ].printer_cdata( ptr->cvar, ptr->cdata ) : UserVarTypeMap [ ptr->type ].printer( ptr->cvar );
1274 XLAL_CHECK_NULL ( valstr != NULL, XLAL_EFUNC );
1275
1276 switch (format)
1277 {
1279 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "\n%s\t%s", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1280 break;
1281
1283 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "%s = %s;\n", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1284 break;
1285
1287 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, " --%s=%s", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1288 break;
1289
1291 XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "--%s = %s :%s;", ptr->name, valstr, UserVarTypeMap[ptr->type].name ) ) != NULL, XLAL_EFUNC );
1292 break;
1293
1294 default:
1295 XLAL_ERROR_NULL ( XLAL_EINVAL, "Unknown format for recording user-input: '%i'\n", format );
1296 break;
1297 } // switch (format)
1298
1299 XLALFree (valstr);
1300 } // while ptr=ptr->next
1301
1302 return record;
1303
1304} // 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:880
format_help_cdataT format_help_cdata
function returning describing format of user variable (with auxilliary data)
Definition: UserInput.c:205
static CHAR * program_name
Definition: UserInput.c:247
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:201
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:1211
static LALUserVariable UVAR_vars
Definition: UserInput.c:245
static CHAR * program_path
Definition: UserInput.c:246
destructorT destructor
destructor for this variable type, NULL if none required
Definition: UserInput.c:199
parserT parser
parser function to parse string as this type
Definition: UserInput.c:200
#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:774
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:202
#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:734
printer_cdataT printer_cdata
'printer' function (with auxilliary data) returning string value for given type
Definition: UserInput.c:204
const char *const name
type name
Definition: UserInput.c:198
static void fprint_wrapped(FILE *f, int line_width, const char *prefix, char *text)
Definition: UserInput.c:790
parser_cdataT parser_cdata
parser function (with auxilliary data) to parse string as this type
Definition: UserInput.c:203
#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:263
const char * lalUserVarHelpBrief
An optional brief description of the program, printed after its name as part of the help page.
Definition: UserInput.c:253
#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:1069
void XLALDestroyUserVars(void)
Free all memory associated with user-variable linked list.
Definition: UserInput.c:354
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:280
CHAR * XLALUserVarGetLogEx(UserVarLogFormat format, const BOOLEAN skip_unset)
Return a log-string representing the complete user-input.
Definition: UserInput.c:1243
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:399
CHAR * XLALUserVarGetLog(UserVarLogFormat format)
Return a log-string representing the complete user-input.
Definition: UserInput.c:1233
const char * lalUserVarHelpDescription
An optional longer description of the program, printed in its own section as part of the help page.
Definition: UserInput.c:258
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:1180
int XLALUserVarReadCfgfile(BOOLEAN *should_exit, const CHAR *cfgfile)
Read config-variables from cfgfile and parse into input-structure.
Definition: UserInput.c:652
@ 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