Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
_num_get.cc
Go to the documentation of this file.
1
30#include <loc/_ctype.h>
31#include <loc/_locale.h>
32#include <loc/_numpunct.h>
33#include <rw/_basic_ios.h>
34
35
37
39 __rw_get_num (void*, const char*, int, int,
40 const char*, _RWSTD_SIZE_T, const char*, _RWSTD_SIZE_T);
41
42
43// array of values of each base 2 through 36 digit, i.e., 0-9, A-Z,
44// and a-z; elements with a value greater than 35 do not correspond
45// to any valid digit
46_RWSTD_EXPORT extern const unsigned char __rw_digit_map[];
47
48// array of 1-based indices for each 8-bit character into an internal
49// table of values of each roman digit, i.e., I, V, X, L, C, D, and M
50// elements with a value greater than 7 do not correspond to a roman digit
51_RWSTD_EXPORT extern const unsigned char __rw_roman_inxs[];
52
53} // namespace __rw
54
55
57
58
59template <class _CharT, class _InputIter>
60_RW::__rw_facet_id num_get<_CharT, _InputIter>::id;
61
62
63
64#ifndef _RWSTD_NO_EXT_NUM_GET
65
66template <class _CharT, class _InputIter>
67typename num_get<_CharT, _InputIter>::iter_type
68num_get<_CharT, _InputIter>::
69get (iter_type __begin, iter_type __end, ios_base &__flags,
70 _RWSTD_IOSTATE &__err, short &__val) const
71{
72 _RWSTD_ASSERT_RANGE (__begin, __end);
73
74 // preserve original value in case it's non-zero and
75 // do_get() fails for reason other than bad grouping
76 long __tmp = __val;
77
78 __begin = do_get (__begin, __end, __flags, __err, __tmp);
79 __val = __rw_check_overflow_short (__tmp, __flags.flags (), __err);
80
81 return __begin;
82}
83
84
85template <class _CharT, class _InputIter>
86typename num_get<_CharT, _InputIter>::iter_type
87num_get<_CharT, _InputIter>::
88get (iter_type __begin, iter_type __end, ios_base &__flags,
89 _RWSTD_IOSTATE &__err, int &__val) const
90{
91 _RWSTD_ASSERT_RANGE (__begin, __end);
92
93 // preserve original value in case it's non-zero and
94 // do_get() fails for reason other than bad grouping
95 long __tmp = long (__val);
96
97 __begin = do_get (__begin, __end, __flags, __err, __tmp);
98 __val = __rw_check_overflow_int (__tmp, __flags.flags (), __err);
99
100 return __begin;
101}
102
103#endif // _RWSTD_NO_EXT_NUM_GET
104
105
106#ifndef _RWSTD_NO_NATIVE_BOOL
107
108template <class _CharT, class _InputIter /* = istreambuf_iterator<_CharT> */>
109typename num_get<_CharT, _InputIter>::iter_type
110num_get<_CharT, _InputIter>::
111do_get (iter_type __begin, iter_type __end, ios_base &__flags,
112 _RWSTD_IOSTATE &__err, bool &__val) const
113{
114 if (0 == (__flags.flags () & _RWSTD_IOS_BOOLALPHA)) {
115 // initialize to an invalid value
116 long __lval = -1L;
117
118 // avoid calling overridden do_get() if it exists
119 typedef num_get<_CharT, _InputIter> _This;
120 __begin = _This::do_get (__begin, __end, __flags, __err, __lval);
121
122 // set failbit in accordance with 22.2.2.1.2, p14 but without
123 // testing for failbit in `err' since the bit could be set even
124 // for valid `val' (e.g., when the positions of thousands_seps
125 // in otherwise valid input do not match grouping)
126 if (_RWSTD_STATIC_CAST (unsigned long, __lval) < 2)
127 __val = 0L != __lval;
128 else
129 __err |= _RW::__rw_failbit;
130
131 return __begin;
132 }
133
134 __err = _RW::__rw_goodbit;
135
136 const numpunct<char_type> &__pun =
137 _RWSTD_USE_FACET (numpunct<char_type>, __flags.getloc ());
138
139 // lwg issue 17
140 typedef basic_string<char_type> string_type;
141
142 const string_type __tnm = __pun.truename ();
143 const string_type __fnm = __pun.falsename ();
144
145 const char_type* const __names[] = {
146 __fnm.c_str (), __tnm.c_str ()
147 };
148
149 const _RWSTD_SIZE_T __sizes[] = {
150 __fnm.size (), __tnm.size ()
151 };
152
153 _RWSTD_SIZE_T __inx = 0;
154
155 int __errtmp = 1; // maximum number of allowed duplicates
156
157 __begin = _RW::__rw_match_name (__begin, __end, __names, __sizes,
158 sizeof __names / sizeof *__names,
159 __inx, __errtmp, 0);
160
161 if (_RWSTD_SIZE_MAX == __inx)
162 __err |= _RW::__rw_failbit;
163 else
164 __val = !!__inx;
165
166 __err |= _RWSTD_IOSTATE (__errtmp);
167
168 return __begin;
169}
170
171#endif // _RWSTD_NO_NATIVE_BOOL
172
173
174template <class _CharT, class _InputIter /* = istreambuf_iterator<_CharT> */>
175typename num_get<_CharT, _InputIter>::iter_type
176num_get<_CharT, _InputIter>::
177_C_get (iter_type __begin, iter_type __end, ios_base &__flags,
178 _RWSTD_IOSTATE &__err, int __type, void *__pval) const
179{
180 __err = _RW::__rw_goodbit;
181
182 const int __fl = __flags.flags ();
183
184 // boolalpha parsing not handled here
185 _RWSTD_ASSERT (__type != _C_bool || !(__fl & _RWSTD_IOS_BOOLALPHA));
186
187 const locale &__loc = __flags.getloc ();
188
189 const numpunct<char_type> &__pun =
190 _RWSTD_USE_FACET (numpunct<char_type>, __loc);
191
192 // 22.2.2.1.2, p8: Stage 2
193
194 char __buf [128 + 2]; // default buffer (128 bits + 2)
195 char *__pbuf = __buf; // pointer to allocated buffer
196 char *__pcur = __buf; // currently processed digit
197 _RWSTD_SIZE_T __bufsize = sizeof __buf; // size of allocated buffer
198
199 _RWSTD_UNUSED (__bufsize);
200
201 const ctype<char_type> &__ctp = _RWSTD_USE_FACET (ctype<char_type>, __loc);
202
203 const _CharT __decimal_point = __pun.decimal_point ();
204 const _CharT __thousands_sep = __pun.thousands_sep ();
205
206 // grouping string and size are lazily initialized only
207 // when the first thousands_sep() is encountered
208 string __grouping;
209 int __grpsz = -1;
210
211 // buffer containing the sizes of thousands_sep-separated
212 // groups of digits and a pointer to the next grouping
213 char __grpbuf [sizeof __buf];
214 char *__pgrp = __grpbuf;
215
216 const char *__grpbeg = 0; // the beginning of the last group
217 const char *__grpend = 0; // the end of the last group
218
219 int __base = unsigned (__fl) >> _RWSTD_IOS_BASEOFF;
220
221 // switch to base-16 for pointer parsing
222 if (_RW::__rw_facet::_C_pvoid == __type)
223 __base = 16;
224 else if (10 == __base && !(__fl & _RWSTD_IOS_BASEFIELD))
225 __base = 0;
226
227 int __subtype = __type; // type of the number being parsed
228
229 typedef unsigned char _UChar;
230
231 // insert a plus sign (ovewrite it with a minus sign if found)
232 // to avoid having to deal with the fact that it's optional
233 *__pcur++ = '+';
234
235 static const _UChar _HexX = _RW::__rw_digit_map [_UChar ('X')];
236 static const _UChar _Sign = _RW::__rw_digit_map [_UChar ('+')];
237
238 // 'x' or 'X' after a leading '0' (the same value for both),
239 // any value outside the valid range [0, 36) is invalid and
240 // will not match any character
241 _UChar __hex_x = _HexX;
242
243 // leading plus or minus sign (the same value for both)
244 // any value outside the valid range [0, 36) is invalid
245 _UChar __ld_sgn = _Sign;
246
247 for ( ; ; ++__begin) {
248
249 if (__begin == __end) {
250 // 22.2.2.1, p13
251 __err |= _RW::__rw_eofbit;
252 break;
253 }
254
255 if (__pcur == __buf + sizeof __buf - 1) {
256 // FIXME: handle long strings of digits
257 __err |= _RW::__rw_failbit;
258 break;
259 }
260
261 const _CharT __wc = *__begin;
262 const char __dp = __decimal_point == __wc ? '.' : '\0';
263
264 if ( __thousands_sep == __wc
265 && _RW::__rw_digit_map [_UChar (__pcur [-1])] < 36
266 && ( __grpsz > 0
267 || __grpsz < 0
268 && (__grpsz = int((__grouping = __pun.grouping ()).size ())))) {
269
270 // the current character is the thousands separator,
271 // the previous character was a digit (and not a sign),
272 // and grouping (lazily initialized above) is not empty
273
274 if (__pcur == __pbuf + 1) {
275 // 22.2.3.1, p2: thousands_sep not allowed to be first
276 // non-fatal error, set failbit but continue parsing
277 __err |= _RW::__rw_failbit;
278 }
279
280 if (__grpend) {
281 // thousands_sep not allowed or recognized after the
282 // end of the mantissa has been reached (i.e., after
283 // the decimal point or after 'E' or 'e')
284 break;
285 }
286
287 // add the length of the current group to the array groups
288 // store UCHAR_MAX if group length exceeds the size of char
289 const _RWSTD_PTRDIFF_T __len = __grpbeg ?
290 __pcur - __grpbeg : __pcur - __pbuf - 1 - (_HexX != __hex_x);
291
292 if (0 == __len) {
293 // fatal error: thousands_sep characters must be separated
294 // by groups of one or more digits
295 __err |= _RW::__rw_failbit;
296 return __begin;
297 }
298
299 *__pgrp++ = char (__len < _UChar (_RWSTD_UCHAR_MAX) ? __len : -1);
300 __grpbeg = __pcur;
301 }
302 else if (!__dp) {
303
304 const char __ch = __ctp.narrow (__wc, '\0');
305
306 // get the digit value of the character; anything over
307 // 35 is not a digit (43 is either the plus sign or
308 // the minus sign, for efficiency); the value 99
309 // indicates an invalid character
310 const _UChar __digit = _RW::__rw_digit_map [_UChar (__ch)];
311
312 // 22.2.2.1.2, p8: Stage 8 calls for widening of the sequence
313 // of narrow digits ("0123456789abcdefABCDEFX+-") and looking
314 // up the current wide character in the widened sequence, but
315 // that may not possible unless the wide character type has
316 // operator==() defined
317
318 if (__subtype & _C_floating) {
319
320 if (__digit < 10)
321 *__pcur++ = __ch;
322 else if (__pcur == __pbuf + 1) {
323 // plus or minus only permitted (but not required)
324 // as the first character of the mantissa
325 if (__ld_sgn == __digit) {
326 // overwrite the default plus with the sign
327 __pcur [-1] = __ch;
328
329 // disable future recognition of the leading sign
330 __ld_sgn = 36;
331 }
332 else
333 break;
334 }
335 else {
336 if (/* 'E' or 'e' == __ch */
337 14 == _RW::__rw_digit_map [_UChar (__ch)]) {
338 const _RWSTD_PTRDIFF_T __diff = __pcur - __pbuf;
339
340 if (2 == __diff && '.' == __pcur [-1])
341 break;
342
343 if (!__grpend)
344 __grpend = __pcur;
345 *__pcur++ = 'e';
346
347 if (__grpsz) {
348 const char __ts =
349 __ctp.narrow (__thousands_sep, '\0');
350 if (/* '+' or '-' == __ts */
351 _Sign == _RW::__rw_digit_map [_UChar (__ts)])
352 __grpsz = 0;
353 }
354 }
355 else if ( 'e' == __pcur [-1]
356 && /* '+' or '-' == __ch */
357 _Sign == _RW::__rw_digit_map [_UChar (__ch)]) {
358 // '+' or '-' only permitted (but not required)
359 // as the first character after 'e' or 'E'
360
361 *__pcur++ = __ch;
362
363 // reached the exponent part of a floating point number
364 // switch to parsing a decimal integer
365 __base = 10;
366 __subtype = _C_int;
367 }
368 else
369 break; // invalid character terminates input
370 }
371 }
372 else {
373 if (__pcur == __pbuf + 1 && __digit == __ld_sgn) {
374 __pcur [-1] = __ch; // overwrite the default '+'
375 __ld_sgn = 36; // disable leading sign
376 }
377 else if (16 == __base) {
378 if (__digit < 16)
379 *__pcur++ = __ch;
380 else if ( __digit == __hex_x
381 && __pcur == __pbuf + 2
382 && __pcur [-1] == '0') {
383 // don't append the 'x' part of the "0x" prefix
384 // and disable the recognition of any future 'x'
385 __hex_x = 36;
386 }
387 else
388 break; // invalid character terminates input
389 }
390 else if (__base > 1) {
391 if (__digit < __base)
392 *__pcur++ = __ch;
393 else
394 break; // invalid character terminates input
395 }
396 else if (0 == __base) {
397
398 // autodetect the base
399
400 if (__digit < 10) {
401 if ( __digit && __digit < 8
402 && *(__pcur - 1) == '0' && __pcur == __pbuf + 2)
403 __base = 8;
404 *__pcur++ = __ch;
405 }
406 else if ( __digit == __hex_x
407 && __pcur == __pbuf + 2
408 && __pcur [-1] == '0') {
409 __hex_x = 36; // disable future 'x'
410 __base = 16; // set base-16
411 --__pcur; // remove leading '0'
412 }
413 else
414 break; // invalid character terminates input
415 }
416 else {
417 if (_RW::__rw_roman_inxs [_UChar (__ch)] <= 7)
418 *__pcur++ = __ch;
419 else if (__pcur == __pbuf + 1 && __digit < 10) {
420 *__pcur++ = __ch;
421 // if the first character is a digit
422 // switch to decimal (base-10) parsing
423 __base = 10;
424 }
425 else {
426 // invalid character terminates input
427 break;
428 }
429 }
430 }
431 }
432 else if (__subtype & _C_floating) {
433 if (__grpend)
434 break;
435
436 __grpend = __pcur;
437 *__pcur++ = '.';
438 }
439 else
440 break;
441 }
442
443 // add the length of the last group to the array of groups
444 {
445 // add the length of the current group to the array groups
446 // store UCHAR_MAX if group length exceeds the size of char
447 _RWSTD_PTRDIFF_T __len;
448
449 if (__grpend) {
450
451#if defined (_RWSTD_NO_STRTOLD) && defined (_RWSTD_NO_STRTOLD_IN_LIBC)
452
453 // detect invalid formats in case strtold() is not
454 // available (scanf() will not detect these)
455
456 if ( 'e' == __pcur [-1]
457 || '-' == __pcur [-1] || '+' == __pcur [-1]) {
458 __err |= _RW::__rw_failbit;
459 return __begin;
460 }
461
462#endif // _RWSTD_NO_STRTOLD && _RWSTD_NO_STRTOLD_IN_LIBC
463
464 }
465 else
466 __grpend = __pcur;
467
468 __len = __grpbeg ?
469 __grpend - __grpbeg : __grpend - __pbuf - 1 - (_HexX != __hex_x);
470
471 if (__grpbeg && 0 == __len) {
472 // fatal error: according to the grammar in [locale.numpunct]
473 // thousands_sep characters must be separated by groups of one
474 // or more digits (i.e., valid input cannot start or end with
475 // a thousands_sep); this needs to be clarified in the text
476 __err |= _RW::__rw_failbit;
477 return __begin;
478 }
479
480 *__pgrp++ = char (__len < _UChar (_RWSTD_UCHAR_MAX) ? __len : -1);
481 }
482
483 *__pgrp = '\0';
484 *__pcur = '\0';
485
486 // verify that the buffers haven't overflowed
487 _RWSTD_ASSERT (__pgrp < __grpbuf + sizeof __grpbuf);
488 _RWSTD_ASSERT (__pcur < __pbuf + __bufsize);
489
490 // set the base determined above
491 const unsigned __fl2 =
492 __fl & ~_RWSTD_IOS_BASEFIELD
495 | __base << _RWSTD_IOS_BASEOFF;
496
497 // 22.2.2.1.2, p11: Stage 3
498 const int __errtmp =
499 _RW::__rw_get_num (__pval, __pbuf, __type, __fl2,
500 __grpbuf, __pgrp - __grpbuf,
501 __grouping.data (), __grouping.size ());
502
503 __err |= _RWSTD_IOSTATE (__errtmp);
504
505 return __begin;
506}
507
508
509} // namespace std
#define _RWSTD_EXPORT
Definition _defs.h:485
#define _RWSTD_IOS_BOOLALPHA
Definition _defs.h:766
#define _RWSTD_IOS_BASEFIELD
Definition _defs.h:796
#define _RWSTD_USE_FACET(type, arg)
Definition _defs.h:949
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_IOS_BASEOFF
Definition _defs.h:805
#define _RWSTD_ASSERT_RANGE(ign1, ign2)
Definition _defs.h:1247
#define _RWSTD_IOS_BASEMASK
Definition _defs.h:804
#define _RWSTD_IOSTATE
Definition _iosfwd.h:91
Definition json.h:5363