wmem: allow wmem_destroy_list to ignore a NULL list.
[metze/wireshark/wip.git] / wsutil / strtoi.c
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 "strtoi.h"
16 #include <errno.h>
17
18 gboolean ws_strtoi64(const gchar* str, const gchar** endptr, gint64* cint)
19 {
20         gchar* end;
21         gint64 val;
22
23         g_assert(cint);
24
25         if (!str) {
26                 errno = EINVAL;
27                 return FALSE;
28         }
29
30         errno = 0;
31         val = g_ascii_strtoll(str, &end, 10);
32         if ((val == 0 && end == str) || (endptr == NULL && *end != '\0')) {
33                 *cint = 0;
34                 if (endptr != NULL)
35                         *endptr = end;
36                 errno = EINVAL;
37                 return FALSE;
38         }
39         if ((val == G_MAXINT64 || val == G_MININT64) && errno == ERANGE) {
40                 /*
41                  * Return the value, so our caller knows whether to
42                  * report the value as "too small" or "too large".
43                  */
44                 *cint = val;
45                 if (endptr != NULL)
46                         *endptr = end;
47                 /* errno is already set */
48                 return FALSE;
49         }
50         if (endptr != NULL)
51                 *endptr = end;
52         *cint = val;
53         return TRUE;
54 }
55
56 #define DEFINE_WS_STRTOI_BITS(bits) \
57 gboolean ws_strtoi##bits(const gchar* str, const gchar** endptr, gint##bits* cint) \
58 { \
59         gint64 val = 0; \
60         if (!ws_strtoi64(str, endptr, &val)) { \
61                 /* \
62                  * For ERANGE, return either G_MININT##bits or \
63                  * G_MAXINT##bits so our caller knows whether \
64                  * to report the value as "too small" or "too \
65                  * large". \
66                  * \
67                  * For other errors, return 0, for parallelism \
68                  * with ws_strtoi64(). \
69                  */ \
70                 if (errno == ERANGE) { \
71                         if (val < 0) \
72                                 *cint = G_MININT##bits; \
73                         else \
74                                 *cint = G_MAXINT##bits; \
75                 } else \
76                         *cint = 0; \
77                 return FALSE; \
78         } \
79         if (val < G_MININT##bits) { \
80                 /* \
81                  * Return G_MININT##bits so our caller knows whether to \
82                  * report the value as "too small" or "too large". \
83                  */ \
84                 *cint = G_MININT##bits; \
85                 errno = ERANGE; \
86                 return FALSE; \
87         } \
88         if (val > G_MAXINT##bits) { \
89                 /* \
90                  * Return G_MAXINT##bits so our caller knows whether to \
91                  * report the value as "too small" or "too large". \
92                  */ \
93                 *cint = G_MAXINT##bits; \
94                 errno = ERANGE; \
95                 return FALSE; \
96         } \
97         *cint = (gint##bits)val; \
98         return TRUE; \
99 }
100
101 DEFINE_WS_STRTOI_BITS(32)
102 DEFINE_WS_STRTOI_BITS(16)
103 DEFINE_WS_STRTOI_BITS(8)
104
105 gboolean ws_basestrtou64(const gchar* str, const gchar** endptr, guint64* cint, int base)
106 {
107         gchar* end;
108         guint64 val;
109
110         g_assert(cint);
111
112         if (!str) {
113                 errno = EINVAL;
114                 return FALSE;
115         }
116
117         if (str[0] == '-' || str[0] == '+') {
118                 /*
119                  * Unsigned numbers don't have a sign.
120                  */
121                 *cint = 0;
122                 if (endptr != NULL)
123                         *endptr = str;
124                 errno = EINVAL;
125                 return FALSE;
126         }
127         errno = 0;
128         val = g_ascii_strtoull(str, &end, base);
129         if ((val == 0 && end == str) || (endptr == NULL && *end != '\0')) {
130                 *cint = 0;
131                 if (endptr != NULL)
132                         *endptr = end;
133                 errno = EINVAL;
134                 return FALSE;
135         }
136         if (val == G_MAXUINT64 && errno == ERANGE) {
137                 /*
138                  * Return the value, because ws_strtoi64() does.
139                  */
140                 *cint = val;
141                 if (endptr != NULL)
142                         *endptr = end;
143                 /* errno is already set */
144                 return FALSE;
145         }
146         if (endptr != NULL)
147                 *endptr = end;
148         *cint = val;
149         return TRUE;
150 }
151
152 gboolean ws_strtou64(const gchar* str, const gchar** endptr, guint64* cint)
153 {
154         return ws_basestrtou64(str, endptr, cint, 10);
155 }
156
157 gboolean ws_hexstrtou64(const gchar* str, const gchar** endptr, guint64* cint)
158 {
159         return ws_basestrtou64(str, endptr, cint, 16);
160 }
161
162 #define DEFINE_WS_STRTOU_BITS(bits) \
163 gboolean ws_basestrtou##bits(const gchar* str, const gchar** endptr, guint##bits* cint, int base) \
164 { \
165         guint64 val; \
166         if (!ws_basestrtou64(str, endptr, &val, base)) { \
167                 /* \
168                  * For ERANGE, return G_MAXUINT##bits for parallelism \
169                  * with ws_strtoi##bits(). \
170                  * \
171                  * For other errors, return 0, for parallelism \
172                  * with ws_basestrtou64(). \
173                  */ \
174                 if (errno == ERANGE) \
175                         *cint = G_MAXUINT##bits; \
176                 else \
177                         *cint = 0; \
178                 return FALSE; \
179         } \
180         if (val > G_MAXUINT##bits) { \
181                 /* \
182                  * Return G_MAXUINT##bits for parallelism with \
183                  * ws_strtoi##bits(). \
184                  */ \
185                 *cint = G_MAXUINT##bits; \
186                 errno = ERANGE; \
187                 return FALSE; \
188         } \
189         *cint = (guint##bits)val; \
190         return TRUE; \
191 } \
192 \
193 gboolean ws_strtou##bits(const gchar* str, const gchar** endptr, guint##bits* cint) \
194 { \
195         return ws_basestrtou##bits(str, endptr, cint, 10); \
196 } \
197 \
198 gboolean ws_hexstrtou##bits(const gchar* str, const gchar** endptr, guint##bits* cint) \
199 { \
200         return ws_basestrtou##bits(str, endptr, cint, 16); \
201 }
202
203 DEFINE_WS_STRTOU_BITS(32)
204 DEFINE_WS_STRTOU_BITS(16)
205 DEFINE_WS_STRTOU_BITS(8)
206
207 /*
208  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
209  *
210  * Local variables:
211  * c-basic-offset: 4
212  * tab-width: 8
213  * indent-tabs-mode: t
214  * End:
215  *
216  * vi: set shiftwidth=4 tabstop=8 noexpandtab:
217  * :indentSize=4:tabSize=8:noTabs=false:
218  */