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
range(register char * s,char ** e,char * set,int lo,int hi)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
powerize(Tm_t * tm,unsigned long p,unsigned long q,unsigned long u)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
tmxdate(register const char * s,char ** e,Time_t now)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