Coverage Report

Created: 2025-06-13 06:29

/src/proj/src/strtod.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Derived from GDAL port/cpl_strtod.cpp
4
 * Purpose:  Functions to convert ASCII string to floating point number.
5
 * Author:   Andrey Kiselev, dron@ak4719.spb.edu.
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2006, Andrey Kiselev
9
 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot
10
 *org>
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included
20
 * in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 ****************************************************************************/
30
31
#include <errno.h>
32
#include <locale.h>
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include "proj.h"
37
#include "proj_config.h"
38
#include "proj_internal.h"
39
40
/************************************************************************/
41
/*                              pj_atof()                               */
42
/************************************************************************/
43
44
/**
45
 * Converts ASCII string to floating point number.
46
 *
47
 * This function converts the initial portion of the string pointed to
48
 * by nptr to double floating point representation. The behavior is the
49
 * same as
50
 *
51
 *   pj_strtod(nptr, nullptr);
52
 *
53
 * This function does the same as standard atof(3), but does not take
54
 * locale in account. That means, the decimal delimiter is always '.'
55
 * (decimal point).
56
 *
57
 * @param nptr Pointer to string to convert.
58
 *
59
 * @return Converted value.
60
 */
61
349k
double pj_atof(const char *nptr) { return pj_strtod(nptr, nullptr); }
62
63
/************************************************************************/
64
/*                     replace_point_by_locale_point()               */
65
/************************************************************************/
66
67
430k
static char *replace_point_by_locale_point(const char *pszNumber, char point) {
68
#if !defined(HAVE_LOCALECONV)
69
70
#if defined(_MSC_VER) /* Visual C++ */
71
#pragma message("localeconv not available")
72
#else
73
#warning "localeconv not available"
74
#endif
75
76
    static char byPoint = 0;
77
    if (byPoint == 0) {
78
        char szBuf[16];
79
        snprintf(szBuf, sizeof(szBuf), "%.1f", 1.0);
80
        byPoint = szBuf[1];
81
    }
82
    if (point != byPoint) {
83
        const char *pszPoint = strchr(pszNumber, point);
84
        if (pszPoint) {
85
            char *pszNew = pj_strdup(pszNumber);
86
            if (!pszNew)
87
                return nullptr;
88
            pszNew[pszPoint - pszNumber] = byPoint;
89
            return pszNew;
90
        }
91
    }
92
93
    return nullptr;
94
95
#else
96
97
430k
    const struct lconv *poLconv = localeconv();
98
430k
    if (poLconv && poLconv->decimal_point &&
99
430k
        poLconv->decimal_point[0] != '\0') {
100
430k
        char byPoint = poLconv->decimal_point[0];
101
102
430k
        if (point != byPoint) {
103
0
            const char *pszLocalePoint = strchr(pszNumber, byPoint);
104
0
            const char *pszPoint = strchr(pszNumber, point);
105
0
            if (pszPoint || pszLocalePoint) {
106
0
                char *pszNew = pj_strdup(pszNumber);
107
0
                if (!pszNew)
108
0
                    return nullptr;
109
0
                if (pszLocalePoint)
110
0
                    pszNew[pszLocalePoint - pszNumber] = ' ';
111
0
                if (pszPoint)
112
0
                    pszNew[pszPoint - pszNumber] = byPoint;
113
0
                return pszNew;
114
0
            }
115
0
        }
116
430k
    }
117
118
430k
    return nullptr;
119
120
430k
#endif
121
430k
}
122
123
/************************************************************************/
124
/*                            pj_strtod()                               */
125
/************************************************************************/
126
127
/**
128
 * Converts ASCII string to floating point number.
129
 *
130
 * This function converts the initial portion of the string pointed to
131
 * by nptr to double floating point representation. This function does the
132
 * same as standard strtod(3), but does not take locale in account and use
133
 * decimal point.
134
 *
135
 * @param nptr Pointer to string to convert.
136
 * @param endptr If is not NULL, a pointer to the character after the last
137
 * character used in the conversion is stored in the location referenced
138
 * by endptr.
139
 *
140
 * @return Converted value.
141
 */
142
430k
double pj_strtod(const char *nptr, char **endptr) {
143
    /* -------------------------------------------------------------------- */
144
    /*  We are implementing a simple method here: copy the input string     */
145
    /*  into the temporary buffer, replace the specified decimal delimiter (.)
146
     */
147
    /*  with the one taken from locale settings (ex ',') and then use standard
148
     * strtod()  */
149
    /*  on that buffer.                                                     */
150
    /* -------------------------------------------------------------------- */
151
430k
    char *pszNumber = replace_point_by_locale_point(nptr, '.');
152
430k
    if (pszNumber) {
153
0
        char *pszNumberEnd;
154
0
        double dfValue = strtod(pszNumber, &pszNumberEnd);
155
156
0
        int nError = errno;
157
158
0
        if (endptr) {
159
0
            ptrdiff_t offset = pszNumberEnd - pszNumber;
160
0
            *endptr = const_cast<char *>(nptr + offset);
161
0
        }
162
163
0
        free(pszNumber);
164
165
0
        errno = nError;
166
167
0
        return dfValue;
168
430k
    } else {
169
430k
        return strtod(nptr, endptr);
170
430k
    }
171
430k
}