LCOV - code coverage report
Current view: directory - port - cpl_strtod.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 47 32 68.1 %
Date: 2010-01-09 Functions: 8 5 62.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_strtod.cpp 15802 2008-11-23 20:11:36Z dron $
       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 15802 2008-11-23 20:11:36Z dron $");
      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                 : /************************************************************************/
      47                 : /*                            CPLAtofDelim()                            */
      48                 : /************************************************************************/
      49                 : 
      50                 : /**
      51                 :  * Converts ASCII string to floating point number.
      52                 :  *
      53                 :  * This function converts the initial portion of the string pointed to
      54                 :  * by nptr to double floating point representation. The behaviour is the
      55                 :  * same as
      56                 :  *
      57                 :  *   CPLStrtodDelim(nptr, (char **)NULL, point);
      58                 :  *
      59                 :  * This function does the same as standard atof(3), but does not take locale
      60                 :  * in account. Instead of locale defined decimal delimiter you can specify
      61                 :  * your own one. Also see notes for CPLAtof() function.
      62                 :  *
      63                 :  * @param nptr Pointer to string to convert.
      64                 :  * @param point Decimal delimiter.
      65                 :  *
      66                 :  * @return Converted value, if any.
      67                 :  */
      68               0 : double CPLAtofDelim(const char *nptr, char point)
      69                 : {
      70               0 :   return CPLStrtodDelim(nptr, 0, point);
      71                 : }
      72                 : 
      73                 : /************************************************************************/
      74                 : /*                              CPLAtof()                               */
      75                 : /************************************************************************/
      76                 : 
      77                 : /**
      78                 :  * Converts ASCII string to floating point number.
      79                 :  *
      80                 :  * This function converts the initial portion of the string pointed to
      81                 :  * by nptr to double floating point representation. The behaviour is the
      82                 :  * same as
      83                 :  *
      84                 :  *   CPLStrtod(nptr, (char **)NULL);
      85                 :  *
      86                 :  * This function does the same as standard atof(3), but does not take
      87                 :  * locale in account. That means, the decimal delimiter is always '.'
      88                 :  * (decimal point). Use CPLAtofDelim() function if you want to specify
      89                 :  * custom delimiter.
      90                 :  *
      91                 :  * IMPORTANT NOTE.
      92                 :  * Existance of this function does not mean you should always use it.
      93                 :  * Sometimes you should use standard locale aware atof(3) and its family. When
      94                 :  * you need to process the user's input (for example, command line parameters)
      95                 :  * use atof(3), because user works in localized environment and her input will
      96                 :  * be done accordingly the locale set. In particular that means we should not
      97                 :  * make assumptions about character used as decimal delimiter, it can be
      98                 :  * either "." or ",".
      99                 :  * But when you are parsing some ASCII file in predefined format, you most
     100                 :  * likely need CPLAtof(), because such files distributed across the systems
     101                 :  * with different locales and floating point representation shoudl be
     102                 :  * considered as a part of file format. If the format uses "." as a delimiter
     103                 :  * the same character must be used when parsing number regardless of actual
     104                 :  * locale setting.
     105                 :  *
     106                 :  * @param nptr Pointer to string to convert.
     107                 :  *
     108                 :  * @return Converted value, if any.
     109                 :  */
     110           17424 : double CPLAtof(const char *nptr)
     111                 : {
     112           17424 :   return CPLStrtod(nptr, 0);
     113                 : }
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                              CPLAtofM()                              */
     117                 : /************************************************************************/
     118                 : 
     119                 : /**
     120                 :  * Converts ASCII string to floating point number using any numeric locale.
     121                 :  *
     122                 :  * This function converts the initial portion of the string pointed to
     123                 :  * by nptr to double floating point representation. This function does the
     124                 :  * same as standard atof(), but it allows a variety of locale representations.
     125                 :  * That is it supports numeric values with either a comma or a period for 
     126                 :  * the decimal delimiter. 
     127                 :  * 
     128                 :  * PS. The M stands for Multi-lingual.
     129                 :  *
     130                 :  * @param nptr The string to convert.
     131                 :  *
     132                 :  * @return Converted value, if any.  Zero on failure.
     133                 :  */
     134                 : 
     135             425 : double CPLAtofM( const char *nptr )
     136                 : 
     137                 : {
     138                 :     int i;
     139                 :     const static int nMaxSearch = 50;
     140                 : 
     141            1453 :     for( i = 0; i < nMaxSearch; i++ )
     142                 :     {
     143            1453 :         if( nptr[i] == ',' )
     144               9 :             return CPLStrtodDelim( nptr, 0, ',' );
     145            1444 :         else if( nptr[i] == '.' || nptr[i] == '\0' )
     146             416 :             return CPLStrtodDelim( nptr, 0, '.' );
     147                 :     }
     148                 : 
     149               0 :     return CPLStrtodDelim( nptr, 0, '.' );
     150                 : }
     151                 : 
     152                 : /************************************************************************/
     153                 : /*                          CPLStrtodDelim()                            */
     154                 : /************************************************************************/
     155                 : 
     156           26459 : static void CPLReplacePointByLocalePoint(char* pszNumber, char point)
     157                 : {
     158                 : #if defined(WIN32CE)
     159                 :     static char byPoint = 0;
     160                 :     if (byPoint == 0)
     161                 :     {
     162                 :         char szBuf[16];
     163                 :         sprintf(szBuf, "%.1f", 1.0);
     164                 :         byPoint = szBuf[1];
     165                 :     }
     166                 :     if (point != byPoint)
     167                 :     {
     168                 :         int     i = 0;
     169                 : 
     170                 :         while ( pszNumber[i] )
     171                 :         {
     172                 :             if ( pszNumber[i] == point )
     173                 :             {
     174                 :                 pszNumber[i] = byPoint;
     175                 :                 break;
     176                 :             }
     177                 :             i++;
     178                 :         }
     179                 :     }
     180                 : #else
     181           26459 :     struct lconv *poLconv = localeconv();
     182           26459 :     if ( poLconv
     183                 :          && poLconv->decimal_point
     184                 :          && strlen(poLconv->decimal_point) > 0 )
     185                 :     {
     186           26459 :         int     i = 0;
     187           26459 :         char    byPoint = poLconv->decimal_point[0];
     188                 : 
     189           26459 :         if (point != byPoint)
     190                 :         {
     191              51 :             while ( pszNumber[i] )
     192                 :             {
     193              42 :                 if ( pszNumber[i] == point )
     194                 :                 {
     195               9 :                     pszNumber[i] = byPoint;
     196               9 :                     break;
     197                 :                 }
     198              33 :                 i++;
     199                 :             }
     200                 :         }
     201                 :     }
     202                 : #endif
     203           26459 : }
     204                 : 
     205                 : 
     206                 : /**
     207                 :  * Converts ASCII string to floating point number using specified delimiter.
     208                 :  *
     209                 :  * This function converts the initial portion of the string pointed to
     210                 :  * by nptr to double floating point representation. This function does the
     211                 :  * same as standard strtod(3), but does not take locale in account. Instead of
     212                 :  * locale defined decimal delimiter you can specify your own one. Also see
     213                 :  * notes for CPLAtof() function.
     214                 :  *
     215                 :  * @param nptr Pointer to string to convert.
     216                 :  * @param endptr If is not NULL, a pointer to the character after the last
     217                 :  * character used in the conversion is stored in the location referenced
     218                 :  * by endptr.
     219                 :  * @param point Decimal delimiter.
     220                 :  *
     221                 :  * @return Converted value, if any.
     222                 :  */
     223           26459 : double CPLStrtodDelim(const char *nptr, char **endptr, char point)
     224                 : {
     225                 : /* -------------------------------------------------------------------- */
     226                 : /*  We are implementing a simple method here: copy the input string     */
     227                 : /*  into the temporary buffer, replace the specified decimal delimiter  */
     228                 : /*  with the one, taken from locale settings and use standard strtod()  */
     229                 : /*  on that buffer.                                                     */
     230                 : /* -------------------------------------------------------------------- */
     231           26459 :     char        *pszNumber = CPLStrdup( nptr );
     232                 :     double      dfValue;
     233                 :     int         nError;
     234                 : 
     235           26459 :     CPLReplacePointByLocalePoint(pszNumber, point);
     236                 : 
     237           26459 :     dfValue = strtod( pszNumber, endptr );
     238           26459 :     nError = errno;
     239                 : 
     240           26459 :     if ( endptr )
     241            8610 :         *endptr = (char *)nptr + (*endptr - pszNumber);
     242                 : 
     243           26459 :     CPLFree( pszNumber );
     244                 : 
     245           26459 :     errno = nError;
     246           26459 :     return dfValue;
     247                 : }
     248                 : 
     249                 : /************************************************************************/
     250                 : /*                             CPLStrtod()                              */
     251                 : /************************************************************************/
     252                 : 
     253                 : /**
     254                 :  * Converts ASCII string to floating point number.
     255                 :  *
     256                 :  * This function converts the initial portion of the string pointed to
     257                 :  * by nptr to double floating point representation. This function does the
     258                 :  * same as standard strtod(3), but does not take locale in account. That
     259                 :  * means, the decimal delimiter is always '.' (decimal point). Use
     260                 :  * CPLStrtodDelim() function if you want to specify custom delimiter. Also
     261                 :  * see notes for CPLAtof() function.
     262                 :  *
     263                 :  * @param nptr Pointer to string to convert.
     264                 :  * @param endptr If is not NULL, a pointer to the character after the last
     265                 :  * character used in the conversion is stored in the location referenced
     266                 :  * by endptr.
     267                 :  *
     268                 :  * @return Converted value, if any.
     269                 :  */
     270           26034 : double CPLStrtod(const char *nptr, char **endptr)
     271                 : {
     272           26034 :     return CPLStrtodDelim(nptr, endptr, '.');
     273                 : }
     274                 : 
     275                 : /************************************************************************/
     276                 : /*                          CPLStrtofDelim()                            */
     277                 : /************************************************************************/
     278                 : 
     279                 : /**
     280                 :  * Converts ASCII string to floating point number using specified delimiter.
     281                 :  *
     282                 :  * This function converts the initial portion of the string pointed to
     283                 :  * by nptr to single floating point representation. This function does the
     284                 :  * same as standard strtof(3), but does not take locale in account. Instead of
     285                 :  * locale defined decimal delimiter you can specify your own one. Also see
     286                 :  * notes for CPLAtof() function.
     287                 :  *
     288                 :  * @param nptr Pointer to string to convert.
     289                 :  * @param endptr If is not NULL, a pointer to the character after the last
     290                 :  * character used in the conversion is stored in the location referenced
     291                 :  * by endptr.
     292                 :  * @param point Decimal delimiter.
     293                 :  *
     294                 :  * @return Converted value, if any.
     295                 :  */
     296               0 : float CPLStrtofDelim(const char *nptr, char **endptr, char point)
     297                 : {
     298                 : #if defined(HAVE_STRTOF)
     299                 : /* -------------------------------------------------------------------- */
     300                 : /*  We are implementing a simple method here: copy the input string     */
     301                 : /*  into the temporary buffer, replace the specified decimal delimiter  */
     302                 : /*  with the one, taken from locale settings and use standard strtof()  */
     303                 : /*  on that buffer.                                                     */
     304                 : /* -------------------------------------------------------------------- */
     305                 : 
     306               0 :     char        *pszNumber = CPLStrdup( nptr );
     307                 :     double      dfValue;
     308                 :     int         nError;
     309                 : 
     310               0 :     CPLReplacePointByLocalePoint(pszNumber, point);
     311                 : 
     312               0 :     dfValue = strtof( pszNumber, endptr );
     313               0 :     nError = errno;
     314                 : 
     315               0 :     if ( endptr )
     316               0 :         *endptr = (char *)nptr + (*endptr - pszNumber);
     317                 : 
     318               0 :     CPLFree( pszNumber );
     319                 : 
     320               0 :     errno = nError;
     321               0 :     return dfValue;
     322                 : 
     323                 : #else
     324                 : 
     325                 :     return (float)CPLStrtodDelim(nptr, endptr, point);
     326                 : 
     327                 : #endif /* HAVE_STRTOF */
     328                 : }
     329                 : 
     330                 : /************************************************************************/
     331                 : /*                             CPLStrtof()                              */
     332                 : /************************************************************************/
     333                 : 
     334                 : /**
     335                 :  * Converts ASCII string to floating point number.
     336                 :  *
     337                 :  * This function converts the initial portion of the string pointed to
     338                 :  * by nptr to single floating point representation. This function does the
     339                 :  * same as standard strtof(3), but does not take locale in account. That
     340                 :  * means, the decimal delimiter is always '.' (decimal point). Use
     341                 :  * CPLStrtofDelim() function if you want to specify custom delimiter. Also
     342                 :  * see notes for CPLAtof() function.
     343                 :  *
     344                 :  * @param nptr Pointer to string to convert.
     345                 :  * @param endptr If is not NULL, a pointer to the character after the last
     346                 :  * character used in the conversion is stored in the location referenced
     347                 :  * by endptr.
     348                 :  *
     349                 :  * @return Converted value, if any.
     350                 :  */
     351               0 : float CPLStrtof(const char *nptr, char **endptr)
     352                 : {
     353               0 :     return CPLStrtofDelim(nptr, endptr, '.');
     354                 : }
     355                 : /* END OF FILE */

Generated by: LCOV version 1.7