/src/samba/lib/util/smb_strtox.c
Line | Count | Source |
1 | | /* |
2 | | * Unix SMB/CIFS implementation. |
3 | | * |
4 | | * Copyright (C) Swen Schillig 2019 |
5 | | * |
6 | | * ** NOTE! The following LGPL license applies to this file. |
7 | | * ** This does NOT imply that all of Samba is released |
8 | | * ** under the LGPL |
9 | | * |
10 | | * This library is free software; you can redistribute it and/or |
11 | | * modify it under the terms of the GNU Lesser General Public |
12 | | * License as published by the Free Software Foundation; either |
13 | | * version 3 of the License, or (at your option) any later version. |
14 | | * |
15 | | * This library 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 GNU |
18 | | * Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | #include "replace.h" |
25 | | #include "smb_strtox.h" |
26 | | |
27 | | /** |
28 | | * Convert a string to an unsigned long integer |
29 | | * |
30 | | * @param nptr pointer to string which is to be converted |
31 | | * @param endptr [optional] reference to remainder of the string |
32 | | * @param base base of the numbering scheme |
33 | | * @param err error occurred during conversion |
34 | | * @flags controlling conversion feature |
35 | | * @result result of the conversion as provided by strtoul |
36 | | * |
37 | | * The following flags are supported |
38 | | * SMB_STR_STANDARD # raise error if negative or non-numeric |
39 | | * SMB_STR_ALLOW_NEGATIVE # allow strings with a leading "-" |
40 | | * SMB_STR_FULL_STR_CONV # entire string must be converted |
41 | | * SMB_STR_ALLOW_NO_CONVERSION # allow empty strings or non-numeric |
42 | | * SMB_STR_GLIBC_STANDARD # act exactly as the standard glibc strtoul |
43 | | * |
44 | | * The following errors are detected |
45 | | * - wrong base |
46 | | * - value overflow |
47 | | * - string with a leading "-" indicating a negative number |
48 | | * - no conversion due to empty string or not representing a number |
49 | | */ |
50 | | unsigned long int |
51 | | smb_strtoul(const char *nptr, char **endptr, int base, int *err, int flags) |
52 | 166k | { |
53 | 166k | unsigned long int val; |
54 | 166k | int saved_errno = errno; |
55 | 166k | char *needle = NULL; |
56 | 166k | char *tmp_endptr = NULL; |
57 | | |
58 | 166k | errno = 0; |
59 | 166k | *err = 0; |
60 | | |
61 | 166k | val = strtoul(nptr, &tmp_endptr, base); |
62 | | |
63 | 166k | if (endptr != NULL) { |
64 | 166k | *endptr = tmp_endptr; |
65 | 166k | } |
66 | | |
67 | 166k | if (errno != 0) { |
68 | 455 | *err = errno; |
69 | 455 | errno = saved_errno; |
70 | 455 | return val; |
71 | 455 | } |
72 | | |
73 | 166k | if ((flags & SMB_STR_ALLOW_NO_CONVERSION) == 0) { |
74 | | /* got an invalid number-string resulting in no conversion */ |
75 | 166k | if (nptr == tmp_endptr) { |
76 | 0 | *err = EINVAL; |
77 | 0 | goto out; |
78 | 0 | } |
79 | 166k | } |
80 | | |
81 | 166k | if ((flags & SMB_STR_ALLOW_NEGATIVE ) == 0) { |
82 | | /* did we convert a negative "number" ? */ |
83 | 166k | needle = strchr(nptr, '-'); |
84 | 166k | if (needle != NULL && needle < tmp_endptr) { |
85 | 0 | *err = EINVAL; |
86 | 0 | goto out; |
87 | 0 | } |
88 | 166k | } |
89 | | |
90 | 166k | if ((flags & SMB_STR_FULL_STR_CONV) != 0) { |
91 | | /* did we convert the entire string ? */ |
92 | 0 | if (tmp_endptr[0] != '\0') { |
93 | 0 | *err = EINVAL; |
94 | 0 | goto out; |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | 166k | out: |
99 | 166k | errno = saved_errno; |
100 | 166k | return val; |
101 | 166k | } |
102 | | |
103 | | /** |
104 | | * Convert a string to an unsigned long long integer |
105 | | * |
106 | | * @param nptr pointer to string which is to be converted |
107 | | * @param endptr [optional] reference to remainder of the string |
108 | | * @param base base of the numbering scheme |
109 | | * @param err error occurred during conversion |
110 | | * @flags controlling conversion feature |
111 | | * @result result of the conversion as provided by strtoull |
112 | | * |
113 | | * The following flags are supported |
114 | | * SMB_STR_STANDARD # raise error if negative or non-numeric |
115 | | * SMB_STR_ALLOW_NEGATIVE # allow strings with a leading "-" |
116 | | * SMB_STR_FULL_STR_CONV # entire string must be converted |
117 | | * SMB_STR_ALLOW_NO_CONVERSION # allow empty strings or non-numeric |
118 | | * SMB_STR_GLIBC_STANDARD # act exactly as the standard glibc strtoul |
119 | | * |
120 | | * The following errors are detected |
121 | | * - wrong base |
122 | | * - value overflow |
123 | | * - string with a leading "-" indicating a negative number |
124 | | * - no conversion due to empty string or not representing a number |
125 | | */ |
126 | | unsigned long long int |
127 | | smb_strtoull(const char *nptr, char **endptr, int base, int *err, int flags) |
128 | 573k | { |
129 | 573k | unsigned long long int val; |
130 | 573k | int saved_errno = errno; |
131 | 573k | char *needle = NULL; |
132 | 573k | char *tmp_endptr = NULL; |
133 | | |
134 | 573k | errno = 0; |
135 | 573k | *err = 0; |
136 | | |
137 | 573k | val = strtoull(nptr, &tmp_endptr, base); |
138 | | |
139 | 573k | if (endptr != NULL) { |
140 | 573k | *endptr = tmp_endptr; |
141 | 573k | } |
142 | | |
143 | 573k | if (errno != 0) { |
144 | 595 | *err = errno; |
145 | 595 | errno = saved_errno; |
146 | 595 | return val; |
147 | 595 | } |
148 | | |
149 | 573k | if ((flags & SMB_STR_ALLOW_NO_CONVERSION) == 0) { |
150 | | /* got an invalid number-string resulting in no conversion */ |
151 | 573k | if (nptr == tmp_endptr) { |
152 | 134k | *err = EINVAL; |
153 | 134k | goto out; |
154 | 134k | } |
155 | 573k | } |
156 | | |
157 | 438k | if ((flags & SMB_STR_ALLOW_NEGATIVE ) == 0) { |
158 | | /* did we convert a negative "number" ? */ |
159 | 438k | needle = strchr(nptr, '-'); |
160 | 438k | if (needle != NULL && needle < tmp_endptr) { |
161 | 3 | *err = EINVAL; |
162 | 3 | goto out; |
163 | 3 | } |
164 | 438k | } |
165 | | |
166 | 438k | if ((flags & SMB_STR_FULL_STR_CONV) != 0) { |
167 | | /* did we convert the entire string ? */ |
168 | 0 | if (tmp_endptr[0] != '\0') { |
169 | 0 | *err = EINVAL; |
170 | 0 | goto out; |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | 573k | out: |
175 | | errno = saved_errno; |
176 | 573k | return val; |
177 | 438k | } |