]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/strtol.cc
update sources to 12.2.8
[ceph.git] / ceph / src / common / strtol.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "strtol.h"
16
17 #include <climits>
18 #include <limits>
19 #include <cmath>
20 #include <sstream>
21 #include <boost/utility/string_view.hpp>
22
23 using std::ostringstream;
24
25 long long strict_strtoll(const boost::string_view str, int base, std::string *err)
26 {
27 char *endptr;
28 errno = 0; /* To distinguish success/failure after call (see man page) */
29 long long ret = strtoll(str.data(), &endptr, base);
30 if (endptr == str.data() || endptr != str.data() + str.size()) {
31 *err = (std::string{"Expected option value to be integer, got '"} +
32 std::string{str} + "'");
33 return 0;
34 }
35 if (errno) {
36 *err = (std::string{"The option value '"} + std::string{str} +
37 "' seems to be invalid");
38 return 0;
39 }
40 *err = "";
41 return ret;
42 }
43
44 long long strict_strtoll(const char *str, int base, std::string *err)
45 {
46 return strict_strtoll(boost::string_view(str), base, err);
47 }
48
49 int strict_strtol(const boost::string_view str, int base, std::string *err)
50 {
51 long long ret = strict_strtoll(str, base, err);
52 if (!err->empty())
53 return 0;
54 if ((ret <= INT_MIN) || (ret >= INT_MAX)) {
55 ostringstream errStr;
56 errStr << "The option value '" << str << "' seems to be invalid";
57 *err = errStr.str();
58 return 0;
59 }
60 return static_cast<int>(ret);
61 }
62
63 int strict_strtol(const char *str, int base, std::string *err)
64 {
65 return strict_strtol(boost::string_view(str), base, err);
66 }
67
68 double strict_strtod(const boost::string_view str, std::string *err)
69 {
70 char *endptr;
71 errno = 0; /* To distinguish success/failure after call (see man page) */
72 double ret = strtod(str.data(), &endptr);
73 if (errno == ERANGE) {
74 ostringstream oss;
75 oss << "strict_strtod: floating point overflow or underflow parsing '"
76 << str << "'";
77 *err = oss.str();
78 return 0.0;
79 }
80 if (endptr == str) {
81 ostringstream oss;
82 oss << "strict_strtod: expected double, got: '" << str << "'";
83 *err = oss.str();
84 return 0;
85 }
86 if (*endptr != '\0') {
87 ostringstream oss;
88 oss << "strict_strtod: garbage at end of string. got: '" << str << "'";
89 *err = oss.str();
90 return 0;
91 }
92 *err = "";
93 return ret;
94 }
95
96 double strict_strtod(const char *str, std::string *err)
97 {
98 return strict_strtod(boost::string_view(str), err);
99 }
100
101 float strict_strtof(const boost::string_view str, std::string *err)
102 {
103 char *endptr;
104 errno = 0; /* To distinguish success/failure after call (see man page) */
105 float ret = strtof(str.data(), &endptr);
106 if (errno == ERANGE) {
107 ostringstream oss;
108 oss << "strict_strtof: floating point overflow or underflow parsing '"
109 << str << "'";
110 *err = oss.str();
111 return 0.0;
112 }
113 if (endptr == str) {
114 ostringstream oss;
115 oss << "strict_strtof: expected float, got: '" << str << "'";
116 *err = oss.str();
117 return 0;
118 }
119 if (*endptr != '\0') {
120 ostringstream oss;
121 oss << "strict_strtof: garbage at end of string. got: '" << str << "'";
122 *err = oss.str();
123 return 0;
124 }
125 *err = "";
126 return ret;
127 }
128
129 float strict_strtof(const char *str, std::string *err)
130 {
131 return strict_strtof(boost::string_view(str), err);
132 }
133
134 template<typename T>
135 T strict_iec_cast(const boost::string_view str, std::string *err)
136 {
137 if (str.empty()) {
138 *err = "strict_iecstrtoll: value not specified";
139 return 0;
140 }
141 // get a view of the unit and of the value
142 boost::string_view unit;
143 boost::string_view n = str;
144 size_t u = str.find_first_not_of("0123456789-+");
145 int m = 0;
146 // deal with unit prefix is there is one
147 if (u != boost::string_view::npos) {
148 n = str.substr(0, u);
149 unit = str.substr(u, str.length() - u);
150 // we accept both old si prefixes as well as the proper iec prefixes
151 // i.e. K, M, ... and Ki, Mi, ...
152 if (unit.back() == 'i') {
153 if (unit.front() == 'B') {
154 *err = "strict_iecstrtoll: illegal prefix \"Bi\"";
155 return 0;
156 }
157 }
158 if (unit.length() > 2) {
159 *err = "strict_iecstrtoll: illegal prefix (length > 2)";
160 return 0;
161 }
162 switch(unit.front()) {
163 case 'K':
164 m = 10;
165 break;
166 case 'M':
167 m = 20;
168 break;
169 case 'G':
170 m = 30;
171 break;
172 case 'T':
173 m = 40;
174 break;
175 case 'P':
176 m = 50;
177 break;
178 case 'E':
179 m = 60;
180 break;
181 case 'B':
182 break;
183 default:
184 *err = "strict_iecstrtoll: unit prefix not recognized";
185 return 0;
186 }
187 }
188
189 long long ll = strict_strtoll(n, 10, err);
190 if (ll < 0 && !std::numeric_limits<T>::is_signed) {
191 *err = "strict_iecstrtoll: value should not be negative";
192 return 0;
193 }
194 if (static_cast<unsigned>(m) >= sizeof(T) * CHAR_BIT) {
195 *err = ("strict_iecstrtoll: the IEC prefix is too large for the designated "
196 "type");
197 return 0;
198 }
199 using promoted_t = typename std::common_type<decltype(ll), T>::type;
200 if (static_cast<promoted_t>(ll) <
201 static_cast<promoted_t>(std::numeric_limits<T>::min()) >> m) {
202 *err = "strict_iecstrtoll: value seems to be too small";
203 return 0;
204 }
205 if (static_cast<promoted_t>(ll) >
206 static_cast<promoted_t>(std::numeric_limits<T>::max()) >> m) {
207 *err = "strict_iecstrtoll: value seems to be too large";
208 return 0;
209 }
210 return (ll << m);
211 }
212
213 template int strict_iec_cast<int>(const boost::string_view str, std::string *err);
214 template long strict_iec_cast<long>(const boost::string_view str, std::string *err);
215 template long long strict_iec_cast<long long>(const boost::string_view str, std::string *err);
216 template uint64_t strict_iec_cast<uint64_t>(const boost::string_view str, std::string *err);
217 template uint32_t strict_iec_cast<uint32_t>(const boost::string_view str, std::string *err);
218
219 uint64_t strict_iecstrtoll(const boost::string_view str, std::string *err)
220 {
221 return strict_iec_cast<uint64_t>(str, err);
222 }
223
224 uint64_t strict_iecstrtoll(const char *str, std::string *err)
225 {
226 return strict_iec_cast<uint64_t>(boost::string_view(str), err);
227 }
228
229 template<typename T>
230 T strict_iec_cast(const char *str, std::string *err)
231 {
232 return strict_iec_cast<T>(boost::string_view(str), err);
233 }
234
235 template int strict_iec_cast<int>(const char *str, std::string *err);
236 template long strict_iec_cast<long>(const char *str, std::string *err);
237 template long long strict_iec_cast<long long>(const char *str, std::string *err);
238 template uint64_t strict_iec_cast<uint64_t>(const char *str, std::string *err);
239 template uint32_t strict_iec_cast<uint32_t>(const char *str, std::string *err);
240
241 template<typename T>
242 T strict_si_cast(const boost::string_view str, std::string *err)
243 {
244 if (str.empty()) {
245 *err = "strict_sistrtoll: value not specified";
246 return 0;
247 }
248 boost::string_view n = str;
249 int m = 0;
250 // deal with unit prefix is there is one
251 if (str.find_first_not_of("0123456789+-") != boost::string_view::npos) {
252 const char &u = str.back();
253 if (u == 'K')
254 m = 3;
255 else if (u == 'M')
256 m = 6;
257 else if (u == 'G')
258 m = 9;
259 else if (u == 'T')
260 m = 12;
261 else if (u == 'P')
262 m = 15;
263 else if (u == 'E')
264 m = 18;
265 else if (u != 'B') {
266 *err = "strict_si_cast: unit prefix not recognized";
267 return 0;
268 }
269
270 if (m >= 3)
271 n = str.substr(0, str.length() -1);
272 }
273
274 long long ll = strict_strtoll(n, 10, err);
275 if (ll < 0 && !std::numeric_limits<T>::is_signed) {
276 *err = "strict_sistrtoll: value should not be negative";
277 return 0;
278 }
279 using promoted_t = typename std::common_type<decltype(ll), T>::type;
280 if (static_cast<promoted_t>(ll) <
281 static_cast<promoted_t>(std::numeric_limits<T>::min()) / pow (10, m)) {
282 *err = "strict_sistrtoll: value seems to be too small";
283 return 0;
284 }
285 if (static_cast<promoted_t>(ll) >
286 static_cast<promoted_t>(std::numeric_limits<T>::max()) / pow (10, m)) {
287 *err = "strict_sistrtoll: value seems to be too large";
288 return 0;
289 }
290 return (ll * pow (10, m));
291 }
292
293 template int strict_si_cast<int>(const boost::string_view str, std::string *err);
294 template long strict_si_cast<long>(const boost::string_view str, std::string *err);
295 template long long strict_si_cast<long long>(const boost::string_view str, std::string *err);
296 template uint64_t strict_si_cast<uint64_t>(const boost::string_view str, std::string *err);
297 template uint32_t strict_si_cast<uint32_t>(const boost::string_view str, std::string *err);
298
299 uint64_t strict_sistrtoll(const boost::string_view str, std::string *err)
300 {
301 return strict_si_cast<uint64_t>(str, err);
302 }
303
304 uint64_t strict_sistrtoll(const char *str, std::string *err)
305 {
306 return strict_si_cast<uint64_t>(str, err);
307 }
308
309 template<typename T>
310 T strict_si_cast(const char *str, std::string *err)
311 {
312 return strict_si_cast<T>(boost::string_view(str), err);
313 }
314
315 template int strict_si_cast<int>(const char *str, std::string *err);
316 template long strict_si_cast<long>(const char *str, std::string *err);
317 template long long strict_si_cast<long long>(const char *str, std::string *err);
318 template uint64_t strict_si_cast<uint64_t>(const char *str, std::string *err);
319 template uint32_t strict_si_cast<uint32_t>(const char *str, std::string *err);