source: mainline/uspace/lib/cpp/include/internal/locale/num_get.hpp@ 349b0f7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 349b0f7 was c5b2b05, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: fixed error handling in num_get parsing

  • Property mode set to 100644
File size: 12.8 KB
Line 
1/*
2 * Copyright (c) 2017 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_INTERNAL_LOCALE_NUM_GET
30#define LIBCPP_INTERNAL_LOCALE_NUM_GET
31
32#include <internal/locale.hpp>
33#include <internal/locale/numpunct.hpp>
34#include <ios>
35#include <iterator>
36#include <limits>
37
38extern "C" {
39#include <errno.h>
40}
41
42namespace std
43{
44 /**
45 * 22.4.2.1, class template num_get:
46 */
47
48 template<class Char, class InputIterator = istreambuf_iterator<Char>>
49 class num_get: public locale::facet
50 {
51 public:
52 using char_type = Char;
53 using iter_type = InputIterator;
54
55 explicit num_get(size_t refs = 0)
56 { /* DUMMY BODY */ }
57
58 iter_type get(iter_type in, iter_type end, ios_base& base,
59 ios_base::iostate& err, bool& v) const
60 {
61 return do_get(in, end, base, err, v);
62 }
63
64 iter_type get(iter_type in, iter_type end, ios_base& base,
65 ios_base::iostate& err, long& v) const
66 {
67 return do_get(in, end, base, err, v);
68 }
69
70 iter_type get(iter_type in, iter_type end, ios_base& base,
71 ios_base::iostate& err, long long& v) const
72 {
73 return do_get(in, end, base, err, v);
74 }
75
76 iter_type get(iter_type in, iter_type end, ios_base& base,
77 ios_base::iostate& err, unsigned short& v) const
78 {
79 return do_get(in, end, base, err, v);
80 }
81
82 iter_type get(iter_type in, iter_type end, ios_base& base,
83 ios_base::iostate& err, unsigned int& v) const
84 {
85 return do_get(in, end, base, err, v);
86 }
87
88 iter_type get(iter_type in, iter_type end, ios_base& base,
89 ios_base::iostate& err, unsigned long& v) const
90 {
91 return do_get(in, end, base, err, v);
92 }
93
94 iter_type get(iter_type in, iter_type end, ios_base& base,
95 ios_base::iostate& err, unsigned long long& v) const
96 {
97 return do_get(in, end, base, err, v);
98 }
99
100 iter_type get(iter_type in, iter_type end, ios_base& base,
101 ios_base::iostate& err, float& v) const
102 {
103 return do_get(in, end, base, err, v);
104 }
105
106 iter_type get(iter_type in, iter_type end, ios_base& base,
107 ios_base::iostate& err, double& v) const
108 {
109 return do_get(in, end, base, err, v);
110 }
111
112 iter_type get(iter_type in, iter_type end, ios_base& base,
113 ios_base::iostate& err, long double& v) const
114 {
115 return do_get(in, end, base, err, v);
116 }
117
118 iter_type get(iter_type in, iter_type end, ios_base& base,
119 ios_base::iostate& err, void*& v) const
120 {
121 return do_get(in, end, base, err, v);
122 }
123
124 static locale::id id;
125
126 ~num_get()
127 { /* DUMMY BODY */ }
128
129 protected:
130 iter_type do_get(iter_type in, iter_type end, ios_base& base,
131 ios_base::iostate& err, bool& v) const
132 {
133 if (in == end)
134 {
135 err = ios_base::eofbit;
136 return in;
137 }
138
139 if ((base.flags() & ios_base::boolalpha) == 0)
140 {
141 int8_t tmp{};
142 in = get_integral_<int64_t>(in, end, base, err, tmp);
143
144 if (tmp == 0)
145 v = false;
146 else if (tmp == 1)
147 v = true;
148 else
149 {
150 v = true;
151 err = ios_base::failbit;
152 }
153 }
154 else
155 {
156 /**
157 * We track both truename() and falsename()
158 * at the same time, once either is matched
159 * or the input is too big without a match
160 * or the input ends the conversion ends
161 * and the result is deduced.
162 */
163
164 auto loc = base.getloc();
165 const auto& nt = use_facet<numpunct<char_type>>(loc);
166
167 auto true_target = nt.truename();
168 auto false_target = nt.falsename();
169
170 if (true_target == "" || false_target == "")
171 {
172 v = (err == ios_base::failbit);
173 return in;
174 }
175
176 auto true_str = true_target;
177 auto false_str = false_target;
178
179 size_t i{};
180 while (true)
181 {
182 if (true_str.size() <= i && false_str.size() <= i)
183 break;
184 auto c = *in++;
185
186 if (i < true_str.size())
187 true_str[i] = c;
188 if (i < false_str.size())
189 false_str[i] = c;
190 ++i;
191
192 if (in == end || *in == '\n')
193 {
194 err = ios_base::eofbit;
195 break;
196 }
197 }
198
199 if (i == true_str.size() && true_str == true_target)
200 {
201 v = true;
202
203 if (++in == end)
204 err = ios_base::eofbit;
205 else
206 err = ios_base::goodbit;
207 }
208 else if (i == false_str.size() && false_str == false_target)
209 {
210 v = false;
211
212 if (in == end)
213 err = (ios_base::failbit | ios_base::eofbit);
214 else
215 err = ios_base::failbit;
216 }
217 else
218 err = ios_base::failbit;
219 }
220
221 return in;
222 }
223
224 iter_type do_get(iter_type in, iter_type end, ios_base& base,
225 ios_base::iostate& err, long& v) const
226 {
227 return get_integral_<int64_t>(in, end, base, err, v);
228 }
229
230 iter_type do_get(iter_type in, iter_type end, ios_base& base,
231 ios_base::iostate& err, long long& v) const
232 {
233 return get_integral_<int64_t>(in, end, base, err, v);
234 }
235
236 iter_type do_get(iter_type in, iter_type end, ios_base& base,
237 ios_base::iostate& err, unsigned short& v) const
238 {
239 return get_integral_<uint64_t>(in, end, base, err, v);
240 }
241
242 iter_type do_get(iter_type in, iter_type end, ios_base& base,
243 ios_base::iostate& err, unsigned int& v) const
244 {
245 return get_integral_<uint64_t>(in, end, base, err, v);
246 }
247
248 iter_type do_get(iter_type in, iter_type end, ios_base& base,
249 ios_base::iostate& err, unsigned long& v) const
250 {
251 return get_integral_<uint64_t>(in, end, base, err, v);
252 }
253
254 iter_type do_get(iter_type in, iter_type end, ios_base& base,
255 ios_base::iostate& err, unsigned long long& v) const
256 {
257 return get_integral_<uint64_t>(in, end, base, err, v);
258 }
259
260 iter_type do_get(iter_type in, iter_type end, ios_base& base,
261 ios_base::iostate& err, float& v) const
262 {
263 // TODO: implement
264 }
265
266 iter_type do_get(iter_type in, iter_type end, ios_base& base,
267 ios_base::iostate& err, double& v) const
268 {
269 // TODO: implement
270 }
271
272 iter_type do_get(iter_type in, iter_type end, ios_base& base,
273 ios_base::iostate& err, long double& v) const
274 {
275 // TODO: implement
276 }
277
278 iter_type do_get(iter_type in, iter_type end, ios_base& base,
279 ios_base::iostate& err, void*& v) const
280 {
281 // TODO: implement
282 }
283
284 private:
285 template<class BaseType, class T>
286 iter_type get_integral_(iter_type in, iter_type end, ios_base& base,
287 ios_base::iostate& err, T& v) const
288 {
289 BaseType res{};
290 unsigned int num_base{10};
291
292 auto basefield = (base.flags() & ios_base::basefield);
293 if (basefield == ios_base::oct)
294 num_base = 8;
295 else if (basefield == ios_base::hex)
296 num_base = 16;
297
298 auto size = fill_buffer_integral_(in, end, base);
299 if (size > 0)
300 {
301 int ret{};
302 if constexpr (is_signed<BaseType>::value)
303 ret = str_int64_t(base.buffer_, nullptr, num_base, false, &res);
304 else
305 ret = str_uint64_t(base.buffer_, nullptr, num_base, false, &res);
306
307 if (ret != EOK)
308 {
309 err |= ios_base::failbit;
310 v = 0;
311 }
312 else if (res > static_cast<BaseType>(numeric_limits<T>::max()))
313 {
314 err |= ios_base::failbit;
315 v = numeric_limits<T>::max();
316 }
317 else if (res < static_cast<BaseType>(numeric_limits<T>::min()))
318 {
319 err |= ios_base::failbit;
320 v = numeric_limits<T>::min();
321 }
322 else
323 v = static_cast<T>(res);
324 }
325 else
326 {
327 err |= ios_base::failbit;
328 v = 0;
329 }
330
331 return in;
332 }
333
334 size_t fill_buffer_integral_(iter_type& in, iter_type end, ios_base& base) const
335 {
336 if (in == end)
337 return 0;
338
339 auto loc = base.getloc();
340 const auto& ct = use_facet<ctype<char_type>>(loc);
341 auto hex = ((base.flags() & ios_base::hex) != 0);
342
343 size_t i{};
344 if (*in == '+' || *in == '-')
345 base.buffer_[i++] = *in++;
346
347 while (in != end && i < ios_base::buffer_size_ - 1)
348 {
349 auto c = *in;
350 if (ct.is(ctype_base::digit, c) || (hex &&
351 ((c >= ct.widen('A') && c <= ct.widen('F')) ||
352 (c >= ct.widen('a') && c <= ct.widen('f')))))
353 {
354 ++in;
355 base.buffer_[i++] = c;
356 }
357 else
358 break;
359 }
360 base.buffer_[i] = char_type{};
361
362 return i;
363 }
364 };
365}
366
367#endif
Note: See TracBrowser for help on using the repository browser.