Coverage Report

Created: 2025-09-27 07:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/goo/gstrtod.cc
Line
Count
Source
1
/* This file is part of Libspectre.
2
 *
3
 * Copyright (C) 2007, 2012 Albert Astals Cid <aacid@kde.org>
4
 * Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
5
 *
6
 * Libspectre is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2, or (at your option)
9
 * any later version.
10
 *
11
 * Libspectre is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
 */
20
21
/* This function comes from spectre-utils from libspectre */
22
23
#include "gstrtod.h"
24
25
#include <clocale>
26
#include <cerrno>
27
#include <cstdlib>
28
#include <cstring>
29
30
0
#define ascii_isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\v')
31
0
#define ascii_isdigit(c) ((c) >= '0' && (c) <= '9')
32
33
double gatof(const char *nptr)
34
664k
{
35
664k
    return gstrtod(nptr, nullptr);
36
664k
}
37
38
double gstrtod(const char *nptr, char **endptr)
39
664k
{
40
664k
    char *fail_pos;
41
664k
    double val;
42
664k
    struct lconv *locale_data;
43
664k
    const char *decimal_point;
44
664k
    int decimal_point_len;
45
664k
    const char *p, *decimal_point_pos;
46
664k
    const char *end = nullptr; /* Silence gcc */
47
664k
    int strtod_errno;
48
49
664k
    fail_pos = nullptr;
50
51
664k
    locale_data = localeconv();
52
664k
    decimal_point = locale_data->decimal_point;
53
664k
    decimal_point_len = strlen(decimal_point);
54
55
664k
    decimal_point_pos = nullptr;
56
664k
    end = nullptr;
57
58
664k
    if (decimal_point[0] != '.' || decimal_point[1] != 0) {
59
0
        p = nptr;
60
        /* Skip leading space */
61
0
        while (ascii_isspace(*p)) {
62
0
            p++;
63
0
        }
64
65
        /* Skip leading optional sign */
66
0
        if (*p == '+' || *p == '-') {
67
0
            p++;
68
0
        }
69
70
0
        if (ascii_isdigit(*p) || *p == '.') {
71
0
            while (ascii_isdigit(*p)) {
72
0
                p++;
73
0
            }
74
75
0
            if (*p == '.') {
76
0
                decimal_point_pos = p++;
77
0
            }
78
79
0
            while (ascii_isdigit(*p)) {
80
0
                p++;
81
0
            }
82
83
0
            if (*p == 'e' || *p == 'E') {
84
0
                p++;
85
0
            }
86
0
            if (*p == '+' || *p == '-') {
87
0
                p++;
88
0
            }
89
0
            while (ascii_isdigit(*p)) {
90
0
                p++;
91
0
            }
92
93
0
            end = p;
94
0
        }
95
        /* For the other cases, we need not convert the decimal point */
96
0
    }
97
98
664k
    if (decimal_point_pos) {
99
0
        char *copy, *c;
100
101
        /* We need to convert the '.' to the locale specific decimal point */
102
0
        copy = (char *)malloc(end - nptr + 1 + decimal_point_len);
103
104
0
        c = copy;
105
0
        memcpy(c, nptr, decimal_point_pos - nptr);
106
0
        c += decimal_point_pos - nptr;
107
0
        memcpy(c, decimal_point, decimal_point_len);
108
0
        c += decimal_point_len;
109
0
        memcpy(c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
110
0
        c += end - (decimal_point_pos + 1);
111
0
        *c = 0;
112
113
0
        errno = 0;
114
0
        val = strtod(copy, &fail_pos);
115
0
        strtod_errno = errno;
116
117
0
        if (fail_pos) {
118
0
            if (fail_pos - copy > decimal_point_pos - nptr) {
119
0
                fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
120
0
            } else {
121
0
                fail_pos = (char *)nptr + (fail_pos - copy);
122
0
            }
123
0
        }
124
125
0
        free(copy);
126
664k
    } else if (end) {
127
0
        char *copy;
128
129
0
        copy = (char *)malloc(end - (char *)nptr + 1);
130
0
        memcpy(copy, nptr, end - nptr);
131
0
        *(copy + (end - (char *)nptr)) = 0;
132
133
0
        errno = 0;
134
0
        val = strtod(copy, &fail_pos);
135
0
        strtod_errno = errno;
136
137
0
        if (fail_pos) {
138
0
            fail_pos = (char *)nptr + (fail_pos - copy);
139
0
        }
140
141
0
        free(copy);
142
664k
    } else {
143
664k
        errno = 0;
144
664k
        val = strtod(nptr, &fail_pos);
145
664k
        strtod_errno = errno;
146
664k
    }
147
148
664k
    if (endptr) {
149
0
        *endptr = fail_pos;
150
0
    }
151
152
664k
    errno = strtod_errno;
153
154
664k
    return val;
155
664k
}