Loading [MathJax]/extensions/TeX/AMSsymbols.js
LAL 7.7.0.1-3a66518
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
StrToGPS.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007 Kipp Cannon
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 * Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19
20#include <ctype.h>
21#include <errno.h>
22#include <locale.h>
23#include <stdlib.h>
24#include <string.h>
25#include <lal/Date.h>
26#include <lal/LALDatatypes.h>
27#include <lal/LALMalloc.h>
28#include <lal/XLALError.h>
29
30
31/*
32 * Check for a base 10 or base 16 number.
33 */
34
35
36static int isbase10(const char *s, int radix)
37{
38 if(*s == radix)
39 s++;
40 return isdigit(*s);
41}
42
43
44static int isbase16(const char *s, int radix)
45{
46 if(*s == '0') {
47 s++;
48 if(*s == 'X' || *s == 'x') {
49 s++;
50 if(*s == radix)
51 s++;
52 return isxdigit(*s);
53 }
54 }
55 return 0;
56}
57
58
59/*
60 * Check that a string contains an exponent.
61 */
62
63
64static int isdecimalexp(const char *s)
65{
66 if(*s == 'E' || *s == 'e') {
67 s++;
68 if(*s == '+' || *s == '-')
69 s++;
70 return isdigit(*s);
71 }
72 return 0;
73}
74
75
76static int isbinaryexp(const char *s)
77{
78 if(*s == 'P' || *s == 'p') {
79 s++;
80 if(*s == '+' || *s == '-')
81 s++;
82 return isdigit(*s);
83 }
84 return 0;
85}
86
87
88/**
89 * Parse an ASCII string into a LIGOTimeGPS structure.
90 */
91int XLALStrToGPS(LIGOTimeGPS *t, const char *nptr, char **endptr)
92{
93 union { char *s; const char *cs; } pconv; /* this is bad */
94 int olderrno;
95 int radix;
96 char *digits;
97 int len=0;
98 int sign;
99 int base;
100 int radixpos;
101 int exppart;
102
103 /* save and clear C library errno so we can check for failures */
104 olderrno = errno;
105 errno = 0;
106
107 /* retrieve the radix character */
108 radix = localeconv()->decimal_point[0];
109
110 /* this is bad ... there is a reason for warnings! */
111 pconv.cs = nptr;
112
113 /* consume leading white space */
114 while(isspace(*(pconv.cs)))
115 (pconv.cs)++;
116 if(endptr)
117 *endptr = pconv.s;
118
119 /* determine the sign */
120 if(*(pconv.cs) == '-') {
121 sign = -1;
122 (pconv.cs)++;
123 } else if(*(pconv.cs) == '+') {
124 sign = +1;
125 (pconv.cs)++;
126 } else
127 sign = +1;
128
129 /* determine the base */
130 if(isbase16((pconv.cs), radix)) {
131 base = 16;
132 (pconv.cs) += 2;
133 } else if(isbase10((pconv.cs), radix)) {
134 base = 10;
135 } else {
136 /* this isn't a recognized number */
137 XLALGPSSet(t, 0, 0);
138 return 0;
139 }
140
141 /* count the number of digits including the radix but not including
142 * the exponent. */
143 radixpos = -1;
144 switch(base) {
145 case 10:
146 for(len = 0; 1; len++) {
147 if(isdigit((pconv.cs)[len]))
148 continue;
149 if((pconv.cs)[len] == radix && radixpos < 0) {
150 radixpos = len;
151 continue;
152 }
153 break;
154 }
155 break;
156
157 case 16:
158 for(len = 0; 1; len++) {
159 if(isxdigit((pconv.cs)[len]))
160 continue;
161 if((pconv.cs)[len] == radix && radixpos < 0) {
162 radixpos = len;
163 continue;
164 }
165 break;
166 }
167 break;
168 }
169
170 /* copy the digits into a scratch space, removing the radix character
171 * if one was found */
172 if(radixpos >= 0) {
173 digits = malloc(len + 1);
174 memcpy(digits, (pconv.cs), radixpos);
175 memcpy(digits + radixpos, (pconv.cs) + radixpos + 1, len - radixpos - 1);
176 digits[len - 1] = '\0';
177 (pconv.cs) += len;
178 len--;
179 } else {
180 digits = malloc(len + 2);
181 memcpy(digits, (pconv.cs), len);
182 digits[len] = '\0';
183 radixpos = len;
184 (pconv.cs) += len;
185 }
186
187 /* check for and parse an exponent, performing an adjustment of the
188 * radix position */
189 exppart = 1;
190 switch(base) {
191 case 10:
192 /* exponent is the number of powers of 10 */
193 if(isdecimalexp((pconv.cs)))
194 radixpos += strtol((pconv.cs) + 1, &pconv.s, 10);
195 break;
196
197 case 16:
198 /* exponent is the number of powers of 2 */
199 if(isbinaryexp((pconv.cs))) {
200 exppart = strtol((pconv.cs) + 1, &pconv.s, 10);
201 radixpos += exppart / 4;
202 exppart %= 4;
203 if(exppart < 0) {
204 radixpos--;
205 exppart += 4;
206 }
207 exppart = 1 << exppart;
208 }
209 break;
210 }
211
212 /* save end of converted characters */
213 if(endptr)
214 *endptr = pconv.s;
215
216 /* insert the radix character, padding the scratch digits with zeroes
217 * if needed */
218 if(radixpos < 2) {
219 digits = realloc(digits, len + 2 + (2 - radixpos));
220 memmove(digits + (2 - radixpos) + 1, digits, len + 1);
221 memset(digits, '0', (2 - radixpos) + 1);
222 if(radixpos == 1)
223 digits[1] = digits[2];
224 radixpos = 2;
225 } else if(radixpos > len) {
226 digits = realloc(digits, radixpos + 2);
227 memset(digits + len, '0', radixpos - len);
228 digits[radixpos + 1] = '\0';
229 } else {
230 memmove(digits + radixpos + 1, digits + radixpos, len - radixpos + 1);
231 }
232 digits[radixpos] = radix;
233
234 /* parse the integer part */
235 XLALINT8NSToGPS(t, sign * strtol(digits, NULL, base) * exppart * XLAL_BILLION_INT8);
236
237 /* parse the fractional part */
238 if(errno != ERANGE) {
239 switch(base) {
240 case 10:
241 break;
242
243 case 16:
244 digits[radixpos - 2] = '0';
245 digits[radixpos - 1] = 'x';
246 radixpos -= 2;
247 break;
248 }
249 XLALGPSAdd(t, sign * strtod(digits + radixpos, NULL) * exppart);
250 }
251
252 /* free the scratch space */
253 free(digits);
254
255 /* check for failures and restore errno if there weren't any */
256 if(errno == ERANGE)
258 errno = olderrno;
259
260 /* success */
261 return 0;
262}
263
264
265/**
266 * \ingroup Date_h
267 * \brief Return a string containing the ASCII base 10 representation of a
268 * LIGOTimeGPS. If s is not NULL, then the string is written to that
269 * location which must be large enough to hold the string plus a 0
270 * terminator. If s is NULL then a new buffer is allocated, and the string
271 * written to it; free the buffer with XLALFree(). The return value is
272 * the address of the string or NULL on failure.
273 */
274char *XLALGPSToStr(char *s, const LIGOTimeGPS *t)
275{
276 char *end;
277 /* so we can play with it */
278 LIGOTimeGPS copy = *t;
279
280 /* make sure we've got a buffer */
281
282 if(!s) {
283 /* 22 = 9 digits to the right of the decimal point +
284 * decimal point + upto 10 digits to the left of the
285 * decimal point plus an optional sign + a null */
286 s = XLALMalloc(22 * sizeof(*s));
287 if(!s)
289 }
290
291 /* normalize the fractional part */
292
293 while(labs(copy.gpsNanoSeconds) >= XLAL_BILLION_INT4) {
294 if(copy.gpsNanoSeconds < 0) {
295 copy.gpsSeconds -= 1;
297 } else {
298 copy.gpsSeconds += 1;
300 }
301 }
302
303 /* if both components are non-zero, make sure they have the same
304 * sign */
305
306 if(copy.gpsSeconds > 0 && copy.gpsNanoSeconds < 0) {
307 copy.gpsSeconds -= 1;
309 } else if(copy.gpsSeconds < 0 && copy.gpsNanoSeconds > 0) {
310 copy.gpsSeconds += 1;
312 }
313
314 /* print */
315
316 if(copy.gpsSeconds < 0 || copy.gpsNanoSeconds < 0)
317 /* number is negative */
318 end = s + sprintf(s, "-%ld.%09ld", labs(copy.gpsSeconds), labs(copy.gpsNanoSeconds));
319 else
320 /* number is non-negative */
321 end = s + sprintf(s, "%ld.%09ld", (long) copy.gpsSeconds, (long) copy.gpsNanoSeconds);
322
323 /* remove trailing 0s and decimal point */
324
325 while(*(--end) == '0')
326 *end = 0;
327 if(*end == '.')
328 *end = 0;
329
330 /* done */
331
332 return s;
333}
#define XLAL_BILLION_INT4
Definition: Date.h:39
#define XLAL_BILLION_INT8
Definition: Date.h:40
static int sign(int s)
Definition: LALStringTest.c:27
static int isbinaryexp(const char *s)
Definition: StrToGPS.c:76
static int isbase16(const char *s, int radix)
Definition: StrToGPS.c:44
static int isbase10(const char *s, int radix)
Definition: StrToGPS.c:36
int XLALStrToGPS(LIGOTimeGPS *t, const char *nptr, char **endptr)
Parse an ASCII string into a LIGOTimeGPS structure.
Definition: StrToGPS.c:91
static int isdecimalexp(const char *s)
Definition: StrToGPS.c:64
char * XLALGPSToStr(char *s, const LIGOTimeGPS *t)
Return a string containing the ASCII base 10 representation of a LIGOTimeGPS.
Definition: StrToGPS.c:274
#define XLALMalloc(n)
Definition: LALMalloc.h:44
#define XLAL_ERROR_NULL(...)
Macro to invoke a failure from a XLAL routine returning a pointer.
Definition: XLALError.h:713
#define XLAL_ERROR(...)
Macro to invoke a failure from a XLAL routine returning an integer.
Definition: XLALError.h:700
@ XLAL_ERANGE
Output range error.
Definition: XLALError.h:411
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
LIGOTimeGPS * XLALGPSSet(LIGOTimeGPS *epoch, INT4 gpssec, INT8 gpsnan)
Sets GPS time given GPS integer seconds and residual nanoseconds.
Definition: XLALTime.c:63
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
Adds a double to a GPS time.
Definition: XLALTime.c:131
LIGOTimeGPS * XLALINT8NSToGPS(LIGOTimeGPS *epoch, INT8 ns)
Converts nano seconds stored as an INT8 to GPS time.
Definition: XLALTime.c:46
Epoch relative to GPS epoch, see LIGOTimeGPS type for more details.
Definition: LALDatatypes.h:458
INT4 gpsSeconds
Seconds since 0h UTC 6 Jan 1980.
Definition: LALDatatypes.h:459
INT4 gpsNanoSeconds
Residual nanoseconds.
Definition: LALDatatypes.h:460