1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 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
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 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 tmfix(tm);
1690 m = dir;
1691 if (state & MONTH)
1692 tm->tm_mday = 1;
1693 else if (m < 0)
1694 m++;
1695 tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1696 j = day - tm->tm_wday;
1697 if (j < 0)
1698 j += 7;
1699 tm->tm_mday += j + m * 7;
1700 if (state & FINAL)
1701 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);
1702 }
1703 else if (day < 0 && (state & FINAL) && (set & DAY))
1704 {
1705 tmfix(tm);
1706 tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year));
1707 }
1708 if (state & WORK)
1709 {
1710 tm->tm_mday = (set & FINAL) ? (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))) : 1;
1711 tmfix(tm);
1712 message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__, tm->tm_mday, tm->tm_wday));
1713 if (tm->tm_wday == 0 && (j = 1) || tm->tm_wday == 6 && (j = 2))
1714 {
1715 if ((tm->tm_mday + j) > (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))))
1716 j -= 3;
1717 tm->tm_mday += j;
1718 }
1719 }
1720 now = tmxtime(tm, zone);
1721 if (tm->tm_year <= 70 && tmxsec(now) > 31536000)
1722 {
1723 now = 0;
1724 last = (char*)o;
1725 }
1726 if (e)
1727 *e = last;
1728 return now;
1729 }
1730