LAL  7.5.0.1-b72065a
UserInputParse.c
Go to the documentation of this file.
1 //
2 // Copyright (C) 2016 Karl Wette
3 // Copyright (C) 2004, 2005, 2015 Reinhard Prix
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with with program; see the file COPYING. If not, write to the
17 // Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 // MA 02110-1301 USA
19 //
20 
21 #include <math.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <string.h>
25 
26 #include <lal/Date.h>
27 #include <lal/StringInput.h>
28 #include <lal/AVFactories.h>
29 #include <lal/StringVector.h>
30 #include <lal/LALConstants.h>
31 #include <lal/LALString.h>
32 #include <lal/TranslateMJD.h>
33 #include <lal/TranslateAngles.h>
34 
35 #include <lal/UserInputParse.h>
36 
37 // ---------- local defines ----------
38 // these constants are taken from StringConvert.c
39 #define LAL_sINT4_MAX LAL_INT8_C(2147483647)
40 #define LAL_sINT8_MAX LAL_INT8_C(9223372036854775807)
41 
42 #define MYMAX(x,y) ( (x) > (y) ? (x) : (y) )
43 #define MYMIN(x,y) ( (x) < (y) ? (x) : (y) )
44 
45 // ==================== function definitions ====================
46 
47 /// Parse a string into an INT8
48 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
49 int
50 XLALParseStringValueAsINT8 ( INT8 *valINT8, ///< [out] return INT8 value
51  const char *valString ///< [in] input string value
52  )
53 {
54  XLAL_CHECK ( (valINT8 != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
55 
56  errno = 0;
57  char *endptr;
58  int base10 = 10;
59  long long valLLong = strtoll ( valString, &endptr, base10 );
60  XLAL_CHECK ( errno == 0, XLAL_EFAILED, "strtoll() failed to convert '%s' into long long!\n", valString );
61  XLAL_CHECK ( (*endptr) == '\0', XLAL_EFAILED, "strtoll(): trailing garbage '%s' found after int-conversion of '%s'\n", endptr, valString );
62 
63  // check range and convert long-int into INT8
64  if ( sizeof(valLLong) > sizeof(INT8) ) { // avoid warning about trivial check
65  XLAL_CHECK ( (valLLong >= -LAL_sINT8_MAX) && (valLLong <= LAL_sINT8_MAX), XLAL_EDOM, "String-conversion '%s' --> '%lli' exceeds INT8 range of +-%"LAL_INT8_FORMAT"\n",
66  valString, valLLong, LAL_sINT8_MAX );
67  }
68 
69  (*valINT8) = (INT8)valLLong;
70 
71  return XLAL_SUCCESS;
72 
73 } // XLALParseStringValueAsINT8()
74 
75 
76 /// Parse a string into an INT4
77 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
78 int
79 XLALParseStringValueAsINT4 ( INT4 *valINT4, ///< [out] return INT4 value
80  const char *valString ///< [in] input string value
81  )
82 {
83  XLAL_CHECK ( (valINT4 != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
84 
85  INT8 valINT8;
86  XLAL_CHECK ( XLALParseStringValueAsINT8 ( &valINT8, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
87 
88  // check range and convert INT8 into INT4
89  XLAL_CHECK ( (valINT8 >= -LAL_sINT4_MAX) && (valINT8 <= LAL_sINT4_MAX), XLAL_EDOM, "String-conversion '%s' --> '%"LAL_INT8_FORMAT"' exceeds INT4 range of +-%"LAL_INT8_FORMAT"\n",
90  valString, valINT8, LAL_sINT4_MAX );
91 
92  (*valINT4) = (INT4)valINT8;
93 
94  return XLAL_SUCCESS;
95 
96 } // XLALParseStringValueAsINT4()
97 
98 
99 /// Parse a string into an UINT8
100 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
101 int
102 XLALParseStringValueAsUINT8 ( UINT8 *valUINT8, ///< [out] return UINT8 value
103  const char *valString ///< [in] input string value
104  )
105 {
106  XLAL_CHECK ( (valUINT8 != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
107 
108  errno = 0;
109  char *endptr;
110  int base10 = 10;
111  unsigned long long valULLong = strtoull ( valString, &endptr, base10 );
112  XLAL_CHECK ( errno == 0, XLAL_EFAILED, "strtoll() failed to convert '%s' into long long!\n", valString );
113  XLAL_CHECK ( (*endptr) == '\0', XLAL_EFAILED, "strtoll(): trailing garbage '%s' found after int-conversion of '%s'\n", endptr, valString );
114 
115  // check range and convert unsigned long-int into UINT8
116  long long valLLong = strtoll ( valString, &endptr, base10 ); // This is to check for negative numbers, which strtoull() accepts
117  errno = 0; // Do not need to check error code
118  XLAL_CHECK ( (valLLong >= 0), XLAL_EDOM, "String-conversion '%s' --> '%lli' exceeds UINT8 range of [0,%"LAL_UINT8_FORMAT"]\n",
119  valString, valLLong, LAL_UINT8_MAX );
120  if ( sizeof(valULLong) > sizeof(UINT8) ) { // avoid warning about trivial check
121  XLAL_CHECK ( (valULLong <= LAL_UINT8_MAX), XLAL_EDOM, "String-conversion '%s' --> '%llu' exceeds UINT8 range of [0,%"LAL_UINT8_FORMAT"]\n",
122  valString, valULLong, LAL_UINT8_MAX );
123  }
124 
125  (*valUINT8) = (UINT8)valULLong;
126 
127  return XLAL_SUCCESS;
128 
129 } // XLALParseStringValueAsUINT8()
130 
131 
132 /// Parse a string into an UINT4
133 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
134 int
135 XLALParseStringValueAsUINT4 ( UINT4 *valUINT4, ///< [out] return UINT4 value
136  const char *valString ///< [in] input string value
137  )
138 {
139  XLAL_CHECK ( (valUINT4 != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
140 
141  UINT8 valUINT8;
142  XLAL_CHECK ( XLALParseStringValueAsUINT8 ( &valUINT8, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
143 
144  // check range and convert UINT8 into UINT4
145  XLAL_CHECK ( (valUINT8 <= LAL_UINT4_MAX), XLAL_EDOM, "String-conversion '%s' --> '%"LAL_UINT8_FORMAT"' exceeds UINT4 range of [0,%"LAL_UINT8_FORMAT"]\n",
146  valString, valUINT8, LAL_UINT4_MAX );
147 
148  (*valUINT4) = (UINT4)valUINT8;
149 
150  return XLAL_SUCCESS;
151 
152 } // XLALParseStringValueAsUINT4()
153 
154 
155 /// Parse a string into a REAL8
156 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
157 int
158 XLALParseStringValueAsREAL8 ( REAL8 *valREAL8, ///< [out] return REAL8 value
159  const char *valString ///< [in] input string value
160  )
161 {
162  XLAL_CHECK ( (valREAL8 != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
163 
164  errno = 0;
165  char *endptr;
166  double valDouble = strtod ( valString, &endptr );
167  XLAL_CHECK ( errno == 0, XLAL_EFAILED, "strtod() failed to convert '%s' into a double!\n", valString );
168  XLAL_CHECK ( (*endptr) == '\0', XLAL_EFAILED, "strtod(): trailing garbage '%s' found after double-conversion of '%s'\n", endptr, valString );
169 
170  (*valREAL8) = (REAL8)valDouble;
171 
172  return XLAL_SUCCESS;
173 
174 } // XLALParseStringValueAsREAL8()
175 
176 /// Parse a string into a REAL4.
177 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
178 int
179 XLALParseStringValueAsREAL4 ( REAL4 *valREAL4, ///< [out] return REAL4 value
180  const char *valString ///< [in] input string value
181  )
182 {
183  XLAL_CHECK ( (valREAL4 != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
184 
185  errno = 0;
186  char *endptr;
187  float valFloat = strtof ( valString, &endptr );
188  XLAL_CHECK ( errno == 0, XLAL_EFAILED, "strtof() failed to convert '%s' into a float!\n", valString );
189  XLAL_CHECK ( (*endptr) == '\0', XLAL_EFAILED, "strtof(): trailing garbage '%s' found after float-conversion of '%s'\n", endptr, valString );
190 
191  (*valREAL4) = (REAL4)valFloat;
192 
193  return XLAL_SUCCESS;
194 
195 } // XLALParseStringValueAsREAL4()
196 
197 ///
198 /// Parse a string containing a floating-point number into integer and fractional part, such that val = valINT + valFrac.
199 ///
200 /// This is useful for parsing strings representing GPS or MJD times wihout loss of ns accuracy.
201 ///
202 int
203 XLALParseStringValueAsINT4PlusFrac ( INT4 *valINT4, ///< [out] return INT4 integer part 'xxx'
204  REAL8 *valFrac, ///< [out] return fractional part '0.yyyy'
205  const char *valString ///< [in] input string value representing a floating-point number "xxx.yyyy"
206  )
207 {
208  XLAL_CHECK ( (valINT4 != NULL) && (valFrac != NULL) && (valString != NULL), XLAL_EINVAL );
209  XLAL_CHECK ( !isspace(valString[0]), XLAL_EINVAL, "No initial whitespace allowed in input string '%s'\n", valString );
210 
211  char buf[256];
212  strncpy ( buf, valString, sizeof(buf)-1 );
213  XLAL_LAST_ELEM(buf) = 0;
214 
215  REAL8 sign = 1;
216  if ( valString[0] == '-' ) { // that's why no initial whitespace is allowed in input string
217  sign = -1;
218  }
219  char *point = strchr ( buf, '.' );
220  // is there a fractional part at all? If yes, parse it, if no, set to 0
221  if ( point != NULL )
222  {
223  (*point) = 0;
224  char fracString[256] = "0.";
225  strcat ( fracString+2, point+1);
226  XLAL_CHECK ( XLALParseStringValueAsREAL8 ( valFrac, fracString ) == XLAL_SUCCESS, XLAL_EFUNC );
227  (*valFrac) *= sign; // correct sign: must agree with integer part
228  }
229  else
230  {
231  (*valFrac) = 0;
232  }
233 
234  // now parse integer part
236 
237  return XLAL_SUCCESS;
238 } // XLALParseStringValueAsINT4PlusFrac()
239 
240 
241 /// Parse a string into a BOOLEAN
242 /// Allowed string-values are (case-insensitive):
243 /// {"yes", "true", "1"} --> TRUE
244 /// {"no", "false", "0"} --> FALSE
245 ///
246 /// NOTE: This throws an error on _any_ extraneous leading or trailing characters or whitespace
247 int
248 XLALParseStringValueAsBOOLEAN ( BOOLEAN *valBOOLEAN, ///< [out] return BOOLEAN value
249  const char *valString ///< [in] input string value
250  )
251 {
252  XLAL_CHECK ( (valBOOLEAN != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
253 
254  /* get rid of case ambiguities */
255  char *valStringLower;
256  XLAL_CHECK ( (valStringLower = XLALMalloc ( strlen(valString) + 1 )) != NULL, XLAL_ENOMEM );
257  strcpy ( valStringLower, valString );
258  XLALStringToLowerCase ( valStringLower );
259 
260  /* parse it as a bool */
261  if ( !strcmp(valStringLower, "yes") || !strcmp(valStringLower, "true") || !strcmp(valStringLower, "1") )
262  {
263  (*valBOOLEAN) = 1;
264  }
265  else if ( !strcmp(valStringLower, "no") || !strcmp(valStringLower, "false") || !strcmp(valStringLower, "0") )
266  {
267  (*valBOOLEAN) = 0;
268  }
269  else
270  {
271  XLALFree ( valStringLower );
272  XLAL_ERROR ( XLAL_EINVAL, "Illegal bool-string '%s', needs to be one of {'yes', 'true', '1'} or {'no', 'false', '0'} (case-insensitive)\n", valString );
273  }
274 
275  XLALFree ( valStringLower );
276 
277  return XLAL_SUCCESS;
278 
279 } // XLALParseStringValueAsBOOLEAN()
280 
281 
282 ///
283 /// Parse a string representing a GPS time into LIGOTimeGPS, without loss of (ns) accuracy
284 ///
285 ///
286 int
287 XLALParseStringValueAsGPS ( LIGOTimeGPS *gps, ///< [out] returned GPS time
288  const char *valString ///< [in] input string representing MJD(TT) time
289  )
290 {
291  XLAL_CHECK ( (gps != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
292 
293  INT4 gpsInt;
294  REAL8 gpsFrac;
295  XLAL_CHECK ( XLALParseStringValueAsINT4PlusFrac ( &gpsInt, &gpsFrac, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
296  INT8 gpsNs = (INT8) round ( gpsFrac * XLAL_BILLION_REAL8 );
297 
298  XLALGPSSet ( gps, gpsInt, gpsNs );
299 
300  return XLAL_SUCCESS;
301 
302 } // XLALParseStringValueAsGPS()
303 
304 
305 ///
306 /// Parse a string representing an 'epoch' into an LIGOTimeGPS, allowing both GPS and MJD(TT) inputs, at ns accuracy.
307 ///
308 /// Allowed input string formats are "INT4.INT4[GPS|MJD]", where the optional postfix 'GPS' or 'MJD' indicates
309 /// the time 'units', which defaults to GPS if no postfix is given. Note that MJD input is interpreted as MJD(TT),
310 /// and translated into GPS using XLALTranslateStringMJDTTtoGPS().
311 /// This ignores initial whitespace, but throws an error on _any_ non-converted trailing characters (including whitespace)
312 ///
313 int
314 XLALParseStringValueAsEPOCH ( LIGOTimeGPS *gps, ///< [out] return LIGOTimeGPS value
315  const char *valString ///< [in] input string value
316  )
317 {
318  XLAL_CHECK ( (gps != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
319 
320  char buf[256];
321  strncpy ( buf, valString, sizeof(buf)-1 );
322  XLAL_LAST_ELEM(buf) = 0;
323 
324  // ---------- first check if there's a postfix indicating the time 'units' (GPS or MJD):
325  BOOLEAN is_gps;
326  char *postfix;
327  if ( (postfix = strstr ( buf, "MJD" )) != NULL )
328  {
329  XLAL_CHECK ( postfix[3] == 0, XLAL_EINVAL, "Input '%s' contains trailing characters after units 'MJD': must be of form 'xxx.yyyMJD'\n", valString );
330  postfix[0] = 0; // cut off postfix
331  is_gps = 0;
332  }
333  else if ( (postfix = strstr ( buf, "GPS" )) != NULL )
334  {
335  XLAL_CHECK ( postfix[3] == 0, XLAL_EINVAL, "Input '%s' contains trailing characters after units 'GPS': must be of form 'xxx.yyy' or 'xxx.yyyGPS'\n", valString );
336  postfix[0] = 0; // cut off postfix
337  is_gps = 1;
338  }
339  else // no postfix: default to 'GPS' units
340  {
341  is_gps = 1;
342  }
343 
344 
345  if ( is_gps )
346  {
348  }
349  else
350  {
351  XLAL_CHECK ( XLALTranslateStringMJDTTtoGPS ( gps, buf ) != NULL, XLAL_EFUNC );
352  }
353 
354  return XLAL_SUCCESS;
355 
356 } // XLALParseStringValueAsEPOCH()
357 
358 
359 ///
360 /// Parse a string representing an 'equatorial longitude' (aka right ascension or RA) into REAL8 radians, allowing for both radians or "hours:minutes:seconds" as input.
361 ///
362 /// Note that "h:m:s" input is translated into radians using XLALTranslateHMStoRAD().
363 ///
364 int
365 XLALParseStringValueAsRAJ ( REAL8 *valRAJ, ///< [out] return longitude value in radians
366  const char *valString ///< [in] input string value
367  )
368 {
369  XLAL_CHECK ( (valRAJ != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
370 
371  // ---------- first check if there's a colon ':' somewhere in the string, which indicates "H:M:S" format
372  const char *colon;
373  if ( (colon = strchr ( valString, ':' )) != NULL )
374  {
375  XLAL_CHECK ( XLALTranslateHMStoRAD ( valRAJ, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
376  }
377  else
378  {
379  XLAL_CHECK ( XLALParseStringValueAsREAL8 ( valRAJ, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
380  }
381 
382  return XLAL_SUCCESS;
383 
384 } // XLALParseStringValueAsRAJ()
385 
386 ///
387 /// Parse a string representing an 'equatorial latitude' (aka declination or DEC) into REAL8 radians, allowing for both radians or "degrees:minutes:seconds" as input.
388 ///
389 /// Note that "d:m:s" input is translated into radians using XLALTranslateDMStoRAD().
390 ///
391 int
392 XLALParseStringValueAsDECJ ( REAL8 *valDECJ, ///< [out] return latitude value in radians
393  const char *valString ///< [in] input string value
394  )
395 {
396  XLAL_CHECK ( (valDECJ != NULL) && (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
397 
398  // ---------- first check if there's a colon ':' somewhere in the string, which indicates "D:M:S" format
399  const char *colon;
400  if ( (colon = strchr ( valString, ':' )) != NULL )
401  {
402  XLAL_CHECK ( XLALTranslateDMStoRAD ( valDECJ, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
403  }
404  else
405  {
406  XLAL_CHECK ( XLALParseStringValueAsREAL8 ( valDECJ, valString ) == XLAL_SUCCESS, XLAL_EFUNC );
407  }
408 
409  return XLAL_SUCCESS;
410 
411 } // XLALParseStringValueAsDECJ()
412 
413 //
414 // Split a range string into parts, return the parts as strings, and
415 // the linear transform used to compute the range from the parsed parts
416 //
417 static int SplitStringIntoRange(const char *str, char part[2][256], int T[2][2]) {
418 
419  // Assume no separators by default, copy 'str' to both parts (--var=point)
420  memset(part[0], 0, sizeof(part[0]));
421  strncpy(part[0], str, sizeof(part[0]) - 1);
422  memset(part[1], 0, sizeof(part[1]));
423  strncpy(part[1], str, sizeof(part[1]) - 1);
424  const int defT[2][2] = {{1, 0}, {0, 1}};
425  memcpy(T, defT, sizeof(defT));
426 
427  // Possible syntaxes
428  const struct {
429  const char sep;
430  int T[2][2];
431  } syntaxes[] = {
432  { ',', { {1, 0}, {0, 1} } }, // --var=start,end
433  { '/', { {1, 0}, {1, 1} } }, // --var=start/band
434  { '~', { {1, -1}, {1, 1} } }, // --var=start~plusminus
435  };
436 
437  // Loop over possible syntaxes
438  for (size_t i = 0; i < XLAL_NUM_ELEM(syntaxes); ++i) {
439 
440  // Look for separator in 'str'
441  const char *found = strchr(str, syntaxes[i].sep);
442  if (found != NULL) {
443 
444  // Copy everything in 'str' up to separator to 'part[0]'
445  memset(part[0], 0, sizeof(part[0]));
446  strncpy(part[0], str, MYMIN((size_t)(found - str), sizeof(part[0]) - 1));
447  XLAL_CHECK( strlen(part[0]) > 0, XLAL_EINVAL, "Input '%s' contains no value before range separator '%c'", str, syntaxes[i].sep );
448 
449  // Copy everything in 'str' past separator to 'part[1]'
450  memset(part[1], 0, sizeof(part[1]));
451  strncpy(part[1], found + 1, sizeof(part[1]) - 1);
452  XLAL_CHECK( strlen(part[1]) > 0, XLAL_EINVAL, "Input '%s' contains no value after range separator '%c'", str, syntaxes[i].sep );
453 
454  // Copy transform to 'T'
455  memcpy(T, syntaxes[i].T, sizeof(syntaxes[i].T));
456 
457  break;
458 
459  }
460 
461  }
462 
463  return XLAL_SUCCESS;
464 
465 }
466 
467 
468 ///
469 /// Parse a string representing a range of REAL8 values into a REAL8Range. Possible formats
470 /// are <tt>start</tt>, <tt>start,end</tt>, <tt>start/band</tt>, or <tt>start~plusminus</tt>.
471 /// Output range is always <tt>low,high</tt> with <tt>range[0] = low; range[1] = high</tt>.
472 ///
474  REAL8Range real8Range, ///< [out] output range of REAL8 values
475  const char *valString ///< [in] input string
476  )
477 {
478 
479  // Check input
480  XLAL_CHECK(real8Range != NULL, XLAL_EFAULT);
481  XLAL_CHECK(valString != NULL, XLAL_EFAULT);
482  XLAL_CHECK(strlen(valString) > 0, XLAL_EINVAL);
483 
484  // Parse range
485  char part[2][256];
486  int T[2][2];
487  XLAL_CHECK( SplitStringIntoRange(valString, part, T) == XLAL_SUCCESS, XLAL_EFUNC );
488  REAL8 val[2];
491  real8Range[0] = T[0][0] * val[0] + T[0][1] * val[1];
492  real8Range[1] = T[1][0] * val[0] + T[1][1] * val[1];
493 
494  // Check range ordering
495  if (real8Range[0] > real8Range[1]) {
496  const REAL8 tmp = real8Range[0];
497  real8Range[0] = real8Range[1];
498  real8Range[1] = tmp;
499  }
500 
501  return XLAL_SUCCESS;
502 
503 }
504 
505 ///
506 /// Parse a string representing a range of INT4 values into a INT4Range. Possible formats
507 /// are <tt>start</tt>, <tt>start,end</tt>, <tt>start/band</tt>, or <tt>start~plusminus</tt>.
508 /// Output range is always <tt>low,high</tt> with <tt>range[0] = low; range[1] = high</tt>.
509 ///
511  INT4Range int4Range, ///< [out] output range of INT4 values
512  const char *valString ///< [in] input string
513  )
514 {
515 
516  // Check input
517  XLAL_CHECK(int4Range != NULL, XLAL_EFAULT);
518  XLAL_CHECK(valString != NULL, XLAL_EFAULT);
519  XLAL_CHECK(strlen(valString) > 0, XLAL_EINVAL);
520 
521  // Parse range
522  char part[2][256];
523  int T[2][2];
524  XLAL_CHECK( SplitStringIntoRange(valString, part, T) == XLAL_SUCCESS, XLAL_EFUNC );
525  INT4 val[2];
528  int4Range[0] = T[0][0] * val[0] + T[0][1] * val[1];
529  int4Range[1] = T[1][0] * val[0] + T[1][1] * val[1];
530 
531  // Check range ordering
532  if (int4Range[0] > int4Range[1]) {
533  const INT4 tmp = int4Range[0];
534  int4Range[0] = int4Range[1];
535  int4Range[1] = tmp;
536  }
537 
538  return XLAL_SUCCESS;
539 
540 } // XLALParseStringValueAsINT4Range()
541 
542 
543 ///
544 /// Parse a string representing a range of LIGOTimeGPS values into a LIGOTimeGPSRange. Possible formats
545 /// are <tt>start</tt>, <tt>start,end</tt>, <tt>start/band</tt>, or <tt>start~plusminus</tt>.
546 /// Output range is always <tt>low,high</tt> with <tt>range[0] = low; range[1] = high</tt>.
547 ///
549  LIGOTimeGPSRange gpsRange, ///< [out] output range of LIGOTimeGPS values
550  const char *valString ///< [in] input string
551  )
552 {
553 
554  // Check input
555  XLAL_CHECK(gpsRange != NULL, XLAL_EFAULT);
556  XLAL_CHECK(valString != NULL, XLAL_EFAULT);
557  XLAL_CHECK(strlen(valString) > 0, XLAL_EINVAL);
558 
559  // Parse range
560  char part[2][256];
561  int T[2][2];
562  XLAL_CHECK( SplitStringIntoRange(valString, part, T) == XLAL_SUCCESS, XLAL_EFUNC );
563  LIGOTimeGPS val[2];
566  XLALINT8NSToGPS( &gpsRange[0], T[0][0] * XLALGPSToINT8NS(&val[0]) + T[0][1] * XLALGPSToINT8NS(&val[1]) );
567  XLALINT8NSToGPS( &gpsRange[1], T[1][0] * XLALGPSToINT8NS(&val[0]) + T[1][1] * XLALGPSToINT8NS(&val[1]) );
568 
569  // Check range ordering
570  if (XLALGPSCmp(&gpsRange[0], &gpsRange[1]) > 0) {
571  const LIGOTimeGPS tmp = gpsRange[0];
572  gpsRange[0] = gpsRange[1];
573  gpsRange[1] = tmp;
574  }
575 
576  return XLAL_SUCCESS;
577 
578 }
579 
580 
581 ///
582 /// Parse a string representing a range of RAJ values into a REAL8Range. Possible formats
583 /// are <tt>start</tt>, <tt>start,end</tt>, <tt>start/band</tt>, or <tt>start~plusminus</tt>.
584 /// Output range is always <tt>low,high</tt> with <tt>range[0] = low; range[1] = high</tt>.
585 ///
587  REAL8Range rajRange, ///< [out] output range of RAJ values
588  const char *valString ///< [in] input string
589  )
590 {
591 
592  // Check input
593  XLAL_CHECK(rajRange != NULL, XLAL_EFAULT);
594  XLAL_CHECK(valString != NULL, XLAL_EFAULT);
595  XLAL_CHECK(strlen(valString) > 0, XLAL_EINVAL);
596 
597  // Parse range
598  char part[2][256];
599  int T[2][2];
600  XLAL_CHECK( SplitStringIntoRange(valString, part, T) == XLAL_SUCCESS, XLAL_EFUNC );
601  REAL8 val[2];
604  rajRange[0] = T[0][0] * val[0] + T[0][1] * val[1];
605  rajRange[1] = T[1][0] * val[0] + T[1][1] * val[1];
606 
607  // Check range ordering
608  if (rajRange[0] > rajRange[1]) {
609  const REAL8 tmp = rajRange[0];
610  rajRange[0] = rajRange[1];
611  rajRange[1] = tmp;
612  }
613 
614  return XLAL_SUCCESS;
615 
616 }
617 
618 
619 ///
620 /// Parse a string representing a range of DECJ values into a REAL8Range. Possible formats
621 /// are <tt>start</tt>, <tt>start,end</tt>, <tt>start/band</tt>, or <tt>start~plusminus</tt>.
622 /// Output range is always <tt>low,high</tt> with <tt>range[0] = low; range[1] = high</tt>.
623 ///
625  REAL8Range decjRange, ///< [out] output range of DECJ values
626  const char *valString ///< [in] input string
627  )
628 {
629 
630  // Check input
631  XLAL_CHECK(decjRange != NULL, XLAL_EFAULT);
632  XLAL_CHECK(valString != NULL, XLAL_EFAULT);
633  XLAL_CHECK(strlen(valString) > 0, XLAL_EINVAL);
634 
635  // Parse range
636  char part[2][256];
637  int T[2][2];
638  XLAL_CHECK( SplitStringIntoRange(valString, part, T) == XLAL_SUCCESS, XLAL_EFUNC );
639  REAL8 val[2];
642  decjRange[0] = T[0][0] * val[0] + T[0][1] * val[1];
643  decjRange[1] = T[1][0] * val[0] + T[1][1] * val[1];
644 
645  // Check range ordering
646  if (decjRange[0] > decjRange[1]) {
647  const REAL8 tmp = decjRange[0];
648  decjRange[0] = decjRange[1];
649  decjRange[1] = tmp;
650  }
651 
652  return XLAL_SUCCESS;
653 
654 }
655 
656 
657 ///
658 /// Parse a string representing a user selection of an enumeration value.
659 /// - Enumeration choices with values < 0 are ignored.
660 /// - Enumeration choice names are case insensitive.
661 ///
662 int XLALParseStringValueAsUserEnum ( int *valEnum, ///< [out] output enumeration value
663  const UserChoices *enumData, ///< [in] possible choices for enumeration values
664  const char *valString ///< [in] input string value
665  )
666 {
667 
668  // Check input
669  XLAL_CHECK(valEnum != NULL, XLAL_EFAULT);
670  XLAL_CHECK(enumData != NULL, XLAL_EFAULT);
671  XLAL_CHECK(valString != NULL, XLAL_EFAULT);
672  XLAL_CHECK(strlen(valString) > 0, XLAL_EINVAL);
673 
674  // Select enumeration value
675  for ( size_t i = 0; i < XLAL_NUM_ELEM(*enumData); ++i ) {
676  if ((*enumData)[i].val >= 0 && (*enumData)[i].name != NULL) {
677  if (XLALStringCaseCompare(valString, (*enumData)[i].name) == 0) {
678  *valEnum = (*enumData)[i].val;
679  return XLAL_SUCCESS;
680  }
681  }
682  }
683  XLAL_ERROR( XLAL_EINVAL, "String '%s' does not name a valid enumeration value", valString );
684 
685 }
686 
687 
688 ///
689 /// Parse a string representing a user selection of a set of bitflags.
690 /// - If the first bitflag choice has a value of zero, it is treated
691 // as a special exclusive case for setting a zero bitflag.
692 /// - Bitflag choices with values <= 0 are ignored.
693 /// - Bigflag choice names are separated by ',' and are case insensitive.
694 ///
695 int XLALParseStringValueAsUserFlag ( int *valFlag, ///< [out] output bitflag value
696  const UserChoices *flagData, ///< [in] possible choices for bitflag values
697  const char *valString ///< [in] input string value
698  )
699 {
700  LALStringVector *valStringNames = NULL;
701 
702  // Check input
703  XLAL_CHECK_FAIL(valFlag != NULL, XLAL_EFAULT);
704  XLAL_CHECK_FAIL(flagData != NULL, XLAL_EFAULT);
705  XLAL_CHECK_FAIL(valString != NULL, XLAL_EFAULT);
706  XLAL_CHECK_FAIL(strlen(valString) > 0, XLAL_EINVAL);
707 
708  // Handle special case of first bitflag with value 0, representing a zero bitflag
709  if ((*flagData)[0].val == 0 && (*flagData)[0].name != NULL && XLALStringCaseCompare(valString, (*flagData)[0].name) == 0) {
710  *valFlag = 0;
711  return XLAL_SUCCESS;
712  }
713 
714  // Parse input string into bitflag names
715  XLAL_CHECK_FAIL( ( valStringNames = XLALParseStringVector( valString, "," ) ) != NULL, XLAL_EFUNC );
716 
717  // Build bitflag value
718  *valFlag = 0;
719  for ( size_t j = 0; j < valStringNames->length; ++j ) {
720  int valFlag_j = 0;
721  for ( size_t i = 0; i < XLAL_NUM_ELEM(*flagData); ++i ) {
722  if ((*flagData)[i].val > 0 && (*flagData)[i].name != NULL) {
723  if (XLALStringCaseCompare(valStringNames->data[j], (*flagData)[i].name) == 0) {
724  valFlag_j = (*flagData)[i].val;
725  break;
726  }
727  }
728  }
729  XLAL_CHECK_FAIL( valFlag_j > 0, XLAL_EINVAL, "String '%s' does not name a valid bitflag value", valStringNames->data[j] );
730  *valFlag |= valFlag_j;
731  }
732 
733  // Cleanup
734  XLALDestroyStringVector( valStringNames );
735 
736  return XLAL_SUCCESS;
737 
738 XLAL_FAIL:
739 
740  // Cleanup
741  XLALDestroyStringVector( valStringNames );
742 
743  return XLAL_FAILURE;
744 
745 }
746 
747 
748 ///
749 /// Duplicate string 'in', removing surrounding quotes \" or \' if present.
750 ///
751 /// \note Quotes at the beginning of the string must be matched at the end,
752 /// otherwise we return an error.
753 ///
754 /// \note The output string (*out) must be NULL
755 ///
756 int
757 XLALParseStringValueAsSTRING ( CHAR **out, ///< [out] return allocated string
758  const CHAR *valStr ///< [in] input string value
759  )
760 {
761  XLAL_CHECK ( (valStr != NULL) && (strlen(valStr) > 0), XLAL_EINVAL );
762  XLAL_CHECK ( (out != NULL) && (*out == NULL), XLAL_EINVAL );
763 
764  CHAR opening_quote = 0;
765  CHAR closing_quote = 0;
766  UINT4 inlen = strlen ( valStr );
767 
768  if ( (valStr[0] == '\'') || (valStr[0] == '\"') ) {
769  opening_quote = valStr[0];
770  }
771  if ( (inlen >= 2) && ( (valStr[inlen-1] == '\'') || (valStr[inlen-1] == '\"') ) ) {
772  closing_quote = valStr[inlen-1];
773  }
774 
775  // check matching quotes
776  XLAL_CHECK ( opening_quote == closing_quote, XLAL_EINVAL, "Unmatched quotes in string [%s]\n", valStr );
777 
778  const CHAR *start = valStr;
779  UINT4 outlen = inlen;
780  if ( opening_quote )
781  {
782  start = valStr + 1;
783  outlen = inlen - 2;
784  }
785 
786  CHAR *ret;
787  XLAL_CHECK ( (ret = XLALCalloc (1, outlen + 1)) != NULL, XLAL_ENOMEM );
788  strncpy ( ret, start, outlen );
789  ret[outlen] = 0;
790 
791  (*out) = ret;
792 
793  return XLAL_SUCCESS;
794 
795 } // XLALParseStringValueAsSTRING()
796 
797 
798 ///
799 /// Parse a string containing a list of comma-separated values (CSV) into a StringVector.
800 /// \note surrounding whitespace and quotes (\' or \") are removed from the individual list entries.
801 ///
802 /// \note The output string-vector (*strVect) must be NULL
803 ///
804 int
805 XLALParseStringValueAsSTRINGVector ( LALStringVector **strVect, ///< [out] allocated string vector
806  const CHAR *valString ///< [in] input string value
807  )
808 {
809  XLAL_CHECK ( (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL );
810  XLAL_CHECK ( (strVect != NULL) && (*strVect == NULL) , XLAL_EINVAL );
811 
812  LALStringVector *ret;
813  XLAL_CHECK ( (ret = XLALCalloc ( 1, sizeof(*ret))) != NULL, XLAL_ENOMEM );
814 
815  const char *start = valString;
816  const char *tmp;
817  do
818  {
819  // create space for the next string-vector entry
820  ret->length ++;
821  XLAL_CHECK ( (ret->data = XLALRealloc ( ret->data, ret->length * sizeof(ret->data[0]) )) != NULL, XLAL_ENOMEM );
822 
823  // determine length of next CSV string value, taking account of quotes
824  size_t len;
825  CHAR inQuotes = 0;
826  tmp = start;
827  do {
828 
829  // simple comma outside of quotes
830  if ( !inQuotes && ((*tmp) == ',') ) {
831  break; // found a separator-comma
832  }
833 
834  // handle quotes
835  if ( (*tmp) == '\'' || (*tmp) == '\"' ) // found quotes
836  {
837  if ( !inQuotes ) {
838  inQuotes = (*tmp); // we've intered quotes
839  } else if ( inQuotes == (*tmp) ) {
840  inQuotes = 0; // we've left quotes, only if closing quotes match opening ones
841  }
842  } // end: if quotes found
843 
844  tmp ++;
845  } while ( (*tmp) != 0 );
846 
847  if ( (*tmp) == 0 ) {
848  len = strlen ( start );
849  } else {
850  len = tmp - start;
851  }
852 
853  // copy this string value with surrounding whitespace removed
854  char *deblanked;
855  XLAL_CHECK ( (deblanked = XLALDeblankString ( start, len ) ) != NULL, XLAL_EFUNC );
856  ret->data[ret->length-1] = NULL;
857  XLAL_CHECK ( XLALParseStringValueAsSTRING ( &(ret->data[ret->length-1]), deblanked ) == XLAL_SUCCESS, XLAL_EFUNC );
858  XLALFree ( deblanked );
859 
860  } while ( ( (*tmp) != 0) && ( *(start = tmp + 1) != 0 ) );
861 
862  (*strVect) = ret;
863 
864  return XLAL_SUCCESS;
865 
866 } // XLALParseStringValueAsSTRINGVector()
867 
868 ///
869 /// Parse a string containing a list of comma-separated values (CSV) into a <CTYPE>Vector.
870 ///
871 /// \note The output string-vector (*vect) must be NULL
872 ///
873 #define DEFN_XLALParseStringValueAsVector(CTYPE) \
874 DECL_XLALParseStringValueAsVector(CTYPE) \
875 { \
876  XLAL_CHECK ( (valString != NULL) && (strlen(valString) > 0), XLAL_EINVAL ); \
877  XLAL_CHECK ( (vect != NULL) && (*vect == NULL) , XLAL_EINVAL ); \
878  \
879  /* parse this as a string vector first */ \
880  LALStringVector *strVect = NULL; \
881  XLAL_CHECK ( XLALParseStringValueAsSTRINGVector ( &strVect, valString ) == XLAL_SUCCESS, XLAL_EFUNC ); \
882  UINT4 numElements = strVect->length; \
883  \
884  /* create corresponding output vector */ \
885  CTYPE##Vector *ret; \
886  XLAL_CHECK ( (ret = XLALCreate##CTYPE##Vector ( numElements )) != NULL, XLAL_EFUNC ); \
887  \
888  /* parse each string value into a REAL8 */ \
889  for ( UINT4 i = 0; i < numElements; i ++ ) \
890  { \
891  XLAL_CHECK ( XLALParseStringValueAs##CTYPE ( &(ret->data[i]), strVect->data[i] ) == XLAL_SUCCESS, XLAL_EFUNC ); \
892  } \
893  \
894  XLALDestroyStringVector ( strVect ); \
895  (*vect) = ret; \
896  return XLAL_SUCCESS; \
897  \
898 } /* XLALParseStringValueAs<CTYPE>Vector() */
899 
#define XLAL_BILLION_REAL8
Definition: Date.h:41
static int sign(int s)
Definition: LALStringTest.c:27
const char *const name
type name
Definition: UserInput.c:193
#define MYMIN(x, y)
#define LAL_sINT4_MAX
#define DEFN_XLALParseStringValueAsVector(CTYPE)
Parse a string containing a list of comma-separated values (CSV) into a <CTYPE>Vector.
static int SplitStringIntoRange(const char *str, char part[2][256], int T[2][2])
#define LAL_sINT8_MAX
#define LAL_UINT4_MAX
Definition: LALConstants.h:80
#define LAL_UINT8_MAX
Definition: LALConstants.h:79
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).
#define XLAL_LAST_ELEM(x)
MACRO to access the last element in a fixed-size array.
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.
float REAL4
Single precision real floating-point number (4 bytes).
#define XLALMalloc(n)
Definition: LALMalloc.h:44
#define XLALCalloc(m, n)
Definition: LALMalloc.h:45
#define XLALFree(p)
Definition: LALMalloc.h:47
#define XLALRealloc(p, n)
Definition: LALMalloc.h:46
#define LAL_INT8_FORMAT
Definition: LALStdio.h:128
#define LAL_UINT8_FORMAT
Definition: LALStdio.h:131
int XLALStringToLowerCase(char *string)
Turn a string in-place into lowercase without using locale-dependent functions.
Definition: LALString.c:153
int XLALStringCaseCompare(const char *s1, const char *s2)
Compare two strings, ignoring case and without using locale-dependent functions.
Definition: LALString.c:210
char * XLALDeblankString(const CHAR *start, UINT4 len)
Copy (and allocate) string from 'start' with length 'len', removing all starting- and trailing blanks...
Definition: StringVector.c:330
void XLALDestroyStringVector(LALStringVector *vect)
XLAL-interface: Free a string-vector ;)
Definition: StringVector.c:204
LALStringVector * XLALParseStringVector(const char *string, const char *delim)
Parse 'string' into a string vector of tokens, delimited by the characters 'delim'.
Definition: StringVector.c:280
int XLALTranslateHMStoRAD(REAL8 *radians, const CHAR *hms)
Translate a string representing an angle in the form "hours:minutes:seconds" into radians.
int XLALTranslateDMStoRAD(REAL8 *radians, const CHAR *dms)
Translate a string representing an angle in the form "degrees:minutes:seconds" into radians.
LIGOTimeGPS * XLALTranslateStringMJDTTtoGPS(LIGOTimeGPS *gps, const char *mjdString)
Parse and convert given string representing MJD(TT) time into LIGOTimeGPS gps time,...
Definition: TranslateMJD.c:91
LIGOTimeGPS LIGOTimeGPSRange[2]
A range of GPS times; first element is minimum, second element is maximum of range.
int XLALParseStringValueAsGPS(LIGOTimeGPS *gps, const char *valString)
Parse a string representing a GPS time into LIGOTimeGPS, without loss of (ns) accuracy.
int XLALParseStringValueAsRAJRange(REAL8Range rajRange, const char *valString)
Parse a string representing a range of RAJ values into a REAL8Range.
int XLALParseStringValueAsUINT8(UINT8 *valUINT8, const char *valString)
Parse a string into an UINT8 This ignores initial whitespace, but throws an error on any non-converte...
int XLALParseStringValueAsUINT4(UINT4 *valUINT4, const char *valString)
Parse a string into an UINT4 This ignores initial whitespace, but throws an error on any non-converte...
int XLALParseStringValueAsEPOCHRange(LIGOTimeGPSRange gpsRange, const char *valString)
Parse a string representing a range of LIGOTimeGPS values into a LIGOTimeGPSRange.
int XLALParseStringValueAsINT4PlusFrac(INT4 *valINT4, REAL8 *valFrac, const char *valString)
Parse a string containing a floating-point number into integer and fractional part,...
REAL8 REAL8Range[2]
A range of REAL8 values; first element is minimum, second element is maximum of range.
int XLALParseStringValueAsEPOCH(LIGOTimeGPS *gps, const char *valString)
Parse a string representing an 'epoch' into an LIGOTimeGPS, allowing both GPS and MJD(TT) inputs,...
int XLALParseStringValueAsINT4(INT4 *valINT4, const char *valString)
Parse a string into an INT4 This ignores initial whitespace, but throws an error on any non-converted...
int XLALParseStringValueAsREAL4(REAL4 *valREAL4, const char *valString)
Parse a string into a REAL4.
int XLALParseStringValueAsREAL8Range(REAL8Range real8Range, const char *valString)
Parse a string representing a range of REAL8 values into a REAL8Range.
int XLALParseStringValueAsINT8(INT8 *valINT8, const char *valString)
Parse a string into an INT8 This ignores initial whitespace, but throws an error on any non-converted...
int XLALParseStringValueAsDECJ(REAL8 *valDECJ, const char *valString)
Parse a string representing an 'equatorial latitude' (aka declination or DEC) into REAL8 radians,...
INT4 INT4Range[2]
A range of INT4 values; first element is minimum, second element is maximum of range.
int XLALParseStringValueAsBOOLEAN(BOOLEAN *valBOOLEAN, const char *valString)
Parse a string into a BOOLEAN Allowed string-values are (case-insensitive): {"yes",...
int XLALParseStringValueAsSTRINGVector(LALStringVector **strVect, const CHAR *valString)
Parse a string containing a list of comma-separated values (CSV) into a StringVector.
int XLALParseStringValueAsDECJRange(REAL8Range decjRange, const char *valString)
Parse a string representing a range of DECJ values into a REAL8Range.
int XLALParseStringValueAsINT4Range(INT4Range int4Range, const char *valString)
Parse a string representing a range of INT4 values into a INT4Range.
int XLALParseStringValueAsRAJ(REAL8 *valRAJ, const char *valString)
Parse a string representing an 'equatorial longitude' (aka right ascension or RA) into REAL8 radians,...
int XLALParseStringValueAsSTRING(CHAR **out, const CHAR *valStr)
Duplicate string 'in', removing surrounding quotes " or \' if present.
int XLALParseStringValueAsREAL8(REAL8 *valREAL8, const char *valString)
Parse a string into a REAL8 This ignores initial whitespace, but throws an error on any non-converted...
int XLALParseStringValueAsUserEnum(int *valEnum, const UserChoices *enumData, const char *valString)
Parse a string representing a user selection of an enumeration value.
int XLALParseStringValueAsUserFlag(int *valFlag, const UserChoices *flagData, const char *valString)
Parse a string representing a user selection of a set of bitflags.
#define XLAL_ERROR(...)
Macro to invoke a failure from a XLAL routine returning an integer.
Definition: XLALError.h:700
#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_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
@ 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_EDOM
Input domain error.
Definition: XLALError.h:410
@ 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
int XLALGPSCmp(const LIGOTimeGPS *t0, const LIGOTimeGPS *t1)
Compares two GPS times.
Definition: XLALTime.c:174
LIGOTimeGPS * XLALGPSSet(LIGOTimeGPS *epoch, INT4 gpssec, INT8 gpsnan)
Sets GPS time given GPS integer seconds and residual nanoseconds.
Definition: XLALTime.c:63
LIGOTimeGPS * XLALINT8NSToGPS(LIGOTimeGPS *epoch, INT8 ns)
Converts nano seconds stored as an INT8 to GPS time.
Definition: XLALTime.c:46
INT8 XLALGPSToINT8NS(const LIGOTimeGPS *epoch)
Converts GPS time to nano seconds stored as an INT8.
Definition: XLALTime.c:36
Vector of type CHAR*, ie 'strings', see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:82
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:86
CHAR ** data
Pointer to the data array.
Definition: LALDatatypes.h:87
Epoch relative to GPS epoch, see LIGOTimeGPS type for more details.
Definition: LALDatatypes.h:458
Possible choices the user may select for an enumeration or bitflag.