Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/wsutil/strtoi.c
Line
Count
Source (jump to first uncovered line)
1
/* strtoi.c
2
 * Utilities to convert strings to integers
3
 *
4
 * Copyright 2016, Dario Lombardo
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
15
#include <errno.h>
16
17
#include <glib.h>
18
19
#include "strtoi.h"
20
#include <wsutil/ws_assert.h>
21
22
bool ws_strtoi64(const char* str, const char** endptr, int64_t* cint)
23
962
{
24
962
  char* end;
25
962
  int64_t val;
26
27
962
  ws_assert(cint);
28
29
962
  if (!str) {
30
0
    errno = EINVAL;
31
0
    return false;
32
0
  }
33
34
962
  errno = 0;
35
962
  val = g_ascii_strtoll(str, &end, 10);
36
962
  if ((val == 0 && end == str) || (endptr == NULL && *end != '\0')) {
37
434
    *cint = 0;
38
434
    if (endptr != NULL)
39
0
      *endptr = end;
40
434
    errno = EINVAL;
41
434
    return false;
42
434
  }
43
528
  if ((val == INT64_MAX || val == INT64_MIN) && errno == ERANGE) {
44
    /*
45
     * Return the value, so our caller knows whether to
46
     * report the value as "too small" or "too large".
47
     */
48
57
    *cint = val;
49
57
    if (endptr != NULL)
50
0
      *endptr = end;
51
    /* errno is already set */
52
57
    return false;
53
57
  }
54
471
  if (endptr != NULL)
55
0
    *endptr = end;
56
471
  *cint = val;
57
471
  return true;
58
528
}
59
60
#define DEFINE_WS_STRTOI_BITS(bits) \
61
962
bool ws_strtoi##bits(const char* str, const char** endptr, int##bits##_t* cint) \
62
962
{ \
63
962
  int64_t val = 0; \
64
962
  if (!ws_strtoi64(str, endptr, &val)) { \
65
491
    /* \
66
491
     * For ERANGE, return either INT##bits##_MIN or \
67
491
     * INT##bits##_MAX so our caller knows whether \
68
491
     * to report the value as "too small" or "too \
69
491
     * large". \
70
491
     * \
71
491
     * For other errors, return 0, for parallelism \
72
491
     * with ws_strtoi64(). \
73
491
     */ \
74
491
    if (errno == ERANGE) { \
75
57
      if (val < 0) \
76
57
        *cint = INT##bits##_MIN; \
77
57
      else \
78
57
        *cint = INT##bits##_MAX; \
79
57
    } else \
80
491
      *cint = 0; \
81
491
    return false; \
82
491
  } \
83
962
  if (val < INT##bits##_MIN) { \
84
95
    /* \
85
95
     * Return INT##bits##_MIN so our caller knows whether to \
86
95
     * report the value as "too small" or "too large". \
87
95
     */ \
88
95
    *cint = INT##bits##_MIN; \
89
95
    errno = ERANGE; \
90
95
    return false; \
91
95
  } \
92
471
  if (val > INT##bits##_MAX) { \
93
134
    /* \
94
134
     * Return INT##bits##_MAX so our caller knows whether to \
95
134
     * report the value as "too small" or "too large". \
96
134
     */ \
97
134
    *cint = INT##bits##_MAX; \
98
134
    errno = ERANGE; \
99
134
    return false; \
100
134
  } \
101
376
  *cint = (int##bits##_t)val; \
102
242
  return true; \
103
376
}
ws_strtoi32
Line
Count
Source
61
962
bool ws_strtoi##bits(const char* str, const char** endptr, int##bits##_t* cint) \
62
962
{ \
63
962
  int64_t val = 0; \
64
962
  if (!ws_strtoi64(str, endptr, &val)) { \
65
491
    /* \
66
491
     * For ERANGE, return either INT##bits##_MIN or \
67
491
     * INT##bits##_MAX so our caller knows whether \
68
491
     * to report the value as "too small" or "too \
69
491
     * large". \
70
491
     * \
71
491
     * For other errors, return 0, for parallelism \
72
491
     * with ws_strtoi64(). \
73
491
     */ \
74
491
    if (errno == ERANGE) { \
75
57
      if (val < 0) \
76
57
        *cint = INT##bits##_MIN; \
77
57
      else \
78
57
        *cint = INT##bits##_MAX; \
79
57
    } else \
80
491
      *cint = 0; \
81
491
    return false; \
82
491
  } \
83
962
  if (val < INT##bits##_MIN) { \
84
95
    /* \
85
95
     * Return INT##bits##_MIN so our caller knows whether to \
86
95
     * report the value as "too small" or "too large". \
87
95
     */ \
88
95
    *cint = INT##bits##_MIN; \
89
95
    errno = ERANGE; \
90
95
    return false; \
91
95
  } \
92
471
  if (val > INT##bits##_MAX) { \
93
134
    /* \
94
134
     * Return INT##bits##_MAX so our caller knows whether to \
95
134
     * report the value as "too small" or "too large". \
96
134
     */ \
97
134
    *cint = INT##bits##_MAX; \
98
134
    errno = ERANGE; \
99
134
    return false; \
100
134
  } \
101
376
  *cint = (int##bits##_t)val; \
102
242
  return true; \
103
376
}
Unexecuted instantiation: ws_strtoi16
Unexecuted instantiation: ws_strtoi8
104
105
DEFINE_WS_STRTOI_BITS(32)
106
DEFINE_WS_STRTOI_BITS(16)
107
DEFINE_WS_STRTOI_BITS(8)
108
109
bool ws_strtoi(const char* str, const char** endptr, int* cint)
110
0
{
111
0
  int64_t val = 0;
112
0
  if (!ws_strtoi64(str, endptr, &val)) {
113
    /*
114
     * For ERANGE, return either INT_MIN or
115
     * INT_MAX so our caller knows whether
116
     * to report the value as "too small" or "too
117
     * large".
118
     *
119
     * For other errors, return 0, for parallelism
120
     * with ws_strtoi64().
121
     */
122
0
    if (errno == ERANGE) {
123
0
      if (val < 0)
124
0
        *cint = INT_MIN;
125
0
      else
126
0
        *cint = INT_MAX;
127
0
    } else
128
0
      *cint = 0;
129
0
    return false;
130
0
  }
131
0
  if (val < INT_MIN) {
132
    /*
133
     * Return INT_MIN so our caller knows whether to
134
     * report the value as "too small" or "too large".
135
     */
136
0
    *cint = INT_MIN;
137
0
    errno = ERANGE;
138
0
    return false;
139
0
  }
140
0
  if (val > INT_MAX) {
141
    /*
142
     * Return INT_MAX so our caller knows whether to
143
     * report the value as "too small" or "too large".
144
     */
145
0
    *cint = INT_MAX;
146
0
    errno = ERANGE;
147
0
    return false;
148
0
  }
149
0
  *cint = (int)val;
150
0
  return true;
151
0
}
152
153
bool ws_basestrtou64(const char* str, const char** endptr, uint64_t* cint, int base)
154
15.7k
{
155
15.7k
  char* end;
156
15.7k
  uint64_t val;
157
158
15.7k
  ws_assert(cint);
159
160
15.7k
  if (!str) {
161
0
    errno = EINVAL;
162
0
    return false;
163
0
  }
164
165
15.7k
  if (str[0] == '-' || str[0] == '+') {
166
    /*
167
     * Unsigned numbers don't have a sign.
168
     */
169
3
    *cint = 0;
170
3
    if (endptr != NULL)
171
0
      *endptr = str;
172
3
    errno = EINVAL;
173
3
    return false;
174
3
  }
175
15.7k
  errno = 0;
176
15.7k
  val = g_ascii_strtoull(str, &end, base);
177
15.7k
  if ((val == 0 && end == str) || (endptr == NULL && *end != '\0')) {
178
418
    *cint = 0;
179
418
    if (endptr != NULL)
180
0
      *endptr = end;
181
418
    errno = EINVAL;
182
418
    return false;
183
418
  }
184
15.3k
  if (val == UINT64_MAX && errno == ERANGE) {
185
    /*
186
     * Return the value, because ws_strtoi64() does.
187
     */
188
0
    *cint = val;
189
0
    if (endptr != NULL)
190
0
      *endptr = end;
191
    /* errno is already set */
192
0
    return false;
193
0
  }
194
15.3k
  if (endptr != NULL)
195
9.43k
    *endptr = end;
196
15.3k
  *cint = val;
197
15.3k
  return true;
198
15.3k
}
199
200
bool ws_strtou64(const char* str, const char** endptr, uint64_t* cint)
201
0
{
202
0
  return ws_basestrtou64(str, endptr, cint, 10);
203
0
}
204
205
bool ws_hexstrtou64(const char* str, const char** endptr, uint64_t* cint)
206
0
{
207
0
  return ws_basestrtou64(str, endptr, cint, 16);
208
0
}
209
210
#define DEFINE_WS_STRTOU_BITS(bits) \
211
15.7k
bool ws_basestrtou##bits(const char* str, const char** endptr, uint##bits##_t* cint, int base) \
212
15.7k
{ \
213
15.7k
  uint64_t val; \
214
15.7k
  if (!ws_basestrtou64(str, endptr, &val, base)) { \
215
421
    /* \
216
421
     * For ERANGE, return UINT##bits##_MAX for parallelism \
217
421
     * with ws_strtoi##bits(). \
218
421
     * \
219
421
     * For other errors, return 0, for parallelism \
220
421
     * with ws_basestrtou64(). \
221
421
     */ \
222
421
    if (errno == ERANGE) \
223
421
      *cint = UINT##bits##_MAX; \
224
421
    else \
225
421
      *cint = 0; \
226
421
    return false; \
227
421
  } \
228
15.7k
  if (val > UINT##bits##_MAX) { \
229
5
    /* \
230
5
     * Return UINT##bits##_MAX for parallelism with \
231
5
     * ws_strtoi##bits(). \
232
5
     */ \
233
5
    *cint = UINT##bits##_MAX; \
234
5
    errno = ERANGE; \
235
5
    return false; \
236
5
  } \
237
15.3k
  *cint = (uint##bits##_t)val; \
238
15.3k
  return true; \
239
15.3k
} \
ws_basestrtou32
Line
Count
Source
211
10.0k
bool ws_basestrtou##bits(const char* str, const char** endptr, uint##bits##_t* cint, int base) \
212
10.0k
{ \
213
10.0k
  uint64_t val; \
214
10.0k
  if (!ws_basestrtou64(str, endptr, &val, base)) { \
215
324
    /* \
216
324
     * For ERANGE, return UINT##bits##_MAX for parallelism \
217
324
     * with ws_strtoi##bits(). \
218
324
     * \
219
324
     * For other errors, return 0, for parallelism \
220
324
     * with ws_basestrtou64(). \
221
324
     */ \
222
324
    if (errno == ERANGE) \
223
324
      *cint = UINT##bits##_MAX; \
224
324
    else \
225
324
      *cint = 0; \
226
324
    return false; \
227
324
  } \
228
10.0k
  if (val > UINT##bits##_MAX) { \
229
3
    /* \
230
3
     * Return UINT##bits##_MAX for parallelism with \
231
3
     * ws_strtoi##bits(). \
232
3
     */ \
233
3
    *cint = UINT##bits##_MAX; \
234
3
    errno = ERANGE; \
235
3
    return false; \
236
3
  } \
237
9.77k
  *cint = (uint##bits##_t)val; \
238
9.77k
  return true; \
239
9.77k
} \
ws_basestrtou16
Line
Count
Source
211
5.68k
bool ws_basestrtou##bits(const char* str, const char** endptr, uint##bits##_t* cint, int base) \
212
5.68k
{ \
213
5.68k
  uint64_t val; \
214
5.68k
  if (!ws_basestrtou64(str, endptr, &val, base)) { \
215
97
    /* \
216
97
     * For ERANGE, return UINT##bits##_MAX for parallelism \
217
97
     * with ws_strtoi##bits(). \
218
97
     * \
219
97
     * For other errors, return 0, for parallelism \
220
97
     * with ws_basestrtou64(). \
221
97
     */ \
222
97
    if (errno == ERANGE) \
223
97
      *cint = UINT##bits##_MAX; \
224
97
    else \
225
97
      *cint = 0; \
226
97
    return false; \
227
97
  } \
228
5.68k
  if (val > UINT##bits##_MAX) { \
229
2
    /* \
230
2
     * Return UINT##bits##_MAX for parallelism with \
231
2
     * ws_strtoi##bits(). \
232
2
     */ \
233
2
    *cint = UINT##bits##_MAX; \
234
2
    errno = ERANGE; \
235
2
    return false; \
236
2
  } \
237
5.58k
  *cint = (uint##bits##_t)val; \
238
5.58k
  return true; \
239
5.58k
} \
ws_basestrtou8
Line
Count
Source
211
1
bool ws_basestrtou##bits(const char* str, const char** endptr, uint##bits##_t* cint, int base) \
212
1
{ \
213
1
  uint64_t val; \
214
1
  if (!ws_basestrtou64(str, endptr, &val, base)) { \
215
0
    /* \
216
0
     * For ERANGE, return UINT##bits##_MAX for parallelism \
217
0
     * with ws_strtoi##bits(). \
218
0
     * \
219
0
     * For other errors, return 0, for parallelism \
220
0
     * with ws_basestrtou64(). \
221
0
     */ \
222
0
    if (errno == ERANGE) \
223
0
      *cint = UINT##bits##_MAX; \
224
0
    else \
225
0
      *cint = 0; \
226
0
    return false; \
227
0
  } \
228
1
  if (val > UINT##bits##_MAX) { \
229
0
    /* \
230
0
     * Return UINT##bits##_MAX for parallelism with \
231
0
     * ws_strtoi##bits(). \
232
0
     */ \
233
0
    *cint = UINT##bits##_MAX; \
234
0
    errno = ERANGE; \
235
0
    return false; \
236
0
  } \
237
1
  *cint = (uint##bits##_t)val; \
238
1
  return true; \
239
1
} \
240
\
241
6.13k
bool ws_strtou##bits(const char* str, const char** endptr, uint##bits##_t* cint) \
242
6.13k
{ \
243
6.13k
  return ws_basestrtou##bits(str, endptr, cint, 10); \
244
6.13k
} \
ws_strtou32
Line
Count
Source
241
453
bool ws_strtou##bits(const char* str, const char** endptr, uint##bits##_t* cint) \
242
453
{ \
243
453
  return ws_basestrtou##bits(str, endptr, cint, 10); \
244
453
} \
ws_strtou16
Line
Count
Source
241
5.68k
bool ws_strtou##bits(const char* str, const char** endptr, uint##bits##_t* cint) \
242
5.68k
{ \
243
5.68k
  return ws_basestrtou##bits(str, endptr, cint, 10); \
244
5.68k
} \
ws_strtou8
Line
Count
Source
241
1
bool ws_strtou##bits(const char* str, const char** endptr, uint##bits##_t* cint) \
242
1
{ \
243
1
  return ws_basestrtou##bits(str, endptr, cint, 10); \
244
1
} \
245
\
246
208
bool ws_hexstrtou##bits(const char* str, const char** endptr, uint##bits##_t* cint) \
247
208
{ \
248
208
  return ws_basestrtou##bits(str, endptr, cint, 16); \
249
208
}
ws_hexstrtou32
Line
Count
Source
246
208
bool ws_hexstrtou##bits(const char* str, const char** endptr, uint##bits##_t* cint) \
247
208
{ \
248
208
  return ws_basestrtou##bits(str, endptr, cint, 16); \
249
208
}
Unexecuted instantiation: ws_hexstrtou16
Unexecuted instantiation: ws_hexstrtou8
250
251
DEFINE_WS_STRTOU_BITS(32)
252
DEFINE_WS_STRTOU_BITS(16)
253
DEFINE_WS_STRTOU_BITS(8)
254
255
bool ws_basestrtou(const char* str, const char** endptr, unsigned* cint, int base)
256
0
{
257
0
  uint64_t val;
258
0
  if (!ws_basestrtou64(str, endptr, &val, base)) {
259
    /*
260
     * For ERANGE, return UINT_MAX for parallelism
261
     * with ws_strtoi().
262
     *
263
     * For other errors, return 0, for parallelism
264
     * with ws_basestrtou64().
265
     */
266
0
    if (errno == ERANGE)
267
0
      *cint = UINT_MAX;
268
0
    else
269
0
      *cint = 0;
270
0
    return false;
271
0
  }
272
0
  if (val > UINT_MAX) {
273
    /*
274
     * Return UINT_MAX for parallelism with
275
     * ws_strtoi().
276
     */
277
0
    *cint = UINT_MAX;
278
0
    errno = ERANGE;
279
0
    return false;
280
0
  }
281
0
  *cint = (unsigned)val;
282
0
  return true;
283
0
}
284
285
bool ws_strtou(const char* str, const char** endptr, unsigned* cint)
286
0
{
287
0
  return ws_basestrtou(str, endptr, cint, 10);
288
0
}
289
\
290
bool ws_hexstrtou(const char* str, const char** endptr, unsigned* cint)
291
0
{
292
0
  return ws_basestrtou(str, endptr, cint, 16);
293
0
}
294
295
/*
296
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
297
 *
298
 * Local variables:
299
 * c-basic-offset: 4
300
 * tab-width: 8
301
 * indent-tabs-mode: t
302
 * End:
303
 *
304
 * vi: set shiftwidth=4 tabstop=8 noexpandtab:
305
 * :indentSize=4:tabSize=8:noTabs=false:
306
 */