Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 <sstream>
20
21 using std::ostringstream;
22
23 long long strict_strtoll(const char *str, int base, std::string *err)
24 {
25   char *endptr;
26   std::string errStr;
27   errno = 0; /* To distinguish success/failure after call (see man page) */
28   long long ret = strtoll(str, &endptr, base);
29
30   if (endptr == str) {
31     errStr = "Expected option value to be integer, got '";
32     errStr.append(str);
33     errStr.append("'");
34     *err =  errStr;
35     return 0;
36   }
37   if ((errno == ERANGE && (ret == LLONG_MAX || ret == LLONG_MIN))
38       || (errno != 0 && ret == 0)) {
39     errStr = "The option value '";
40     errStr.append(str);
41     errStr.append("'");
42     errStr.append(" seems to be invalid");
43     *err = errStr;
44     return 0;
45   }
46   if (*endptr != '\0') {
47     errStr = "The option value '";
48     errStr.append(str);
49     errStr.append("'");
50     errStr.append(" contains invalid digits");
51     *err =  errStr;
52     return 0;
53   }
54   *err = "";
55   return ret;
56 }
57
58 int strict_strtol(const char *str, int base, std::string *err)
59 {
60   std::string errStr;
61   long long ret = strict_strtoll(str, base, err);
62   if (!err->empty())
63     return 0;
64   if ((ret <= INT_MIN) || (ret >= INT_MAX)) {
65     errStr = "The option value '";
66     errStr.append(str);
67     errStr.append("'");
68     errStr.append(" seems to be invalid");
69     *err = errStr;
70     return 0;
71   }
72   return static_cast<int>(ret);
73 }
74
75 double strict_strtod(const char *str, std::string *err)
76 {
77   char *endptr;
78   errno = 0; /* To distinguish success/failure after call (see man page) */
79   double ret = strtod(str, &endptr);
80   if (errno == ERANGE) {
81     ostringstream oss;
82     oss << "strict_strtod: floating point overflow or underflow parsing '"
83         << str << "'";
84     *err = oss.str();
85     return 0.0;
86   }
87   if (endptr == str) {
88     ostringstream oss;
89     oss << "strict_strtod: expected double, got: '" << str << "'";
90     *err = oss.str();
91     return 0;
92   }
93   if (*endptr != '\0') {
94     ostringstream oss;
95     oss << "strict_strtod: garbage at end of string. got: '" << str << "'";
96     *err = oss.str();
97     return 0;
98   }
99   *err = "";
100   return ret;
101 }
102
103 float strict_strtof(const char *str, std::string *err)
104 {
105   char *endptr;
106   errno = 0; /* To distinguish success/failure after call (see man page) */
107   float ret = strtof(str, &endptr);
108   if (errno == ERANGE) {
109     ostringstream oss;
110     oss << "strict_strtof: floating point overflow or underflow parsing '"
111         << str << "'";
112     *err = oss.str();
113     return 0.0;
114   }
115   if (endptr == str) {
116     ostringstream oss;
117     oss << "strict_strtof: expected float, got: '" << str << "'";
118     *err = oss.str();
119     return 0;
120   }
121   if (*endptr != '\0') {
122     ostringstream oss;
123     oss << "strict_strtof: garbage at end of string. got: '" << str << "'";
124     *err = oss.str();
125     return 0;
126   }
127   *err = "";
128   return ret;
129 }
130
131 template<typename T>
132 T strict_si_cast(const char *str, std::string *err)
133 {
134   std::string s(str);
135   if (s.empty()) {
136     *err = "strict_sistrtoll: value not specified";
137     return 0;
138   }
139   const char &u = s.back();
140   int m = 0;
141   if (u == 'B')
142     m = 0;
143   else if (u == 'K')
144     m = 10;
145   else if (u == 'M')
146     m = 20;
147   else if (u == 'G')
148     m = 30;
149   else if (u == 'T')
150     m = 40;
151   else if (u == 'P')
152     m = 50;
153   else if (u == 'E')
154     m = 60;
155   else
156     m = -1;
157
158   if (m >= 0)
159     s.pop_back();
160   else
161     m = 0;
162
163   long long ll = strict_strtoll(s.c_str(), 10, err);
164   if (ll < 0 && !std::numeric_limits<T>::is_signed) {
165     *err = "strict_sistrtoll: value should not be negative";
166     return 0;
167   }
168   if (static_cast<unsigned>(m) >= sizeof(T) * CHAR_BIT) {
169     *err = ("strict_sistrtoll: the SI prefix is too large for the designated "
170             "type");
171     return 0;
172   }
173   using promoted_t = typename std::common_type<decltype(ll), T>::type;
174   if (static_cast<promoted_t>(ll) <
175       static_cast<promoted_t>(std::numeric_limits<T>::min()) >> m) {
176     *err = "strict_sistrtoll: value seems to be too small";
177     return 0;
178   }
179   if (static_cast<promoted_t>(ll) >
180       static_cast<promoted_t>(std::numeric_limits<T>::max()) >> m) {
181     *err = "strict_sistrtoll: value seems to be too large";
182     return 0;
183   }
184   return (ll << m);
185 }
186
187 template int strict_si_cast<int>(const char *str, std::string *err);
188 template long strict_si_cast<long>(const char *str, std::string *err);
189 template long long strict_si_cast<long long>(const char *str, std::string *err);
190 template uint64_t strict_si_cast<uint64_t>(const char *str, std::string *err);
191 template uint32_t strict_si_cast<uint32_t>(const char *str, std::string *err);
192
193 uint64_t strict_sistrtoll(const char *str, std::string *err)
194 {
195   return strict_si_cast<uint64_t>(str, err);
196 }