1/* 2 * Copyright (c) 1999 3 * Silicon Graphics Computer Systems, Inc. 4 * 5 * Copyright (c) 1999 6 * Boris Fomitchev 7 * 8 * This material is provided "as is", with absolutely no warranty expressed 9 * or implied. Any use is at your own risk. 10 * 11 * Permission to use or copy this software for any purpose is hereby granted 12 * without fee, provided the above notices are retained on all copies. 13 * Permission to modify the code and to distribute modified code is granted, 14 * provided the above notices are retained, and a notice that the code was 15 * modified is included with the above copyright notice. 16 * 17 */ 18#ifndef _STLP_TIME_FACETS_C 19#define _STLP_TIME_FACETS_C 20 21#ifndef _STLP_INTERNAL_TIME_FACETS_H 22# include <stl/_time_facets.h> 23#endif 24 25#ifndef _STLP_INTERNAL_NUM_PUT_H 26# include <stl/_num_put.h> 27#endif 28 29#ifndef _STLP_INTERNAL_NUM_GET_H 30# include <stl/_num_get.h> 31#endif 32 33_STLP_BEGIN_NAMESPACE 34 35//---------------------------------------------------------------------- 36// Declarations of static template members. 37 38template <class _CharT, class _InputIterator> 39locale::id time_get<_CharT, _InputIterator>::id; 40 41template <class _CharT, class _OutputIterator> 42locale::id time_put<_CharT, _OutputIterator>::id; 43 44_STLP_MOVE_TO_PRIV_NAMESPACE 45 46/* Matching input against a list of names 47 48 * Alphabetic input of the names of months and the names 49 * of weekdays requires matching input against a list of names. 50 * We use a simple generic algorithm to accomplish this. This 51 * algorithm is not very efficient, especially for longer lists 52 * of names, but it probably does not matter for the initial 53 * implementation and it may never matter, since we do not expect 54 * this kind of input to be used very often. The algorithm 55 * could be improved fairly simply by creating a new list of 56 * names still in the running at each iteration. A more sophisticated 57 * approach would be to build a tree to do the matching. 58 * 59 * We compare each character of the input to the corresponding 60 * character of each name on the list that has not been eliminated, 61 * either because every character in the name has already been 62 * matched, or because some character has not been matched. We 63 * continue only as long as there are some names that have not been 64 * eliminated. 65 66 * We do not really need a random access iterator (a forward iterator 67 * would do), but the extra generality makes the notation clumsier, 68 * and we don't really need it. 69 70 * We can recognize a failed match by the fact that the return value 71 * will be __name_end. 72 */ 73 74#define _MAXNAMES 24 75 76template <class _InIt, class _NameIt> 77size_t _STLP_CALL 78__match(_InIt& __first, _InIt& __last, _NameIt __name, _NameIt __name_end) { 79 typedef ptrdiff_t difference_type; 80 difference_type __n = __name_end - __name; 81 difference_type __i, __start = 0; 82 size_t __pos = 0; 83 difference_type __check_count = __n; 84 bool __do_not_check[_MAXNAMES]; 85 size_t __matching_name_index = __n; 86 87 memset(__do_not_check, 0, sizeof(__do_not_check)); 88 89 while (__first != __last) { 90 difference_type __new_n = __n; 91 for (__i = __start; __i < __n; ++__i) { 92 if (!__do_not_check[__i]) { 93 if (*__first == __name[__i][__pos]) { 94 if (__pos == (__name[__i].size() - 1)) { 95 __matching_name_index = __i; 96 __do_not_check[__i] = true; 97 if (__i == __start) ++__start; 98 --__check_count; 99 if (__check_count == 0) { 100 ++__first; 101 return __matching_name_index; 102 } 103 } 104 __new_n = __i + 1; 105 } 106 else { 107 __do_not_check[__i] = true; 108 if (__i == __start) ++__start; 109 --__check_count; 110 if (__check_count == 0) 111 return __matching_name_index; 112 } 113 } 114 else { 115 if (__i == __start) ++ __start; 116 } 117 } 118 119 __n = __new_n; 120 ++__first; ++__pos; 121 } 122 123 return __matching_name_index; 124} 125 126// __get_formatted_time reads input that is assumed to be formatted 127// according to the rules for the C strftime function (C standard, 128// 7.12.3.5). This function is used to implement the do_get_time 129// and do_get_date virtual functions, which depend on the locale 130// specifications for the time and day formats respectively. 131// Note the catchall default case, intended mainly for the '%Z' 132// format designator, which does not make sense here since the 133// representation of timezones is not part of the locale. 134// 135// The case branches are implemented either by doing a match using 136// the appopriate name table or by doing a __get_integer_nogroup. 137// 138// 'y' format is assumed to mean that the input represents years 139// since 1900. That is, 2002 should be represented as 102. There 140// is no century-guessing. 141// 142// The match is successful if and only if the second component of the 143// return value is format_end. 144 145// Note that the antepenultimate parameter is being used only to determine 146// the correct overloading for the calls to __get_integer_nogroup. 147template <class _InIt1, class _Ch, class _TimeInfo> 148string::const_iterator _STLP_CALL 149__get_formatted_time _STLP_WEAK (_InIt1 __first, _InIt1 __last, 150 string::const_iterator __format, string::const_iterator __format_end, 151 _Ch*, const _TimeInfo& __table, 152 const ios_base& __s, ios_base::iostate& __err, tm* __t) { 153 const ctype<_Ch>& __ct = use_facet<ctype<_Ch> >(__s.getloc()); 154 size_t offset; 155 156 while (__first != __last && __format != __format_end) { 157 offset = 0; 158 if (*__format == '%') { 159 ++__format; 160 char __c = *__format; 161 if (__c == '#') { //MS extension 162 ++__format; 163 __c = *__format; 164 } 165 166 switch (__c) { 167 case 'A': 168 offset = 7; 169 case 'a': { 170 size_t __index = __match(__first, __last, 171 __table._M_dayname + offset, __table._M_dayname + offset + 7); 172 if (__index == 7) 173 return __format; 174 __t->tm_wday = __STATIC_CAST(int, __index); 175 break; 176 } 177 178 case 'B': 179 offset = 12; 180 case 'b': { 181 size_t __index = __match(__first, __last, 182 __table._M_monthname + offset, __table._M_monthname + offset + 12); 183 if (__index == 12) 184 return __format; 185 __t->tm_mon = __STATIC_CAST(int, __index); 186 break; 187 } 188 189 case 'd': { 190 bool __pr = __get_decimal_integer(__first, __last, __t->tm_mday, __STATIC_CAST(_Ch*, 0)); 191 if (!__pr || __t->tm_mday < 1 || __t->tm_mday > 31) { 192 __err |= ios_base::failbit; 193 return __format; 194 } 195 break; 196 } 197 198 case 'H': case 'I': { 199 bool __pr = __get_decimal_integer(__first, __last, __t->tm_hour, __STATIC_CAST(_Ch*, 0)); 200 if (!__pr) 201 return __format; 202 break; 203 } 204 205 case 'j': { 206 bool __pr = __get_decimal_integer(__first, __last, __t->tm_yday, __STATIC_CAST(_Ch*, 0)); 207 if (!__pr) 208 return __format; 209 break; 210 } 211 212 case 'm': { 213 bool __pr = __get_decimal_integer(__first, __last, __t->tm_mon, __STATIC_CAST(_Ch*, 0)); 214 --__t->tm_mon; 215 if (!__pr || __t->tm_mon < 0 || __t->tm_mon > 11) { 216 __err |= ios_base::failbit; 217 return __format; 218 } 219 break; 220 } 221 222 case 'M': { 223 bool __pr = __get_decimal_integer(__first, __last, __t->tm_min, __STATIC_CAST(_Ch*, 0)); 224 if (!__pr) 225 return __format; 226 break; 227 } 228 229 case 'p': { 230 size_t __index = __match(__first, __last, 231 __table._M_am_pm + 0, __table._M_am_pm + 2); 232 if (__index == 2) 233 return __format; 234 // 12:00 PM <=> 12:00, 12:00 AM <=> 00:00 235 if (__index == 1 && __t->tm_hour != 12 ) 236 __t->tm_hour += 12; 237 if (__index == 0 && __t->tm_hour == 12 ) 238 __t->tm_hour = 0; 239 break; 240 } 241 242 case 'S': { 243 bool __pr = __get_decimal_integer(__first, __last, __t->tm_sec, __STATIC_CAST(_Ch*, 0)); 244 if (!__pr) 245 return __format; 246 break; 247 } 248 249 case 'y': { 250 bool __pr = __get_decimal_integer(__first, __last, __t->tm_year, __STATIC_CAST(_Ch*, 0)); 251 if (!__pr) 252 return __format; 253 break; 254 } 255 256 case 'Y': { 257 bool __pr = __get_decimal_integer(__first, __last, __t->tm_year, __STATIC_CAST(_Ch*, 0)); 258 __t->tm_year -= 1900; 259 if (!__pr) 260 return __format; 261 break; 262 } 263 264 default: 265 break; 266 } 267 } 268 else { 269 if (*__first++ != __ct.widen(*__format)) break; 270 } 271 272 ++__format; 273 } 274 275 return __format; 276} 277 278template <class _InIt, class _TimeInfo> 279bool _STLP_CALL 280__get_short_or_long_dayname(_InIt& __first, _InIt& __last, const _TimeInfo& __table, tm* __t) { 281 size_t __index = __match(__first, __last, __table._M_dayname + 0, __table._M_dayname + 14); 282 if (__index != 14) { 283 __t->tm_wday = __STATIC_CAST(int, __index % 7); 284 return true; 285 } 286 return false; 287} 288 289template <class _InIt, class _TimeInfo> 290bool _STLP_CALL 291__get_short_or_long_monthname(_InIt& __first, _InIt& __last, const _TimeInfo& __table, tm* __t) { 292 size_t __index = __match(__first, __last, __table._M_monthname + 0, __table._M_monthname + 24); 293 if (__index != 24) { 294 __t->tm_mon = __STATIC_CAST(int, __index % 12); 295 return true; 296 } 297 return false; 298} 299 300_STLP_MOVE_TO_STD_NAMESPACE 301 302template <class _Ch, class _InIt> 303_InIt 304time_get<_Ch, _InIt>::do_get_date(_InIt __s, _InIt __end, 305 ios_base& __str, ios_base::iostate& __err, 306 tm* __t) const { 307 typedef string::const_iterator string_iterator; 308 309 string_iterator __format = this->_M_timeinfo._M_date_format.begin(); 310 string_iterator __format_end = this->_M_timeinfo._M_date_format.end(); 311 312 string_iterator __result 313 = _STLP_PRIV __get_formatted_time(__s, __end, __format, __format_end, 314 __STATIC_CAST(_Ch*, 0), this->_M_timeinfo, 315 __str, __err, __t); 316 if (__result == __format_end) 317 __err = ios_base::goodbit; 318 else { 319 __err = ios_base::failbit; 320 if (__s == __end) 321 __err |= ios_base::eofbit; 322 } 323 return __s; 324} 325 326template <class _Ch, class _InIt> 327_InIt 328time_get<_Ch, _InIt>::do_get_time(_InIt __s, _InIt __end, 329 ios_base& __str, ios_base::iostate& __err, 330 tm* __t) const { 331 typedef string::const_iterator string_iterator; 332 string_iterator __format = this->_M_timeinfo._M_time_format.begin(); 333 string_iterator __format_end = this->_M_timeinfo._M_time_format.end(); 334 335 string_iterator __result 336 = _STLP_PRIV __get_formatted_time(__s, __end, __format, __format_end, 337 __STATIC_CAST(_Ch*, 0), this->_M_timeinfo, 338 __str, __err, __t); 339 __err = __result == __format_end ? ios_base::goodbit 340 : ios_base::failbit; 341 if (__s == __end) 342 __err |= ios_base::eofbit; 343 return __s; 344} 345 346template <class _Ch, class _InIt> 347_InIt 348time_get<_Ch, _InIt>::do_get_year(_InIt __s, _InIt __end, 349 ios_base&, ios_base::iostate& __err, 350 tm* __t) const { 351 if (__s == __end) { 352 __err = ios_base::failbit | ios_base::eofbit; 353 return __s; 354 } 355 356 bool __pr = _STLP_PRIV __get_decimal_integer(__s, __end, __t->tm_year, __STATIC_CAST(_Ch*, 0)); 357 __t->tm_year -= 1900; 358 __err = __pr ? ios_base::goodbit : ios_base::failbit; 359 if (__s == __end) 360 __err |= ios_base::eofbit; 361 362 return __s; 363} 364 365template <class _Ch, class _InIt> 366_InIt 367time_get<_Ch, _InIt>::do_get_weekday(_InIt __s, _InIt __end, 368 ios_base &__str, ios_base::iostate &__err, 369 tm *__t) const { 370 bool __result = 371 _STLP_PRIV __get_short_or_long_dayname(__s, __end, this->_M_timeinfo, __t); 372 if (__result) 373 __err = ios_base::goodbit; 374 else { 375 __err = ios_base::failbit; 376 if (__s == __end) 377 __err |= ios_base::eofbit; 378 } 379 return __s; 380} 381 382template <class _Ch, class _InIt> 383_InIt 384time_get<_Ch, _InIt>::do_get_monthname(_InIt __s, _InIt __end, 385 ios_base &__str, ios_base::iostate &__err, 386 tm *__t) const { 387 bool __result = 388 _STLP_PRIV __get_short_or_long_monthname(__s, __end, this->_M_timeinfo, __t); 389 if (__result) 390 __err = ios_base::goodbit; 391 else { 392 __err = ios_base::failbit; 393 if (__s == __end) 394 __err |= ios_base::eofbit; 395 } 396 return __s; 397} 398 399template<class _Ch, class _OutputIter> 400_OutputIter 401time_put<_Ch,_OutputIter>::put(_OutputIter __s, ios_base& __f, _Ch __fill, 402 const tm* __tmb, const _Ch* __pat, 403 const _Ch* __pat_end) const { 404 const ctype<_Ch>& _Ct = use_facet<ctype<_Ch> >(__f.getloc()); 405 while (__pat != __pat_end) { 406 char __c = _Ct.narrow(*__pat, 0); 407 if (__c == '%') { 408 char __mod = 0; 409 ++__pat; 410 __c = _Ct.narrow(*__pat++, 0); 411 if (__c == '#') { // MS extension 412 __mod = __c; 413 __c = _Ct.narrow(*__pat++, 0); 414 } 415 __s = do_put(__s, __f, __fill, __tmb, __c, __mod); 416 } 417 else 418 *__s++ = *__pat++; 419 } 420 return __s; 421} 422 423template<class _Ch, class _OutputIter> 424_OutputIter 425time_put<_Ch,_OutputIter>::do_put(_OutputIter __s, ios_base& __f, _Ch /* __fill */, 426 const tm* __tmb, char __format, 427 char __modifier ) const { 428 const ctype<_Ch>& __ct = use_facet<ctype<_Ch> >(__f.getloc()); 429 _STLP_BASIC_IOSTRING(_Ch) __buf; 430 _STLP_PRIV __write_formatted_time(__buf, __ct, __format, __modifier, this->_M_timeinfo, __tmb); 431 return copy(__buf.begin(), __buf.end(), __s); 432} 433 434_STLP_END_NAMESPACE 435 436#endif /* _STLP_TIME_FACETS_C */ 437 438// Local Variables: 439// mode:C++ 440// End: 441