]>
git.proxmox.com Git - ceph.git/blob - 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
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
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.
23 #include <string_view>
25 using std::ostringstream
;
27 bool strict_strtob(const char* str
, std::string
*err
)
29 if (strcasecmp(str
, "false") == 0) {
31 } else if (strcasecmp(str
, "true") == 0) {
34 int b
= strict_strtol(str
, 10, err
);
39 long long strict_strtoll(std::string_view str
, int base
, std::string
*err
)
42 errno
= 0; /* To distinguish success/failure after call (see man page) */
43 long long ret
= strtoll(str
.data(), &endptr
, base
);
44 if (endptr
== str
.data() || endptr
!= str
.data() + str
.size()) {
45 *err
= (std::string
{"Expected option value to be integer, got '"} +
46 std::string
{str
} + "'");
50 *err
= (std::string
{"The option value '"} + std::string
{str
} +
51 "' seems to be invalid");
58 int strict_strtol(std::string_view str
, int base
, std::string
*err
)
60 long long ret
= strict_strtoll(str
, base
, err
);
63 if ((ret
< INT_MIN
) || (ret
> INT_MAX
)) {
65 errStr
<< "The option value '" << str
<< "' seems to be invalid";
69 return static_cast<int>(ret
);
72 int strict_strtol(const char *str
, int base
, std::string
*err
)
74 return strict_strtol(std::string_view(str
), base
, err
);
77 double strict_strtod(std::string_view str
, std::string
*err
)
80 errno
= 0; /* To distinguish success/failure after call (see man page) */
81 double ret
= strtod(str
.data(), &endptr
);
82 if (errno
== ERANGE
) {
84 oss
<< "strict_strtod: floating point overflow or underflow parsing '"
91 oss
<< "strict_strtod: expected double, got: '" << str
<< "'";
95 if (*endptr
!= '\0') {
97 oss
<< "strict_strtod: garbage at end of string. got: '" << str
<< "'";
105 float strict_strtof(std::string_view str
, std::string
*err
)
108 errno
= 0; /* To distinguish success/failure after call (see man page) */
109 float ret
= strtof(str
.data(), &endptr
);
110 if (errno
== ERANGE
) {
112 oss
<< "strict_strtof: floating point overflow or underflow parsing '"
119 oss
<< "strict_strtof: expected float, got: '" << str
<< "'";
123 if (*endptr
!= '\0') {
125 oss
<< "strict_strtof: garbage at end of string. got: '" << str
<< "'";
134 T
strict_iec_cast(std::string_view str
, std::string
*err
)
137 *err
= "strict_iecstrtoll: value not specified";
140 // get a view of the unit and of the value
141 std::string_view unit
;
142 std::string_view n
= str
;
143 size_t u
= str
.find_first_not_of("0123456789-+");
145 // deal with unit prefix if there is one
146 if (u
!= std::string_view::npos
) {
147 n
= str
.substr(0, u
);
148 unit
= str
.substr(u
, str
.length() - u
);
149 // we accept both old si prefixes as well as the proper iec prefixes
150 // i.e. K, M, ... and Ki, Mi, ...
151 if (unit
.back() == 'i') {
152 if (unit
.front() == 'B') {
153 *err
= "strict_iecstrtoll: illegal prefix \"Bi\"";
157 if (unit
.length() > 2) {
158 *err
= "strict_iecstrtoll: illegal prefix (length > 2)";
161 switch(unit
.front()) {
183 *err
= "strict_iecstrtoll: unit prefix not recognized";
188 long long ll
= strict_strtoll(n
, 10, err
);
189 if (ll
< 0 && !std::numeric_limits
<T
>::is_signed
) {
190 *err
= "strict_iecstrtoll: value should not be negative";
193 if (static_cast<unsigned>(m
) >= sizeof(T
) * CHAR_BIT
) {
194 *err
= ("strict_iecstrtoll: the IEC prefix is too large for the designated "
198 using promoted_t
= typename
std::common_type
<decltype(ll
), T
>::type
;
199 if (static_cast<promoted_t
>(ll
) <
200 static_cast<promoted_t
>(std::numeric_limits
<T
>::min()) >> m
) {
201 *err
= "strict_iecstrtoll: value seems to be too small";
204 if (static_cast<promoted_t
>(ll
) >
205 static_cast<promoted_t
>(std::numeric_limits
<T
>::max()) >> m
) {
206 *err
= "strict_iecstrtoll: value seems to be too large";
212 template int strict_iec_cast
<int>(std::string_view str
, std::string
*err
);
213 template long strict_iec_cast
<long>(std::string_view str
, std::string
*err
);
214 template long long strict_iec_cast
<long long>(std::string_view str
, std::string
*err
);
215 template uint64_t strict_iec_cast
<uint64_t>(std::string_view str
, std::string
*err
);
216 template uint32_t strict_iec_cast
<uint32_t>(std::string_view str
, std::string
*err
);
218 uint64_t strict_iecstrtoll(std::string_view str
, std::string
*err
)
220 return strict_iec_cast
<uint64_t>(str
, err
);
224 T
strict_si_cast(std::string_view str
, std::string
*err
)
227 *err
= "strict_sistrtoll: value not specified";
230 std::string_view n
= str
;
232 // deal with unit prefix is there is one
233 if (str
.find_first_not_of("0123456789+-") != std::string_view::npos
) {
234 const char &u
= str
.back();
248 *err
= "strict_si_cast: unit prefix not recognized";
253 n
= str
.substr(0, str
.length() -1);
256 long long ll
= strict_strtoll(n
, 10, err
);
257 if (ll
< 0 && !std::numeric_limits
<T
>::is_signed
) {
258 *err
= "strict_sistrtoll: value should not be negative";
261 using promoted_t
= typename
std::common_type
<decltype(ll
), T
>::type
;
262 auto v
= static_cast<promoted_t
>(ll
);
263 auto coefficient
= static_cast<promoted_t
>(powl(10, m
));
264 if (v
!= std::clamp(v
,
265 (static_cast<promoted_t
>(std::numeric_limits
<T
>::min()) /
267 (static_cast<promoted_t
>(std::numeric_limits
<T
>::max()) /
269 *err
= "strict_sistrtoll: value out of range";
272 return v
* coefficient
;
275 template int strict_si_cast
<int>(std::string_view str
, std::string
*err
);
276 template long strict_si_cast
<long>(std::string_view str
, std::string
*err
);
277 template long long strict_si_cast
<long long>(std::string_view str
, std::string
*err
);
278 template uint64_t strict_si_cast
<uint64_t>(std::string_view str
, std::string
*err
);
279 template uint32_t strict_si_cast
<uint32_t>(std::string_view str
, std::string
*err
);