Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jansson-2.14/src/strconv.c
Line
Count
Source
1
#include "jansson_private.h"
2
#include "strbuffer.h"
3
#include <assert.h>
4
#include <errno.h>
5
#include <math.h>
6
#include <stdio.h>
7
#include <string.h>
8
9
/* need jansson_private_config.h to get the correct snprintf */
10
#ifdef HAVE_CONFIG_H
11
#include <jansson_private_config.h>
12
#endif
13
14
#if JSON_HAVE_LOCALECONV
15
#include <locale.h>
16
17
/*
18
  - This code assumes that the decimal separator is exactly one
19
    character.
20
21
  - If setlocale() is called by another thread between the call to
22
    localeconv() and the call to sprintf() or strtod(), the result may
23
    be wrong. setlocale() is not thread-safe and should not be used
24
    this way. Multi-threaded programs should use uselocale() instead.
25
*/
26
27
0
static void to_locale(strbuffer_t *strbuffer) {
28
0
    const char *point;
29
0
    char *pos;
30
31
0
    point = localeconv()->decimal_point;
32
0
    if (*point == '.') {
33
        /* No conversion needed */
34
0
        return;
35
0
    }
36
37
0
    pos = strchr(strbuffer->value, '.');
38
0
    if (pos)
39
0
        *pos = *point;
40
0
}
41
42
0
static void from_locale(char *buffer) {
43
0
    const char *point;
44
0
    char *pos;
45
46
0
    point = localeconv()->decimal_point;
47
0
    if (*point == '.') {
48
        /* No conversion needed */
49
0
        return;
50
0
    }
51
52
0
    pos = strchr(buffer, *point);
53
0
    if (pos)
54
0
        *pos = '.';
55
0
}
56
#endif
57
58
0
int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
59
0
    double value;
60
0
    char *end;
61
62
0
#if JSON_HAVE_LOCALECONV
63
0
    to_locale(strbuffer);
64
0
#endif
65
66
0
    errno = 0;
67
0
    value = strtod(strbuffer->value, &end);
68
0
    assert(end == strbuffer->value + strbuffer->length);
69
70
0
    if ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
71
        /* Overflow */
72
0
        return -1;
73
0
    }
74
75
0
    *out = value;
76
0
    return 0;
77
0
}
78
79
0
int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
80
0
    int ret;
81
0
    char *start, *end;
82
0
    size_t length;
83
84
0
    if (precision == 0)
85
0
        precision = 17;
86
87
0
    ret = snprintf(buffer, size, "%.*g", precision, value);
88
0
    if (ret < 0)
89
0
        return -1;
90
91
0
    length = (size_t)ret;
92
0
    if (length >= size)
93
0
        return -1;
94
95
0
#if JSON_HAVE_LOCALECONV
96
0
    from_locale(buffer);
97
0
#endif
98
99
    /* Make sure there's a dot or 'e' in the output. Otherwise
100
       a real is converted to an integer when decoding */
101
0
    if (strchr(buffer, '.') == NULL && strchr(buffer, 'e') == NULL) {
102
0
        if (length + 3 >= size) {
103
            /* No space to append ".0" */
104
0
            return -1;
105
0
        }
106
0
        buffer[length] = '.';
107
0
        buffer[length + 1] = '0';
108
0
        buffer[length + 2] = '\0';
109
0
        length += 2;
110
0
    }
111
112
    /* Remove leading '+' from positive exponent. Also remove leading
113
       zeros from exponents (added by some printf() implementations) */
114
0
    start = strchr(buffer, 'e');
115
0
    if (start) {
116
0
        start++;
117
0
        end = start + 1;
118
119
0
        if (*start == '-')
120
0
            start++;
121
122
0
        while (*end == '0')
123
0
            end++;
124
125
0
        if (end != start) {
126
0
            memmove(start, end, length - (size_t)(end - buffer));
127
0
            length -= (size_t)(end - start);
128
0
        }
129
0
    }
130
131
0
    return (int)length;
132
0
}