LCOV - code coverage report
Current view: directory - port - cpl_strtod.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 48 33 68.8 %
Date: 2011-12-18 Functions: 8 5 62.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_strtod.cpp 23556 2011-12-12 21:49:34Z rouault $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Functions to convert ASCII string to floating point number.
       6                 :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu.
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2006, Andrey Kiselev
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include <locale.h>
      31                 : #include <errno.h>
      32                 : #include <stdlib.h>
      33                 : 
      34                 : #include "cpl_conv.h"
      35                 : 
      36                 : CPL_CVSID("$Id: cpl_strtod.cpp 23556 2011-12-12 21:49:34Z rouault $");
      37                 : 
      38                 : // XXX: with GCC 2.95 strtof() function is only available when in c99 mode.
      39                 : // Fix it here not touching the compiler options.
      40                 : #if defined(HAVE_STRTOF) && !HAVE_DECL_STRTOF
      41                 : extern "C" {
      42                 : extern float strtof(const char *nptr, char **endptr);
      43                 : }
      44                 : #endif
      45                 : 
      46                 : #ifndef NAN
      47                 : #  ifdef HUGE_VAL
      48                 : #    define NAN (HUGE_VAL * 0.0)
      49                 : #  else
      50                 : 
      51                 : static float CPLNaN(void)
      52                 : {
      53                 :     float fNan;
      54                 :     int nNan = 0x7FC00000;
      55                 :     memcpy(&fNan, &nNan, 4);
      56                 :     return fNan;
      57                 : }
      58                 : 
      59                 : #    define NAN CPLNan()
      60                 : #  endif
      61                 : #endif
      62                 : 
      63                 : /************************************************************************/
      64                 : /*                            CPLAtofDelim()                            */
      65                 : /************************************************************************/
      66                 : 
      67                 : /**
      68                 :  * Converts ASCII string to floating point number.
      69                 :  *
      70                 :  * This function converts the initial portion of the string pointed to
      71                 :  * by nptr to double floating point representation. The behaviour is the
      72                 :  * same as
      73                 :  *
      74                 :  *   CPLStrtodDelim(nptr, (char **)NULL, point);
      75                 :  *
      76                 :  * This function does the same as standard atof(3), but does not take locale
      77                 :  * in account. Instead of locale defined decimal delimiter you can specify
      78                 :  * your own one. Also see notes for CPLAtof() function.
      79                 :  *
      80                 :  * @param nptr Pointer to string to convert.
      81                 :  * @param point Decimal delimiter.
      82                 :  *
      83                 :  * @return Converted value, if any.
      84                 :  */
      85               0 : double CPLAtofDelim(const char *nptr, char point)
      86                 : {
      87               0 :   return CPLStrtodDelim(nptr, 0, point);
      88                 : }
      89                 : 
      90                 : /************************************************************************/
      91                 : /*                              CPLAtof()                               */
      92                 : /************************************************************************/
      93                 : 
      94                 : /**
      95                 :  * Converts ASCII string to floating point number.
      96                 :  *
      97                 :  * This function converts the initial portion of the string pointed to
      98                 :  * by nptr to double floating point representation. The behaviour is the
      99                 :  * same as
     100                 :  *
     101                 :  *   CPLStrtod(nptr, (char **)NULL);
     102                 :  *
     103                 :  * This function does the same as standard atof(3), but does not take
     104                 :  * locale in account. That means, the decimal delimiter is always '.'
     105                 :  * (decimal point). Use CPLAtofDelim() function if you want to specify
     106                 :  * custom delimiter.
     107                 :  *
     108                 :  * IMPORTANT NOTE.
     109                 :  * Existance of this function does not mean you should always use it.
     110                 :  * Sometimes you should use standard locale aware atof(3) and its family. When
     111                 :  * you need to process the user's input (for example, command line parameters)
     112                 :  * use atof(3), because user works in localized environment and her input will
     113                 :  * be done accordingly the locale set. In particular that means we should not
     114                 :  * make assumptions about character used as decimal delimiter, it can be
     115                 :  * either "." or ",".
     116                 :  * But when you are parsing some ASCII file in predefined format, you most
     117                 :  * likely need CPLAtof(), because such files distributed across the systems
     118                 :  * with different locales and floating point representation shoudl be
     119                 :  * considered as a part of file format. If the format uses "." as a delimiter
     120                 :  * the same character must be used when parsing number regardless of actual
     121                 :  * locale setting.
     122                 :  *
     123                 :  * @param nptr Pointer to string to convert.
     124                 :  *
     125                 :  * @return Converted value, if any.
     126                 :  */
     127          937384 : double CPLAtof(const char *nptr)
     128                 : {
     129          937384 :   return CPLStrtod(nptr, 0);
     130                 : }
     131                 : 
     132                 : /************************************************************************/
     133                 : /*                              CPLAtofM()                              */
     134                 : /************************************************************************/
     135                 : 
     136                 : /**
     137                 :  * Converts ASCII string to floating point number using any numeric locale.
     138                 :  *
     139                 :  * This function converts the initial portion of the string pointed to
     140                 :  * by nptr to double floating point representation. This function does the
     141                 :  * same as standard atof(), but it allows a variety of locale representations.
     142                 :  * That is it supports numeric values with either a comma or a period for 
     143                 :  * the decimal delimiter. 
     144                 :  * 
     145                 :  * PS. The M stands for Multi-lingual.
     146                 :  *
     147                 :  * @param nptr The string to convert.
     148                 :  *
     149                 :  * @return Converted value, if any.  Zero on failure.
     150                 :  */
     151                 : 
     152          356876 : double CPLAtofM( const char *nptr )
     153                 : 
     154                 : {
     155                 :     int i;
     156                 :     const static int nMaxSearch = 50;
     157                 : 
     158         2164050 :     for( i = 0; i < nMaxSearch; i++ )
     159                 :     {
     160         2164050 :         if( nptr[i] == ',' )
     161             189 :             return CPLStrtodDelim( nptr, 0, ',' );
     162         2163861 :         else if( nptr[i] == '.' || nptr[i] == '\0' )
     163          356687 :             return CPLStrtodDelim( nptr, 0, '.' );
     164                 :     }
     165                 : 
     166               0 :     return CPLStrtodDelim( nptr, 0, '.' );
     167                 : }
     168                 : 
     169                 : /************************************************************************/
     170                 : /*                      CPLReplacePointByLocalePoint()                  */
     171                 : /************************************************************************/
     172                 : 
     173         1303752 : static char* CPLReplacePointByLocalePoint(const char* pszNumber, char point)
     174                 : {
     175                 : #if defined(WIN32CE) || defined(__ANDROID__)
     176                 :     static char byPoint = 0;
     177                 :     if (byPoint == 0)
     178                 :     {
     179                 :         char szBuf[16];
     180                 :         sprintf(szBuf, "%.1f", 1.0);
     181                 :         byPoint = szBuf[1];
     182                 :     }
     183                 :     if (point != byPoint)
     184                 :     {
     185                 :         const char* pszPoint = strchr(pszNumber, point);
     186                 :         if (pszPoint)
     187                 :         {
     188                 :             char* pszNew = CPLStrdup(pszNumber);
     189                 :             pszNew[pszPoint - pszNumber] = byPoint;
     190                 :             return pszNew;
     191                 :         }
     192                 :     }
     193                 : #else
     194         1303752 :     struct lconv *poLconv = localeconv();
     195         1303752 :     if ( poLconv
     196                 :          && poLconv->decimal_point
     197                 :          && strlen(poLconv->decimal_point) > 0 )
     198                 :     {
     199         1303752 :         char    byPoint = poLconv->decimal_point[0];
     200                 : 
     201         1303752 :         if (point != byPoint)
     202                 :         {
     203             189 :             const char* pszPoint = strchr(pszNumber, point);
     204             189 :             if (pszPoint)
     205                 :             {
     206             189 :                 char* pszNew = CPLStrdup(pszNumber);
     207             189 :                 pszNew[pszPoint - pszNumber] = byPoint;
     208             189 :                 return pszNew;
     209                 :             }
     210                 :         }
     211                 :     }
     212                 : #endif
     213         1303563 :     return (char*) pszNumber;
     214                 : }
     215                 : 
     216                 : /************************************************************************/
     217                 : /*                          CPLStrtodDelim()                            */
     218                 : /************************************************************************/
     219                 : 
     220                 : /**
     221                 :  * Converts ASCII string to floating point number using specified delimiter.
     222                 :  *
     223                 :  * This function converts the initial portion of the string pointed to
     224                 :  * by nptr to double floating point representation. This function does the
     225                 :  * same as standard strtod(3), but does not take locale in account. Instead of
     226                 :  * locale defined decimal delimiter you can specify your own one. Also see
     227                 :  * notes for CPLAtof() function.
     228                 :  *
     229                 :  * @param nptr Pointer to string to convert.
     230                 :  * @param endptr If is not NULL, a pointer to the character after the last
     231                 :  * character used in the conversion is stored in the location referenced
     232                 :  * by endptr.
     233                 :  * @param point Decimal delimiter.
     234                 :  *
     235                 :  * @return Converted value, if any.
     236                 :  */
     237         1303951 : double CPLStrtodDelim(const char *nptr, char **endptr, char point)
     238                 : {
     239         1303951 :    if (EQUAL(nptr,"nan") || EQUAL(nptr, "1.#QNAN") ||
     240                 :        EQUAL(nptr, "-1.#QNAN") || EQUAL(nptr, "-1.#IND"))
     241             199 :        return NAN;
     242                 : 
     243                 : /* -------------------------------------------------------------------- */
     244                 : /*  We are implementing a simple method here: copy the input string     */
     245                 : /*  into the temporary buffer, replace the specified decimal delimiter  */
     246                 : /*  with the one, taken from locale settings and use standard strtod()  */
     247                 : /*  on that buffer.                                                     */
     248                 : /* -------------------------------------------------------------------- */
     249                 :     double      dfValue;
     250                 :     int         nError;
     251                 : 
     252         1303752 :     char*       pszNumber = CPLReplacePointByLocalePoint(nptr, point);
     253                 : 
     254         1303752 :     dfValue = strtod( pszNumber, endptr );
     255         1303752 :     nError = errno;
     256                 : 
     257         1303752 :     if ( endptr )
     258            9691 :         *endptr = (char *)nptr + (*endptr - pszNumber);
     259                 : 
     260         1303752 :     if (pszNumber != (char*) nptr)
     261             189 :         CPLFree( pszNumber );
     262                 : 
     263         1303752 :     errno = nError;
     264         1303752 :     return dfValue;
     265                 : }
     266                 : 
     267                 : /************************************************************************/
     268                 : /*                             CPLStrtod()                              */
     269                 : /************************************************************************/
     270                 : 
     271                 : /**
     272                 :  * Converts ASCII string to floating point number.
     273                 :  *
     274                 :  * This function converts the initial portion of the string pointed to
     275                 :  * by nptr to double floating point representation. This function does the
     276                 :  * same as standard strtod(3), but does not take locale in account. That
     277                 :  * means, the decimal delimiter is always '.' (decimal point). Use
     278                 :  * CPLStrtodDelim() function if you want to specify custom delimiter. Also
     279                 :  * see notes for CPLAtof() function.
     280                 :  *
     281                 :  * @param nptr Pointer to string to convert.
     282                 :  * @param endptr If is not NULL, a pointer to the character after the last
     283                 :  * character used in the conversion is stored in the location referenced
     284                 :  * by endptr.
     285                 :  *
     286                 :  * @return Converted value, if any.
     287                 :  */
     288          947075 : double CPLStrtod(const char *nptr, char **endptr)
     289                 : {
     290          947075 :     return CPLStrtodDelim(nptr, endptr, '.');
     291                 : }
     292                 : 
     293                 : /************************************************************************/
     294                 : /*                          CPLStrtofDelim()                            */
     295                 : /************************************************************************/
     296                 : 
     297                 : /**
     298                 :  * Converts ASCII string to floating point number using specified delimiter.
     299                 :  *
     300                 :  * This function converts the initial portion of the string pointed to
     301                 :  * by nptr to single floating point representation. This function does the
     302                 :  * same as standard strtof(3), but does not take locale in account. Instead of
     303                 :  * locale defined decimal delimiter you can specify your own one. Also see
     304                 :  * notes for CPLAtof() function.
     305                 :  *
     306                 :  * @param nptr Pointer to string to convert.
     307                 :  * @param endptr If is not NULL, a pointer to the character after the last
     308                 :  * character used in the conversion is stored in the location referenced
     309                 :  * by endptr.
     310                 :  * @param point Decimal delimiter.
     311                 :  *
     312                 :  * @return Converted value, if any.
     313                 :  */
     314               0 : float CPLStrtofDelim(const char *nptr, char **endptr, char point)
     315                 : {
     316                 : #if defined(HAVE_STRTOF)
     317                 : /* -------------------------------------------------------------------- */
     318                 : /*  We are implementing a simple method here: copy the input string     */
     319                 : /*  into the temporary buffer, replace the specified decimal delimiter  */
     320                 : /*  with the one, taken from locale settings and use standard strtof()  */
     321                 : /*  on that buffer.                                                     */
     322                 : /* -------------------------------------------------------------------- */
     323                 : 
     324                 :     double      dfValue;
     325                 :     int         nError;
     326                 : 
     327               0 :     char*       pszNumber = CPLReplacePointByLocalePoint(nptr, point);
     328                 : 
     329               0 :     dfValue = strtof( pszNumber, endptr );
     330               0 :     nError = errno;
     331                 : 
     332               0 :     if ( endptr )
     333               0 :         *endptr = (char *)nptr + (*endptr - pszNumber);
     334                 : 
     335               0 :     if (pszNumber != (char*) nptr)
     336               0 :         CPLFree( pszNumber );
     337                 : 
     338               0 :     errno = nError;
     339               0 :     return dfValue;
     340                 : 
     341                 : #else
     342                 : 
     343                 :     return (float)CPLStrtodDelim(nptr, endptr, point);
     344                 : 
     345                 : #endif /* HAVE_STRTOF */
     346                 : }
     347                 : 
     348                 : /************************************************************************/
     349                 : /*                             CPLStrtof()                              */
     350                 : /************************************************************************/
     351                 : 
     352                 : /**
     353                 :  * Converts ASCII string to floating point number.
     354                 :  *
     355                 :  * This function converts the initial portion of the string pointed to
     356                 :  * by nptr to single floating point representation. This function does the
     357                 :  * same as standard strtof(3), but does not take locale in account. That
     358                 :  * means, the decimal delimiter is always '.' (decimal point). Use
     359                 :  * CPLStrtofDelim() function if you want to specify custom delimiter. Also
     360                 :  * see notes for CPLAtof() function.
     361                 :  *
     362                 :  * @param nptr Pointer to string to convert.
     363                 :  * @param endptr If is not NULL, a pointer to the character after the last
     364                 :  * character used in the conversion is stored in the location referenced
     365                 :  * by endptr.
     366                 :  *
     367                 :  * @return Converted value, if any.
     368                 :  */
     369               0 : float CPLStrtof(const char *nptr, char **endptr)
     370                 : {
     371               0 :     return CPLStrtofDelim(nptr, endptr, '.');
     372                 : }
     373                 : 
     374                 : /* END OF FILE */

Generated by: LCOV version 1.7