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 38 template <class _CharT, class _InputIterator> 39 locale::id time_get<_CharT, _InputIterator>::id; 40 41 template <class _CharT, class _OutputIterator> 42 locale::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 76 template <class _InIt, class _NameIt> 77 size_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. 147 template <class _InIt1, class _Ch, class _TimeInfo> 148 string::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 typedef basic_string<_Ch, char_traits<_Ch>, allocator<_Ch> > string_type; 155 size_t offset; 156 157 while (__first != __last && __format != __format_end) { 158 offset = 0; 159 if (*__format == '%') { 160 ++__format; 161 char __c = *__format; 162 if (__c == '#') { //MS extension 163 ++__format; 164 __c = *__format; 165 } 166 167 switch (__c) { 168 case 'A': 169 offset = 7; 170 case 'a': { 171 size_t __index = __match(__first, __last, 172 __table._M_dayname + offset, __table._M_dayname + offset + 7); 173 if (__index == 7) 174 return __format; 175 __t->tm_wday = __STATIC_CAST(int, __index); 176 break; 177 } 178 179 case 'B': 180 offset = 12; 181 case 'b': { 182 size_t __index = __match(__first, __last, 183 __table._M_monthname + offset, __table._M_monthname + offset + 12); 184 if (__index == 12) 185 return __format; 186 __t->tm_mon = __STATIC_CAST(int, __index); 187 break; 188 } 189 190 case 'd': { 191 bool __pr = __get_decimal_integer(__first, __last, __t->tm_mday, __STATIC_CAST(_Ch*, 0)); 192 if (!__pr || __t->tm_mday < 1 || __t->tm_mday > 31) { 193 __err |= ios_base::failbit; 194 return __format; 195 } 196 break; 197 } 198 199 case 'H': case 'I': { 200 bool __pr = __get_decimal_integer(__first, __last, __t->tm_hour, __STATIC_CAST(_Ch*, 0)); 201 if (!__pr) 202 return __format; 203 break; 204 } 205 206 case 'j': { 207 bool __pr = __get_decimal_integer(__first, __last, __t->tm_yday, __STATIC_CAST(_Ch*, 0)); 208 if (!__pr) 209 return __format; 210 break; 211 } 212 213 case 'm': { 214 bool __pr = __get_decimal_integer(__first, __last, __t->tm_mon, __STATIC_CAST(_Ch*, 0)); 215 --__t->tm_mon; 216 if (!__pr || __t->tm_mon < 0 || __t->tm_mon > 11) { 217 __err |= ios_base::failbit; 218 return __format; 219 } 220 break; 221 } 222 223 case 'M': { 224 bool __pr = __get_decimal_integer(__first, __last, __t->tm_min, __STATIC_CAST(_Ch*, 0)); 225 if (!__pr) 226 return __format; 227 break; 228 } 229 230 case 'p': { 231 size_t __index = __match(__first, __last, 232 __table._M_am_pm + 0, __table._M_am_pm + 2); 233 if (__index == 2) 234 return __format; 235 // 12:00 PM <=> 12:00, 12:00 AM <=> 00:00 236 if (__index == 1 && __t->tm_hour != 12 ) 237 __t->tm_hour += 12; 238 if (__index == 0 && __t->tm_hour == 12 ) 239 __t->tm_hour = 0; 240 break; 241 } 242 243 case 'S': { 244 bool __pr = __get_decimal_integer(__first, __last, __t->tm_sec, __STATIC_CAST(_Ch*, 0)); 245 if (!__pr) 246 return __format; 247 break; 248 } 249 250 case 'y': { 251 bool __pr = __get_decimal_integer(__first, __last, __t->tm_year, __STATIC_CAST(_Ch*, 0)); 252 if (!__pr) 253 return __format; 254 break; 255 } 256 257 case 'Y': { 258 bool __pr = __get_decimal_integer(__first, __last, __t->tm_year, __STATIC_CAST(_Ch*, 0)); 259 __t->tm_year -= 1900; 260 if (!__pr) 261 return __format; 262 break; 263 } 264 265 default: 266 break; 267 } 268 } 269 else { 270 if (*__first++ != __ct.widen(*__format)) break; 271 } 272 273 ++__format; 274 } 275 276 return __format; 277 } 278 279 template <class _InIt, class _TimeInfo> 280 bool _STLP_CALL 281 __get_short_or_long_dayname(_InIt& __first, _InIt& __last, const _TimeInfo& __table, tm* __t) { 282 size_t __index = __match(__first, __last, __table._M_dayname + 0, __table._M_dayname + 14); 283 if (__index != 14) { 284 __t->tm_wday = __STATIC_CAST(int, __index % 7); 285 return true; 286 } 287 return false; 288 } 289 290 template <class _InIt, class _TimeInfo> 291 bool _STLP_CALL 292 __get_short_or_long_monthname(_InIt& __first, _InIt& __last, const _TimeInfo& __table, tm* __t) { 293 size_t __index = __match(__first, __last, __table._M_monthname + 0, __table._M_monthname + 24); 294 if (__index != 24) { 295 __t->tm_mon = __STATIC_CAST(int, __index % 12); 296 return true; 297 } 298 return false; 299 } 300 301 _STLP_MOVE_TO_STD_NAMESPACE 302 303 template <class _Ch, class _InIt> 304 _InIt 305 time_get<_Ch, _InIt>::do_get_date(_InIt __s, _InIt __end, 306 ios_base& __str, ios_base::iostate& __err, 307 tm* __t) const { 308 typedef string::const_iterator string_iterator; 309 310 string_iterator __format = this->_M_timeinfo._M_date_format.begin(); 311 string_iterator __format_end = this->_M_timeinfo._M_date_format.end(); 312 313 string_iterator __result 314 = _STLP_PRIV __get_formatted_time(__s, __end, __format, __format_end, 315 __STATIC_CAST(_Ch*, 0), this->_M_timeinfo, 316 __str, __err, __t); 317 if (__result == __format_end) 318 __err = ios_base::goodbit; 319 else { 320 __err = ios_base::failbit; 321 if (__s == __end) 322 __err |= ios_base::eofbit; 323 } 324 return __s; 325 } 326 327 template <class _Ch, class _InIt> 328 _InIt 329 time_get<_Ch, _InIt>::do_get_time(_InIt __s, _InIt __end, 330 ios_base& __str, ios_base::iostate& __err, 331 tm* __t) const { 332 typedef string::const_iterator string_iterator; 333 string_iterator __format = this->_M_timeinfo._M_time_format.begin(); 334 string_iterator __format_end = this->_M_timeinfo._M_time_format.end(); 335 336 string_iterator __result 337 = _STLP_PRIV __get_formatted_time(__s, __end, __format, __format_end, 338 __STATIC_CAST(_Ch*, 0), this->_M_timeinfo, 339 __str, __err, __t); 340 __err = __result == __format_end ? ios_base::goodbit 341 : ios_base::failbit; 342 if (__s == __end) 343 __err |= ios_base::eofbit; 344 return __s; 345 } 346 347 template <class _Ch, class _InIt> 348 _InIt 349 time_get<_Ch, _InIt>::do_get_year(_InIt __s, _InIt __end, 350 ios_base&, ios_base::iostate& __err, 351 tm* __t) const { 352 if (__s == __end) { 353 __err = ios_base::failbit | ios_base::eofbit; 354 return __s; 355 } 356 357 bool __pr = _STLP_PRIV __get_decimal_integer(__s, __end, __t->tm_year, __STATIC_CAST(_Ch*, 0)); 358 __t->tm_year -= 1900; 359 __err = __pr ? ios_base::goodbit : ios_base::failbit; 360 if (__s == __end) 361 __err |= ios_base::eofbit; 362 363 return __s; 364 } 365 366 template <class _Ch, class _InIt> 367 _InIt 368 time_get<_Ch, _InIt>::do_get_weekday(_InIt __s, _InIt __end, 369 ios_base &__str, ios_base::iostate &__err, 370 tm *__t) const { 371 bool __result = 372 _STLP_PRIV __get_short_or_long_dayname(__s, __end, this->_M_timeinfo, __t); 373 if (__result) 374 __err = ios_base::goodbit; 375 else { 376 __err = ios_base::failbit; 377 if (__s == __end) 378 __err |= ios_base::eofbit; 379 } 380 return __s; 381 } 382 383 template <class _Ch, class _InIt> 384 _InIt 385 time_get<_Ch, _InIt>::do_get_monthname(_InIt __s, _InIt __end, 386 ios_base &__str, ios_base::iostate &__err, 387 tm *__t) const { 388 bool __result = 389 _STLP_PRIV __get_short_or_long_monthname(__s, __end, this->_M_timeinfo, __t); 390 if (__result) 391 __err = ios_base::goodbit; 392 else { 393 __err = ios_base::failbit; 394 if (__s == __end) 395 __err |= ios_base::eofbit; 396 } 397 return __s; 398 } 399 400 template<class _Ch, class _OutputIter> 401 _OutputIter 402 time_put<_Ch,_OutputIter>::put(_OutputIter __s, ios_base& __f, _Ch __fill, 403 const tm* __tmb, const _Ch* __pat, 404 const _Ch* __pat_end) const { 405 const ctype<_Ch>& _Ct = use_facet<ctype<_Ch> >(__f.getloc()); 406 while (__pat != __pat_end) { 407 char __c = _Ct.narrow(*__pat, 0); 408 if (__c == '%') { 409 char __mod = 0; 410 ++__pat; 411 __c = _Ct.narrow(*__pat++, 0); 412 if (__c == '#') { // MS extension 413 __mod = __c; 414 __c = _Ct.narrow(*__pat++, 0); 415 } 416 __s = do_put(__s, __f, __fill, __tmb, __c, __mod); 417 } 418 else 419 *__s++ = *__pat++; 420 } 421 return __s; 422 } 423 424 template<class _Ch, class _OutputIter> 425 _OutputIter 426 time_put<_Ch,_OutputIter>::do_put(_OutputIter __s, ios_base& __f, _Ch /* __fill */, 427 const tm* __tmb, char __format, 428 char __modifier ) const { 429 const ctype<_Ch>& __ct = use_facet<ctype<_Ch> >(__f.getloc()); 430 _STLP_BASIC_IOSTRING(_Ch) __buf; 431 _STLP_PRIV __write_formatted_time(__buf, __ct, __format, __modifier, this->_M_timeinfo, __tmb); 432 return copy(__buf.begin(), __buf.end(), __s); 433 } 434 435 _STLP_END_NAMESPACE 436 437 #endif /* _STLP_TIME_FACETS_C */ 438 439 // Local Variables: 440 // mode:C++ 441 // End: 442