GPS4Palm

Source Code Documentation


fp.c

Go to the documentation of this file.
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 }

Created: Mon, 08 Oct 2007 22:33:16 +0200
Copyright ©2004 M. Prinke