Loading [MathJax]/extensions/TeX/AMSsymbols.js
LAL 7.7.0.1-00ddc7f
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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)
49int
50XLALParseStringValueAsINT8 ( 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)
78int
79XLALParseStringValueAsINT4 ( 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)
101int
102XLALParseStringValueAsUINT8 ( 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)
134int
135XLALParseStringValueAsUINT4 ( 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)
157int
158XLALParseStringValueAsREAL8 ( 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)
178int
179XLALParseStringValueAsREAL4 ( 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///
202int
203XLALParseStringValueAsINT4PlusFrac ( 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
247int
248XLALParseStringValueAsBOOLEAN ( 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///
286int
287XLALParseStringValueAsGPS ( 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///
313int
314XLALParseStringValueAsEPOCH ( 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///
364int
365XLALParseStringValueAsRAJ ( 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 {
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///
391int
392XLALParseStringValueAsDECJ ( 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//
417static 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///
662int 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///
695int 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
738XLAL_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///
756int
757XLALParseStringValueAsSTRING ( 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///
804int
805XLALParseStringValueAsSTRINGVector ( 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) \
874DECL_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
void XLALDestroyStringVector(LALStringVector *vect)
XLAL-interface: Free a string-vector ;)
Definition: StringVector.c:204
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
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
LIGOTimeGPS * XLALGPSSet(LIGOTimeGPS *epoch, INT4 gpssec, INT8 gpsnan)
Sets GPS time given GPS integer seconds and residual nanoseconds.
Definition: XLALTime.c:63
int XLALGPSCmp(const LIGOTimeGPS *t0, const LIGOTimeGPS *t1)
Compares two GPS times.
Definition: XLALTime.c:174
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.