360 lines
11 KiB
C++
360 lines
11 KiB
C++
/***************************************************************************
|
|
*
|
|
* _time_get.cc - definition of std::time_get members
|
|
*
|
|
* $Id: _time_get.cc 597438 2007-11-22 15:44:53Z 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 1994-2006 Rogue Wave Software.
|
|
*
|
|
**************************************************************************/
|
|
|
|
|
|
#include <streambuf>
|
|
#include <loc/_ctype.h>
|
|
#include <loc/_punct.h>
|
|
#include <loc/_locale.h>
|
|
|
|
|
|
_RWSTD_NAMESPACE (__rw) {
|
|
|
|
_RWSTD_EXPORT _RWSTD_SIZE_T
|
|
__rw_get_timepunct (const __rw_facet *pfacet,
|
|
int data [4], _RWSTD_C::tm *tmb, int **pmem,
|
|
const void *names[], _RWSTD_SIZE_T sizes[]);
|
|
|
|
} // namespace __rw
|
|
|
|
|
|
_RWSTD_NAMESPACE (std) {
|
|
|
|
|
|
template <class _CharT, class _InputIter>
|
|
_RW::__rw_facet_id time_get<_CharT, _InputIter>::id;
|
|
|
|
|
|
template <class _CharT, class _InputIter>
|
|
_TYPENAME time_get<_CharT, _InputIter>::iter_type
|
|
time_get<_CharT, _InputIter>::
|
|
get (iter_type __it, iter_type __end, ios_base &__fl, _RWSTD_IOSTATE &__err,
|
|
tm *__tmb, const char_type *__pat, const char_type *__pat_end) const
|
|
{
|
|
_RWSTD_ASSERT (0 != __pat);
|
|
_RWSTD_ASSERT (__pat <= __pat_end);
|
|
|
|
const ctype<char_type> &__ctp =
|
|
_RWSTD_USE_FACET (ctype<char_type>, __fl.getloc ());
|
|
|
|
// extension: `tmb' may be 0
|
|
tm __tmp = __tmb ? *__tmb : tm ();
|
|
|
|
_RWSTD_IOSTATE __errtmp = _RW::__rw_goodbit;
|
|
|
|
char __fmt [] = { '\0', '\0' };
|
|
|
|
for (; __pat != __pat_end; ++__pat) {
|
|
|
|
if (__errtmp) {
|
|
// failed to match the whole pattern
|
|
__errtmp |= _RW::__rw_failbit;
|
|
break;
|
|
}
|
|
|
|
const char __ch = __ctp.narrow (*__pat, '\0');
|
|
|
|
if (__fmt [0]) {
|
|
if ('E' == __ch || 'O' == __ch)
|
|
__fmt [1] = __ch;
|
|
else if ('.' == __ch || __ch >= '0' && __ch <= '9') {
|
|
// FIXME: handle the "%.[0-9]*" HP-UX extension
|
|
}
|
|
else {
|
|
__it = do_get (__it, __end, __fl, __errtmp, &__tmp, __ch,
|
|
__fmt [1]);
|
|
__fmt [0] = __fmt [1] = '\0'; // reset
|
|
}
|
|
}
|
|
else if ('%' == __ch) {
|
|
__fmt [0] = __ch;
|
|
}
|
|
else if (__ctp.is (ctype_base::space, *__pat)) {
|
|
// skip all whitespace characters
|
|
while (__it != __end && __ctp.is (ctype_base::space, *__it))
|
|
++__it;
|
|
}
|
|
else {
|
|
if (__it != __end && __ch == __ctp.narrow (*__it, '\0'))
|
|
++__it;
|
|
else {
|
|
// mismatch between pattern and input
|
|
__errtmp |= _RW::__rw_failbit;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// store value only on success
|
|
if (!(__errtmp & ~_RW::__rw_eofbit) && __tmb)
|
|
*__tmb = __tmp;
|
|
|
|
__err |= __errtmp;
|
|
|
|
return __it;
|
|
}
|
|
|
|
|
|
template <class _CharT, class _InputIter>
|
|
/* virtual */ _TYPENAME time_get<_CharT, _InputIter>::iter_type
|
|
time_get<_CharT, _InputIter>::
|
|
do_get (iter_type __it, iter_type __end, ios_base &__fl,
|
|
_RWSTD_IOSTATE &__err, tm *__tmb,
|
|
char __fmt, char __modifier /* = '\0' */) const
|
|
{
|
|
// enough pointers for 100 alternative numeric symbols and their sizes
|
|
const char_type* __names [100];
|
|
_RWSTD_SIZE_T __sizes [sizeof __names / sizeof *__names];
|
|
|
|
const void** __pv =
|
|
_RWSTD_REINTERPRET_CAST (const void**, __names);
|
|
|
|
tm __tmp = __tmb ? *__tmb : tm ();
|
|
|
|
int *__pmem = 0; // pointer to std::tm member
|
|
|
|
_RWSTD_SIZE_T __dup; // number of allowed duplicates
|
|
|
|
const ctype<char_type> &__ctp =
|
|
_RWSTD_USE_FACET (ctype<char_type>, __fl.getloc ());
|
|
|
|
switch (__fmt) {
|
|
|
|
case 'A': case 'a': case 'B': case 'b': case 'h':
|
|
// names of days and months can have duplicates (i.e.,
|
|
// it can be either a full name aor an abbreviation)
|
|
__dup = 2;
|
|
break;
|
|
|
|
case 'n': case 't': { // any whitespace
|
|
|
|
for ( ; ; ++__it) {
|
|
|
|
if (__it == __end) {
|
|
__err |= _RW::__rw_eofbit;
|
|
break;
|
|
}
|
|
|
|
if (!__ctp.is (ctype_base::space, *__it))
|
|
break;
|
|
}
|
|
|
|
return __it;
|
|
}
|
|
|
|
default: __dup = 1;
|
|
}
|
|
|
|
int __data [4] = {
|
|
// array of input data for __rw_get_timepunct will on output
|
|
// contain data needed to interpret values parsed below
|
|
__fmt, __modifier, sizeof (char_type) > sizeof (char), 0
|
|
};
|
|
|
|
// get the number of punctuator (or format) string(s) and their values
|
|
const _RWSTD_SIZE_T __cnt =
|
|
_RW::__rw_get_timepunct (this, __data, &__tmp,
|
|
&__pmem, __pv, __sizes);
|
|
|
|
if (1 == __cnt) {
|
|
_RWSTD_ASSERT (0 != __names [0]);
|
|
|
|
// single punctuator string stored in `names [0]'
|
|
// e.g., "%m/%d/%y" for the format of "%D" (`fmt' == 'D')
|
|
return get (__it, __end, __fl, __err, __tmb,
|
|
__names [0], __names [0] + __sizes [0]);
|
|
}
|
|
|
|
_RWSTD_IOSTATE __errtmp = _RW::__rw_goodbit;
|
|
|
|
if (__cnt > 1) {
|
|
|
|
// parse string on input
|
|
|
|
// set `inx' to 0 to allow numeric input, SIZE_MAX otherwise
|
|
_RWSTD_SIZE_T __inx = 'O' == __modifier ? 0 : _RWSTD_SIZE_MAX;
|
|
|
|
// on function input, `interr' contains the maximum number
|
|
// of duplicates; on output, it contains an iostate value
|
|
// and `inx' contains the index of the parsed name within
|
|
// the `names' array
|
|
int __interr = int (__dup);
|
|
|
|
__it = _RW::__rw_match_name (__it, __end, __names, __sizes,
|
|
__cnt, __inx, __interr, &__fl);
|
|
|
|
__errtmp = _RWSTD_IOSTATE (__interr);
|
|
|
|
if (__inx == _RWSTD_SIZE_MAX) {
|
|
|
|
// if no name matches, and the first name is the empty
|
|
// (i.e., alt_digits 0 is not defined), try to match
|
|
// and extract all zeros
|
|
if ( !__errtmp && 0 == __sizes [0]
|
|
&& __it != __end && '0' == __ctp.narrow (*__it, '\0')) {
|
|
|
|
while ('0' == __ctp.narrow (*__it, '\0')) {
|
|
|
|
if (++__it == __end) {
|
|
__errtmp |= _RW::__rw_eofbit;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
}
|
|
else if ('p' == __fmt) {
|
|
if (__pmem) {
|
|
if (!__inx && 11 == *__pmem)
|
|
*__pmem = 0;
|
|
else if (*__pmem < 12) {
|
|
if (!__inx || 11 != *__pmem)
|
|
*__pmem += int (__inx * 12) + 1;
|
|
else
|
|
*__pmem += 1;
|
|
}
|
|
else {
|
|
// invalid data
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
}
|
|
else {
|
|
// invalid (or unimplemented) format
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
}
|
|
else if (__pmem) {
|
|
_RWSTD_ASSERT (0 != __pmem);
|
|
|
|
if (__inx == __cnt && !__sizes [0] || __inx >= 2 * __cnt)
|
|
*__pmem = int (__inx - __cnt);
|
|
else if (__inx < __cnt)
|
|
*__pmem = int (__inx % (__cnt / __dup));
|
|
else
|
|
__errtmp |= _RW::__rw_failbit;
|
|
|
|
const int __adj = __data [0]; // value to increment result by
|
|
const int __fac = __data [1]; // value to multiply result by
|
|
|
|
*__pmem = *__pmem * __fac + __adj;
|
|
|
|
const int __lob = __data [2]; // lower bound on valid input
|
|
const int __hib = __data [3]; // upper bound on valid input
|
|
|
|
// validate input value
|
|
if (*__pmem < __lob || *__pmem > __hib)
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
else {
|
|
// invalid (or unimplemented) format
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
}
|
|
else if (__pmem) {
|
|
|
|
// parse numeric input
|
|
|
|
_RWSTD_SIZE_T __nread = 0;
|
|
|
|
int __mem = 0;
|
|
|
|
for ( ; ; ++__it, ++__nread) {
|
|
if (__it == __end) {
|
|
__err |= _RW::__rw_eofbit;
|
|
break;
|
|
}
|
|
|
|
const char_type __c = *__it;
|
|
if (!__ctp.is (ctype_base::digit, __c))
|
|
break;
|
|
|
|
const char __ch = __ctp.narrow (__c, '\0');
|
|
if (__ch < '0' || __ch > '9')
|
|
break;
|
|
|
|
__mem = 10 * __mem + __ch - '0';
|
|
}
|
|
|
|
if (__nread) {
|
|
|
|
const int __adj = __data [0]; // value to increment result by
|
|
const int __fac = __data [1]; // value to multiply result by
|
|
|
|
int __lob = __data [2]; // lower bound on valid input
|
|
int __hib = __data [3]; // upper bound on valid input
|
|
|
|
if ('y' == __fmt) {
|
|
|
|
// IEEE Std 1003.1-2001: When a century is not otherwise
|
|
// specified, values in the range [69,99] shall refer to
|
|
// years 1969 to 1999 inclusive, and values in the range
|
|
// [00,68] shall refer to years 2000 to 2068 inclusive.
|
|
|
|
if (__mem > 99) {
|
|
__lob = -1900;
|
|
__hib = _RWSTD_INT_MAX - 1900;
|
|
__mem -= 1900;
|
|
}
|
|
else {
|
|
__lob = 69;
|
|
__hib = 168;
|
|
|
|
if (__mem < 69)
|
|
__mem += 100;
|
|
}
|
|
}
|
|
|
|
*__pmem = __mem * __fac + __adj;
|
|
|
|
// validate input value
|
|
if (*__pmem < __lob || *__pmem > __hib)
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
else {
|
|
// invalid data
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
}
|
|
else {
|
|
// invalid (or unimplemented) format
|
|
__errtmp |= _RW::__rw_failbit;
|
|
}
|
|
|
|
if (!(__errtmp & ~_RW::__rw_eofbit) && __tmb)
|
|
*__tmb = __tmp;
|
|
|
|
__err |= __errtmp;
|
|
|
|
return __it;
|
|
}
|
|
|
|
|
|
} // namespace std
|