StringConvert.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Jolien Creighton, Peter Shawhan
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /******************************** <lalVerbatim file="StringConvertCV">
00021 Authors: Creighton, T. D.
00022          Shawhan, P. S.   (LALStringToGPS)
00023 $Id: StringConvert.c,v 1.12 2007/06/08 14:41:53 bema Exp $
00024 **************************************************** </lalVerbatim> */
00025 
00026 /********************************************************** <lalLaTeX>
00027 
00028 \subsection{Module \texttt{StringConvert.c}}
00029 \label{ss:StringConvert.c}
00030 
00031 Converts a string into a numerical value.
00032 
00033 \subsubsection*{Prototypes}
00034 \vspace{0.1in}
00035 \input{StringConvertCP}
00036 \idx{LALStringToI2()}
00037 \idx{LALStringToI4()}
00038 \idx{LALStringToI8()}
00039 \idx{LALStringToU2()}
00040 \idx{LALStringToU4()}
00041 \idx{LALStringToU8()}
00042 \idx{LALStringToS()}
00043 \idx{LALStringToD()}
00044 \idx{LALStringToC()}
00045 \idx{LALStringToZ()}
00046 \idx{LALStringToGPS()}
00047 
00048 \subsubsection*{Description}
00049 
00050 These routines parse the string \verb@*string@ and compute a numerical
00051 value \verb@*value@ of the appropriate datatype.  If
00052 \verb@endptr@$\neq$\verb@NULL@, then after conversion \verb@*endptr@
00053 will point to the character after the last character used in the
00054 conversion.  The routine will always return without error if the
00055 arguments are valid, regardless of the contents of \verb@string@;
00056 failure to parse a number is indicated by \verb@*endptr@ being set
00057 equal to \verb@string@ (provided \verb@endptr@$\neq$\verb@NULL@).
00058 
00059 For integer or floating-point conversion to occur, \verb@string@ must
00060 consist of zero or more whitespace characters followed by a number in
00061 any standard base-ten integer or floating-point representation
00062 (described in detail below); the conversion will stop as soon as the
00063 routine encounters a character that is not part of the number.  For
00064 instance, parsing the string \verb@"   123bad"@ will return
00065 \verb@*value@=123, and \verb@*endptr@ will point to the substring
00066 \verb@"bad"@; it is up to the calling routine to determine whether
00067 this is an acceptable input.  By contrast, parsing the string
00068 \verb@" bad"@ will leave \verb@*value@ unchanged and \verb@*endptr@
00069 pointing to the start of the original string.  In general, if the
00070 routine returns with \verb@*endptr@$\neq$\verb@string@ and
00071 \verb@**endptr@ is a whitespace or \verb@'\0'@ character, then the
00072 format was unambiguously acceptable.
00073 
00074 Complex conversion is essentially equivalent to performing
00075 floating-point conversion on \verb@string@ to get the real part, and
00076 again on \verb@*endptr@ to get the imaginary part.  Normally this
00077 means that an acceptable format is two floating-point representations
00078 separated by (and possibly preceded with) whitespace, although the
00079 intervening whitespace can be omitted if the separation between the
00080 two numbers is unambiguous.  Thus the string \verb@"-1.0+3.5"@ will be
00081 unambiguously read as $-1.0+3.5i$, but \verb@"-1.03.5"@ will be read
00082 as $-1.03+0.5i$ (since the conversion of the real part stops at the
00083 second \verb@'.'@ character), which may or may not be the intended
00084 conversion.
00085 
00086 GPS conversion is similar to floating-point conversion, but the result
00087 is stored in a \verb@LIGOTimeGPS@ structure as two integer values
00088 representing seconds and nanoseconds.  The \verb@LALStringToGPS@
00089 function does {\it not} convert the string to an intermediate
00090 \verb@REAL8@ value, but parses the string specially to retain the
00091 full precision of the string representation to the nearest nanosecond.
00092 
00093 \subsubsection*{Algorithm}
00094 
00095 These functions (other than \verb@LALStringToGPS@)
00096 emulate the standard C functions \verb@strtol()@,
00097 \verb@strtoul()@, and \verb@strtod()@, except that they follow LAL
00098 calling conventions and return values of the appropriate LAL
00099 datatypes.  For integer conversion, only base-ten (decimal)
00100 representations are supported.  Otherwise, the valid format is as for
00101 the corresponding C functions, which we summarize below:
00102 
00103 A string to be converted to an \verb@INT@$n$ (where $n$=2, 4, or 8)
00104 consists of zero or more whitespace characters as determined by
00105 \verb@isspace()@, followed optionally by a single \verb@'+'@ or
00106 \verb@'-'@ character, followed by one or more decimal digits;
00107 conversion stops at the first non-digit character after this.  If the
00108 result would overflow or underflow the \verb@INT@$n$ representation,
00109 then the value is set to \verb@LAL_INT@$n$\verb@_MAX@$=2^{8n-1}-1$ or
00110 \verb@LAL_INT@$n$\verb@_MIN@$=-2^{8n-1}$, respectively.
00111 
00112 A string to be converted to a \verb@UINT@$n$ follows the same format,
00113 except that a leading negative sign character \verb@'-'@ is
00114 \emph{ignored} (the routine will compute the magnitude of the result),
00115 and the return value is capped at
00116 \verb@LAL_UINT@$n$\verb@_MAX@$=2^{8n}-1$.
00117 
00118 A string to be converted to a floating-point number (\verb@REAL4@ or
00119 \verb@REAL8@) consists of zero or more whitespace characters as
00120 determined by \verb@isspace()@, followed optionally by a single
00121 \verb@'+'@ or \verb@'-'@ character, followed by a sequence of one or
00122 more decimal digits optionally containing a decimal point \verb@'.'@,
00123 optionally followed by an exponent.  An exponent consists of a single
00124 \verb@'E'@ or \verb@'e'@ character, followed optionally by a single
00125 \verb@'+'@ or \verb@'-'@ character, followed by a sequence of one or
00126 more decimal digits.  If the converted value would overflow,
00127 $\pm$\verb@LAL_REAL@$n$\verb@_MAX@ is returned, as appropriate.  If
00128 the value would underflow, 0 is returned.
00129 
00130 A string to be converted to a complex number (\verb@COMPLEX8@ or
00131 \verb@COMPLEX16@) consists of two floating-point format substrings
00132 concatenated together, where the first character of the second
00133 substring cannot be interpreted as a continuation of the first number.
00134 Usually this means that the second substring will contain at least one
00135 leading whitespace character, though this is not strictly necessary.
00136 Overflow or underflow is dealt with as above.
00137 
00138 A string to be converted to a GPS time can have the format of an integer
00139 or a floating-point number, as described above.  The optional exponent
00140 in the floating-point form is supported, and both positive and negative
00141 GPS times are permitted.  If the result would overflow the
00142 \verb@LIGOTimeGPS@ representation (too far in the future), then the
00143 \verb@gpsSeconds@ and \verb@gpsNanoSeconds@ fields are set to
00144 \verb@LAL_INT4_MAX@ and $999999999$, respectively.
00145 For an underflow (too far in the past), the fields
00146 are set to \verb@LAL_INT4_MIN@ and $0$.
00147 
00148 Internally, the floating-point conversion routines call
00149 \verb@strtod()@, then cap and cast the result as necessary.  The
00150 complex conversion routines simply call their floating-point
00151 counterpart twice.  The integer routines call an internal function
00152 \verb@LALStringToU8AndSign()@, which does what you would expect, then
00153 cap and cast the result as necessary.  (The C routines \verb@strtol()@
00154 and \verb@strtol()@ are not used as they are not guaranteed to have
00155 8-byte precision.)
00156 
00157 \subsubsection*{Uses}
00158 
00159 \subsubsection*{Notes}
00160 
00161 \vfill{\footnotesize\input{StringConvertCV}}
00162 
00163 ******************************************************* </lalLaTeX> */
00164 
00165 #include <ctype.h>
00166 #include <lal/LALStdlib.h>
00167 #include <lal/LALConstants.h>
00168 #include <lal/StringInput.h>
00169 
00170 NRCSID( STRINGCONVERTC, "$Id: StringConvert.c,v 1.12 2007/06/08 14:41:53 bema Exp $" );
00171 
00172 /* Extremal integer values, all expressed as unsigned long long. */
00173 #define LAL_UINT8_MAX   LAL_UINT8_C(18446744073709551615)
00174 #define LAL_UINT4_MAX   LAL_UINT8_C(4294967295)
00175 #define LAL_UINT2_MAX   LAL_UINT8_C(65535)
00176 #define LAL_INT8_MAX    LAL_UINT8_C(9223372036854775807)
00177 #define LAL_INT4_MAX    LAL_UINT8_C(2147483647)
00178 #define LAL_INT2_MAX    LAL_UINT8_C(32767)
00179 #define LAL_INT8_ABSMIN LAL_UINT8_C(9223372036854775808)
00180 #define LAL_INT4_ABSMIN LAL_UINT8_C(2147483648)
00181 #define LAL_INT2_ABSMIN LAL_UINT8_C(32768)
00182 
00183 /* Maximum number of digits we ever need to parse for an integer. */
00184 #define LAL_UINT8_MAXDIGITS (20)
00185 
00186 /* Internal function to parse integer strings into UINT8 magnitudes
00187    plus a sign. */
00188 static UINT8
00189 LALStringToU8AndSign( INT2 *sign, const CHAR *string, CHAR **endptr )
00190 {
00191   union { char *s; const char *cs; } bad;/* there is a REASON for warnings... */
00192   const CHAR *here = string;         /* current position in string */
00193   CHAR c;                            /* current character in string */
00194   UINT4 n = LAL_UINT8_MAXDIGITS - 1; /* number of worry-free digits */
00195   UINT8 value;                       /* current converted value */
00196 
00197   /* Skip leading space, and read sign character, if any. */
00198   *sign = 1;
00199   while ( isspace( *here ) )
00200     here++;
00201   if ( *here == '+' )
00202     here++;
00203   else if ( *here == '-' ) {
00204     *sign = -1;
00205     here++;
00206   }
00207 
00208   /* Read first digit.  Abort if it's not a digit. */
00209   if ( isdigit( (int)( c = *here ) ) ) {
00210     value = (UINT8)( c - '0' );
00211     here++;
00212   } else {
00213     bad.cs = string; /* ... and this avoids the warnings... BAD! */
00214     *endptr = bad.s;
00215     return 0;
00216   }
00217 
00218   /* Otherwise, start reading number.  Stop if we get close to
00219      overflowing. */
00220   while ( isdigit( (int)( c = *here ) ) && --n ) {
00221     value *= LAL_INT8_C(10);
00222     value += (UINT8)( c - '0' );
00223     here++;
00224   }
00225 
00226   /* Proceed with caution near overflow.  At this point, if n==0, then
00227      c = *here is the (LAL_UINT8_MAXDIGITS)th digit read, but value
00228      does not yet incorporate it. */
00229   if ( !n ) {
00230     here++;
00231     if ( isdigit( (int)( *here ) ) ) {
00232       value = LAL_UINT8_MAX;
00233       do
00234         here++;
00235       while ( isdigit( (int)( *here ) ) );
00236     } else if ( value > LAL_UINT8_MAX/LAL_INT8_C(10) ) {
00237       value = LAL_UINT8_MAX;
00238     } else {
00239       UINT8 increment = (UINT8)( c - '0' );
00240       value *= 10;
00241       if ( value > LAL_UINT8_MAX - increment )
00242         value = LAL_UINT8_MAX;
00243       else
00244         value += increment;
00245     }
00246   }
00247 
00248   /* Return appropriate values. */
00249   bad.cs = here; /* ... and this avoids the warnings... BAD! */
00250   *endptr = bad.s;
00251   return value;
00252 }
00253 
00254 
00255 /* <lalVerbatim file="StringConvertCP"> */
00256 void
00257 LALStringToU2( LALStatus *stat, UINT2 *value, const CHAR *string, CHAR **endptr )
00258 { /* </lalVerbatim> */
00259   UINT8 absValue; /* magnitude of parsed number */
00260   INT2 sign;      /* sign of parsed number */
00261   CHAR *end;      /* substring following parsed number */
00262 
00263   INITSTATUS( stat, "LALStringToU2", STRINGCONVERTC );
00264 
00265   /* Check for valid input arguments. */
00266   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00267   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00268 
00269   /* Parse string.  Return if nothing was parsed. */
00270   absValue = LALStringToU8AndSign( &sign, string, &end );
00271   if ( string == end ) {
00272     if ( endptr )
00273       *endptr = end;
00274     RETURN( stat );
00275   }
00276 
00277   /* Cap (if necessary), cast, and return. */
00278   if ( absValue > LAL_UINT2_MAX )
00279     *value = (UINT2)( LAL_UINT2_MAX );
00280   else
00281     *value = (UINT2)( absValue );
00282   if ( endptr )
00283     *endptr = end;
00284   RETURN( stat );
00285 }
00286 
00287 
00288 /* <lalVerbatim file="StringConvertCP"> */
00289 void
00290 LALStringToU4( LALStatus *stat, UINT4 *value, const CHAR *string, CHAR **endptr )
00291 { /* </lalVerbatim> */
00292   UINT8 absValue; /* magnitude of parsed number */
00293   INT2 sign;      /* sign of parsed number */
00294   CHAR *end;      /* substring following parsed number */
00295 
00296   INITSTATUS( stat, "LALStringToU4", STRINGCONVERTC );
00297 
00298   /* Check for valid input arguments. */
00299   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00300   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00301 
00302   /* Parse string.  Return if nothing was parsed. */
00303   absValue = LALStringToU8AndSign( &sign, string, &end );
00304   if ( string == end ) {
00305     if ( endptr )
00306       *endptr = end;
00307     RETURN( stat );
00308   }
00309 
00310   /* Cap (if necessary), cast, and return. */
00311   if ( absValue > LAL_UINT4_MAX )
00312     *value = (UINT4)( LAL_UINT4_MAX );
00313   else
00314     *value = (UINT4)( absValue );
00315   if ( endptr )
00316     *endptr = end;
00317   RETURN( stat );
00318 }
00319 
00320 
00321 /* <lalVerbatim file="StringConvertCP"> */
00322 void
00323 LALStringToU8( LALStatus *stat, UINT8 *value, const CHAR *string, CHAR **endptr )
00324 { /* </lalVerbatim> */
00325   UINT8 absValue; /* magnitude of parsed number */
00326   INT2 sign;      /* sign of parsed number */
00327   CHAR *end;      /* substring following parsed number */
00328 
00329   INITSTATUS( stat, "LALStringToU8", STRINGCONVERTC );
00330 
00331   /* Check for valid input arguments. */
00332   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00333   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00334 
00335   /* Parse string.  Return if nothing was parsed. */
00336   absValue = LALStringToU8AndSign( &sign, string, &end );
00337   if ( string == end ) {
00338     if ( endptr )
00339       *endptr = end;
00340     RETURN( stat );
00341   }
00342 
00343   /* Set values and return. */
00344   *value = absValue;
00345   if ( endptr )
00346     *endptr = end;
00347   RETURN( stat );
00348 }
00349 
00350 
00351 /* <lalVerbatim file="StringConvertCP"> */
00352 void
00353 LALStringToI2( LALStatus *stat, INT2 *value, const CHAR *string, CHAR **endptr )
00354 { /* </lalVerbatim> */
00355   UINT8 absValue; /* magnitude of parsed number */
00356   INT2 sign;      /* sign of parsed number */
00357   CHAR *end;      /* substring following parsed number */
00358 
00359   INITSTATUS( stat, "LALStringToI2", STRINGCONVERTC );
00360 
00361   /* Check for valid input arguments. */
00362   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00363   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00364 
00365   /* Parse string.  Return if nothing was parsed. */
00366   absValue = LALStringToU8AndSign( &sign, string, &end );
00367   if ( string == end ) {
00368     if ( endptr )
00369       *endptr = end;
00370     RETURN( stat );
00371   }
00372 
00373   /* Cap (if necessary), cast, and return. */
00374   if ( sign > 0 ) {
00375     if ( absValue > LAL_INT2_MAX )
00376       *value = (INT2)( LAL_INT2_MAX );
00377     else
00378       *value = (INT2)( absValue );
00379   } else {
00380     if ( absValue > LAL_INT2_ABSMIN )
00381       *value = (INT2)( -LAL_INT2_ABSMIN );
00382     else
00383       *value = (INT2)( -absValue );
00384   }
00385   if ( endptr )
00386     *endptr = end;
00387   RETURN( stat );
00388 }
00389 
00390 
00391 /* <lalVerbatim file="StringConvertCP"> */
00392 void
00393 LALStringToI4( LALStatus *stat, INT4 *value, const CHAR *string, CHAR **endptr )
00394 { /* </lalVerbatim> */
00395   UINT8 absValue; /* magnitude of parsed number */
00396   INT2 sign;      /* sign of parsed number */
00397   CHAR *end;      /* substring following parsed number */
00398 
00399   INITSTATUS( stat, "LALStringToI4", STRINGCONVERTC );
00400 
00401   /* Check for valid input arguments. */
00402   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00403   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00404 
00405   /* Parse string.  Return if nothing was parsed. */
00406   absValue = LALStringToU8AndSign( &sign, string, &end );
00407   if ( string == end ) {
00408     if ( endptr )
00409       *endptr = end;
00410     RETURN( stat );
00411   }
00412 
00413   /* Cap (if necessary), cast, and return. */
00414   if ( sign > 0 ) {
00415     if ( absValue > LAL_INT4_MAX )
00416       *value = (INT4)( LAL_INT4_MAX );
00417     else
00418       *value = (INT4)( absValue );
00419   } else {
00420     if ( absValue > LAL_INT4_ABSMIN )
00421       *value = (INT4)( -LAL_INT4_ABSMIN );
00422     else
00423       *value = (INT4)( -absValue );
00424   }
00425   if ( endptr )
00426     *endptr = end;
00427   RETURN( stat );
00428 }
00429 
00430 
00431 /* <lalVerbatim file="StringConvertCP"> */
00432 void
00433 LALStringToI8( LALStatus *stat, INT8 *value, const CHAR *string, CHAR **endptr )
00434 { /* </lalVerbatim> */
00435   UINT8 absValue; /* magnitude of parsed number */
00436   INT2 sign;      /* sign of parsed number */
00437   CHAR *end;      /* substring following parsed number */
00438 
00439   INITSTATUS( stat, "LALStringToI8", STRINGCONVERTC );
00440 
00441   /* Check for valid input arguments. */
00442   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00443   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00444 
00445   /* Parse string.  Return if nothing was parsed. */
00446   absValue = LALStringToU8AndSign( &sign, string, &end );
00447   if ( string == end ) {
00448     if ( endptr )
00449       *endptr = end;
00450     RETURN( stat );
00451   }
00452 
00453   /* Cap (if necessary), cast, and return. */
00454   if ( sign > 0 ) {
00455     if ( absValue > LAL_INT8_MAX )
00456       *value = (INT8)( LAL_INT8_MAX );
00457     else
00458       *value = (INT8)( absValue );
00459   } else {
00460     if ( absValue > LAL_INT8_ABSMIN )
00461       *value = (INT8)( -LAL_INT8_ABSMIN );
00462     else
00463       *value = (INT8)( -absValue );
00464   }
00465   if ( endptr )
00466     *endptr = end;
00467   RETURN( stat );
00468 }
00469 
00470 
00471 /* <lalVerbatim file="StringConvertCP"> */
00472 void
00473 LALStringToS( LALStatus *stat, REAL4 *value, const CHAR *string, CHAR **endptr )
00474 { /* </lalVerbatim> */
00475   REAL8 myValue; /* internal representation of value */
00476   CHAR *end;     /* substring following parsed number */
00477 
00478   INITSTATUS( stat, "LALStringToS", STRINGCONVERTC );
00479 
00480   /* Check for valid input arguments. */
00481   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00482   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00483 
00484   /* Parse string.  Return if nothing was parsed. */
00485   myValue = strtod( string, &end );
00486   if ( string == end ) {
00487     if ( endptr )
00488       *endptr = end;
00489     RETURN( stat );
00490   }
00491 
00492   /* Cap (if necessary), cast, and return. */
00493   if ( myValue > LAL_REAL4_MAX )
00494     *value = (REAL4)( LAL_REAL4_MAX );
00495   else if ( myValue < -LAL_REAL4_MAX )
00496     *value = (REAL4)( -LAL_REAL4_MAX );
00497   else
00498     *value = (REAL4)( myValue );
00499   if ( endptr )
00500     *endptr = end;
00501   RETURN( stat );
00502 }
00503 
00504 
00505 /* <lalVerbatim file="StringConvertCP"> */
00506 void
00507 LALStringToD( LALStatus *stat, REAL8 *value, const CHAR *string, CHAR **endptr )
00508 { /* </lalVerbatim> */
00509   REAL8 myValue; /* internal representation of value */
00510   CHAR *end;     /* substring following parsed number */
00511 
00512   INITSTATUS( stat, "LALStringToD", STRINGCONVERTC );
00513 
00514   /* Check for valid input arguments. */
00515   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00516   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00517 
00518   /* Parse string.  Return if nothing was parsed. */
00519   myValue = strtod( string, &end );
00520   if ( string == end ) {
00521     if ( endptr )
00522       *endptr = end;
00523     RETURN( stat );
00524   }
00525 
00526   /* Set values and return. */
00527   if ( myValue > LAL_REAL8_MAX )
00528     *value = LAL_REAL8_MAX;
00529   else if ( myValue < -LAL_REAL8_MAX )
00530     *value = -LAL_REAL8_MAX;
00531   else
00532     *value = myValue;
00533   if ( endptr )
00534     *endptr = end;
00535   RETURN( stat );
00536 }
00537 
00538 
00539 /* <lalVerbatim file="StringConvertCP"> */
00540 void
00541 LALStringToC( LALStatus *stat, COMPLEX8 *value, const CHAR *string, CHAR **endptr )
00542 { /* </lalVerbatim> */
00543   REAL4 re, im; /* real and imaginary parts */
00544   CHAR *end;    /* substring following parsed numbers */
00545 
00546   INITSTATUS( stat, "LALStringToC", STRINGCONVERTC );
00547   ATTATCHSTATUSPTR( stat );
00548 
00549   /* Check for valid input arguments. */
00550   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00551   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00552 
00553   /* Parse string.  Return if nothing was parsed. */
00554   TRY( LALStringToS( stat->statusPtr, &re, string, &end ), stat );
00555   TRY( LALStringToS( stat->statusPtr, &im, end, &end ), stat );
00556   if ( string == end ) {
00557     if ( endptr )
00558       *endptr = end;
00559     DETATCHSTATUSPTR( stat );
00560     RETURN( stat );
00561   }
00562 
00563   /* Set values and return. */
00564   value->re = re;
00565   value->im = im;
00566   if ( endptr )
00567     *endptr = end;
00568   DETATCHSTATUSPTR( stat );
00569   RETURN( stat );
00570 }
00571 
00572 
00573 /* <lalVerbatim file="StringConvertCP"> */
00574 void
00575 LALStringToZ( LALStatus *stat, COMPLEX16 *value, const CHAR *string, CHAR **endptr )
00576 { /* </lalVerbatim> */
00577   REAL8 re, im; /* real and imaginary parts */
00578   CHAR *end;    /* substring following parsed numbers */
00579 
00580   INITSTATUS( stat, "LALStringToZ", STRINGCONVERTC );
00581   ATTATCHSTATUSPTR( stat );
00582 
00583   /* Check for valid input arguments. */
00584   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00585   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00586 
00587   /* Parse string.  Return if nothing was parsed. */
00588   TRY( LALStringToD( stat->statusPtr, &re, string, &end ), stat );
00589   TRY( LALStringToD( stat->statusPtr, &im, end, &end ), stat );
00590   if ( string == end ) {
00591     if ( endptr )
00592       *endptr = end;
00593     DETATCHSTATUSPTR( stat );
00594     RETURN( stat );
00595   }
00596 
00597   /* Set values and return. */
00598   value->re = re;
00599   value->im = im;
00600   if ( endptr )
00601     *endptr = end;
00602   DETATCHSTATUSPTR( stat );
00603   RETURN( stat );
00604 }
00605 
00606 
00607 /* <lalVerbatim file="StringConvertCP"> */
00608 void
00609 LALStringToGPS( LALStatus *stat, LIGOTimeGPS *value, const CHAR *string, CHAR **endptr )
00610 { /* </lalVerbatim> */
00611 
00612   /* Trick borrowed from LALStringToU8AndSign() to avoid compiler warnings */
00613   union { char *s; const char *cs; } bad;/* there is a REASON for warnings... */
00614 
00615   const CHAR *here = string;   /* current position in string */
00616   INT4 signval;       /* sign of value (+1 or -1) */
00617   CHAR mantissa[32];  /* local string to store mantissa digits */
00618   INT4 mdigits;       /* number of digits in mantissa */
00619   INT4 dppos;         /* position of decimal point in mantissa, i.e. the
00620                          number of mantissa digits preceding the decimal point
00621                          (initially -1 if no decimal point in input.) */
00622   const CHAR *ehere;  /* string pointer for parsing exponent */
00623   INT4 exponent;      /* exponent given in string */
00624   INT2 esignval;      /* sign of exponent value (+1 or -1) */
00625   UINT8 absValue;     /* magnitude of parsed number */
00626   CHAR *eend;         /* substring following parsed number */
00627   INT4 nanosecSet;    /* flag to indicate if nanoseconds field has been set */
00628   INT4 idigit;        /* Digit value: 0 for 1s digit, 1 for 10s digit, etc. */
00629 
00630   INITSTATUS( stat, "LALStringToGPS", STRINGCONVERTC );
00631   ATTATCHSTATUSPTR( stat );
00632 
00633   /* Check for valid input arguments. */
00634   ASSERT( value, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00635   ASSERT( string, stat, STRINGINPUTH_ENUL, STRINGINPUTH_MSGENUL );
00636 
00637   /* Skip leading space, and read sign character, if any. */
00638   signval = 1;
00639   while ( isspace( *here ) )
00640     here++;
00641   if ( *here == '+' )
00642     here++;
00643   else if ( *here == '-' ) {
00644     signval = -1;
00645     here++;
00646   }
00647 
00648   /* Copy the mantissa into a local string, keeping track of the
00649      location of the decimal point */
00650   mdigits = 0;
00651   dppos = -1;
00652   while ( (*here >= '0' && *here <= '9') || (*here == '.') ) {
00653 
00654     if ( *here == '.' ) {
00655       /* This is a decimal point */
00656       if ( dppos >= 0 ) {
00657         /* This is second decimal point encountered, so parsing must stop */
00658         break;
00659       } else {
00660         /* Record the position of the decimal point */
00661         dppos = mdigits;
00662       }
00663 
00664     } else if ( *here == '0' && mdigits == 1 && mantissa[0] == '0' ) {
00665       /* We only want to keep at most one leading zero.  This is an
00666          additional leading zero, so simply ignore it. */
00667 
00668     } else {
00669       /* This is a digit.  Append it to the local mantissa string, unless
00670          the mantissa string is already full, in which case ignore it */
00671       if ( (UINT4) mdigits < sizeof(mantissa) ) {
00672         mantissa[mdigits] = *here;
00673         mdigits++;
00674       }
00675     }
00676 
00677     here++;
00678 
00679   }
00680 
00681   /* If there is no mantissa, then return without consuming any characters
00682      and without modifying 'value' */
00683   if ( mdigits == 0 ) {
00684     if ( endptr ) {
00685       bad.cs = string; /* ... and this avoids the warnings... BAD! */
00686       *endptr = bad.s;
00687     }
00688     DETATCHSTATUSPTR( stat );
00689     RETURN( stat );
00690   }
00691 
00692   /* If there was no explicit decimal point, then it is implicitly
00693      after all of the mantissa digits */
00694   if ( dppos == -1 ) { dppos = mdigits; }
00695 
00696   /* Read the exponent, if present */
00697   exponent = 0;
00698   if ( *here == 'E' || *here == 'e' ) {
00699     /* So far, this looks like an exponent.  Set working pointer. */
00700     ehere = here + 1;
00701 
00702     /* Parse the exponent value */
00703     absValue = LALStringToU8AndSign( &esignval, ehere, &eend );
00704     if ( eend == ehere ) {
00705       /* Nothing was parsed, so this isn't a valid exponent.  Leave
00706          things as they are, with 'here' pointing to the 'E' or 'e'
00707          that we thought introduced an exponent. */
00708     } else {
00709       /* We successfully parsed the exponent */
00710       exponent = (INT4) ( esignval * absValue );
00711       /* Update the 'here' pointer to just after the exponent */
00712       here = eend;
00713     }
00714 
00715   }
00716 
00717   /* The exponent simply modifies the decimal point position */
00718   dppos += exponent;
00719 
00720   /* OK, now we have the sign ('signval'), mantissa string, and
00721      decimal point location, and the 'here' pointer points to the
00722      first character after the part of the string we parsed. */
00723 
00724   nanosecSet = 0;
00725 
00726   if ( dppos > 11 ) {
00727     /* This is an overflow (positive) or underflow (negative) */
00728     if ( signval == 1 ) {
00729       value->gpsSeconds = (INT4) LAL_INT4_MAX;
00730       value->gpsNanoSeconds = 999999999;
00731     } else {
00732       value->gpsSeconds = (INT4)( -LAL_INT4_ABSMIN );
00733       value->gpsNanoSeconds = 0;
00734     }
00735 
00736   } else if ( dppos < -9 ) {
00737     /* The time is effectively zero */
00738     value->gpsSeconds = 0;
00739     value->gpsNanoSeconds = 0;
00740 
00741   } else {
00742 
00743     /* Pick out the integer part */
00744     absValue = 0;
00745     for ( idigit=0; idigit<dppos && idigit<mdigits; idigit++ ) {
00746       absValue = 10*absValue + (UINT8) ( mantissa[idigit]-'0' );
00747     }
00748     /* Fill in missing powers of ten if not all digits were present */
00749     for ( ; idigit<dppos; idigit++ ) {
00750       absValue *= 10;
00751     }
00752 
00753     /* Cap (if necessary) and cast */
00754     if ( signval > 0 ) {
00755       if ( absValue > LAL_INT4_MAX ) {
00756         value->gpsSeconds = (INT4)( LAL_INT4_MAX );
00757         value->gpsNanoSeconds = 999999999;
00758         nanosecSet = 1;
00759       } else
00760         value->gpsSeconds = (INT4)( absValue );
00761     } else {
00762       if ( absValue >= LAL_INT4_ABSMIN ) {
00763         value->gpsSeconds = (INT4)( -LAL_INT4_ABSMIN );
00764         value->gpsNanoSeconds = 0;
00765         nanosecSet = 1;
00766       } else
00767         value->gpsSeconds = (INT4)( -absValue );
00768     }
00769 
00770     /* Finally, set nanoseconds field (if not already set by over/underflow) */
00771     if ( ! nanosecSet ) {
00772 
00773       absValue = 0;
00774       for ( idigit=dppos; idigit<dppos+9 && idigit<mdigits; idigit++ ) {
00775         if ( idigit >= 0 ) {
00776           absValue = 10*absValue + (UINT8) ( mantissa[idigit]-'0' );
00777         }
00778       }
00779       /* If there is another digit, use it to round */
00780       if ( idigit==dppos+9 && idigit<mdigits ) {
00781         if ( mantissa[idigit] >= '5' ) {
00782           absValue++;
00783         }
00784       }
00785       /* Fill in missing powers of ten if not all digits were present */
00786       for ( ; idigit<dppos+9; idigit++ ) {
00787         absValue *= 10;
00788       }
00789 
00790       value->gpsNanoSeconds = (INT4) ( signval * absValue );
00791 
00792       /* Check for wraparound due to rounding */
00793       if ( value->gpsNanoSeconds >= 1000000000 ) {
00794         value->gpsNanoSeconds -= 1000000000;
00795         value->gpsSeconds += 1;
00796       }
00797       /* Ensure that nanoseconds field is nonnegative */
00798       while ( value->gpsNanoSeconds < 0 ) {
00799         value->gpsNanoSeconds += 1000000000;
00800         value->gpsSeconds -= 1;
00801       }
00802 
00803     }
00804 
00805   }
00806 
00807   /* Set end pointer (if passed) and return. */
00808   if ( endptr ) {
00809     bad.cs = here; /* ... and this avoids the warnings... BAD! */
00810     *endptr = bad.s;
00811   }
00812   DETATCHSTATUSPTR( stat );
00813   RETURN( stat );
00814 }

Generated on Sat Sep 6 03:07:40 2008 for LAL by  doxygen 1.5.2