1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 /* 24 * Glenn Fowler 25 * AT&T Research 26 * 27 * Time_t conversion support 28 * 29 * relative times inspired by Steve Bellovin's netnews getdate(3) 30 */ 31 32 #include <tmx.h> 33 #include <ctype.h> 34 #include <debug.h> 35 36 #define dig1(s,n) ((n)=((*(s)++)-'0')) 37 #define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 38 #define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 39 #define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 40 41 #undef BREAK 42 43 #define BREAK (1<<0) 44 #define CCYYMMDDHHMMSS (1<<1) 45 #define CRON (1<<2) 46 #define DAY (1<<3) 47 #define EXACT (1<<4) 48 #define FINAL (1<<5) 49 #define HOLD (1<<6) 50 #define HOUR (1<<7) 51 #define LAST (1<<8) 52 #define MDAY (1<<9) 53 #define MINUTE (1<<10) 54 #define MONTH (1<<11) 55 #define NEXT (1<<12) 56 #define NSEC (1<<13) 57 #define ORDINAL (1<<14) 58 #define SECOND (1<<15) 59 #define THIS (1L<<16) 60 #define WDAY (1L<<17) 61 #define WORK (1L<<18) 62 #define YEAR (1L<<19) 63 #define ZONE (1L<<20) 64 65 #define FFMT "%s%s%s%s%s%s%s|" 66 #define FLAGS(f) (f&EXACT)?"|EXACT":"",(f&LAST)?"|LAST":"",(f&THIS)?"|THIS":"",(f&NEXT)?"|NEXT":"",(f&ORDINAL)?"|ORDINAL":"",(f&FINAL)?"|FINAL":"",(f&WORK)?"|WORK":"" 67 /* 68 * parse cron range into set 69 * return: -1:error 0:* 1:some 70 */ 71 72 static int 73 range(register char* s, char** e, char* set, int lo, int hi) 74 { 75 int n; 76 int m; 77 int i; 78 char* t; 79 80 while (isspace(*s) || *s == '_') 81 s++; 82 if (*s == '*') 83 { 84 *e = s + 1; 85 return 0; 86 } 87 memset(set, 0, hi + 1); 88 for (;;) 89 { 90 n = strtol(s, &t, 10); 91 if (s == t || n < lo || n > hi) 92 return -1; 93 i = 1; 94 if (*(s = t) == '-') 95 { 96 m = strtol(++s, &t, 10); 97 if (s == t || m < n || m > hi) 98 return -1; 99 if (*(s = t) == '/') 100 { 101 i = strtol(++s, &t, 10); 102 if (s == t || i < 1) 103 return -1; 104 s = t; 105 } 106 } 107 else 108 m = n; 109 for (; n <= m; n += i) 110 set[n] = 1; 111 if (*s != ',') 112 break; 113 s++; 114 } 115 *e = s; 116 return 1; 117 } 118 119 /* 120 * normalize <p,q> to power of 10 u in tm 121 */ 122 123 static void 124 powerize(Tm_t* tm, unsigned long p, unsigned long q, unsigned long u) 125 { 126 Time_t t = p; 127 128 while (q > u) 129 { 130 q /= 10; 131 t /= 10; 132 } 133 while (q < u) 134 { 135 q *= 10; 136 t *= 10; 137 } 138 tm->tm_nsec += (int)(t % TMX_RESOLUTION); 139 tm->tm_sec += (int)(t / TMX_RESOLUTION); 140 } 141 142 #define K1(c1) (c1) 143 #define K2(c1,c2) (((c1)<<8)|(c2)) 144 #define K3(c1,c2,c3) (((c1)<<16)|((c2)<<8)|(c3)) 145 #define K4(c1,c2,c3,c4) (((c1)<<24)|((c2)<<16)|((c3)<<8)|(c4)) 146 147 #define P_INIT(n) w = n; p = q = 0; u = (char*)s + 1 148 149 /* 150 * parse date expression in s and return Time_t value 151 * 152 * if non-null, e points to the first invalid sequence in s 153 * now provides default values 154 */ 155 156 Time_t 157 tmxdate(register const char* s, char** e, Time_t now) 158 { 159 register Tm_t* tm; 160 register long n; 161 register int w; 162 unsigned long set; 163 unsigned long state; 164 unsigned long flags; 165 Time_t fix; 166 char* t; 167 char* u; 168 const char* o; 169 const char* x; 170 char* last; 171 char* type; 172 int day; 173 int dir; 174 int dst; 175 int zone; 176 int c; 177 int f; 178 int i; 179 int j; 180 int k; 181 int l; 182 long m; 183 unsigned long p; 184 unsigned long q; 185 Tm_zone_t* zp; 186 Tm_t ts; 187 char skip[UCHAR_MAX + 1]; 188 189 /* 190 * check DATEMSK first 191 */ 192 193 debug((error(-1, "AHA tmxdate 2009-03-06"))); 194 fix = tmxscan(s, &last, NiL, &t, now, 0); 195 if (t && !*last) 196 { 197 if (e) 198 *e = last; 199 return fix; 200 } 201 o = s; 202 203 reset: 204 205 /* 206 * use now for defaults 207 */ 208 209 tm = tmxtm(&ts, now, NiL); 210 tm_info.date = tm->tm_zone; 211 day = -1; 212 dir = 0; 213 dst = TM_DST; 214 set = state = 0; 215 type = 0; 216 zone = TM_LOCALZONE; 217 skip[0] = 0; 218 for (n = 1; n <= UCHAR_MAX; n++) 219 skip[n] = isspace(n) || strchr("_,;@=|!^()[]{}", n); 220 221 /* 222 * get <weekday year month day hour minutes seconds ?[ds]t [ap]m> 223 */ 224 225 again: 226 for (;;) 227 { 228 state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS); 229 if ((set|state) & (YEAR|MONTH|DAY)) 230 skip['/'] = 1; 231 message((-1, "AHA#%d state=" FFMT " set=" FFMT, __LINE__, FLAGS(state), FLAGS(set))); 232 for (;;) 233 { 234 if (*s == '.' || *s == '-' || *s == '+') 235 { 236 if (((set|state) & (YEAR|MONTH|HOUR|MINUTE|ZONE)) == (YEAR|MONTH|HOUR|MINUTE) && (i = tmgoff(s, &t, TM_LOCALZONE)) != TM_LOCALZONE) 237 { 238 zone = i; 239 state |= ZONE; 240 if (!*(s = t)) 241 break; 242 } 243 else if (*s == '+') 244 break; 245 } 246 else if (!skip[*s]) 247 break; 248 s++; 249 } 250 if (!*(last = (char*)s)) 251 break; 252 if (*s == '#') 253 { 254 if (isdigit(*++s)) 255 { 256 now = strtoull(s, &t, 0); 257 sns: 258 if (*(s = t) == '.') 259 { 260 fix = 0; 261 m = 1000000000; 262 while (isdigit(*++s)) 263 fix += (*s - '0') * (m /= 10); 264 now = tmxsns(now, fix); 265 } 266 else if (now <= 0x7fffffff) 267 now = tmxsns(now, 0); 268 goto reset; 269 } 270 else if (*s++ == '#') 271 { 272 now = tmxtime(tm, zone); 273 goto reset; 274 } 275 break; 276 } 277 if ((*s == 'P' || *s == 'p') && (!isalpha(*(s + 1)) || (*(s + 1) == 'T' || *(s + 1) == 't') && !isalpha(*(s + 2)))) 278 { 279 Tm_t otm; 280 281 /* 282 * iso duration 283 */ 284 285 otm = *tm; 286 t = (char*)s; 287 m = 0; 288 P_INIT('Y'); 289 do 290 { 291 c = *++s; 292 duration_next: 293 switch (c) 294 { 295 case 0: 296 m++; 297 if ((char*)s > u) 298 { 299 s--; 300 c = '_'; 301 goto duration_next; 302 } 303 break; 304 case 'T': 305 case 't': 306 m++; 307 if ((char*)s > u) 308 { 309 s++; 310 c = 'D'; 311 goto duration_next; 312 } 313 continue; 314 case 'Y': 315 case 'y': 316 m = 0; 317 if (q > 1) 318 tm->tm_sec += (365L*24L*60L*60L) * p / q; 319 else 320 tm->tm_year += p; 321 P_INIT('M'); 322 continue; 323 case 'm': 324 if (!m) 325 m = 1; 326 /*FALLTHROUGH*/ 327 case 'M': 328 switch (*(s + 1)) 329 { 330 case 'I': 331 case 'i': 332 s++; 333 m = 1; 334 w = 'S'; 335 break; 336 case 'O': 337 case 'o': 338 s++; 339 m = 0; 340 w = 'H'; 341 break; 342 case 'S': 343 case 's': 344 s++; 345 m = 2; 346 w = 's'; 347 break; 348 } 349 switch (m) 350 { 351 case 0: 352 m = 1; 353 if (q > 1) 354 tm->tm_sec += (3042L*24L*60L*60L) * p / q / 100L; 355 else 356 tm->tm_mon += p; 357 break; 358 case 1: 359 m = 2; 360 if (q > 1) 361 tm->tm_sec += (60L) * p / q; 362 else 363 tm->tm_min += p; 364 break; 365 default: 366 if (q > 1) 367 powerize(tm, p, q, 1000UL); 368 else 369 tm->tm_nsec += p * 1000000L; 370 break; 371 } 372 P_INIT(w); 373 continue; 374 case 'W': 375 case 'w': 376 m = 0; 377 if (q > 1) 378 tm->tm_sec += (7L*24L*60L*60L) * p / q; 379 else 380 tm->tm_mday += 7 * p; 381 P_INIT('D'); 382 continue; 383 case 'D': 384 case 'd': 385 m = 0; 386 if (q > 1) 387 tm->tm_sec += (24L*60L*60L) * p / q; 388 else 389 tm->tm_mday += p; 390 P_INIT('H'); 391 continue; 392 case 'H': 393 case 'h': 394 m = 1; 395 if (q > 1) 396 tm->tm_sec += (60L*60L) * p / q; 397 else 398 tm->tm_hour += p; 399 P_INIT('m'); 400 continue; 401 case 'S': 402 case 's': 403 m = 2; 404 /*FALLTHROUGH*/ 405 case ' ': 406 case '_': 407 case '\n': 408 case '\r': 409 case '\t': 410 case '\v': 411 if (q > 1) 412 powerize(tm, p, q, 1000000000UL); 413 else 414 tm->tm_sec += p; 415 P_INIT('U'); 416 continue; 417 case 'U': 418 case 'u': 419 switch (*(s + 1)) 420 { 421 case 'S': 422 case 's': 423 s++; 424 break; 425 } 426 m = 0; 427 if (q > 1) 428 powerize(tm, p, q, 1000000UL); 429 else 430 tm->tm_nsec += p * 1000L; 431 P_INIT('N'); 432 continue; 433 case 'N': 434 case 'n': 435 switch (*(s + 1)) 436 { 437 case 'S': 438 case 's': 439 s++; 440 break; 441 } 442 m = 0; 443 if (q > 1) 444 powerize(tm, p, q, 1000000000UL); 445 else 446 tm->tm_nsec += p; 447 P_INIT('Y'); 448 continue; 449 case '.': 450 if (q) 451 goto exact; 452 q = 1; 453 continue; 454 case '-': 455 c = 'M'; 456 u = (char*)s++; 457 while (*++u && *u != ':') 458 if (*u == '-') 459 { 460 c = 'Y'; 461 break; 462 } 463 goto duration_next; 464 case ':': 465 c = 'm'; 466 u = (char*)s++; 467 while (*++u) 468 if (*u == ':') 469 { 470 c = 'H'; 471 break; 472 } 473 goto duration_next; 474 case '0': 475 case '1': 476 case '2': 477 case '3': 478 case '4': 479 case '5': 480 case '6': 481 case '7': 482 case '8': 483 case '9': 484 q *= 10; 485 p = p * 10 + (c - '0'); 486 continue; 487 default: 488 exact: 489 *tm = otm; 490 s = (const char*)t + 1; 491 if (*t == 'p') 492 { 493 state |= HOLD|EXACT; 494 set &= ~(EXACT|LAST|NEXT|THIS); 495 set |= state & (EXACT|LAST|NEXT|THIS); 496 } 497 goto again; 498 } 499 break; 500 } while (c); 501 continue; 502 } 503 f = -1; 504 if (*s == '+') 505 { 506 while (isspace(*++s) || *s == '_'); 507 n = strtol(s, &t, 0); 508 if (w = t - s) 509 { 510 for (s = t; skip[*s]; s++); 511 state |= (f = n) ? NEXT : THIS; 512 set &= ~(EXACT|LAST|NEXT|THIS); 513 set |= state & (EXACT|LAST|NEXT|THIS); 514 } 515 else 516 s = last; 517 } 518 if (!(state & CRON)) 519 { 520 /* 521 * check for cron date 522 * 523 * min hour day-of-month month day-of-week 524 * 525 * if it's cron then determine the next time 526 * that satisfies the specification 527 * 528 * NOTE: the only spacing is ' '||'_'||';' 529 */ 530 531 i = 0; 532 n = *(t = (char*)s); 533 for (;;) 534 { 535 if (n == '*') 536 n = *++s; 537 else if (!isdigit(n)) 538 break; 539 else 540 while ((n = *++s) == ',' || n == '-' || n == '/' || isdigit(n)); 541 if (n != ' ' && n != '_' && n != ';') 542 { 543 if (!n) 544 i++; 545 break; 546 } 547 i++; 548 while ((n = *++s) == ' ' || n == '_'); 549 } 550 if (i == 5) 551 { 552 Time_t tt; 553 char hit[60]; 554 char mon[13]; 555 char day[7]; 556 557 state |= CRON; 558 flags = 0; 559 tm->tm_sec = 0; 560 tm->tm_min++; 561 tmfix(tm); 562 563 /* 564 * minute 565 */ 566 567 if ((k = range(t, &t, hit, 0, 59)) < 0) 568 break; 569 if (k && !hit[i = tm->tm_min]) 570 { 571 hit[i] = 1; 572 do if (++i > 59) 573 { 574 i = 0; 575 if (++tm->tm_hour > 59) 576 { 577 tm->tm_min = i; 578 tmfix(tm); 579 } 580 } while (!hit[i]); 581 tm->tm_min = i; 582 } 583 584 /* 585 * hour 586 */ 587 588 if ((k = range(t, &t, hit, 0, 23)) < 0) 589 break; 590 if (k && !hit[i = tm->tm_hour]) 591 { 592 hit[i] = 1; 593 do if (++i > 23) 594 { 595 i = 0; 596 if (++tm->tm_mday > 28) 597 { 598 tm->tm_hour = i; 599 tmfix(tm); 600 } 601 } while (!hit[i]); 602 tm->tm_hour = i; 603 } 604 605 /* 606 * day of month 607 */ 608 609 if ((k = range(t, &t, hit, 1, 31)) < 0) 610 break; 611 if (k) 612 flags |= DAY|MDAY; 613 614 /* 615 * month 616 */ 617 618 if ((k = range(t, &t, mon, 1, 12)) < 0) 619 break; 620 if (k) 621 flags |= MONTH; 622 else 623 for (i = 1; i <= 12; i++) 624 mon[i] = 1; 625 626 /* 627 * day of week 628 */ 629 630 if ((k = range(t, &t, day, 0, 6)) < 0) 631 break; 632 if (k) 633 flags |= WDAY; 634 s = t; 635 if (flags & (MONTH|MDAY|WDAY)) 636 { 637 fix = tmxtime(tm, zone); 638 tm = tmxtm(tm, fix, tm->tm_zone); 639 i = tm->tm_mon + 1; 640 j = tm->tm_mday; 641 k = tm->tm_wday; 642 for (;;) 643 { 644 if (!mon[i]) 645 { 646 if (++i > 12) 647 { 648 i = 1; 649 tm->tm_year++; 650 } 651 tm->tm_mon = i - 1; 652 tm->tm_mday = 1; 653 tt = tmxtime(tm, zone); 654 if (tt < fix) 655 goto done; 656 tm = tmxtm(tm, tt, tm->tm_zone); 657 i = tm->tm_mon + 1; 658 j = tm->tm_mday; 659 k = tm->tm_wday; 660 continue; 661 } 662 if (flags & (MDAY|WDAY)) 663 { 664 if ((flags & (MDAY|WDAY)) == (MDAY|WDAY)) 665 { 666 if (hit[j] && day[k]) 667 break; 668 } 669 else if ((flags & MDAY) && hit[j]) 670 break; 671 else if ((flags & WDAY) && day[k]) 672 break; 673 if (++j > 28) 674 { 675 tm->tm_mon = i - 1; 676 tm->tm_mday = j; 677 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 678 i = tm->tm_mon + 1; 679 j = tm->tm_mday; 680 k = tm->tm_wday; 681 } 682 else if ((flags & WDAY) && ++k > 6) 683 k = 0; 684 } 685 else if (flags & MONTH) 686 break; 687 } 688 tm->tm_mon = i - 1; 689 tm->tm_mday = j; 690 tm->tm_wday = k; 691 } 692 continue; 693 } 694 s = t; 695 } 696 n = -1; 697 if (isdigit(*s)) 698 { 699 n = strtol(s, &t, 10); 700 if ((w = t - s) && *t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && isdigit(*(t + 3))) 701 { 702 now = n; 703 goto sns; 704 } 705 if ((*t == 'T' || *t == 't') && ((set|state) & (YEAR|MONTH|DAY)) == (YEAR|MONTH) && isdigit(*(t + 1))) 706 t++; 707 u = t + (*t == '-'); 708 message((-1, "AHA#%d n=%d w=%d u='%c' f=%d t=\"%s\"", __LINE__, n, w, *u, f, t)); 709 if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1))) 710 { 711 if (w == 4) 712 { 713 if ((n -= 1900) < TM_WINDOW) 714 break; 715 } 716 else if (n < TM_WINDOW) 717 n += 100; 718 m = n; 719 n = strtol(++u, &t, 10); 720 if ((i = (t - u)) < 2 || i > 3) 721 break; 722 if (i == 3) 723 { 724 k = n % 10; 725 n /= 10; 726 } 727 else if (*t != '-') 728 k = 1; 729 else if (*++t && dig1(t, k) < 1 || k > 7) 730 break; 731 if (n < 0 || n > 53) 732 break; 733 if (k == 7) 734 k = 0; 735 tm->tm_year = m; 736 tmweek(tm, 2, n, k); 737 set |= YEAR|MONTH|DAY; 738 s = t; 739 continue; 740 } 741 else if (w == 6 || w == 8 && (n / 1000000) > 12) 742 { 743 t = (char*)s; 744 flags = 0; 745 if (w == 8 || w == 6 && *u != 'T' && *u != 't') 746 { 747 dig4(t, m); 748 if ((m -= 1900) < TM_WINDOW) 749 break; 750 } 751 else 752 { 753 dig2(t, m); 754 if (m < TM_WINDOW) 755 m += 100; 756 } 757 flags |= YEAR; 758 if (dig2(t, l) <= 0 || l > 12) 759 break; 760 flags |= MONTH; 761 if (*t != 'T' && *t != 't' || !isdigit(*++t)) 762 { 763 if (w == 6) 764 goto save_yymm; 765 if (dig2(t, k) < 1 || k > 31) 766 break; 767 flags |= DAY; 768 goto save_yymmdd; 769 } 770 n = strtol(s = t, &t, 0); 771 if ((t - s) < 2) 772 break; 773 if (dig2(s, j) > 24) 774 break; 775 if ((t - s) < 2) 776 { 777 if ((t - s) == 1 || *t++ != '-') 778 break; 779 n = strtol(s = t, &t, 0); 780 if ((t - s) < 2) 781 break; 782 } 783 if (dig2(s, i) > 59) 784 break; 785 flags |= HOUR|MINUTE; 786 if ((t - s) == 2) 787 { 788 if (dig2(s, n) > (59 + TM_MAXLEAP)) 789 break; 790 flags |= SECOND; 791 } 792 else if (t - s) 793 break; 794 else 795 n = 0; 796 p = 0; 797 if (*t == '.') 798 { 799 q = 1000000000; 800 while (isdigit(*++t)) 801 p += (*t - '0') * (q /= 10); 802 set |= NSEC; 803 } 804 if (n > (59 + TM_MAXLEAP)) 805 break; 806 goto save; 807 } 808 else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0) 809 { 810 message((-1, "AHA#%d n=%d", __LINE__, n)); 811 ordinal: 812 if (n) 813 n--; 814 message((-1, "AHA#%d n=%d", __LINE__, n)); 815 state |= ((f = n) ? NEXT : THIS)|ORDINAL; 816 set &= ~(EXACT|LAST|NEXT|THIS); 817 set |= state & (EXACT|LAST|NEXT|THIS); 818 for (s = t; skip[*s]; s++); 819 if (isdigit(*s)) 820 { 821 if (n = strtol(s, &t, 10)) 822 n--; 823 s = t; 824 if (*s == '_') 825 s++; 826 } 827 else 828 n = -1; 829 dir = f; 830 message((-1, "AHA#%d f=%d n=%d state=" FFMT, __LINE__, f, n, FLAGS(state))); 831 } 832 else 833 { 834 for (u = t; isspace(*u); u++); 835 message((-1, "AHA#%d n=%d u=\"%s\"", __LINE__, n, u)); 836 if ((j = tmlex(u, NiL, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0 && tm_data.lex[j] == TM_PARTS) 837 s = u; 838 else 839 { 840 message((-1, "AHA#%d t=\"%s\"", __LINE__, t)); 841 if (!(state & (LAST|NEXT|THIS)) && ((i = t - s) == 4 && (*t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && *(t + 3) != '.' || (!*t || isspace(*t) || *t == '_' || isalnum(*t)) && n >= 0 && (n % 100) < 60 && ((m = (n / 100)) < 20 || m < 24 && !((set|state) & (YEAR|MONTH|HOUR|MINUTE)))) || i > 4 && i <= 12)) 842 { 843 /* 844 * various { date(1) touch(1) } formats 845 * 846 * [[cc]yy[mm]]ddhhmm[.ss[.nn...]] 847 * [cc]yyjjj 848 * hhmm[.ss[.nn...]] 849 */ 850 851 message((-1, "AHA#%d t=\"%s\"", __LINE__, t)); 852 flags = 0; 853 if (state & CCYYMMDDHHMMSS) 854 break; 855 state |= CCYYMMDDHHMMSS; 856 p = 0; 857 if ((i == 7 || i == 5) && (!*t || *t == 'Z' || *t == 'z')) 858 { 859 if (i == 7) 860 { 861 dig4(s, m); 862 if ((m -= 1900) < TM_WINDOW) 863 break; 864 } 865 else if (dig2(s, m) < TM_WINDOW) 866 m += 100; 867 dig3(s, k); 868 l = 1; 869 j = 0; 870 i = 0; 871 n = 0; 872 flags |= MONTH; 873 } 874 else if (i & 1) 875 break; 876 else 877 { 878 u = t; 879 if (i == 12) 880 { 881 x = s; 882 dig2(x, m); 883 if (m <= 12) 884 { 885 u -= 4; 886 i -= 4; 887 x = s + 8; 888 dig4(x, m); 889 } 890 else 891 dig4(s, m); 892 if (m < 1969 || m >= 3000) 893 break; 894 m -= 1900; 895 } 896 else if (i == 10) 897 { 898 x = s; 899 if (!dig2(x, m) || m > 12 || !dig2(x, m) || m > 31 || dig2(x, m) > 24 || dig2(x, m) > 60 || dig2(x, m) <= 60 && !(tm_info.flags & TM_DATESTYLE)) 900 dig2(s, m); 901 else 902 { 903 u -= 2; 904 i -= 2; 905 x = s + 8; 906 dig2(x, m); 907 } 908 if (m < TM_WINDOW) 909 m += 100; 910 } 911 else 912 m = tm->tm_year; 913 if ((u - s) < 8) 914 l = tm->tm_mon + 1; 915 else if (dig2(s, l) <= 0 || l > 12) 916 break; 917 else 918 flags |= MONTH; 919 if ((u - s) < 6) 920 k = tm->tm_mday; 921 else if (dig2(s, k) < 1 || k > 31) 922 break; 923 else 924 flags |= DAY; 925 if ((u - s) < 4) 926 break; 927 if (dig2(s, j) > 24) 928 break; 929 if (dig2(s, i) > 59) 930 break; 931 flags |= HOUR|MINUTE; 932 if ((u - s) == 2) 933 { 934 dig2(s, n); 935 flags |= SECOND; 936 } 937 else if (u - s) 938 break; 939 else if (*t != '.') 940 n = 0; 941 else 942 { 943 n = strtol(t + 1, &t, 10); 944 flags |= SECOND; 945 if (*t == '.') 946 { 947 q = 1000000000; 948 while (isdigit(*++t)) 949 p += (*t - '0') * (q /= 10); 950 set |= NSEC; 951 } 952 } 953 if (n > (59 + TM_MAXLEAP)) 954 break; 955 } 956 save: 957 tm->tm_hour = j; 958 tm->tm_min = i; 959 tm->tm_sec = n; 960 tm->tm_nsec = p; 961 save_yymmdd: 962 tm->tm_mday = k; 963 save_yymm: 964 tm->tm_mon = l - 1; 965 tm->tm_year = m; 966 s = t; 967 set |= flags; 968 continue; 969 } 970 for (s = t; skip[*s]; s++); 971 message((-1, "AHA#%d s=\"%s\"", __LINE__, s)); 972 if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY)) 973 { 974 c = *s; 975 if ((state & HOUR) || n > 24) 976 break; 977 while (isspace(*++s) || *s == '_'); 978 if (!isdigit(*s)) 979 break; 980 i = n; 981 n = strtol(s, &t, 10); 982 for (s = t; isspace(*s) || *s == '_'; s++); 983 if (n > 59) 984 break; 985 j = n; 986 m = 0; 987 if (*s == c) 988 { 989 while (isspace(*++s) || *s == '_'); 990 if (!isdigit(*s)) 991 break; 992 n = strtol(s, &t, 10); 993 s = t; 994 if (n > (59 + TM_MAXLEAP)) 995 break; 996 set |= SECOND; 997 while (isspace(*s)) 998 s++; 999 if (*s == '.') 1000 { 1001 q = 1000000000; 1002 while (isdigit(*++s)) 1003 m += (*s - '0') * (q /= 10); 1004 set |= NSEC; 1005 } 1006 } 1007 else 1008 n = 0; 1009 set |= HOUR|MINUTE; 1010 skip[':'] = 1; 1011 k = tm->tm_hour; 1012 tm->tm_hour = i; 1013 l = tm->tm_min; 1014 tm->tm_min = j; 1015 tm->tm_sec = n; 1016 tm->tm_nsec = m; 1017 while (isspace(*s)) 1018 s++; 1019 switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2)) 1020 { 1021 case TM_MERIDIAN: 1022 s = t; 1023 if (i == 12) 1024 tm->tm_hour = i = 0; 1025 break; 1026 case TM_MERIDIAN+1: 1027 if (i < 12) 1028 tm->tm_hour = i += 12; 1029 break; 1030 } 1031 if (f >= 0 || (state & (LAST|NEXT))) 1032 { 1033 message((-1, "AHA#%d f=%d i=%d j=%d k=%d l=%d", __LINE__, f, i, j, k, l)); 1034 state &= ~HOLD; 1035 if (f < 0) 1036 { 1037 if (state & LAST) 1038 f = -1; 1039 else if (state & NEXT) 1040 f = 1; 1041 else 1042 f = 0; 1043 } 1044 if (f > 0) 1045 { 1046 if (i > k || i == k && j > l) 1047 f--; 1048 } 1049 else if (i < k || i == k && j < l) 1050 f++; 1051 if (f > 0) 1052 { 1053 tm->tm_hour += f * 24; 1054 while (tm->tm_hour >= 24) 1055 { 1056 tm->tm_hour -= 24; 1057 tm->tm_mday++; 1058 } 1059 } 1060 else if (f < 0) 1061 { 1062 tm->tm_hour += f * 24; 1063 while (tm->tm_hour < 24) 1064 { 1065 tm->tm_hour += 24; 1066 tm->tm_mday--; 1067 } 1068 } 1069 } 1070 continue; 1071 } 1072 } 1073 } 1074 } 1075 for (;;) 1076 { 1077 message((-1, "AHA#%d s=\"%s\"", __LINE__, s)); 1078 if (*s == '-' || *s == '+') 1079 { 1080 if (((set|state) & (MONTH|DAY|HOUR|MINUTE)) == (MONTH|DAY|HOUR|MINUTE) || *s == '+' && (!isdigit(s[1]) || !isdigit(s[2]) || s[3] != ':' && (s[3] != '.' || ((set|state) & (YEAR|MONTH)) != (YEAR|MONTH)))) 1081 break; 1082 s++; 1083 } 1084 else if (skip[*s]) 1085 s++; 1086 else 1087 break; 1088 } 1089 if (isalpha(*s)) 1090 { 1091 if (n > 0) 1092 { 1093 x = s; 1094 q = *s++; 1095 message((-1, "AHA#%d n=%d q='%c'", __LINE__, n, q)); 1096 if (isalpha(*s)) 1097 { 1098 q <<= 8; 1099 q |= *s++; 1100 if (isalpha(*s)) 1101 { 1102 if (tmlex(s, &t, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES, NiL, 0) >= 0) 1103 s = t; 1104 if (isalpha(*s)) 1105 { 1106 q <<= 8; 1107 q |= *s++; 1108 if (isalpha(*s)) 1109 { 1110 q <<= 8; 1111 q |= *s++; 1112 if (isalpha(*s)) 1113 q = 0; 1114 } 1115 } 1116 } 1117 } 1118 switch (q) 1119 { 1120 case K1('y'): 1121 case K1('Y'): 1122 case K2('y','r'): 1123 case K2('Y','R'): 1124 tm->tm_year += n; 1125 set |= YEAR; 1126 continue; 1127 case K1('M'): 1128 case K2('m','o'): 1129 case K2('M','O'): 1130 tm->tm_mon += n; 1131 set |= MONTH; 1132 continue; 1133 case K1('w'): 1134 case K1('W'): 1135 case K2('w','k'): 1136 case K2('W','K'): 1137 tm->tm_mday += n * 7; 1138 set |= DAY; 1139 continue; 1140 case K1('d'): 1141 case K1('D'): 1142 case K2('d','a'): 1143 case K2('d','y'): 1144 case K2('D','A'): 1145 case K2('D','Y'): 1146 tm->tm_mday += n; 1147 set |= DAY; 1148 continue; 1149 case K1('h'): 1150 case K1('H'): 1151 case K2('h','r'): 1152 case K2('H','R'): 1153 tm->tm_hour += n; 1154 set |= HOUR; 1155 continue; 1156 case K1('m'): 1157 case K2('m','n'): 1158 case K2('M','N'): 1159 tm->tm_min += n; 1160 set |= MINUTE; 1161 continue; 1162 case K1('s'): 1163 case K2('s','c'): 1164 case K1('S'): 1165 case K2('S','C'): 1166 tm->tm_sec += n; 1167 set |= SECOND; 1168 continue; 1169 case K2('m','s'): 1170 case K3('m','s','c'): 1171 case K4('m','s','e','c'): 1172 case K2('M','S'): 1173 case K3('M','S','C'): 1174 case K4('M','S','E','C'): 1175 tm->tm_nsec += n * 1000000L; 1176 continue; 1177 case K1('u'): 1178 case K2('u','s'): 1179 case K3('u','s','c'): 1180 case K4('u','s','e','c'): 1181 case K1('U'): 1182 case K2('U','S'): 1183 case K3('U','S','C'): 1184 case K4('U','S','E','C'): 1185 tm->tm_nsec += n * 1000L; 1186 continue; 1187 case K2('n','s'): 1188 case K3('n','s','c'): 1189 case K4('n','s','e','c'): 1190 case K2('N','S'): 1191 case K3('N','S','C'): 1192 case K4('N','S','E','C'): 1193 tm->tm_nsec += n; 1194 continue; 1195 } 1196 s = x; 1197 } 1198 if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0) 1199 { 1200 if (tm_data.lex[j] == TM_PARTS || n < 1000) 1201 { 1202 s = t; 1203 switch (tm_data.lex[j]) 1204 { 1205 case TM_EXACT: 1206 state |= HOLD|EXACT; 1207 set &= ~(EXACT|LAST|NEXT|THIS); 1208 set |= state & (EXACT|LAST|NEXT|THIS); 1209 continue; 1210 case TM_LAST: 1211 state |= HOLD|LAST; 1212 set &= ~(EXACT|LAST|NEXT|THIS); 1213 set |= state & (EXACT|LAST|NEXT|THIS); 1214 continue; 1215 case TM_THIS: 1216 state |= HOLD|THIS; 1217 set &= ~(EXACT|LAST|NEXT|THIS); 1218 set |= state & (EXACT|LAST|NEXT|THIS); 1219 n = 0; 1220 continue; 1221 case TM_NEXT: 1222 /* 1223 * disambiguate english "last ... in" 1224 */ 1225 1226 if (!((state|set) & LAST)) 1227 { 1228 state |= HOLD|NEXT; 1229 set &= ~(EXACT|LAST|NEXT|THIS); 1230 set |= state & (EXACT|LAST|NEXT|THIS); 1231 continue; 1232 } 1233 /*FALLTHROUGH*/ 1234 case TM_FINAL: 1235 state |= HOLD|THIS|FINAL; 1236 set &= ~(EXACT|LAST|NEXT|THIS); 1237 set |= state & (EXACT|LAST|NEXT|THIS|FINAL); 1238 continue; 1239 case TM_WORK: 1240 message((-1, "AHA#%d WORK", __LINE__)); 1241 state |= WORK; 1242 set |= DAY; 1243 if (state & LAST) 1244 { 1245 state &= ~LAST; 1246 set &= ~LAST; 1247 state |= FINAL; 1248 set |= FINAL; 1249 } 1250 goto clear_hour; 1251 case TM_ORDINAL: 1252 j += TM_ORDINALS - TM_ORDINAL; 1253 message((-1, "AHA#%d j=%d", __LINE__, j)); 1254 /*FALLTHROUGH*/ 1255 case TM_ORDINALS: 1256 n = j - TM_ORDINALS + 1; 1257 message((-1, "AHA#%d n=%d", __LINE__, n)); 1258 goto ordinal; 1259 case TM_MERIDIAN: 1260 if (f >= 0) 1261 f++; 1262 else if (state & LAST) 1263 f = -1; 1264 else if (state & THIS) 1265 f = 1; 1266 else if (state & NEXT) 1267 f = 2; 1268 else 1269 f = 0; 1270 if (n > 0) 1271 { 1272 if (n > 24) 1273 goto done; 1274 tm->tm_hour = n; 1275 } 1276 for (k = tm->tm_hour; k < 0; k += 24); 1277 k %= 24; 1278 if (j == TM_MERIDIAN) 1279 { 1280 if (k == 12) 1281 tm->tm_hour -= 12; 1282 } 1283 else if (k < 12) 1284 tm->tm_hour += 12; 1285 if (n > 0) 1286 goto clear_min; 1287 continue; 1288 case TM_DAY_ABBREV: 1289 j += TM_DAY - TM_DAY_ABBREV; 1290 /*FALLTHROUGH*/ 1291 case TM_DAY: 1292 case TM_PARTS: 1293 case TM_HOURS: 1294 state |= set & (EXACT|LAST|NEXT|THIS); 1295 if (!(state & (LAST|NEXT|THIS))) 1296 for (;;) 1297 { 1298 while (skip[*s]) 1299 s++; 1300 if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0) 1301 { 1302 s = t; 1303 if (k <= 2) 1304 state |= LAST; 1305 else if (k <= 5) 1306 state |= THIS; 1307 else if (k <= 8) 1308 state |= NEXT; 1309 else 1310 state |= EXACT; 1311 } 1312 else 1313 { 1314 state |= (n > 0) ? NEXT : THIS; 1315 break; 1316 } 1317 set &= ~(EXACT|LAST|NEXT|THIS); 1318 set |= state & (EXACT|LAST|NEXT|THIS); 1319 } 1320 /*FALLTHROUGH*/ 1321 case TM_DAYS: 1322 message((-1, "AHA#%d n=%d j=%d f=%d state=" FFMT, __LINE__, n, j, f, FLAGS(state))); 1323 if (n == -1) 1324 { 1325 /* 1326 * disambiguate english "second" 1327 */ 1328 1329 if (j == TM_PARTS && f == -1) 1330 { 1331 state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ 1332 n = 2; 1333 goto ordinal; 1334 } 1335 n = 1; 1336 } 1337 1338 /* 1339 * disambiguate "last" vs. { "previous" "final" } 1340 */ 1341 1342 while (isspace(*s)) 1343 s++; 1344 message((-1, "AHA#%d disambiguate LAST s='%s'", __LINE__, s)); 1345 if ((k = tmlex(s, &t, tm_info.format + TM_NEXT, TM_EXACT - TM_NEXT, NiL, 0)) >= 0 || (k = tmlex(s, &t, tm_info.format + TM_PARTS + 3, 1, NiL, 0)) >= 0) 1346 { 1347 s = t; 1348 if (state & LAST) 1349 { 1350 state &= ~LAST; 1351 set &= ~LAST; 1352 state |= FINAL; 1353 set |= FINAL; 1354 message((-1, "AHA#%d LAST => FINAL", __LINE__)); 1355 } 1356 else 1357 state &= ~(THIS|NEXT); 1358 } 1359 message((-1, "AHA#%d disambiguate LAST k=%d", __LINE__, k)); 1360 if (state & LAST) 1361 n = -n; 1362 else if (!(state & NEXT)) 1363 n--; 1364 m = (f > 0) ? f * n : n; 1365 message((-1, "AHA#%d f=%d n=%d i=%d j=%d k=%d l=%d m=%d state=" FFMT, __LINE__, f, n, i, j, k, l, m, FLAGS(state))); 1366 switch (j) 1367 { 1368 case TM_DAYS+0: 1369 tm->tm_mday--; 1370 set |= DAY; 1371 goto clear_hour; 1372 case TM_DAYS+1: 1373 set |= DAY; 1374 goto clear_hour; 1375 case TM_DAYS+2: 1376 tm->tm_mday++; 1377 set |= DAY; 1378 goto clear_hour; 1379 case TM_PARTS+0: 1380 set |= SECOND; 1381 if ((m < 0 ? -m : m) > (365L*24L*60L*60L)) 1382 { 1383 now = tmxtime(tm, zone) + tmxsns(m, 0); 1384 goto reset; 1385 } 1386 tm->tm_sec += m; 1387 goto clear_nsec; 1388 case TM_PARTS+1: 1389 tm->tm_min += m; 1390 set |= MINUTE; 1391 goto clear_sec; 1392 case TM_PARTS+2: 1393 tm->tm_hour += m; 1394 set |= MINUTE; 1395 goto clear_min; 1396 case TM_PARTS+3: 1397 message((-1, "AHA#%d DAY m=%d n=%d%s", __LINE__, m, n, (state & LAST) ? " LAST" : "")); 1398 if ((state & (LAST|NEXT|THIS)) == LAST) 1399 tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); 1400 else if (state & ORDINAL) 1401 tm->tm_mday = m + 1; 1402 else 1403 tm->tm_mday += m; 1404 if (!(set & (FINAL|WORK))) 1405 set |= HOUR; 1406 goto clear_hour; 1407 case TM_PARTS+4: 1408 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 1409 tm->tm_mday += 7 * m - tm->tm_wday + 1; 1410 set |= DAY; 1411 goto clear_hour; 1412 case TM_PARTS+5: 1413 tm->tm_mon += m; 1414 set |= MONTH; 1415 goto clear_mday; 1416 case TM_PARTS+6: 1417 tm->tm_year += m; 1418 goto clear_mon; 1419 case TM_HOURS+0: 1420 tm->tm_mday += m; 1421 set |= DAY; 1422 goto clear_hour; 1423 case TM_HOURS+1: 1424 tm->tm_mday += m; 1425 tm->tm_hour = 6; 1426 set |= HOUR; 1427 goto clear_min; 1428 case TM_HOURS+2: 1429 tm->tm_mday += m; 1430 tm->tm_hour = 12; 1431 set |= HOUR; 1432 goto clear_min; 1433 case TM_HOURS+3: 1434 tm->tm_mday += m; 1435 tm->tm_hour = 18; 1436 set |= HOUR; 1437 goto clear_min; 1438 } 1439 if (m >= 0 && (state & ORDINAL)) 1440 tm->tm_mday = 1; 1441 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 1442 day = j -= TM_DAY; 1443 if (!dir) 1444 dir = m; 1445 message((-1, "AHA#%d j=%d m=%d", __LINE__, j, m)); 1446 j -= tm->tm_wday; 1447 message((-1, "AHA#%d mday=%d wday=%d day=%d dir=%d f=%d i=%d j=%d l=%d m=%d", __LINE__, tm->tm_mday, tm->tm_wday, day, dir, f, i, j, l, m)); 1448 if (state & (LAST|NEXT|THIS)) 1449 { 1450 if (state & ORDINAL) 1451 { 1452 while (isspace(*s)) 1453 s++; 1454 if (isdigit(*s) || tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0) >= 0) 1455 { 1456 state &= ~(LAST|NEXT|THIS); 1457 goto clear_hour; 1458 } 1459 } 1460 if (j < 0) 1461 j += 7; 1462 } 1463 else if (j > 0) 1464 j -= 7; 1465 message((-1, "AHA#%d day=%d mday=%d f=%d m=%d j=%d state=" FFMT, __LINE__, day, tm->tm_mday, f, m, j, FLAGS(state))); 1466 set |= DAY; 1467 if (set & (FINAL|WORK)) 1468 goto clear_hour; 1469 else if (state & (LAST|NEXT|THIS)) 1470 { 1471 if (f >= 0) 1472 day = -1; 1473 else if (m > 0 && (state & (NEXT|YEAR|MONTH)) == NEXT && j >= 0) 1474 m--; 1475 tm->tm_mday += j + m * 7; 1476 set &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ 1477 state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ 1478 if (!(state & EXACT)) 1479 goto clear_hour; 1480 } 1481 continue; 1482 case TM_MONTH_ABBREV: 1483 j += TM_MONTH - TM_MONTH_ABBREV; 1484 /*FALLTHROUGH*/ 1485 case TM_MONTH: 1486 if (state & MONTH) 1487 goto done; 1488 state |= MONTH; 1489 i = tm->tm_mon; 1490 tm->tm_mon = j - TM_MONTH; 1491 if (n < 0) 1492 { 1493 while (skip[*s]) 1494 s++; 1495 if (isdigit(*s)) 1496 { 1497 n = strtol(s, &t, 10); 1498 if (n <= 31 && *t != ':') 1499 s = t; 1500 else 1501 n = -1; 1502 } 1503 } 1504 if (n >= 0) 1505 { 1506 if (n > 31) 1507 goto done; 1508 state |= DAY|MDAY; 1509 tm->tm_mday = n; 1510 if (f > 0) 1511 tm->tm_year += f; 1512 } 1513 if (state & (LAST|NEXT|THIS)) 1514 { 1515 n = i; 1516 goto rel_month; 1517 } 1518 continue; 1519 case TM_UT: 1520 if (state & ZONE) 1521 goto done; 1522 state |= ZONE; 1523 zone = tmgoff(s, &t, 0); 1524 s = t; 1525 continue; 1526 case TM_DT: 1527 if (!dst) 1528 goto done; 1529 if (!(state & ZONE)) 1530 { 1531 dst = tm->tm_zone->dst; 1532 zone = tm->tm_zone->west; 1533 } 1534 zone += tmgoff(s, &t, dst); 1535 s = t; 1536 dst = 0; 1537 state |= ZONE; 1538 continue; 1539 case TM_NOISE: 1540 continue; 1541 } 1542 } 1543 } 1544 if (n < 1000) 1545 { 1546 if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst))) 1547 { 1548 s = t; 1549 zone = zp->west + dst; 1550 tm_info.date = zp; 1551 state |= ZONE; 1552 if (n < 0) 1553 continue; 1554 } 1555 else if (!type && (zp = tmtype(s, &t))) 1556 { 1557 s = t; 1558 type = zp->type; 1559 if (n < 0) 1560 continue; 1561 } 1562 state |= BREAK; 1563 } 1564 } 1565 else if (*s == '/') 1566 { 1567 if (!(state & (YEAR|MONTH)) && n >= 1969 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12) 1568 { 1569 state |= YEAR; 1570 tm->tm_year = n - 1900; 1571 s = t; 1572 i--; 1573 } 1574 else 1575 { 1576 if ((state & MONTH) || n <= 0 || n > 31) 1577 break; 1578 if (isalpha(*++s)) 1579 { 1580 if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0) 1581 break; 1582 if (i >= TM_MONTH) 1583 i -= TM_MONTH; 1584 s = t; 1585 } 1586 else 1587 { 1588 i = n - 1; 1589 n = strtol(s, &t, 10); 1590 s = t; 1591 if (n <= 0 || n > 31) 1592 break; 1593 if (*s == '/' && !isdigit(*(s + 1))) 1594 break; 1595 } 1596 state |= DAY; 1597 tm->tm_mday = n; 1598 } 1599 state |= MONTH; 1600 n = tm->tm_mon; 1601 tm->tm_mon = i; 1602 if (*s == '/') 1603 { 1604 n = strtol(++s, &t, 10); 1605 w = t - s; 1606 s = t; 1607 if (*s == '/' || *s == ':' || *s == '-' || *s == '_') 1608 s++; 1609 } 1610 else 1611 { 1612 if (state & (LAST|NEXT|THIS)) 1613 { 1614 rel_month: 1615 if (state & LAST) 1616 tm->tm_year -= (tm->tm_mon < n) ? 0 : 1; 1617 else 1618 tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0); 1619 if (state & MDAY) 1620 goto clear_hour; 1621 set &= ~(LAST|NEXT|THIS); /*AHA*/ 1622 state &= ~(LAST|NEXT|THIS); /*AHA*/ 1623 goto clear_mday; 1624 } 1625 continue; 1626 } 1627 } 1628 if (n < 0 || w > 4) 1629 break; 1630 if (w == 4) 1631 { 1632 if ((state & YEAR) || n < 1969 || n >= 3000) 1633 break; 1634 state |= YEAR; 1635 tm->tm_year = n - 1900; 1636 } 1637 else if (w == 3) 1638 { 1639 if (state & (MONTH|MDAY|WDAY)) 1640 break; 1641 state |= MONTH|DAY|MDAY; 1642 tm->tm_mon = 0; 1643 tm->tm_mday = n; 1644 } 1645 else if (w == 2 && !(state & YEAR)) 1646 { 1647 state |= YEAR; 1648 if (n < TM_WINDOW) 1649 n += 100; 1650 tm->tm_year = n; 1651 } 1652 else if (!(state & MONTH) && n >= 1 && n <= 12) 1653 { 1654 state |= MONTH; 1655 tm->tm_mon = n - 1; 1656 } 1657 else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31) 1658 { 1659 state |= DAY|MDAY|WDAY; 1660 tm->tm_mday = n; 1661 } 1662 else 1663 break; 1664 if (state & BREAK) 1665 { 1666 last = t; 1667 break; 1668 } 1669 continue; 1670 clear_mon: 1671 if ((set|state) & (EXACT|MONTH)) 1672 continue; 1673 tm->tm_mon = 0; 1674 clear_mday: 1675 set |= MONTH; 1676 if ((set|state) & (EXACT|DAY|HOUR)) 1677 continue; 1678 tm->tm_mday = 1; 1679 clear_hour: 1680 message((-1, "AHA#%d DAY", __LINE__)); 1681 set |= DAY; 1682 if ((set|state) & (EXACT|HOUR)) 1683 continue; 1684 tm->tm_hour = 0; 1685 clear_min: 1686 set |= HOUR; 1687 if ((set|state) & (EXACT|MINUTE)) 1688 continue; 1689 tm->tm_min = 0; 1690 clear_sec: 1691 set |= MINUTE; 1692 if ((set|state) & (EXACT|SECOND)) 1693 continue; 1694 tm->tm_sec = 0; 1695 clear_nsec: 1696 set |= SECOND; 1697 if ((set|state) & (EXACT|NSEC)) 1698 continue; 1699 tm->tm_nsec = 0; 1700 } 1701 done: 1702 if (day >= 0 && !(state & (MDAY|WDAY))) 1703 { 1704 message((-1, "AHA#%d day=%d dir=%d state=" FFMT, __LINE__, day, dir, FLAGS(state))); 1705 tmfix(tm); 1706 m = dir; 1707 if (state & MONTH) 1708 tm->tm_mday = 1; 1709 else if (m < 0) 1710 m++; 1711 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 1712 j = day - tm->tm_wday; 1713 if (j < 0) 1714 j += 7; 1715 tm->tm_mday += j + m * 7; 1716 if (state & FINAL) 1717 for (n = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); (tm->tm_mday + 7) <= n; tm->tm_mday += 7); 1718 } 1719 else if (day < 0 && (state & FINAL) && (set & DAY)) 1720 { 1721 tmfix(tm); 1722 tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); 1723 } 1724 if (state & WORK) 1725 { 1726 tm->tm_mday = (set & FINAL) ? (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))) : 1; 1727 tmfix(tm); 1728 message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__, tm->tm_mday, tm->tm_wday)); 1729 if (tm->tm_wday == 0 && (j = 1) || tm->tm_wday == 6 && (j = 2)) 1730 { 1731 if ((tm->tm_mday + j) > (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)))) 1732 j -= 3; 1733 tm->tm_mday += j; 1734 } 1735 } 1736 now = tmxtime(tm, zone); 1737 if (tm->tm_year <= 70 && tmxsec(now) > 31536000) 1738 { 1739 now = 0; 1740 last = (char*)o; 1741 } 1742 if (e) 1743 *e = last; 1744 return now; 1745 } 1746