StrToGPS.c

Go to the documentation of this file.
00001 /*
00002  * $Id: StrToGPS.c,v 1.18 2008/04/29 01:12:11 kipp Exp $
00003  *
00004  * Copyright (C) 2007  Kipp Cannon
00005  *
00006  * This program is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU General Public License as published by the
00008  * Free Software Foundation; either version 2 of the License, or (at your
00009  * option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
00014  * Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 
00021 
00022 #include <ctype.h>
00023 #include <errno.h>
00024 #include <locale.h>
00025 #include <stdlib.h>
00026 #include <lal/Date.h>
00027 #include <lal/LALDatatypes.h>
00028 
00029 
00030 #include <lal/LALRCSID.h>
00031 NRCSID (STRTOGPSC,"$Id: StrToGPS.c,v 1.18 2008/04/29 01:12:11 kipp Exp $");
00032 
00033 
00034 /*
00035  * Check for a base 10 or base 16 number.
00036  */
00037 
00038 
00039 static int isbase10(const char *s, int radix)
00040 {
00041         if(*s == radix)
00042                 s++;
00043         if(isdigit(*s))
00044                 return(1);
00045         return(0);
00046 }
00047 
00048 
00049 static int isbase16(const char *s, int radix)
00050 {
00051         if(*s == '0') {
00052                 s++;
00053                 if(*s == 'X' || *s == 'x') {
00054                         s++;
00055                         if(*s == radix)
00056                                 s++;
00057                         if(isxdigit(*s))
00058                                 return(1);
00059                 }
00060         }
00061         return(0);
00062 }
00063 
00064 
00065 /*
00066  * Check that a string contains an exponent.
00067  */
00068 
00069 
00070 static int isdecimalexp(const char *s)
00071 {
00072         if(*s == 'E' || *s == 'e') {
00073                 s++;
00074                 if(*s == '+' || *s == '-')
00075                         s++;
00076                 if(isdigit(*s))
00077                         return(1);
00078         }
00079         return(0);
00080 }
00081 
00082 
00083 static int isbinaryexp(const char *s)
00084 {
00085         if(*s == 'P' || *s == 'p') {
00086                 s++;
00087                 if(*s == '+' || *s == '-')
00088                         s++;
00089                 if(isdigit(*s))
00090                         return(1);
00091         }
00092         return(0);
00093 }
00094 
00095 
00096 /**
00097  * Parse an ASCII string into a LIGOTimeGPS structure.
00098  */
00099 
00100 
00101 int XLALStrToGPS(LIGOTimeGPS *t, const char *nptr, char **endptr)
00102 {
00103         static const char func[] = "XLALStrToGPS";
00104         union { char *s; const char *cs; } pconv; /* this is bad */
00105         int olderrno;
00106         int radix;
00107         char *digits;
00108         int len;
00109         int sign;
00110         int base;
00111         int radixpos;
00112         int exppart;
00113 
00114         /* save and clear C library errno so we can check for failures */
00115         olderrno = errno;
00116         errno = 0;
00117 
00118         /* retrieve the radix character */
00119         radix = localeconv()->decimal_point[0];
00120 
00121         /* this is bad ... there is a reason for warnings! */
00122         pconv.cs = nptr;
00123 
00124         /* consume leading white space */
00125         while(isspace(*(pconv.cs)))
00126                 (pconv.cs)++;
00127         if(endptr)
00128                 *endptr  = pconv.s;
00129 
00130         /* determine the sign */
00131         if(*(pconv.cs) == '-') {
00132                 sign = -1;
00133                 (pconv.cs)++;
00134         } else if(*(pconv.cs) == '+') {
00135                 sign = +1;
00136                 (pconv.cs)++;
00137         } else
00138                 sign = +1;
00139 
00140         /* determine the base */
00141         if(isbase16((pconv.cs), radix)) {
00142                 base = 16;
00143                 (pconv.cs) += 2;
00144         } else if(isbase10((pconv.cs), radix)) {
00145                 base = 10;
00146         } else {
00147                 /* this isn't a recognized number */
00148                 XLALGPSSet(t, 0, 0);
00149                 return(0);
00150         }
00151 
00152         /* count the number of digits including the radix but not including
00153          * the exponent. */
00154         radixpos = -1;
00155         switch(base) {
00156         case 10:
00157                 for(len = 0; 1; len++) {
00158                         if(isdigit((pconv.cs)[len]))
00159                                 continue;
00160                         if((pconv.cs)[len] == radix && radixpos < 0) {
00161                                 radixpos = len;
00162                                 continue;
00163                         }
00164                         break;
00165                 }
00166                 break;
00167         
00168         case 16:
00169                 for(len = 0; 1; len++) {
00170                         if(isxdigit((pconv.cs)[len]))
00171                                 continue;
00172                         if((pconv.cs)[len] == radix && radixpos < 0) {
00173                                 radixpos = len;
00174                                 continue;
00175                         }
00176                         break;
00177                 }
00178                 break;
00179         }
00180 
00181         /* copy the digits into a scratch space, removing the radix character
00182          * if one was found */
00183         if(radixpos >= 0) {
00184                 digits = malloc(len + 1);
00185                 memcpy(digits, (pconv.cs), radixpos);
00186                 memcpy(digits + radixpos, (pconv.cs) + radixpos + 1, len - radixpos - 1);
00187                 digits[len - 1] = '\0';
00188                 (pconv.cs) += len;
00189                 len--;
00190         } else {
00191                 digits = malloc(len + 2);
00192                 memcpy(digits, (pconv.cs), len);
00193                 digits[len] = '\0';
00194                 radixpos = len;
00195                 (pconv.cs) += len;
00196         }
00197 
00198         /* check for and parse an exponent, performing an adjustment of the
00199          * radix position */
00200         exppart = 1;
00201         switch(base) {
00202         case 10:
00203                 /* exponent is the number of powers of 10 */
00204                 if(isdecimalexp((pconv.cs)))
00205                         radixpos += strtol((pconv.cs) + 1, &pconv.s, 10);
00206                 break;
00207 
00208         case 16:
00209                 /* exponent is the number of powers of 2 */
00210                 if(isbinaryexp((pconv.cs))) {
00211                         exppart = strtol((pconv.cs) + 1, &pconv.s, 10);
00212                         radixpos += exppart / 4;
00213                         exppart %= 4;
00214                         if(exppart < 0) {
00215                                 radixpos--;
00216                                 exppart += 4;
00217                         }
00218                         exppart = 1 << exppart;
00219                 }
00220                 break;
00221         }
00222 
00223         /* save end of converted characters */
00224         if(endptr)
00225                 *endptr = pconv.s;
00226 
00227         /* insert the radix character, padding the scratch digits with zeroes
00228          * if needed */
00229         if(radixpos < 2) {
00230                 digits = realloc(digits, len + 2 + (2 - radixpos));
00231                 memmove(digits + (2 - radixpos) + 1, digits, len + 1);
00232                 memset(digits, '0', (2 - radixpos) + 1);
00233                 if(radixpos == 1)
00234                         digits[1] = digits[2];
00235                 radixpos = 2;
00236         } else if(radixpos > len) {
00237                 digits = realloc(digits, radixpos + 2);
00238                 memset(digits + len, '0', radixpos - len);
00239                 digits[radixpos + 1] = '\0';
00240         } else {
00241                 memmove(digits + radixpos + 1, digits + radixpos, len - radixpos + 1);
00242         }
00243         digits[radixpos] = radix;
00244 
00245         /* parse the integer part */
00246         XLALINT8NSToGPS(t, sign * strtol(digits, NULL, base) * exppart * 1000000000ll);
00247 
00248         /* parse the fractional part */
00249         if(errno != ERANGE) {
00250                 switch(base) {
00251                 case 10:
00252                         break;
00253 
00254                 case 16:
00255                         digits[radixpos - 2] = '0';
00256                         digits[radixpos - 1] = 'x';
00257                         radixpos -= 2;
00258                         break;
00259                 }
00260                 XLALGPSAdd(t, sign * strtod(digits + radixpos, NULL) * exppart);
00261         }
00262 
00263         /* free the scratch space */
00264         free(digits);
00265 
00266         /* check for failures and restore errno if there weren't any */
00267         if(errno == ERANGE)
00268                 XLAL_ERROR(func, XLAL_ERANGE);
00269         errno = olderrno;
00270 
00271         /* success */
00272         return(0);
00273 }
00274 
00275 
00276 /**
00277  * Return a string containing the ASCII base 10 representation of a
00278  * LIGOTimeGPS.  If s is not NULL, then the string is written to that
00279  * location which must be large enough to hold the string plus a '\0'
00280  * terminator.  If s is NULL then a new buffer is allocated, and the string
00281  * written to it.  The return value is the address of the string or NULL on
00282  * failure.
00283  */
00284 
00285 
00286 char *XLALGPSToStr(char *s, const LIGOTimeGPS *t)
00287 {
00288         static const char func[] = "XLALGPSToStr";
00289         const long billion = 1000000000;
00290         /* so we can play with it */
00291         LIGOTimeGPS copy = *t;
00292 
00293         /* make sure we've got a buffer */
00294 
00295         if(!s) {
00296                 /* 21 = 9 digits to the right of the decimal point +
00297                  * decimal point + upto 10 digits to the left of the
00298                  * decimal point plus an optional sign + a null */
00299                 s = XLALMalloc(21 * sizeof(*s));
00300                 if(!s)
00301                         XLAL_ERROR_NULL(func, XLAL_EFUNC);
00302         }
00303 
00304         /* normalize the fractional part */
00305 
00306         while(labs(copy.gpsNanoSeconds) > billion) {
00307                 if(copy.gpsNanoSeconds < 0) {
00308                         copy.gpsSeconds -= 1;
00309                         copy.gpsNanoSeconds += billion;
00310                 } else {
00311                         copy.gpsSeconds += 1;
00312                         copy.gpsNanoSeconds -= billion;
00313                 }
00314         }
00315 
00316         /* if both components are non-zero, make sure they have the same
00317          * sign */
00318 
00319         if(copy.gpsSeconds > 0 && copy.gpsNanoSeconds < 0) {
00320                 copy.gpsSeconds -= 1;
00321                 copy.gpsNanoSeconds += billion;
00322         } else if(copy.gpsSeconds < 0 && copy.gpsNanoSeconds > 0) {
00323                 copy.gpsSeconds += 1;
00324                 copy.gpsNanoSeconds -= billion;
00325         }
00326 
00327         /* print */
00328 
00329         if(copy.gpsSeconds < 0 || copy.gpsNanoSeconds < 0)
00330                 /* number is negative */
00331                 sprintf(s, "-%ld.%09ld", labs(copy.gpsSeconds), labs(copy.gpsNanoSeconds));
00332         else
00333                 /* number is non-negative */
00334                 sprintf(s, "%ld.%09ld", (long) copy.gpsSeconds, (long) copy.gpsNanoSeconds);
00335 
00336         return s;
00337 }

Generated on Tue Oct 14 02:32:29 2008 for LAL by  doxygen 1.5.2