510 lines
18 KiB
C++
510 lines
18 KiB
C++
/***************************************************************************
|
|
*
|
|
* _num_get.cc - definition of std::num_get members
|
|
*
|
|
* $Id: _num_get.cc 648752 2008-04-16 17:01:56Z faridz $
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* permissions and limitations under the License.
|
|
*
|
|
* Copyright 2001-2008 Rogue Wave Software, Inc.
|
|
*
|
|
**************************************************************************/
|
|
|
|
|
|
#include <loc/_ctype.h>
|
|
#include <loc/_locale.h>
|
|
#include <loc/_numpunct.h>
|
|
#include <rw/_basic_ios.h>
|
|
|
|
|
|
_RWSTD_NAMESPACE (__rw) {
|
|
|
|
_RWSTD_EXPORT int
|
|
__rw_get_num (void*, const char*, int, int,
|
|
const char*, _RWSTD_SIZE_T, const char*, _RWSTD_SIZE_T);
|
|
|
|
|
|
// array of values of each base 2 through 36 digit, i.e., 0-9, A-Z,
|
|
// and a-z; elements with a value greater than 35 do not correspond
|
|
// to any valid digit
|
|
_RWSTD_EXPORT extern const unsigned char __rw_digit_map[];
|
|
|
|
// array of 1-based indices for each 8-bit character into an internal
|
|
// table of values of each roman digit, i.e., I, V, X, L, C, D, and M
|
|
// elements with a value greater than 7 do not correspond to a roman digit
|
|
_RWSTD_EXPORT extern const unsigned char __rw_roman_inxs[];
|
|
|
|
} // namespace __rw
|
|
|
|
|
|
_RWSTD_NAMESPACE (std) {
|
|
|
|
|
|
template <class _CharT, class _InputIter>
|
|
_RW::__rw_facet_id num_get<_CharT, _InputIter>::id;
|
|
|
|
|
|
|
|
#ifndef _RWSTD_NO_EXT_NUM_GET
|
|
|
|
template <class _CharT, class _InputIter>
|
|
_TYPENAME num_get<_CharT, _InputIter>::iter_type
|
|
num_get<_CharT, _InputIter>::
|
|
get (iter_type __begin, iter_type __end, ios_base &__flags,
|
|
_RWSTD_IOSTATE &__err, short &__val) const
|
|
{
|
|
_RWSTD_ASSERT_RANGE (__begin, __end);
|
|
|
|
// preserve original value in case it's non-zero and
|
|
// do_get() fails for reason other than bad grouping
|
|
long __tmp = __val;
|
|
|
|
__begin = do_get (__begin, __end, __flags, __err, __tmp);
|
|
__val = __rw_check_overflow_short (__tmp, __flags.flags (), __err);
|
|
|
|
return __begin;
|
|
}
|
|
|
|
|
|
template <class _CharT, class _InputIter>
|
|
_TYPENAME num_get<_CharT, _InputIter>::iter_type
|
|
num_get<_CharT, _InputIter>::
|
|
get (iter_type __begin, iter_type __end, ios_base &__flags,
|
|
_RWSTD_IOSTATE &__err, int &__val) const
|
|
{
|
|
_RWSTD_ASSERT_RANGE (__begin, __end);
|
|
|
|
// preserve original value in case it's non-zero and
|
|
// do_get() fails for reason other than bad grouping
|
|
long __tmp = long (__val);
|
|
|
|
__begin = do_get (__begin, __end, __flags, __err, __tmp);
|
|
__val = __rw_check_overflow_int (__tmp, __flags.flags (), __err);
|
|
|
|
return __begin;
|
|
}
|
|
|
|
#endif // _RWSTD_NO_EXT_NUM_GET
|
|
|
|
|
|
#ifndef _RWSTD_NO_NATIVE_BOOL
|
|
|
|
template <class _CharT, class _InputIter /* = istreambuf_iterator<_CharT> */>
|
|
_TYPENAME num_get<_CharT, _InputIter>::iter_type
|
|
num_get<_CharT, _InputIter>::
|
|
do_get (iter_type __begin, iter_type __end, ios_base &__flags,
|
|
_RWSTD_IOSTATE &__err, bool &__val) const
|
|
{
|
|
if (0 == (__flags.flags () & _RWSTD_IOS_BOOLALPHA)) {
|
|
// initialize to an invalid value
|
|
long __lval = -1L;
|
|
|
|
// avoid calling overridden do_get() if it exists
|
|
typedef num_get<_CharT, _InputIter> _This;
|
|
__begin = _This::do_get (__begin, __end, __flags, __err, __lval);
|
|
|
|
// set failbit in accordance with 22.2.2.1.2, p14 but without
|
|
// testing for failbit in `err' since the bit could be set even
|
|
// for valid `val' (e.g., when the positions of thousands_seps
|
|
// in otherwise valid input do not match grouping)
|
|
if (_RWSTD_STATIC_CAST (unsigned long, __lval) < 2)
|
|
__val = 0L != __lval;
|
|
else
|
|
__err |= _RW::__rw_failbit;
|
|
|
|
return __begin;
|
|
}
|
|
|
|
__err = _RW::__rw_goodbit;
|
|
|
|
const numpunct<char_type> &__pun =
|
|
_RWSTD_USE_FACET (numpunct<char_type>, __flags.getloc ());
|
|
|
|
// lwg issue 17
|
|
typedef basic_string<char_type> string_type;
|
|
|
|
const string_type __tnm = __pun.truename ();
|
|
const string_type __fnm = __pun.falsename ();
|
|
|
|
const char_type* const __names[] = {
|
|
__fnm.c_str (), __tnm.c_str ()
|
|
};
|
|
|
|
const _RWSTD_SIZE_T __sizes[] = {
|
|
__fnm.size (), __tnm.size ()
|
|
};
|
|
|
|
_RWSTD_SIZE_T __inx = 0;
|
|
|
|
int __errtmp = 1; // maximum number of allowed duplicates
|
|
|
|
__begin = _RW::__rw_match_name (__begin, __end, __names, __sizes,
|
|
sizeof __names / sizeof *__names,
|
|
__inx, __errtmp, 0);
|
|
|
|
if (_RWSTD_SIZE_MAX == __inx)
|
|
__err |= _RW::__rw_failbit;
|
|
else
|
|
__val = !!__inx;
|
|
|
|
__err |= _RWSTD_IOSTATE (__errtmp);
|
|
|
|
return __begin;
|
|
}
|
|
|
|
#endif // _RWSTD_NO_NATIVE_BOOL
|
|
|
|
|
|
template <class _CharT, class _InputIter /* = istreambuf_iterator<_CharT> */>
|
|
_TYPENAME num_get<_CharT, _InputIter>::iter_type
|
|
num_get<_CharT, _InputIter>::
|
|
_C_get (iter_type __begin, iter_type __end, ios_base &__flags,
|
|
_RWSTD_IOSTATE &__err, int __type, void *__pval) const
|
|
{
|
|
__err = _RW::__rw_goodbit;
|
|
|
|
const int __fl = __flags.flags ();
|
|
|
|
// boolalpha parsing not handled here
|
|
_RWSTD_ASSERT (__type != _C_bool || !(__fl & _RWSTD_IOS_BOOLALPHA));
|
|
|
|
const locale &__loc = __flags.getloc ();
|
|
|
|
const numpunct<char_type> &__pun =
|
|
_RWSTD_USE_FACET (numpunct<char_type>, __loc);
|
|
|
|
// 22.2.2.1.2, p8: Stage 2
|
|
|
|
char __buf [128 + 2]; // default buffer (128 bits + 2)
|
|
char *__pbuf = __buf; // pointer to allocated buffer
|
|
char *__pcur = __buf; // currently processed digit
|
|
_RWSTD_SIZE_T __bufsize = sizeof __buf; // size of allocated buffer
|
|
|
|
_RWSTD_UNUSED (__bufsize);
|
|
|
|
const ctype<char_type> &__ctp = _RWSTD_USE_FACET (ctype<char_type>, __loc);
|
|
|
|
const _CharT __decimal_point = __pun.decimal_point ();
|
|
const _CharT __thousands_sep = __pun.thousands_sep ();
|
|
|
|
// grouping string and size are lazily initialized only
|
|
// when the first thousands_sep() is encountered
|
|
string __grouping;
|
|
int __grpsz = -1;
|
|
|
|
// buffer containing the sizes of thousands_sep-separated
|
|
// groups of digits and a pointer to the next grouping
|
|
char __grpbuf [sizeof __buf];
|
|
char *__pgrp = __grpbuf;
|
|
|
|
const char *__grpbeg = 0; // the beginning of the last group
|
|
const char *__grpend = 0; // the end of the last group
|
|
|
|
int __base = unsigned (__fl) >> _RWSTD_IOS_BASEOFF;
|
|
|
|
// switch to base-16 for pointer parsing
|
|
if (_RW::__rw_facet::_C_pvoid == __type)
|
|
__base = 16;
|
|
else if (10 == __base && !(__fl & _RWSTD_IOS_BASEFIELD))
|
|
__base = 0;
|
|
|
|
int __subtype = __type; // type of the number being parsed
|
|
|
|
typedef unsigned char _UChar;
|
|
|
|
// insert a plus sign (ovewrite it with a minus sign if found)
|
|
// to avoid having to deal with the fact that it's optional
|
|
*__pcur++ = '+';
|
|
|
|
static const _UChar _HexX = _RW::__rw_digit_map [_UChar ('X')];
|
|
static const _UChar _Sign = _RW::__rw_digit_map [_UChar ('+')];
|
|
|
|
// 'x' or 'X' after a leading '0' (the same value for both),
|
|
// any value outside the valid range [0, 36) is invalid and
|
|
// will not match any character
|
|
_UChar __hex_x = _HexX;
|
|
|
|
// leading plus or minus sign (the same value for both)
|
|
// any value outside the valid range [0, 36) is invalid
|
|
_UChar __ld_sgn = _Sign;
|
|
|
|
for ( ; ; ++__begin) {
|
|
|
|
if (__begin == __end) {
|
|
// 22.2.2.1, p13
|
|
__err |= _RW::__rw_eofbit;
|
|
break;
|
|
}
|
|
|
|
if (__pcur == __buf + sizeof __buf - 1) {
|
|
// FIXME: handle long strings of digits
|
|
__err |= _RW::__rw_failbit;
|
|
break;
|
|
}
|
|
|
|
const _CharT __wc = *__begin;
|
|
const char __dp = __decimal_point == __wc ? '.' : '\0';
|
|
|
|
if ( __thousands_sep == __wc
|
|
&& _RW::__rw_digit_map [_UChar (__pcur [-1])] < 36
|
|
&& ( __grpsz > 0
|
|
|| __grpsz < 0
|
|
&& (__grpsz = int((__grouping = __pun.grouping ()).size ())))) {
|
|
|
|
// the current character is the thousands separator,
|
|
// the previous character was a digit (and not a sign),
|
|
// and grouping (lazily initialized above) is not empty
|
|
|
|
if (__pcur == __pbuf + 1) {
|
|
// 22.2.3.1, p2: thousands_sep not allowed to be first
|
|
// non-fatal error, set failbit but continue parsing
|
|
__err |= _RW::__rw_failbit;
|
|
}
|
|
|
|
if (__grpend) {
|
|
// thousands_sep not allowed or recognized after the
|
|
// end of the mantissa has been reached (i.e., after
|
|
// the decimal point or after 'E' or 'e')
|
|
break;
|
|
}
|
|
|
|
// add the length of the current group to the array groups
|
|
// store UCHAR_MAX if group length exceeds the size of char
|
|
const _RWSTD_PTRDIFF_T __len = __grpbeg ?
|
|
__pcur - __grpbeg : __pcur - __pbuf - 1 - (_HexX != __hex_x);
|
|
|
|
if (0 == __len) {
|
|
// fatal error: thousands_sep characters must be separated
|
|
// by groups of one or more digits
|
|
__err |= _RW::__rw_failbit;
|
|
return __begin;
|
|
}
|
|
|
|
*__pgrp++ = char (__len < _UChar (_RWSTD_UCHAR_MAX) ? __len : -1);
|
|
__grpbeg = __pcur;
|
|
}
|
|
else if (!__dp) {
|
|
|
|
const char __ch = __ctp.narrow (__wc, '\0');
|
|
|
|
// get the digit value of the character; anything over
|
|
// 35 is not a digit (43 is either the plus sign or
|
|
// the minus sign, for efficiency); the value 99
|
|
// indicates an invalid character
|
|
const _UChar __digit = _RW::__rw_digit_map [_UChar (__ch)];
|
|
|
|
// 22.2.2.1.2, p8: Stage 8 calls for widening of the sequence
|
|
// of narrow digits ("0123456789abcdefABCDEFX+-") and looking
|
|
// up the current wide character in the widened sequence, but
|
|
// that may not possible unless the wide character type has
|
|
// operator==() defined
|
|
|
|
if (__subtype & _C_floating) {
|
|
|
|
if (__digit < 10)
|
|
*__pcur++ = __ch;
|
|
else if (__pcur == __pbuf + 1) {
|
|
// plus or minus only permitted (but not required)
|
|
// as the first character of the mantissa
|
|
if (__ld_sgn == __digit) {
|
|
// overwrite the default plus with the sign
|
|
__pcur [-1] = __ch;
|
|
|
|
// disable future recognition of the leading sign
|
|
__ld_sgn = 36;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
else {
|
|
if (/* 'E' or 'e' == __ch */
|
|
14 == _RW::__rw_digit_map [_UChar (__ch)]) {
|
|
const _RWSTD_PTRDIFF_T __diff = __pcur - __pbuf;
|
|
|
|
if (2 == __diff && '.' == __pcur [-1])
|
|
break;
|
|
|
|
if (!__grpend)
|
|
__grpend = __pcur;
|
|
*__pcur++ = 'e';
|
|
|
|
if (__grpsz) {
|
|
const char __ts =
|
|
__ctp.narrow (__thousands_sep, '\0');
|
|
if (/* '+' or '-' == __ts */
|
|
_Sign == _RW::__rw_digit_map [_UChar (__ts)])
|
|
__grpsz = 0;
|
|
}
|
|
}
|
|
else if ( 'e' == __pcur [-1]
|
|
&& /* '+' or '-' == __ch */
|
|
_Sign == _RW::__rw_digit_map [_UChar (__ch)]) {
|
|
// '+' or '-' only permitted (but not required)
|
|
// as the first character after 'e' or 'E'
|
|
|
|
*__pcur++ = __ch;
|
|
|
|
// reached the exponent part of a floating point number
|
|
// switch to parsing a decimal integer
|
|
__base = 10;
|
|
__subtype = _C_int;
|
|
}
|
|
else
|
|
break; // invalid character terminates input
|
|
}
|
|
}
|
|
else {
|
|
if (__pcur == __pbuf + 1 && __digit == __ld_sgn) {
|
|
__pcur [-1] = __ch; // overwrite the default '+'
|
|
__ld_sgn = 36; // disable leading sign
|
|
}
|
|
else if (16 == __base) {
|
|
if (__digit < 16)
|
|
*__pcur++ = __ch;
|
|
else if ( __digit == __hex_x
|
|
&& __pcur == __pbuf + 2
|
|
&& __pcur [-1] == '0') {
|
|
// don't append the 'x' part of the "0x" prefix
|
|
// and disable the recognition of any future 'x'
|
|
__hex_x = 36;
|
|
}
|
|
else
|
|
break; // invalid character terminates input
|
|
}
|
|
else if (__base > 1) {
|
|
if (__digit < __base)
|
|
*__pcur++ = __ch;
|
|
else
|
|
break; // invalid character terminates input
|
|
}
|
|
else if (0 == __base) {
|
|
|
|
// autodetect the base
|
|
|
|
if (__digit < 10) {
|
|
if ( __digit && __digit < 8
|
|
&& *(__pcur - 1) == '0' && __pcur == __pbuf + 2)
|
|
__base = 8;
|
|
*__pcur++ = __ch;
|
|
}
|
|
else if ( __digit == __hex_x
|
|
&& __pcur == __pbuf + 2
|
|
&& __pcur [-1] == '0') {
|
|
__hex_x = 36; // disable future 'x'
|
|
__base = 16; // set base-16
|
|
--__pcur; // remove leading '0'
|
|
}
|
|
else
|
|
break; // invalid character terminates input
|
|
}
|
|
else {
|
|
if (_RW::__rw_roman_inxs [_UChar (__ch)] <= 7)
|
|
*__pcur++ = __ch;
|
|
else if (__pcur == __pbuf + 1 && __digit < 10) {
|
|
*__pcur++ = __ch;
|
|
// if the first character is a digit
|
|
// switch to decimal (base-10) parsing
|
|
__base = 10;
|
|
}
|
|
else {
|
|
// invalid character terminates input
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (__subtype & _C_floating) {
|
|
if (__grpend)
|
|
break;
|
|
|
|
__grpend = __pcur;
|
|
*__pcur++ = '.';
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// add the length of the last group to the array of groups
|
|
{
|
|
// add the length of the current group to the array groups
|
|
// store UCHAR_MAX if group length exceeds the size of char
|
|
_RWSTD_PTRDIFF_T __len;
|
|
|
|
if (__grpend) {
|
|
|
|
#if defined (_RWSTD_NO_STRTOLD) && defined (_RWSTD_NO_STRTOLD_IN_LIBC)
|
|
|
|
// detect invalid formats in case strtold() is not
|
|
// available (scanf() will not detect these)
|
|
|
|
if ( 'e' == __pcur [-1]
|
|
|| '-' == __pcur [-1] || '+' == __pcur [-1]) {
|
|
__err |= _RW::__rw_failbit;
|
|
return __begin;
|
|
}
|
|
|
|
#endif // _RWSTD_NO_STRTOLD && _RWSTD_NO_STRTOLD_IN_LIBC
|
|
|
|
}
|
|
else
|
|
__grpend = __pcur;
|
|
|
|
__len = __grpbeg ?
|
|
__grpend - __grpbeg : __grpend - __pbuf - 1 - (_HexX != __hex_x);
|
|
|
|
if (__grpbeg && 0 == __len) {
|
|
// fatal error: according to the grammar in [locale.numpunct]
|
|
// thousands_sep characters must be separated by groups of one
|
|
// or more digits (i.e., valid input cannot start or end with
|
|
// a thousands_sep); this needs to be clarified in the text
|
|
__err |= _RW::__rw_failbit;
|
|
return __begin;
|
|
}
|
|
|
|
*__pgrp++ = char (__len < _UChar (_RWSTD_UCHAR_MAX) ? __len : -1);
|
|
}
|
|
|
|
*__pgrp = '\0';
|
|
*__pcur = '\0';
|
|
|
|
// verify that the buffers haven't overflowed
|
|
_RWSTD_ASSERT (__pgrp < __grpbuf + sizeof __grpbuf);
|
|
_RWSTD_ASSERT (__pcur < __pbuf + __bufsize);
|
|
|
|
// set the base determined above
|
|
const unsigned __fl2 =
|
|
__fl & ~_RWSTD_IOS_BASEFIELD
|
|
& ~( _RWSTD_STATIC_CAST (unsigned, _RWSTD_IOS_BASEMASK)
|
|
<< _RWSTD_IOS_BASEOFF)
|
|
| __base << _RWSTD_IOS_BASEOFF;
|
|
|
|
// 22.2.2.1.2, p11: Stage 3
|
|
const int __errtmp =
|
|
_RW::__rw_get_num (__pval, __pbuf, __type, __fl2,
|
|
__grpbuf, __pgrp - __grpbuf,
|
|
__grouping.data (), __grouping.size ());
|
|
|
|
__err |= _RWSTD_IOSTATE (__errtmp);
|
|
|
|
return __begin;
|
|
}
|
|
|
|
|
|
} // namespace std
|