1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2009 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 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 if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1))) 709 { 710 if (w == 4) 711 { 712 if ((n -= 1900) < TM_WINDOW) 713 break; 714 } 715 else if (n < TM_WINDOW) 716 n += 100; 717 m = n; 718 n = strtol(++u, &t, 10); 719 if ((i = (t - u)) < 2 || i > 3) 720 break; 721 if (i == 3) 722 { 723 k = n % 10; 724 n /= 10; 725 } 726 else if (*t != '-') 727 k = 1; 728 else if (*++t && dig1(t, k) < 1 || k > 7) 729 break; 730 if (n < 0 || n > 53) 731 break; 732 if (k == 7) 733 k = 0; 734 tm->tm_year = m; 735 tmweek(tm, 2, n, k); 736 set |= YEAR|MONTH|DAY; 737 s = t; 738 continue; 739 } 740 else if (w == 6 || w == 8 && (n / 1000000) > 12) 741 { 742 t = (char*)s; 743 flags = 0; 744 if (w == 8 || w == 6 && *u != 'T' && *u != 't') 745 { 746 dig4(t, m); 747 if ((m -= 1900) < TM_WINDOW) 748 break; 749 } 750 else 751 { 752 dig2(t, m); 753 if (m < TM_WINDOW) 754 m += 100; 755 } 756 flags |= YEAR; 757 if (dig2(t, l) <= 0 || l > 12) 758 break; 759 flags |= MONTH; 760 if (*t != 'T' && *t != 't' || !isdigit(*++t)) 761 { 762 if (w == 6) 763 goto save_yymm; 764 if (dig2(t, k) < 1 || k > 31) 765 break; 766 flags |= DAY; 767 goto save_yymmdd; 768 } 769 n = strtol(s = t, &t, 0); 770 if ((t - s) < 2) 771 break; 772 if (dig2(s, j) > 24) 773 break; 774 if ((t - s) < 2) 775 { 776 if ((t - s) == 1 || *t++ != '-') 777 break; 778 n = strtol(s = t, &t, 0); 779 if ((t - s) < 2) 780 break; 781 } 782 if (dig2(s, i) > 59) 783 break; 784 flags |= HOUR|MINUTE; 785 if ((t - s) == 2) 786 { 787 if (dig2(s, n) > (59 + TM_MAXLEAP)) 788 break; 789 flags |= SECOND; 790 } 791 else if (t - s) 792 break; 793 else 794 n = 0; 795 p = 0; 796 if (*t == '.') 797 { 798 q = 1000000000; 799 while (isdigit(*++t)) 800 p += (*t - '0') * (q /= 10); 801 set |= NSEC; 802 } 803 if (n > (59 + TM_MAXLEAP)) 804 break; 805 goto save; 806 } 807 else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0) 808 { 809 message((-1, "AHA#%d n=%d", __LINE__, n)); 810 ordinal: 811 if (n) 812 n--; 813 message((-1, "AHA#%d n=%d", __LINE__, n)); 814 state |= ((f = n) ? NEXT : THIS)|ORDINAL; 815 set &= ~(EXACT|LAST|NEXT|THIS); 816 set |= state & (EXACT|LAST|NEXT|THIS); 817 for (s = t; skip[*s]; s++); 818 if (isdigit(*s)) 819 { 820 if (n = strtol(s, &t, 10)) 821 n--; 822 s = t; 823 if (*s == '_') 824 s++; 825 } 826 else 827 n = -1; 828 dir = f; 829 message((-1, "AHA#%d f=%d n=%d state=" FFMT, __LINE__, f, n, FLAGS(state))); 830 } 831 else 832 { 833 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)) 834 { 835 /* 836 * various { date(1) touch(1) } formats 837 * 838 * [[cc]yy[mm]]ddhhmm[.ss[.nn...]] 839 * [cc]yyjjj 840 * hhmm[.ss[.nn...]] 841 */ 842 843 flags = 0; 844 if (state & CCYYMMDDHHMMSS) 845 break; 846 state |= CCYYMMDDHHMMSS; 847 p = 0; 848 if ((i == 7 || i == 5) && (!*t || *t == 'Z' || *t == 'z')) 849 { 850 if (i == 7) 851 { 852 dig4(s, m); 853 if ((m -= 1900) < TM_WINDOW) 854 break; 855 } 856 else if (dig2(s, m) < TM_WINDOW) 857 m += 100; 858 dig3(s, k); 859 l = 1; 860 j = 0; 861 i = 0; 862 n = 0; 863 flags |= MONTH; 864 } 865 else if (i & 1) 866 break; 867 else 868 { 869 u = t; 870 if (i == 12) 871 { 872 x = s; 873 dig2(x, m); 874 if (m <= 12) 875 { 876 u -= 4; 877 i -= 4; 878 x = s + 8; 879 dig4(x, m); 880 } 881 else 882 dig4(s, m); 883 if (m < 1969 || m >= 3000) 884 break; 885 m -= 1900; 886 } 887 else if (i == 10) 888 { 889 x = s; 890 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)) 891 dig2(s, m); 892 else 893 { 894 u -= 2; 895 i -= 2; 896 x = s + 8; 897 dig2(x, m); 898 } 899 if (m < TM_WINDOW) 900 m += 100; 901 } 902 else 903 m = tm->tm_year; 904 if ((u - s) < 8) 905 l = tm->tm_mon + 1; 906 else if (dig2(s, l) <= 0 || l > 12) 907 break; 908 else 909 flags |= MONTH; 910 if ((u - s) < 6) 911 k = tm->tm_mday; 912 else if (dig2(s, k) < 1 || k > 31) 913 break; 914 else 915 flags |= DAY; 916 if ((u - s) < 4) 917 break; 918 if (dig2(s, j) > 24) 919 break; 920 if (dig2(s, i) > 59) 921 break; 922 flags |= HOUR|MINUTE; 923 if ((u - s) == 2) 924 { 925 dig2(s, n); 926 flags |= SECOND; 927 } 928 else if (u - s) 929 break; 930 else if (*t != '.') 931 n = 0; 932 else 933 { 934 n = strtol(t + 1, &t, 10); 935 flags |= SECOND; 936 if (*t == '.') 937 { 938 q = 1000000000; 939 while (isdigit(*++t)) 940 p += (*t - '0') * (q /= 10); 941 set |= NSEC; 942 } 943 } 944 if (n > (59 + TM_MAXLEAP)) 945 break; 946 } 947 save: 948 tm->tm_hour = j; 949 tm->tm_min = i; 950 tm->tm_sec = n; 951 tm->tm_nsec = p; 952 save_yymmdd: 953 tm->tm_mday = k; 954 save_yymm: 955 tm->tm_mon = l - 1; 956 tm->tm_year = m; 957 s = t; 958 set |= flags; 959 continue; 960 } 961 for (s = t; skip[*s]; s++); 962 if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY)) 963 { 964 c = *s; 965 if ((state & HOUR) || n > 24) 966 break; 967 while (isspace(*++s) || *s == '_'); 968 if (!isdigit(*s)) 969 break; 970 i = n; 971 n = strtol(s, &t, 10); 972 for (s = t; isspace(*s) || *s == '_'; s++); 973 if (n > 59) 974 break; 975 j = n; 976 m = 0; 977 if (*s == c) 978 { 979 while (isspace(*++s) || *s == '_'); 980 if (!isdigit(*s)) 981 break; 982 n = strtol(s, &t, 10); 983 s = t; 984 if (n > (59 + TM_MAXLEAP)) 985 break; 986 set |= SECOND; 987 while (isspace(*s)) 988 s++; 989 if (*s == '.') 990 { 991 q = 1000000000; 992 while (isdigit(*++s)) 993 m += (*s - '0') * (q /= 10); 994 set |= NSEC; 995 } 996 } 997 else 998 n = 0; 999 set |= HOUR|MINUTE; 1000 skip[':'] = 1; 1001 k = tm->tm_hour; 1002 tm->tm_hour = i; 1003 l = tm->tm_min; 1004 tm->tm_min = j; 1005 tm->tm_sec = n; 1006 tm->tm_nsec = m; 1007 while (isspace(*s)) 1008 s++; 1009 switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2)) 1010 { 1011 case TM_MERIDIAN: 1012 s = t; 1013 if (i == 12) 1014 tm->tm_hour = i = 0; 1015 break; 1016 case TM_MERIDIAN+1: 1017 if (i < 12) 1018 tm->tm_hour = i += 12; 1019 break; 1020 } 1021 if (f >= 0 || (state & (LAST|NEXT))) 1022 { 1023 message((-1, "AHA#%d f=%d i=%d j=%d k=%d l=%d", __LINE__, f, i, j, k, l)); 1024 state &= ~HOLD; 1025 if (f < 0) 1026 { 1027 if (state & LAST) 1028 f = -1; 1029 else if (state & NEXT) 1030 f = 1; 1031 else 1032 f = 0; 1033 } 1034 if (f > 0) 1035 { 1036 if (i > k || i == k && j > l) 1037 f--; 1038 } 1039 else if (i < k || i == k && j < l) 1040 f++; 1041 if (f > 0) 1042 { 1043 tm->tm_hour += f * 24; 1044 while (tm->tm_hour >= 24) 1045 { 1046 tm->tm_hour -= 24; 1047 tm->tm_mday++; 1048 } 1049 } 1050 else if (f < 0) 1051 { 1052 tm->tm_hour += f * 24; 1053 while (tm->tm_hour < 24) 1054 { 1055 tm->tm_hour += 24; 1056 tm->tm_mday--; 1057 } 1058 } 1059 } 1060 continue; 1061 } 1062 } 1063 } 1064 for (;;) 1065 { 1066 if (*s == '-' || *s == '+') 1067 { 1068 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)))) 1069 break; 1070 s++; 1071 } 1072 else if (skip[*s]) 1073 s++; 1074 else 1075 break; 1076 } 1077 if (isalpha(*s)) 1078 { 1079 if (n > 0) 1080 { 1081 x = s; 1082 q = *s++; 1083 if (isalpha(*s)) 1084 { 1085 q <<= 8; 1086 q |= *s++; 1087 if (isalpha(*s)) 1088 { 1089 if (tmlex(s, &t, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES, NiL, 0) >= 0) 1090 s = t; 1091 if (isalpha(*s)) 1092 { 1093 q <<= 8; 1094 q |= *s++; 1095 if (isalpha(*s)) 1096 { 1097 q <<= 8; 1098 q |= *s++; 1099 if (isalpha(*s)) 1100 q = 0; 1101 } 1102 } 1103 } 1104 } 1105 switch (q) 1106 { 1107 case K1('y'): 1108 case K1('Y'): 1109 case K2('y','r'): 1110 case K2('Y','R'): 1111 tm->tm_year += n; 1112 set |= YEAR; 1113 continue; 1114 case K1('M'): 1115 case K2('m','o'): 1116 case K2('M','O'): 1117 tm->tm_mon += n; 1118 set |= MONTH; 1119 continue; 1120 case K1('w'): 1121 case K1('W'): 1122 case K2('w','k'): 1123 case K2('W','K'): 1124 tm->tm_mday += n * 7; 1125 set |= DAY; 1126 continue; 1127 case K1('d'): 1128 case K1('D'): 1129 case K2('d','a'): 1130 case K2('d','y'): 1131 case K2('D','A'): 1132 case K2('D','Y'): 1133 tm->tm_mday += n; 1134 set |= DAY; 1135 continue; 1136 case K1('h'): 1137 case K1('H'): 1138 case K2('h','r'): 1139 case K2('H','R'): 1140 tm->tm_hour += n; 1141 set |= HOUR; 1142 continue; 1143 case K1('m'): 1144 case K2('m','n'): 1145 case K2('M','N'): 1146 tm->tm_min += n; 1147 set |= MINUTE; 1148 continue; 1149 case K1('s'): 1150 case K2('s','c'): 1151 case K1('S'): 1152 case K2('S','C'): 1153 tm->tm_sec += n; 1154 set |= SECOND; 1155 continue; 1156 case K2('m','s'): 1157 case K3('m','s','c'): 1158 case K4('m','s','e','c'): 1159 case K2('M','S'): 1160 case K3('M','S','C'): 1161 case K4('M','S','E','C'): 1162 tm->tm_nsec += n * 1000000L; 1163 continue; 1164 case K1('u'): 1165 case K2('u','s'): 1166 case K3('u','s','c'): 1167 case K4('u','s','e','c'): 1168 case K1('U'): 1169 case K2('U','S'): 1170 case K3('U','S','C'): 1171 case K4('U','S','E','C'): 1172 tm->tm_nsec += n * 1000L; 1173 continue; 1174 case K2('n','s'): 1175 case K3('n','s','c'): 1176 case K4('n','s','e','c'): 1177 case K2('N','S'): 1178 case K3('N','S','C'): 1179 case K4('N','S','E','C'): 1180 tm->tm_nsec += n; 1181 continue; 1182 } 1183 s = x; 1184 } 1185 if (n < 1000) 1186 { 1187 if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0) 1188 { 1189 s = t; 1190 switch (tm_data.lex[j]) 1191 { 1192 case TM_EXACT: 1193 state |= HOLD|EXACT; 1194 set &= ~(EXACT|LAST|NEXT|THIS); 1195 set |= state & (EXACT|LAST|NEXT|THIS); 1196 continue; 1197 case TM_LAST: 1198 state |= HOLD|LAST; 1199 set &= ~(EXACT|LAST|NEXT|THIS); 1200 set |= state & (EXACT|LAST|NEXT|THIS); 1201 continue; 1202 case TM_THIS: 1203 state |= HOLD|THIS; 1204 set &= ~(EXACT|LAST|NEXT|THIS); 1205 set |= state & (EXACT|LAST|NEXT|THIS); 1206 n = 0; 1207 continue; 1208 case TM_NEXT: 1209 /* 1210 * disambiguate english "last ... in" 1211 */ 1212 1213 if (!((state|set) & LAST)) 1214 { 1215 state |= HOLD|NEXT; 1216 set &= ~(EXACT|LAST|NEXT|THIS); 1217 set |= state & (EXACT|LAST|NEXT|THIS); 1218 continue; 1219 } 1220 /*FALLTHROUGH*/ 1221 case TM_FINAL: 1222 state |= HOLD|THIS|FINAL; 1223 set &= ~(EXACT|LAST|NEXT|THIS); 1224 set |= state & (EXACT|LAST|NEXT|THIS|FINAL); 1225 continue; 1226 case TM_WORK: 1227 message((-1, "AHA#%d WORK", __LINE__)); 1228 state |= WORK; 1229 set |= DAY; 1230 if (state & LAST) 1231 { 1232 state &= ~LAST; 1233 set &= ~LAST; 1234 state |= FINAL; 1235 set |= FINAL; 1236 } 1237 goto clear_hour; 1238 case TM_ORDINAL: 1239 j += TM_ORDINALS - TM_ORDINAL; 1240 message((-1, "AHA#%d j=%d", __LINE__, j)); 1241 /*FALLTHROUGH*/ 1242 case TM_ORDINALS: 1243 n = j - TM_ORDINALS + 1; 1244 message((-1, "AHA#%d n=%d", __LINE__, n)); 1245 goto ordinal; 1246 case TM_MERIDIAN: 1247 if (f >= 0) 1248 f++; 1249 else if (state & LAST) 1250 f = -1; 1251 else if (state & THIS) 1252 f = 1; 1253 else if (state & NEXT) 1254 f = 2; 1255 else 1256 f = 0; 1257 if (n > 0) 1258 { 1259 if (n > 24) 1260 goto done; 1261 tm->tm_hour = n; 1262 } 1263 for (k = tm->tm_hour; k < 0; k += 24); 1264 k %= 24; 1265 if (j == TM_MERIDIAN) 1266 { 1267 if (k == 12) 1268 tm->tm_hour -= 12; 1269 } 1270 else if (k < 12) 1271 tm->tm_hour += 12; 1272 if (n > 0) 1273 goto clear_min; 1274 continue; 1275 case TM_DAY_ABBREV: 1276 j += TM_DAY - TM_DAY_ABBREV; 1277 /*FALLTHROUGH*/ 1278 case TM_DAY: 1279 case TM_PARTS: 1280 case TM_HOURS: 1281 state |= set & (EXACT|LAST|NEXT|THIS); 1282 if (!(state & (LAST|NEXT|THIS))) 1283 for (;;) 1284 { 1285 while (skip[*s]) 1286 s++; 1287 if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0) 1288 { 1289 s = t; 1290 if (k <= 2) 1291 state |= LAST; 1292 else if (k <= 5) 1293 state |= THIS; 1294 else if (k <= 8) 1295 state |= NEXT; 1296 else 1297 state |= EXACT; 1298 } 1299 else 1300 { 1301 state |= (n > 0) ? NEXT : THIS; 1302 break; 1303 } 1304 set &= ~(EXACT|LAST|NEXT|THIS); 1305 set |= state & (EXACT|LAST|NEXT|THIS); 1306 } 1307 /*FALLTHROUGH*/ 1308 case TM_DAYS: 1309 message((-1, "AHA#%d n=%d j=%d f=%d state=" FFMT, __LINE__, n, j, f, FLAGS(state))); 1310 if (n == -1) 1311 { 1312 /* 1313 * disambiguate english "second" 1314 */ 1315 1316 if (j == TM_PARTS && f == -1) 1317 { 1318 state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ 1319 n = 2; 1320 goto ordinal; 1321 } 1322 n = 1; 1323 } 1324 1325 /* 1326 * disambiguate "last" vs. { "previous" "final" } 1327 */ 1328 1329 while (isspace(*s)) 1330 s++; 1331 message((-1, "AHA#%d disambiguate LAST s='%s'", __LINE__, s)); 1332 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) 1333 { 1334 s = t; 1335 if (state & LAST) 1336 { 1337 state &= ~LAST; 1338 set &= ~LAST; 1339 state |= FINAL; 1340 set |= FINAL; 1341 message((-1, "AHA#%d LAST => FINAL", __LINE__)); 1342 } 1343 else 1344 state &= ~(THIS|NEXT); 1345 } 1346 message((-1, "AHA#%d disambiguate LAST k=%d", __LINE__, k)); 1347 if (state & LAST) 1348 n = -n; 1349 else if (!(state & NEXT)) 1350 n--; 1351 m = (f > 0) ? f * n : n; 1352 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))); 1353 switch (j) 1354 { 1355 case TM_DAYS+0: 1356 tm->tm_mday--; 1357 set |= DAY; 1358 goto clear_hour; 1359 case TM_DAYS+1: 1360 set |= DAY; 1361 goto clear_hour; 1362 case TM_DAYS+2: 1363 tm->tm_mday++; 1364 set |= DAY; 1365 goto clear_hour; 1366 case TM_PARTS+0: 1367 set |= SECOND; 1368 if ((m < 0 ? -m : m) > (365L*24L*60L*60L)) 1369 { 1370 now = tmxtime(tm, zone) + tmxsns(m, 0); 1371 goto reset; 1372 } 1373 tm->tm_sec += m; 1374 goto clear_nsec; 1375 case TM_PARTS+1: 1376 tm->tm_min += m; 1377 set |= MINUTE; 1378 goto clear_sec; 1379 case TM_PARTS+2: 1380 tm->tm_hour += m; 1381 set |= MINUTE; 1382 goto clear_min; 1383 case TM_PARTS+3: 1384 message((-1, "AHA#%d DAY m=%d n=%d%s", __LINE__, m, n, (state & LAST) ? " LAST" : "")); 1385 if ((state & (LAST|NEXT|THIS)) == LAST) 1386 tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); 1387 else if (state & ORDINAL) 1388 tm->tm_mday = m + 1; 1389 else 1390 tm->tm_mday += m; 1391 if (!(set & (FINAL|WORK))) 1392 set |= HOUR; 1393 goto clear_hour; 1394 case TM_PARTS+4: 1395 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 1396 tm->tm_mday += 7 * m - tm->tm_wday + 1; 1397 set |= DAY; 1398 goto clear_hour; 1399 case TM_PARTS+5: 1400 tm->tm_mon += m; 1401 set |= MONTH; 1402 goto clear_mday; 1403 case TM_PARTS+6: 1404 tm->tm_year += m; 1405 goto clear_mon; 1406 case TM_HOURS+0: 1407 tm->tm_mday += m; 1408 set |= DAY; 1409 goto clear_hour; 1410 case TM_HOURS+1: 1411 tm->tm_mday += m; 1412 tm->tm_hour = 6; 1413 set |= HOUR; 1414 goto clear_min; 1415 case TM_HOURS+2: 1416 tm->tm_mday += m; 1417 tm->tm_hour = 12; 1418 set |= HOUR; 1419 goto clear_min; 1420 case TM_HOURS+3: 1421 tm->tm_mday += m; 1422 tm->tm_hour = 18; 1423 set |= HOUR; 1424 goto clear_min; 1425 } 1426 if (m >= 0 && (state & ORDINAL)) 1427 tm->tm_mday = 1; 1428 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 1429 day = j -= TM_DAY; 1430 if (!dir) 1431 dir = m; 1432 message((-1, "AHA#%d j=%d m=%d", __LINE__, j, m)); 1433 j -= tm->tm_wday; 1434 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)); 1435 if (state & (LAST|NEXT|THIS)) 1436 { 1437 if (state & ORDINAL) 1438 { 1439 while (isspace(*s)) 1440 s++; 1441 if (isdigit(*s) || tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0) >= 0) 1442 { 1443 state &= ~(LAST|NEXT|THIS); 1444 goto clear_hour; 1445 } 1446 } 1447 if (j < 0) 1448 j += 7; 1449 } 1450 else if (j > 0) 1451 j -= 7; 1452 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))); 1453 set |= DAY; 1454 if (set & (FINAL|WORK)) 1455 goto clear_hour; 1456 else if (state & (LAST|NEXT|THIS)) 1457 { 1458 if (f >= 0) 1459 day = -1; 1460 else if (m > 0 && (state & (NEXT|YEAR|MONTH)) == NEXT && j >= 0) 1461 m--; 1462 tm->tm_mday += j + m * 7; 1463 set &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ 1464 state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ 1465 if (!(state & EXACT)) 1466 goto clear_hour; 1467 } 1468 continue; 1469 case TM_MONTH_ABBREV: 1470 j += TM_MONTH - TM_MONTH_ABBREV; 1471 /*FALLTHROUGH*/ 1472 case TM_MONTH: 1473 if (state & MONTH) 1474 goto done; 1475 state |= MONTH; 1476 i = tm->tm_mon; 1477 tm->tm_mon = j - TM_MONTH; 1478 if (n < 0) 1479 { 1480 while (skip[*s]) 1481 s++; 1482 if (isdigit(*s)) 1483 { 1484 n = strtol(s, &t, 10); 1485 if (n <= 31 && *t != ':') 1486 s = t; 1487 else 1488 n = -1; 1489 } 1490 } 1491 if (n >= 0) 1492 { 1493 if (n > 31) 1494 goto done; 1495 state |= DAY|MDAY; 1496 tm->tm_mday = n; 1497 if (f > 0) 1498 tm->tm_year += f; 1499 } 1500 if (state & (LAST|NEXT|THIS)) 1501 { 1502 n = i; 1503 goto rel_month; 1504 } 1505 continue; 1506 case TM_UT: 1507 if (state & ZONE) 1508 goto done; 1509 state |= ZONE; 1510 zone = tmgoff(s, &t, 0); 1511 s = t; 1512 continue; 1513 case TM_DT: 1514 if (!dst) 1515 goto done; 1516 if (!(state & ZONE)) 1517 { 1518 dst = tm->tm_zone->dst; 1519 zone = tm->tm_zone->west; 1520 } 1521 zone += tmgoff(s, &t, dst); 1522 s = t; 1523 dst = 0; 1524 state |= ZONE; 1525 continue; 1526 case TM_NOISE: 1527 continue; 1528 } 1529 } 1530 if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst))) 1531 { 1532 s = t; 1533 zone = zp->west + dst; 1534 tm_info.date = zp; 1535 state |= ZONE; 1536 if (n < 0) 1537 continue; 1538 } 1539 else if (!type && (zp = tmtype(s, &t))) 1540 { 1541 s = t; 1542 type = zp->type; 1543 if (n < 0) 1544 continue; 1545 } 1546 state |= BREAK; 1547 } 1548 } 1549 else if (*s == '/') 1550 { 1551 if (!(state & (YEAR|MONTH)) && n >= 1969 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12) 1552 { 1553 state |= YEAR; 1554 tm->tm_year = n - 1900; 1555 s = t; 1556 i--; 1557 } 1558 else 1559 { 1560 if ((state & MONTH) || n <= 0 || n > 31) 1561 break; 1562 if (isalpha(*++s)) 1563 { 1564 if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0) 1565 break; 1566 if (i >= TM_MONTH) 1567 i -= TM_MONTH; 1568 s = t; 1569 } 1570 else 1571 { 1572 i = n - 1; 1573 n = strtol(s, &t, 10); 1574 s = t; 1575 if (n <= 0 || n > 31) 1576 break; 1577 if (*s == '/' && !isdigit(*(s + 1))) 1578 break; 1579 } 1580 state |= DAY; 1581 tm->tm_mday = n; 1582 } 1583 state |= MONTH; 1584 n = tm->tm_mon; 1585 tm->tm_mon = i; 1586 if (*s == '/') 1587 { 1588 n = strtol(++s, &t, 10); 1589 w = t - s; 1590 s = t; 1591 if (*s == '/' || *s == ':' || *s == '-' || *s == '_') 1592 s++; 1593 } 1594 else 1595 { 1596 if (state & (LAST|NEXT|THIS)) 1597 { 1598 rel_month: 1599 if (state & LAST) 1600 tm->tm_year -= (tm->tm_mon < n) ? 0 : 1; 1601 else 1602 tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0); 1603 if (state & MDAY) 1604 goto clear_hour; 1605 set &= ~(LAST|NEXT|THIS); /*AHA*/ 1606 state &= ~(LAST|NEXT|THIS); /*AHA*/ 1607 goto clear_mday; 1608 } 1609 continue; 1610 } 1611 } 1612 if (n < 0 || w > 4) 1613 break; 1614 if (w == 4) 1615 { 1616 if ((state & YEAR) || n < 1969 || n >= 3000) 1617 break; 1618 state |= YEAR; 1619 tm->tm_year = n - 1900; 1620 } 1621 else if (w == 3) 1622 { 1623 if (state & (MONTH|MDAY|WDAY)) 1624 break; 1625 state |= MONTH|DAY|MDAY; 1626 tm->tm_mon = 0; 1627 tm->tm_mday = n; 1628 } 1629 else if (w == 2 && !(state & YEAR)) 1630 { 1631 state |= YEAR; 1632 if (n < TM_WINDOW) 1633 n += 100; 1634 tm->tm_year = n; 1635 } 1636 else if (!(state & MONTH) && n >= 1 && n <= 12) 1637 { 1638 state |= MONTH; 1639 tm->tm_mon = n - 1; 1640 } 1641 else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31) 1642 { 1643 state |= DAY|MDAY|WDAY; 1644 tm->tm_mday = n; 1645 } 1646 else 1647 break; 1648 if (state & BREAK) 1649 { 1650 last = t; 1651 break; 1652 } 1653 continue; 1654 clear_mon: 1655 if ((set|state) & (EXACT|MONTH)) 1656 continue; 1657 tm->tm_mon = 0; 1658 clear_mday: 1659 set |= MONTH; 1660 if ((set|state) & (EXACT|DAY|HOUR)) 1661 continue; 1662 tm->tm_mday = 1; 1663 clear_hour: 1664 message((-1, "AHA#%d DAY", __LINE__)); 1665 set |= DAY; 1666 if ((set|state) & (EXACT|HOUR)) 1667 continue; 1668 tm->tm_hour = 0; 1669 clear_min: 1670 set |= HOUR; 1671 if ((set|state) & (EXACT|MINUTE)) 1672 continue; 1673 tm->tm_min = 0; 1674 clear_sec: 1675 set |= MINUTE; 1676 if ((set|state) & (EXACT|SECOND)) 1677 continue; 1678 tm->tm_sec = 0; 1679 clear_nsec: 1680 set |= SECOND; 1681 if ((set|state) & (EXACT|NSEC)) 1682 continue; 1683 tm->tm_nsec = 0; 1684 } 1685 done: 1686 if (day >= 0 && !(state & (MDAY|WDAY))) 1687 { 1688 message((-1, "AHA#%d day=%d dir=%d state=" FFMT, __LINE__, day, dir, FLAGS(state))); 1689 m = dir; 1690 if (state & MONTH) 1691 tm->tm_mday = 1; 1692 else if (m < 0) 1693 m++; 1694 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); 1695 j = day - tm->tm_wday; 1696 if (j < 0) 1697 j += 7; 1698 tm->tm_mday += j + m * 7; 1699 if (state & FINAL) 1700 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); 1701 } 1702 else if (day < 0 && (state & FINAL) && (set & DAY)) 1703 tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); 1704 if (state & WORK) 1705 { 1706 tm->tm_mday = (set & FINAL) ? (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))) : 1; 1707 tmfix(tm); 1708 message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__, tm->tm_mday, tm->tm_wday)); 1709 if (tm->tm_wday == 0 && (j = 1) || tm->tm_wday == 6 && (j = 2)) 1710 { 1711 if ((tm->tm_mday + j) > (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)))) 1712 j -= 3; 1713 tm->tm_mday += j; 1714 } 1715 } 1716 now = tmxtime(tm, zone); 1717 if (tm->tm_year <= 70 && tmxsec(now) > 31536000) 1718 { 1719 now = 0; 1720 last = (char*)o; 1721 } 1722 if (e) 1723 *e = last; 1724 return now; 1725 } 1726