1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 35 #define dig1(s,n) ((n)=((*(s)++)-'0')) 36 #define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 37 #define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 38 #define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 39 40 #define BREAK (1<<0) 41 #define CCYYMMDDHHMMSS (1<<1) 42 #define CRON (1<<2) 43 #define DAY (1<<3) 44 #define EXACT (1<<4) 45 #define FINAL (1<<5) 46 #define HOLD (1<<6) 47 #define HOUR (1<<7) 48 #define LAST (1<<8) 49 #define MDAY (1<<9) 50 #define MINUTE (1<<10) 51 #define MONTH (1<<11) 52 #define NEXT (1<<12) 53 #define NSEC (1<<13) 54 #define SECOND (1<<14) 55 #define THIS (1L<<15) 56 #define WDAY (1L<<16) 57 #define YEAR (1L<<17) 58 #define ZONE (1L<<18) 59 60 /* 61 * parse cron range into set 62 * return: -1:error 0:* 1:some 63 */ 64 65 static int 66 range(register char* s, char** e, char* set, int lo, int hi) 67 { 68 int n; 69 int m; 70 int i; 71 char* t; 72 73 while (isspace(*s) || *s == '_') 74 s++; 75 if (*s == '*') 76 { 77 *e = s + 1; 78 return 0; 79 } 80 memset(set, 0, hi + 1); 81 for (;;) 82 { 83 n = strtol(s, &t, 10); 84 if (s == t || n < lo || n > hi) 85 return -1; 86 i = 1; 87 if (*(s = t) == '-') 88 { 89 m = strtol(++s, &t, 10); 90 if (s == t || m < n || m > hi) 91 return -1; 92 if (*(s = t) == '/') 93 { 94 i = strtol(++s, &t, 10); 95 if (s == t || i < 1) 96 return -1; 97 s = t; 98 } 99 } 100 else 101 m = n; 102 for (; n <= m; n += i) 103 set[n] = 1; 104 if (*s != ',') 105 break; 106 s++; 107 } 108 *e = s; 109 return 1; 110 } 111 112 /* 113 * parse date expression in s and return Time_t value 114 * 115 * if non-null, e points to the first invalid sequence in s 116 * now provides default values 117 */ 118 119 Time_t 120 tmxdate(register const char* s, char** e, Time_t now) 121 { 122 register Tm_t* tm; 123 register long n; 124 register int w; 125 unsigned long set; 126 unsigned long state; 127 unsigned long flags; 128 Time_t fix; 129 char* t; 130 char* u; 131 const char* x; 132 char* last; 133 char* type; 134 int day; 135 int dir; 136 int dst; 137 int zone; 138 int c; 139 int f; 140 int i; 141 int j; 142 int k; 143 int l; 144 long m; 145 long p; 146 long q; 147 Tm_zone_t* zp; 148 char skip[UCHAR_MAX + 1]; 149 150 /* 151 * check DATEMSK first 152 */ 153 154 fix = tmxscan(s, &last, NiL, &t, now, 0); 155 if (t && !*last) 156 { 157 if (e) 158 *e = last; 159 return fix; 160 } 161 162 reset: 163 164 /* 165 * use now for defaults 166 */ 167 168 tm = tmxmake(now); 169 tm_info.date = tm_info.zone; 170 day = -1; 171 dst = TM_DST; 172 set = state = 0; 173 type = 0; 174 zone = TM_LOCALZONE; 175 skip[0] = 0; 176 for (n = 1; n <= UCHAR_MAX; n++) 177 skip[n] = isspace(n) || strchr("_,;@=|!^()[]{}", n); 178 179 /* 180 * get <weekday year month day hour minutes seconds ?[ds]t [ap]m> 181 */ 182 183 for (;;) 184 { 185 state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS); 186 if ((set|state) & (YEAR|MONTH|DAY)) 187 skip['/'] = 1; 188 for (;;) 189 { 190 if (*s == '.' || *s == '-' || *s == '+') 191 { 192 if (((set|state) & (YEAR|MONTH|HOUR|MINUTE|ZONE)) == (YEAR|MONTH|HOUR|MINUTE) && (i = tmgoff(s, &t, TM_LOCALZONE)) != TM_LOCALZONE) 193 { 194 zone = i; 195 state |= ZONE; 196 if (!*(s = t)) 197 break; 198 } 199 else if (*s == '+') 200 break; 201 } 202 else if (!skip[*s]) 203 break; 204 s++; 205 } 206 if (!*(last = (char*)s)) 207 break; 208 if (*s == '#') 209 { 210 if (isdigit(*++s)) 211 { 212 now = strtoull(s, &t, 0); 213 sns: 214 if (*(s = t) == '.') 215 { 216 fix = 0; 217 m = 1000000000; 218 while (isdigit(*++s)) 219 fix += (*s - '0') * (m /= 10); 220 now = tmxsns(now, fix); 221 } 222 else if (now <= 0x7fffffff) 223 now = tmxsns(now, 0); 224 goto reset; 225 } 226 else if (*s++ == '#') 227 { 228 now = tmxtime(tm, zone); 229 goto reset; 230 } 231 break; 232 } 233 f = -1; 234 if (*s == '+') 235 { 236 while (isspace(*++s) || *s == '_'); 237 n = strtol(s, &t, 0); 238 if (w = t - s) 239 { 240 for (s = t; skip[*s]; s++); 241 state |= (f = n) ? NEXT : THIS; 242 set &= ~(EXACT|LAST|NEXT|THIS); 243 set |= state & (EXACT|LAST|NEXT|THIS); 244 } 245 else 246 s = last; 247 } 248 if (!(state & CRON)) 249 { 250 /* 251 * check for cron date 252 * 253 * min hour day-of-month month day-of-week 254 * 255 * if it's cron then determine the next time 256 * that satisfies the specification 257 * 258 * NOTE: the only spacing is ' '||'_'||';' 259 */ 260 261 i = 0; 262 n = *(t = (char*)s); 263 for (;;) 264 { 265 if (n == '*') 266 n = *++s; 267 else if (!isdigit(n)) 268 break; 269 else 270 while ((n = *++s) == ',' || n == '-' || n == '/' || isdigit(n)); 271 if (n != ' ' && n != '_' && n != ';') 272 { 273 if (!n) 274 i++; 275 break; 276 } 277 i++; 278 while ((n = *++s) == ' ' || n == '_'); 279 } 280 if (i == 5) 281 { 282 Time_t tt; 283 char hit[60]; 284 char mon[12]; 285 char day[7]; 286 287 state |= CRON; 288 flags = 0; 289 tm->tm_sec = 0; 290 tm->tm_min++; 291 tmfix(tm); 292 293 /* 294 * minute 295 */ 296 297 if ((k = range(t, &t, hit, 0, 59)) < 0) 298 break; 299 if (k && !hit[i = tm->tm_min]) 300 { 301 hit[i] = 1; 302 do if (++i > 59) 303 { 304 i = 0; 305 if (++tm->tm_hour > 59) 306 { 307 tm->tm_min = i; 308 tmfix(tm); 309 } 310 } while (!hit[i]); 311 tm->tm_min = i; 312 } 313 314 /* 315 * hour 316 */ 317 318 if ((k = range(t, &t, hit, 0, 23)) < 0) 319 break; 320 if (k && !hit[i = tm->tm_hour]) 321 { 322 hit[i] = 1; 323 do if (++i > 23) 324 { 325 i = 0; 326 if (++tm->tm_mday > 28) 327 { 328 tm->tm_hour = i; 329 tmfix(tm); 330 } 331 } while (!hit[i]); 332 tm->tm_hour = i; 333 } 334 335 /* 336 * day of month 337 */ 338 339 if ((k = range(t, &t, hit, 1, 31)) < 0) 340 break; 341 if (k) 342 flags |= DAY|MDAY; 343 344 /* 345 * month 346 */ 347 348 if ((k = range(t, &t, mon, 1, 12)) < 0) 349 break; 350 if (k) 351 flags |= MONTH; 352 else 353 for (i = 1; i <= 12; i++) 354 mon[i] = 1; 355 356 /* 357 * day of week 358 */ 359 360 if ((k = range(t, &t, day, 0, 6)) < 0) 361 break; 362 if (k) 363 flags |= WDAY; 364 s = t; 365 if (flags & (MONTH|MDAY|WDAY)) 366 { 367 fix = tmxtime(tm, zone); 368 tm = tmxmake(fix); 369 i = tm->tm_mon + 1; 370 j = tm->tm_mday; 371 k = tm->tm_wday; 372 for (;;) 373 { 374 if (!mon[i]) 375 { 376 if (++i > 12) 377 { 378 i = 1; 379 tm->tm_year++; 380 } 381 tm->tm_mon = i - 1; 382 tm->tm_mday = 1; 383 tt = tmxtime(tm, zone); 384 if (tt < fix) 385 goto done; 386 tm = tmxmake(tt); 387 i = tm->tm_mon + 1; 388 j = tm->tm_mday; 389 k = tm->tm_wday; 390 continue; 391 } 392 if (flags & (MDAY|WDAY)) 393 { 394 if ((flags & (MDAY|WDAY)) == (MDAY|WDAY)) 395 { 396 if (hit[j] && day[k]) 397 break; 398 } 399 else if ((flags & MDAY) && hit[j]) 400 break; 401 else if ((flags & WDAY) && day[k]) 402 break; 403 if (++j > 28) 404 { 405 tm->tm_mon = i - 1; 406 tm->tm_mday = j; 407 tm = tmxmake(tmxtime(tm, zone)); 408 i = tm->tm_mon + 1; 409 j = tm->tm_mday; 410 k = tm->tm_wday; 411 } 412 else if ((flags & WDAY) && ++k > 6) 413 k = 0; 414 } 415 else if (flags & MONTH) 416 break; 417 } 418 tm->tm_mon = i - 1; 419 tm->tm_mday = j; 420 tm->tm_wday = k; 421 } 422 continue; 423 } 424 s = t; 425 } 426 n = -1; 427 if (isdigit(*s)) 428 { 429 n = strtol(s, &t, 10); 430 if ((w = t - s) && *t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && isdigit(*(t + 3))) 431 { 432 now = n; 433 goto sns; 434 } 435 u = t + (*t == '-'); 436 if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1))) 437 { 438 t = u; 439 if (w == 4) 440 { 441 if ((n -= 1900) < TM_WINDOW) 442 break; 443 } 444 else if (n < TM_WINDOW) 445 n += 100; 446 m = n; 447 n = strtol(s = t + 1, &t, 0); 448 if ((i = (t - s)) < 2 || i > 3) 449 break; 450 if (dig2(s, j) < 0 || j > 53) 451 break; 452 if (!(t - s) && *t == '-') 453 n = strtol(s = t + 1, &t, 0); 454 if (!(i = (t - s))) 455 k = 1; 456 else if (i != 1 || dig1(s, k) < 1 || k > 7) 457 break; 458 else if (k == 7) 459 k = 0; 460 tm->tm_year = m; 461 tmweek(tm, 2, j, k); 462 set |= YEAR|MONTH|DAY; 463 continue; 464 } 465 else if ((w == 6 || w == 8) && (*u == 'T' || *u == 't') && isdigit(*(u + 1))) 466 { 467 t = u; 468 flags = 0; 469 if (w == 8) 470 { 471 dig4(s, m); 472 if ((m -= 1900) < TM_WINDOW) 473 break; 474 } 475 else 476 { 477 dig2(s, m); 478 if (m < TM_WINDOW) 479 m += 100; 480 } 481 flags |= YEAR; 482 if (dig2(s, l) <= 0 || l > 12) 483 break; 484 flags |= MONTH; 485 if (dig2(s, k) < 1 || k > 31) 486 break; 487 n = strtol(s = t + 1, &t, 0); 488 if ((t - s) < 2) 489 break; 490 if (dig2(s, j) > 24) 491 break; 492 if ((t - s) < 2) 493 { 494 if ((t - s) == 1 || *t++ != '-') 495 break; 496 n = strtol(s = t, &t, 0); 497 if ((t - s) < 2) 498 break; 499 } 500 if (dig2(s, i) > 59) 501 break; 502 flags |= HOUR|MINUTE; 503 if ((t - s) == 2) 504 { 505 if (dig2(s, n) > (59 + TM_MAXLEAP)) 506 break; 507 flags |= SECOND; 508 } 509 else if (t - s) 510 break; 511 else 512 n = 0; 513 p = 0; 514 if (*t == '.') 515 { 516 q = 1000000000; 517 while (isdigit(*++t)) 518 p += (*t - '0') * (q /= 10); 519 set |= NSEC; 520 } 521 if (n > (59 + TM_MAXLEAP)) 522 break; 523 goto save; 524 } 525 else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0) 526 { 527 ordinal: 528 state |= (f = n) ? NEXT : THIS; 529 set &= ~(EXACT|LAST|NEXT|THIS); 530 set |= state & (EXACT|LAST|NEXT|THIS); 531 for (s = t; skip[*s]; s++); 532 if (isdigit(*s)) 533 { 534 n = strtol(s, &t, 10); 535 s = t; 536 if (*s == '_') 537 s++; 538 } 539 else 540 n = -1; 541 } 542 else 543 { 544 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)) 545 { 546 /* 547 * various { date(1) touch(1) } formats 548 * 549 * [[cc]yy[mm]]ddhhmm[.ss[.nn...]] 550 * [cc]yyjjj 551 * hhmm[.ss[.nn...]] 552 */ 553 554 flags = 0; 555 if (state & CCYYMMDDHHMMSS) 556 break; 557 state |= CCYYMMDDHHMMSS; 558 p = 0; 559 if ((i == 7 || i == 5) && !*t) 560 { 561 if (i == 7) 562 { 563 dig4(s, m); 564 if ((m -= 1900) < TM_WINDOW) 565 break; 566 } 567 else if (dig2(s, m) < TM_WINDOW) 568 m += 100; 569 dig3(s, k); 570 l = 1; 571 j = 0; 572 i = 0; 573 n = 0; 574 flags |= MONTH; 575 } 576 else if (i & 1) 577 break; 578 else 579 { 580 u = t; 581 if (i == 12) 582 { 583 x = s; 584 dig2(x, m); 585 if (m <= 12) 586 { 587 u -= 4; 588 i -= 4; 589 x = s + 8; 590 dig4(x, m); 591 } 592 else 593 dig4(s, m); 594 m -= 1900; 595 } 596 else if (i == 10) 597 { 598 x = s; 599 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)) 600 dig2(s, m); 601 else 602 { 603 u -= 2; 604 i -= 2; 605 x = s + 8; 606 dig2(x, m); 607 } 608 if (m < TM_WINDOW) 609 m += 100; 610 } 611 else 612 m = tm->tm_year; 613 if ((u - s) < 8) 614 l = tm->tm_mon + 1; 615 else if (dig2(s, l) <= 0 || l > 12) 616 break; 617 else 618 flags |= MONTH; 619 if ((u - s) < 6) 620 k = tm->tm_mday; 621 else if (dig2(s, k) < 1 || k > 31) 622 break; 623 else 624 flags |= DAY; 625 if ((u - s) < 4) 626 break; 627 if (dig2(s, j) > 24) 628 break; 629 if (dig2(s, i) > 59) 630 break; 631 flags |= HOUR|MINUTE; 632 if ((u - s) == 2) 633 { 634 dig2(s, n); 635 flags |= SECOND; 636 } 637 else if (u - s) 638 break; 639 else if (*t != '.') 640 n = 0; 641 else 642 { 643 n = strtol(t + 1, &t, 10); 644 flags |= SECOND; 645 if (*t == '.') 646 { 647 q = 1000000000; 648 while (isdigit(*++t)) 649 p += (*t - '0') * (q /= 10); 650 set |= NSEC; 651 } 652 } 653 if (n > (59 + TM_MAXLEAP)) 654 break; 655 } 656 save: 657 tm->tm_year = m; 658 tm->tm_mon = l - 1; 659 tm->tm_mday = k; 660 tm->tm_hour = j; 661 tm->tm_min = i; 662 tm->tm_sec = n; 663 tm->tm_nsec = p; 664 s = t; 665 set |= flags; 666 continue; 667 } 668 for (s = t; skip[*s]; s++); 669 if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY)) 670 { 671 c = *s; 672 if ((state & HOUR) || n > 24) 673 break; 674 while (isspace(*++s) || *s == '_'); 675 if (!isdigit(*s)) 676 break; 677 i = n; 678 n = strtol(s, &t, 10); 679 for (s = t; isspace(*s) || *s == '_'; s++); 680 if (n > 59) 681 break; 682 j = n; 683 m = 0; 684 if (*s == c) 685 { 686 while (isspace(*++s) || *s == '_'); 687 if (!isdigit(*s)) 688 break; 689 n = strtol(s, &t, 10); 690 s = t; 691 if (n > (59 + TM_MAXLEAP)) 692 break; 693 set |= SECOND; 694 while (isspace(*s)) 695 s++; 696 if (*s == '.') 697 { 698 q = 1000000000; 699 while (isdigit(*++s)) 700 m += (*s - '0') * (q /= 10); 701 set |= NSEC; 702 } 703 } 704 else 705 n = 0; 706 set |= HOUR|MINUTE; 707 skip[':'] = 1; 708 k = tm->tm_hour; 709 tm->tm_hour = i; 710 l = tm->tm_min; 711 tm->tm_min = j; 712 tm->tm_sec = n; 713 tm->tm_nsec = m; 714 while (isspace(*s)) 715 s++; 716 switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2)) 717 { 718 case TM_MERIDIAN: 719 s = t; 720 if (i == 12) 721 tm->tm_hour = i = 0; 722 break; 723 case TM_MERIDIAN+1: 724 if (i < 12) 725 tm->tm_hour = i += 12; 726 break; 727 } 728 if (f >= 0 || (state & (LAST|NEXT))) 729 { 730 state &= ~HOLD; 731 if (f < 0) 732 { 733 if (state & LAST) 734 f = -1; 735 else if (state & NEXT) 736 f = 1; 737 else 738 f = 0; 739 } 740 if (f > 0) 741 { 742 if (i > k || i == k && j > l) 743 f--; 744 } 745 else if (i < k || i == k && j < l) 746 f++; 747 if (f > 0) 748 { 749 tm->tm_hour += f * 24; 750 while (tm->tm_hour >= 24) 751 { 752 tm->tm_hour -= 24; 753 tm->tm_mday++; 754 } 755 } 756 else if (f < 0) 757 { 758 tm->tm_hour += f * 24; 759 while (tm->tm_hour < 24) 760 { 761 tm->tm_hour += 24; 762 tm->tm_mday--; 763 } 764 } 765 } 766 continue; 767 } 768 } 769 } 770 for (;;) 771 { 772 if (*s == '-' || *s == '+') 773 { 774 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)))) 775 break; 776 s++; 777 } 778 else if (skip[*s]) 779 s++; 780 else 781 break; 782 } 783 if (isalpha(*s) && n < 1000) 784 { 785 if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0) 786 { 787 s = t; 788 switch (tm_data.lex[j]) 789 { 790 case TM_EXACT: 791 state |= HOLD|EXACT; 792 set &= ~(EXACT|LAST|NEXT|THIS); 793 set |= state & (EXACT|LAST|NEXT|THIS); 794 continue; 795 case TM_LAST: 796 state |= HOLD|LAST; 797 set &= ~(EXACT|LAST|NEXT|THIS); 798 set |= state & (EXACT|LAST|NEXT|THIS); 799 continue; 800 case TM_THIS: 801 state |= HOLD|THIS; 802 set &= ~(EXACT|LAST|NEXT|THIS); 803 set |= state & (EXACT|LAST|NEXT|THIS); 804 n = 0; 805 continue; 806 case TM_NEXT: 807 /* 808 * disambiguate english "last ... in" 809 */ 810 811 if (!((state|set) & LAST)) 812 { 813 state |= HOLD|NEXT; 814 set &= ~(EXACT|LAST|NEXT|THIS); 815 set |= state & (EXACT|LAST|NEXT|THIS); 816 continue; 817 } 818 /*FALLTHROUGH*/ 819 case TM_FINAL: 820 state |= HOLD|THIS|FINAL; 821 set &= ~(EXACT|LAST|NEXT|THIS); 822 set |= state & (EXACT|LAST|NEXT|THIS|FINAL); 823 continue; 824 case TM_ORDINAL: 825 j += TM_ORDINALS - TM_ORDINAL; 826 /*FALLTHROUGH*/ 827 case TM_ORDINALS: 828 n = j - TM_ORDINALS + 1; 829 goto ordinal; 830 case TM_MERIDIAN: 831 if (f >= 0) 832 f++; 833 else if (state & LAST) 834 f = -1; 835 else if (state & THIS) 836 f = 1; 837 else if (state & NEXT) 838 f = 2; 839 else 840 f = 0; 841 if (n > 0) 842 { 843 if (n > 24) 844 goto done; 845 tm->tm_hour = n; 846 } 847 for (k = tm->tm_hour; k < 0; k += 24); 848 k %= 24; 849 if (j == TM_MERIDIAN) 850 { 851 if (k == 12) 852 tm->tm_hour -= 12; 853 } 854 else if (k < 12) 855 tm->tm_hour += 12; 856 if (n > 0) 857 goto clear_min; 858 continue; 859 case TM_DAY_ABBREV: 860 j += TM_DAY - TM_DAY_ABBREV; 861 /*FALLTHROUGH*/ 862 case TM_DAY: 863 case TM_PARTS: 864 case TM_HOURS: 865 state |= set & (EXACT|LAST|NEXT|THIS); 866 if (!(state & (LAST|NEXT|THIS))) 867 for (;;) 868 { 869 while (skip[*s]) 870 s++; 871 if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0) 872 { 873 s = t; 874 if (k <= 2) 875 state |= LAST; 876 else if (k <= 5) 877 state |= THIS; 878 else if (k <= 8) 879 state |= NEXT; 880 else 881 state |= EXACT; 882 } 883 else 884 { 885 state |= (n > 0) ? NEXT : THIS; 886 break; 887 } 888 set &= ~(EXACT|LAST|NEXT|THIS); 889 set |= state & (EXACT|LAST|NEXT|THIS); 890 } 891 /*FALLTHROUGH*/ 892 case TM_DAYS: 893 if (n == -1) 894 { 895 /* 896 * disambiguate english "second" 897 */ 898 899 if (j == TM_PARTS && f == -1) 900 { 901 n = 2; 902 goto ordinal; 903 } 904 n = 1; 905 } 906 if (state & LAST) 907 n = -n; 908 else if (!(state & NEXT)) 909 n--; 910 m = (f > 0) ? f * n : n; 911 switch (j) 912 { 913 case TM_DAYS+0: 914 tm->tm_mday--; 915 set |= DAY; 916 goto clear_hour; 917 case TM_DAYS+1: 918 set |= DAY; 919 goto clear_hour; 920 case TM_DAYS+2: 921 tm->tm_mday++; 922 set |= DAY; 923 goto clear_hour; 924 case TM_PARTS+0: 925 set |= SECOND; 926 if ((m < 0 ? -m : m) > (365L*24L*60L*60L)) 927 { 928 now = tmxtime(tm, zone) + tmxsns(m, 0); 929 goto reset; 930 } 931 tm->tm_sec += m; 932 goto clear_nsec; 933 case TM_PARTS+1: 934 tm->tm_min += m; 935 set |= MINUTE; 936 goto clear_sec; 937 case TM_PARTS+2: 938 tm->tm_hour += m; 939 set |= MINUTE; 940 goto clear_min; 941 case TM_PARTS+3: 942 tm->tm_mday += m; 943 if (!(set & FINAL)) 944 set |= HOUR; 945 goto clear_hour; 946 case TM_PARTS+4: 947 tm = tmxmake(tmxtime(tm, zone)); 948 tm->tm_mday += 7 * m - tm->tm_wday + 1; 949 set |= DAY; 950 goto clear_hour; 951 case TM_PARTS+5: 952 tm->tm_mon += m; 953 set |= MONTH; 954 goto clear_mday; 955 case TM_PARTS+6: 956 tm->tm_year += m; 957 goto clear_mon; 958 case TM_HOURS+0: 959 tm->tm_mday += m; 960 set |= DAY; 961 goto clear_hour; 962 case TM_HOURS+1: 963 tm->tm_mday += m; 964 tm->tm_hour = 6; 965 set |= HOUR; 966 goto clear_min; 967 case TM_HOURS+2: 968 tm->tm_mday += m; 969 tm->tm_hour = 12; 970 set |= HOUR; 971 goto clear_min; 972 case TM_HOURS+3: 973 tm->tm_mday += m; 974 tm->tm_hour = 18; 975 set |= HOUR; 976 goto clear_min; 977 } 978 tm = tmxmake(tmxtime(tm, zone)); 979 day = j -= TM_DAY; 980 dir = m; 981 j -= tm->tm_wday; 982 if (state & (LAST|NEXT|THIS)) 983 { 984 if (j < 0) 985 j += 7; 986 } 987 else if (j > 0) 988 j -= 7; 989 tm->tm_mday += j + m * 7; 990 set |= DAY; 991 if (state & (LAST|NEXT|THIS)) 992 goto clear_hour; 993 continue; 994 case TM_MONTH_ABBREV: 995 j += TM_MONTH - TM_MONTH_ABBREV; 996 /*FALLTHROUGH*/ 997 case TM_MONTH: 998 if (state & MONTH) 999 goto done; 1000 state |= MONTH; 1001 i = tm->tm_mon; 1002 tm->tm_mon = j - TM_MONTH; 1003 if (n < 0) 1004 { 1005 while (skip[*s]) 1006 s++; 1007 if (isdigit(*s)) 1008 { 1009 n = strtol(s, &t, 10); 1010 if (n <= 31 && *t != ':') 1011 s = t; 1012 else 1013 n = -1; 1014 } 1015 } 1016 if (n >= 0) 1017 { 1018 if (n > 31) 1019 goto done; 1020 state |= DAY|MDAY; 1021 tm->tm_mday = n; 1022 if (f > 0) 1023 tm->tm_year += f; 1024 } 1025 if (state & (LAST|NEXT|THIS)) 1026 { 1027 n = i; 1028 goto rel_month; 1029 } 1030 continue; 1031 case TM_UT: 1032 if (state & ZONE) 1033 goto done; 1034 state |= ZONE; 1035 zone = tmgoff(s, &t, 0); 1036 s = t; 1037 continue; 1038 case TM_DT: 1039 if (!dst) 1040 goto done; 1041 if (!(state & ZONE)) 1042 { 1043 dst = tm_info.zone->dst; 1044 zone = tm_info.zone->west; 1045 } 1046 zone += tmgoff(s, &t, dst); 1047 s = t; 1048 dst = 0; 1049 state |= ZONE; 1050 continue; 1051 case TM_NOISE: 1052 continue; 1053 } 1054 } 1055 if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst))) 1056 { 1057 s = t; 1058 zone = zp->west + dst; 1059 tm_info.date = zp; 1060 state |= ZONE; 1061 continue; 1062 } 1063 if (!type && (zp = tmtype(s, &t))) 1064 { 1065 s = t; 1066 type = zp->type; 1067 continue; 1068 } 1069 state |= BREAK; 1070 } 1071 else if (*s == '/') 1072 { 1073 if (!(state & (YEAR|MONTH)) && n >= 1900 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12) 1074 { 1075 state |= YEAR; 1076 tm->tm_year = n - 1900; 1077 s = t; 1078 i--; 1079 } 1080 else 1081 { 1082 if ((state & MONTH) || n <= 0 || n > 31) 1083 break; 1084 if (isalpha(*++s)) 1085 { 1086 if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0) 1087 break; 1088 if (i >= TM_MONTH) 1089 i -= TM_MONTH; 1090 s = t; 1091 } 1092 else 1093 { 1094 i = n - 1; 1095 n = strtol(s, &t, 10); 1096 s = t; 1097 if (n <= 0 || n > 31) 1098 break; 1099 if (*s == '/' && !isdigit(*(s + 1))) 1100 break; 1101 } 1102 state |= DAY; 1103 tm->tm_mday = n; 1104 } 1105 state |= MONTH; 1106 n = tm->tm_mon; 1107 tm->tm_mon = i; 1108 if (*s == '/') 1109 { 1110 n = strtol(++s, &t, 10); 1111 w = t - s; 1112 s = t; 1113 if (*s == '/' || *s == ':' || *s == '-' || *s == '_') 1114 s++; 1115 } 1116 else 1117 { 1118 if (state & (LAST|NEXT|THIS)) 1119 { 1120 rel_month: 1121 if (state & LAST) 1122 tm->tm_year -= (tm->tm_mon < n) ? 0 : 1; 1123 else 1124 tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0); 1125 if (state & MDAY) 1126 goto clear_hour; 1127 goto clear_mday; 1128 } 1129 continue; 1130 } 1131 } 1132 if (n < 0 || w > 4) 1133 break; 1134 if (w == 4) 1135 { 1136 if ((state & YEAR) || n < 1900 || n >= 3000) 1137 break; 1138 state |= YEAR; 1139 tm->tm_year = n - 1900; 1140 } 1141 else if (w == 3) 1142 { 1143 if (state & (MONTH|MDAY|WDAY)) 1144 break; 1145 state |= MONTH|DAY|MDAY; 1146 tm->tm_mon = 0; 1147 tm->tm_mday = n; 1148 } 1149 else if (w == 2 && !(state & YEAR)) 1150 { 1151 state |= YEAR; 1152 if (n < TM_WINDOW) 1153 n += 100; 1154 tm->tm_year = n; 1155 } 1156 else if (!(state & MONTH) && n >= 1 && n <= 12) 1157 { 1158 state |= MONTH; 1159 tm->tm_mon = n - 1; 1160 } 1161 else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31) 1162 { 1163 state |= DAY|MDAY|WDAY; 1164 tm->tm_mday = n; 1165 } 1166 else 1167 break; 1168 if (state & BREAK) 1169 { 1170 last = t; 1171 break; 1172 } 1173 continue; 1174 clear_mon: 1175 if ((set|state) & (EXACT|MONTH)) 1176 continue; 1177 tm->tm_mon = 0; 1178 clear_mday: 1179 set |= MONTH; 1180 if ((set|state) & (EXACT|DAY|HOUR)) 1181 continue; 1182 tm->tm_mday = 1; 1183 clear_hour: 1184 set |= DAY; 1185 if ((set|state) & (EXACT|HOUR)) 1186 continue; 1187 tm->tm_hour = 0; 1188 clear_min: 1189 set |= HOUR; 1190 if ((set|state) & (EXACT|MINUTE)) 1191 continue; 1192 tm->tm_min = 0; 1193 clear_sec: 1194 set |= MINUTE; 1195 if ((set|state) & (EXACT|SECOND)) 1196 continue; 1197 tm->tm_sec = 0; 1198 clear_nsec: 1199 set |= SECOND; 1200 if ((set|state) & (EXACT|NSEC)) 1201 continue; 1202 tm->tm_nsec = 0; 1203 } 1204 done: 1205 if (day >= 0 && !(state & (MDAY|WDAY))) 1206 { 1207 if ((m = dir) > 0) 1208 m--; 1209 if (state & MONTH) 1210 tm->tm_mday = 1; 1211 else if (m < 0) 1212 m++; 1213 tm = tmxmake(tmxtime(tm, zone)); 1214 j = day - tm->tm_wday; 1215 if (j < 0) 1216 j += 7; 1217 tm->tm_mday += j + m * 7; 1218 if (state & FINAL) 1219 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); 1220 } 1221 else if (day < 0 && (state & FINAL) && (set & DAY)) 1222 tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); 1223 if (e) 1224 *e = last; 1225 return tmxtime(tm, zone); 1226 } 1227