LAL  7.5.0.1-08ee4f4
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) \
58 int 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, ...
71 typedef enum {
72  UVAR_TYPE_START=0, // internal start marker for range checking
73 
74  UVAR_TYPE_BOOLEAN, // boolean
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 //
105 typedef 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 ----------
119 int XLALRegisterUserVar (void *cvar, const void *cdata, const CHAR *name, UserVarType type, CHAR optchar, UserVarCategory category, const CHAR *help);
120 int XLALUserVarPrintUsage ( FILE *file );
121 int XLALUserVarPrintHelp ( FILE *file );
122 static void format_user_var_names( char *s );
123 static 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
152 typedef void (*destructorT)(void *cvar);
153 typedef int (*parserT)(void *cvar, const char *valstr);
154 typedef char *(*printerT)(const void *cvar);
155 typedef int (*parser_cdataT)(void *cvar, const void *cdata, const char *valstr);
156 typedef char *(*printer_cdataT)(const void *cvar, const void *cdata);
157 typedef 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
191 static 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>,..." ),
236 };
237 
238 
239 // ---------- The module-local linked list to hold the user-variables
240 static LALUserVariable UVAR_vars; // empty head
241 static CHAR *program_path = NULL; // keep a pointer to the program path
242 static 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  */
248 const 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  */
253 const 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  */
274 int
275 XLALRegisterUserVar ( 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
305  LALUserVariable *ptr = &UVAR_vars;
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 );
332  format_user_var_names( ptr->help );
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  */
348 void
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  */
393 int
394 XLALUserVarReadCmdline ( 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  {
539  case UVAR_TYPE_BOOLEAN:
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  */
646 int
647 XLALUserVarReadCfgfile ( 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
659  LALUserVariable *ptr = &UVAR_vars;
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  */
728 int
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  */
768 void
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  */
784 void
785 fprint_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  */
874 int
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;
1040 XLAL_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  */
1063 int
1064 XLALUserVarReadAllInput ( 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  */
1174 int
1175 XLALUserVarWasSet ( 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  */
1205 void
1206 XLALUserVarCheck( 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  */
1227 CHAR *
1228 XLALUserVarGetLog ( 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  */
1237 CHAR *
1238 XLALUserVarGetLogEx ( 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  {
1249  case UVAR_LOGFMT_RAWFORM:
1250  case UVAR_LOGFMT_CMDLINE:
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  {
1273  case UVAR_LOGFMT_RAWFORM:
1274  XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "\n%s\t%s", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1275  break;
1276 
1277  case UVAR_LOGFMT_CFGFILE:
1278  XLAL_CHECK_NULL ( ( record = XLALStringAppendFmt ( record, "%s = %s;\n", ptr->name, valstr ) ) != NULL, XLAL_EFUNC );
1279  break;
1280 
1281  case UVAR_LOGFMT_CMDLINE:
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
char *(* printer_cdataT)(const void *cvar, const void *cdata)
Definition: UserInput.c:156
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
int(* parser_cdataT)(void *cvar, const void *cdata, const char *valstr)
Definition: UserInput.c:155
printerT printer
'printer' function returning string value for given type
Definition: UserInput.c:196
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
static const struct @13 UserVarTypeMap[UVAR_TYPE_END]
char *(* printerT)(const void *cvar)
Definition: UserInput.c:154
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
#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
char *(* format_help_cdataT)(const void *cdata)
Definition: UserInput.c:157
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
UINT4Vector * XLALConfigFileGetUnreadEntries(const LALParsedDataFile *cfgdata)
Return a list of unread config-file entries, NULL if none found (without error).
Definition: ConfigFile.c:398
int XLALParseDataFile(LALParsedDataFile **cfgdata, const CHAR *path)
Parse an ASCII data-file into a pre-cleaned array of lines.
Definition: ConfigFile.c:65
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 * 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 * 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
const LALVCSInfo *const LALVCSInfoList[16]
NULL-terminated list of VCS and build information structures
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,...
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
CHAR * XLALUserVarGetLog(UserVarLogFormat format)
Return a log-string representing the complete user-input.
Definition: UserInput.c:1228
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
CHAR * XLALUserVarGetLogEx(UserVarLogFormat format, const BOOLEAN skip_unset)
Return a log-string representing the complete user-input.
Definition: UserInput.c:1238
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
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
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