00001 /***************************************************************************** 00002 * 00003 * $RCSfile: fp_8c-source.html,v $ 00004 * 00005 * Double to String/String to Double Conversion Routines 00006 * 00007 * Written by Bill Ezell <wje@quackers.net> 00008 * http://www.mv.com/users/wje/pilot.html 00009 * 00010 * $Author: mp $ 00011 * 00012 * $Date: 2007-10-08 20:40:33 $ 00013 * 00014 * $Revision: 1.7.2.1 $ 00015 * 00016 * $Log: fp_8c-source.html,v $ 00016 * Revision 1.7.2.1 2007-10-08 20:40:33 mp 00016 * updated for gps4palm V0.9.5 beta 00016 * 00017 * Revision 1.6 2004-11-23 17:46:11 mp 00018 * removed unused variable 00019 * 00020 * Revision 1.5 2004/04/30 16:30:39 mp 00021 * modified comments for doxygen 00022 * 00023 * Revision 1.4 2004/03/20 11:17:41 mp 00024 * changed float to double 00025 * 00026 * Revision 1.3 2004/03/09 19:03:54 mp 00027 * Fixed search for decimal point in strings with multiple numerical values. 00028 * 00029 * Revision 1.2 2004/03/06 15:56:06 mp 00030 * added parameter trailP to cvt_atof() 00031 * 00032 * Revision 1.1 2003/12/31 12:32:17 mp 00033 * imported to CVS 00034 * 00035 * 00036 ****************************************************************************/ 00037 00038 #include "fp.h" 00039 00040 #ifdef UNIX 00041 #define StrChr(x,y) strchr(x,y) 00042 #define StrCopy(x,y) strcpy(x,y) 00043 #define StrLen(x) strlen(x) 00044 00045 #include <stdlib.h> 00046 #include <string.h> 00047 #else 00048 #define StrChr(x,y) strchr(x,y) 00049 #define StrCopy(x,y) strcpy(x,y) 00050 #define StrLen(x) strlen(x) 00051 #include <Unix/sys_types.h> 00052 #include "stringil.h" 00053 #endif 00054 00055 /* fp.c - simple float/ascii conversion routines 00056 * 00057 * These routines handle signed fixed-point strings only; no exponential 00058 * notation is supported. 00059 * 00060 * Contains: 00061 * 00062 * double cvt_atof(char *srcP, char **trailP, short *fracP) 00063 * converts the passed string to a double. If fracP is not 0, the 00064 * number of fractional digits found will be returned there. If 00065 * trailP is not 0, the pointer to the remaining substring will be 00066 * returned there. 00067 * An acceptable string is of the form [+-]digits[.digits]; leading 00068 * whitespace is ignored. 00069 * 00070 * void format_number(double src, short digits, char *destP) 00071 * converts the floating point src to a string; the value of digits 00072 * determines the number of fractional digits to produce. 00073 * The result will be rounded by adding 1/2 of the least-significant 00074 * digit position's scaling value to the fractional part and then truncating 00075 * the fractional part; e.g. 3.6 is rounded by adding .05 to the value. 00076 * 00077 * WARNING: if you use these functions with Pilot gcc, you MUST include 00078 * the function prototypes (below) in your code! Otherwise, gcc will 00079 * generate incorrect calls and your code won't work. 00080 * 00081 */ 00082 00083 00084 /* Internal prototypes */ 00085 00086 static unsigned long cvt_atoul(char *); 00087 static void cvt_ultoa(unsigned long,char *); 00088 00089 00090 /***************************************************************************** 00091 * FUNCTION: cvt_ultoa 00092 * 00093 * DESCRIPTION: Convert unsigned long value to string. 00094 * 00095 * PARAMETERS: value -- unsigned long value 00096 * strP -- ptr to string buffer for returning result 00097 * 00098 * RETURNED: % 00099 *****************************************************************************/ 00100 static void cvt_ultoa(unsigned long value, char *strP) 00101 { 00102 int i; 00103 char *cP; 00104 char tmpstr[16]; /* a 32 bit long can give up to 10 digits */ 00105 00106 if( value <= 9 ) /* a quick special case */ 00107 { 00108 *strP++ = value + '0'; 00109 *strP = '\0'; 00110 return; 00111 } 00112 00113 /* We convert the number backwards */ 00114 for( cP = tmpstr+9, i = 10; i-- > 0; ) 00115 { 00116 *cP-- = (value % 10) + '0'; 00117 value /= 10; 00118 } 00119 00120 tmpstr[10] = '\0'; 00121 00122 for( cP = tmpstr; *cP && (*cP == '0'); ) 00123 ++cP; 00124 00125 StrCopy(strP,cP); 00126 } 00127 00128 00129 /***************************************************************************** 00130 * FUNCTION: cvt_atoul 00131 * 00132 * DESCRIPTION: Convert string to unsigned long. 00133 * 00134 * PARAMETERS: strP -- string to convert 00135 * 00136 * RETURNED: unsigned long value. 00137 *****************************************************************************/ 00138 static unsigned long cvt_atoul(char *strP) 00139 { 00140 unsigned long value; 00141 00142 for( value = 0; (*strP >= '0') && (*strP <= '9'); ) 00143 { 00144 value *= 10; 00145 value += *strP++ - '0'; 00146 } 00147 00148 return(value); 00149 } 00150 00151 00152 /***************************************************************************** 00153 * FUNCTION: num_len 00154 * 00155 * DESCRIPTION: Return length of numerical substring. 00156 * 00157 * PARAMETERS: strP -- string to search 00158 * 00159 * RETURNED: Length of numerical substring. 00160 *****************************************************************************/ 00161 static unsigned num_len(char *strP) 00162 { 00163 unsigned i = 0; 00164 00165 while ((*strP >= '0') && (*strP <= '9')) { 00166 strP++; 00167 i++; 00168 } 00169 return i; 00170 } 00171 00172 00173 /***************************************************************************** 00174 * FUNCTION: find_decimal 00175 * 00176 * DESCRIPTION: Search for decimal point, but stop at any non-numerical 00177 * character. 00178 * 00179 * PARAMETERS: strP -- string to search 00180 * 00181 * RETURNED: Pointer to position of decimal point within string or NULL 00182 * if no decimal point found. 00183 *****************************************************************************/ 00184 static char *find_decimal(char *strP) 00185 { 00186 while ((*strP >= '0') && (*strP <= '9')) { 00187 strP++; 00188 } 00189 return ((*strP == '.') ? strP : NULL); 00190 } 00191 00192 00193 /****************************************************************************/ 00194 /** 00195 * Convert string to a double precision floating point value. 00196 * 00197 * \param strP string to convert 00198 * \param trailP pointer to remaining, unconverted part of string 00199 * \param fracP if not null, return number of fractional digits 00200 * 00201 * \return double precision floating point value 00202 *****************************************************************************/ 00203 double cvt_atof(char *strP, char **trailP, short *fracP) 00204 { 00205 int i; 00206 int neg; 00207 char *cP; 00208 unsigned long ipart,fpart; 00209 double rslt; 00210 00211 while( (*strP == ' ') || (*strP == '\t') ) /* trim whitespace */ 00212 ++strP; 00213 00214 if( *strP == '-' ) /* check for neg. */ 00215 { 00216 neg = 1; 00217 ++strP; 00218 } 00219 else 00220 { 00221 neg = 0; 00222 00223 if( *strP == '+' ) /* drop any sign */ 00224 ++strP; 00225 } 00226 00227 ipart = cvt_atoul(strP); /* get integer part */ 00228 if( fracP ) 00229 *fracP = 0; 00230 00231 if ( trailP ) 00232 *trailP = strP + num_len(strP); 00233 00234 if( (cP = find_decimal(strP)) ) 00235 { 00236 i = num_len(++cP); 00237 if ( trailP ) 00238 *trailP = cP + i; 00239 fpart = cvt_atoul(cP); /* and frac part */ 00240 rslt = (double)fpart; 00241 00242 if( fracP ) 00243 *fracP = i; 00244 while( i-- > 0 ) /* scale as needed */ 00245 rslt /= 10.0; 00246 00247 rslt += (double)ipart; 00248 } 00249 else 00250 rslt = (double)ipart; 00251 00252 return( neg?-rslt:rslt ); 00253 } 00254 00255 00256 /****************************************************************************/ 00257 /** 00258 * Format a double precision floating point value into a string. 00259 * 00260 * \param value value to format 00261 * \param frac number of fractional digits 00262 * \param strP pointer to destination string buffer 00263 * 00264 *****************************************************************************/ 00265 void format_number(double value, short frac, char *strP) 00266 { 00267 int i; 00268 unsigned long ipart, fpart; 00269 double limit; 00270 char str[16]; 00271 00272 if( frac > (sizeof(str) - 1) ) /* limit frac digits */ 00273 frac = sizeof(str) - 1; 00274 00275 if( value < 0.0 ) 00276 { 00277 *strP++ = '-'; 00278 value = -value; 00279 } 00280 00281 ipart = (long)value; 00282 value -= (double)ipart; /* recover frac part as int */ 00283 for( limit = 1.0, i = frac; i-- > 0; ) 00284 { 00285 value *= 10.0; 00286 limit *= 10.0; 00287 } 00288 00289 value += 0.5; /* do some rounding */ 00290 if( value >= limit ) 00291 { 00292 fpart = 0; /* overflowed */ 00293 ipart++; 00294 } 00295 else 00296 fpart = (unsigned long)(value); 00297 00298 cvt_ultoa(ipart,strP); 00299 00300 if( frac ) 00301 { 00302 cvt_ultoa(fpart,str); 00303 strP += StrLen(strP); 00304 *strP++ = '.'; 00305 00306 for( i = StrLen(str); i++ < frac; ) 00307 *strP++ = '0'; /* need some padding */ 00308 StrCopy(strP,str); /* and now the value */ 00309 } 00310 }