Always set *cint before returning.
[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  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include "strtoi.h"
28 #include <errno.h>
29
30 gboolean ws_strtoi64(const gchar* str, gint64* cint)
31 {
32         gchar* endptr;
33         gint64 val;
34
35         errno = 0;
36         val = g_ascii_strtoll(str, &endptr, 10);
37         if ((val == 0 && endptr == str) || (*endptr != 0)) {
38                 *cint = 0;
39                 errno = EINVAL;
40                 return FALSE;
41         }
42         if ((val == G_MAXINT64 || val == G_MININT64) && errno == ERANGE) {
43                 /*
44                  * Return the value, so our caller knows whether to
45                  * report the value as "too small" or "too large".
46                  */
47                 *cint = val;
48                 /* errno is already set */
49                 return FALSE;
50         }
51         *cint = val;
52         return TRUE;
53 }
54
55 gboolean ws_strtou64(const gchar* str, guint64* cint)
56 {
57         gchar* endptr;
58         guint64 val;
59
60         if (str[0] == '-' || str[0] == '+') {
61                 /*
62                  * Unsigned numbers don't have a sign.
63                  */
64                 *cint = 0;
65                 errno = EINVAL;
66                 return FALSE;
67         }
68         errno = 0;
69         val = g_ascii_strtoull(str, &endptr, 10);
70         if ((val == 0 && endptr == str) || (*endptr != 0)) {
71                 *cint = 0;
72                 errno = EINVAL;
73                 return FALSE;
74         }
75         if (val == G_MAXUINT64 && errno == ERANGE) {
76                 /*
77                  * Return the value, because ws_strtoi64() does.
78                  */
79                 *cint = val;
80                 /* errno is already set */
81                 return FALSE;
82         }
83         *cint = val;
84         return TRUE;
85 }
86
87 #define DEFINE_WS_STRTOI_BITS(bits) \
88 gboolean ws_strtoi##bits(const gchar* str, gint##bits* cint) \
89 { \
90         gint64 val; \
91         if (!ws_strtoi64(str, &val)) { \
92                 /* \
93                  * For ERANGE, return either G_MININT##bits or \
94                  * G_MAXINT##bits so our caller knows whether \
95                  * to report the value as "too small" or "too \
96                  * large". \
97                  * \
98                  * For other errors, return 0, for parallelism \
99                  * with ws_strtoi64(). \
100                  */ \
101                 if (errno == ERANGE) { \
102                         if (val < 0) \
103                                 *cint = G_MININT##bits; \
104                         else \
105                                 *cint = G_MAXINT##bits; \
106                 } else \
107                         *cint = 0; \
108                 return FALSE; \
109         } \
110         if (val < G_MININT##bits) { \
111                 /* \
112                  * Return G_MININT##bits so our caller knows whether to \
113                  * report the value as "too small" or "too large". \
114                  */ \
115                 *cint = G_MININT##bits; \
116                 errno = ERANGE; \
117                 return FALSE; \
118         } \
119         if (val > G_MAXINT##bits) { \
120                 /* \
121                  * Return G_MAXINT##bits so our caller knows whether to \
122                  * report the value as "too small" or "too large". \
123                  */ \
124                 *cint = G_MAXINT##bits; \
125                 errno = ERANGE; \
126                 return FALSE; \
127         } \
128         *cint = (gint##bits)val; \
129         return TRUE; \
130 }
131
132 DEFINE_WS_STRTOI_BITS(32)
133 DEFINE_WS_STRTOI_BITS(16)
134 DEFINE_WS_STRTOI_BITS(8)
135
136 #define DEFINE_WS_STRTOU_BITS(bits) \
137 int ws_strtou##bits(const gchar* str, guint##bits* cint) \
138 { \
139         guint64 val; \
140         if (!ws_strtou64(str, &val)) { \
141                 /* \
142                  * For ERANGE, return G_MAXUINT##bits for parallelism \
143                  * with ws_strtoi##bits(). \
144                  * \
145                  * For other errors, return 0, for parallelism \
146                  * with ws_strtou64(). \
147                  */ \
148                 if (errno == ERANGE) \
149                         *cint = G_MAXUINT##bits; \
150                 else \
151                         *cint = 0; \
152                 return FALSE; \
153         } \
154         if (val > G_MAXUINT##bits) { \
155                 /* \
156                  * Return G_MAXUINT##bits for parallelism with \
157                  * ws_strtoi##bits(). \
158                  */ \
159                 *cint = G_MAXUINT##bits; \
160                 errno = ERANGE; \
161                 return FALSE; \
162         } \
163         *cint = (guint##bits)val; \
164         return TRUE; \
165 }
166
167 DEFINE_WS_STRTOU_BITS(32)
168 DEFINE_WS_STRTOU_BITS(16)
169 DEFINE_WS_STRTOU_BITS(8)
170
171 /*
172  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
173  *
174  * Local variables:
175  * c-basic-offset: 4
176  * tab-width: 8
177  * indent-tabs-mode: t
178  * End:
179  *
180  * vi: set shiftwidth=4 tabstop=8 noexpandtab:
181  * :indentSize=4:tabSize=8:noTabs=false:
182  */