1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin * Glenn Fowler
25da2e3ebdSchin * AT&T Research
26da2e3ebdSchin *
27da2e3ebdSchin * Time_t conversion support
28da2e3ebdSchin *
29da2e3ebdSchin * relative times inspired by Steve Bellovin's netnews getdate(3)
30da2e3ebdSchin */
31da2e3ebdSchin
32da2e3ebdSchin #include <tmx.h>
33da2e3ebdSchin #include <ctype.h>
347c2fbfb3SApril Chin #include <debug.h>
35da2e3ebdSchin
36da2e3ebdSchin #define dig1(s,n) ((n)=((*(s)++)-'0'))
37da2e3ebdSchin #define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
38da2e3ebdSchin #define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
39da2e3ebdSchin #define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
40da2e3ebdSchin
4134f9b3eeSRoland Mainz #undef BREAK
4234f9b3eeSRoland Mainz
43da2e3ebdSchin #define BREAK (1<<0)
44da2e3ebdSchin #define CCYYMMDDHHMMSS (1<<1)
45da2e3ebdSchin #define CRON (1<<2)
46da2e3ebdSchin #define DAY (1<<3)
47da2e3ebdSchin #define EXACT (1<<4)
48da2e3ebdSchin #define FINAL (1<<5)
49da2e3ebdSchin #define HOLD (1<<6)
50da2e3ebdSchin #define HOUR (1<<7)
51da2e3ebdSchin #define LAST (1<<8)
52da2e3ebdSchin #define MDAY (1<<9)
53da2e3ebdSchin #define MINUTE (1<<10)
54da2e3ebdSchin #define MONTH (1<<11)
55da2e3ebdSchin #define NEXT (1<<12)
56da2e3ebdSchin #define NSEC (1<<13)
577c2fbfb3SApril Chin #define ORDINAL (1<<14)
587c2fbfb3SApril Chin #define SECOND (1<<15)
597c2fbfb3SApril Chin #define THIS (1L<<16)
607c2fbfb3SApril Chin #define WDAY (1L<<17)
6134f9b3eeSRoland Mainz #define WORK (1L<<18)
6234f9b3eeSRoland Mainz #define YEAR (1L<<19)
6334f9b3eeSRoland Mainz #define ZONE (1L<<20)
64da2e3ebdSchin
6534f9b3eeSRoland Mainz #define FFMT "%s%s%s%s%s%s%s|"
6634f9b3eeSRoland Mainz #define FLAGS(f) (f&EXACT)?"|EXACT":"",(f&LAST)?"|LAST":"",(f&THIS)?"|THIS":"",(f&NEXT)?"|NEXT":"",(f&ORDINAL)?"|ORDINAL":"",(f&FINAL)?"|FINAL":"",(f&WORK)?"|WORK":""
67da2e3ebdSchin /*
68da2e3ebdSchin * parse cron range into set
69da2e3ebdSchin * return: -1:error 0:* 1:some
70da2e3ebdSchin */
71da2e3ebdSchin
72da2e3ebdSchin static int
range(register char * s,char ** e,char * set,int lo,int hi)73da2e3ebdSchin range(register char* s, char** e, char* set, int lo, int hi)
74da2e3ebdSchin {
75da2e3ebdSchin int n;
76da2e3ebdSchin int m;
77da2e3ebdSchin int i;
78da2e3ebdSchin char* t;
79da2e3ebdSchin
80da2e3ebdSchin while (isspace(*s) || *s == '_')
81da2e3ebdSchin s++;
82da2e3ebdSchin if (*s == '*')
83da2e3ebdSchin {
84da2e3ebdSchin *e = s + 1;
85da2e3ebdSchin return 0;
86da2e3ebdSchin }
87da2e3ebdSchin memset(set, 0, hi + 1);
88da2e3ebdSchin for (;;)
89da2e3ebdSchin {
90da2e3ebdSchin n = strtol(s, &t, 10);
91da2e3ebdSchin if (s == t || n < lo || n > hi)
92da2e3ebdSchin return -1;
93da2e3ebdSchin i = 1;
94da2e3ebdSchin if (*(s = t) == '-')
95da2e3ebdSchin {
96da2e3ebdSchin m = strtol(++s, &t, 10);
97da2e3ebdSchin if (s == t || m < n || m > hi)
98da2e3ebdSchin return -1;
99da2e3ebdSchin if (*(s = t) == '/')
100da2e3ebdSchin {
101da2e3ebdSchin i = strtol(++s, &t, 10);
102da2e3ebdSchin if (s == t || i < 1)
103da2e3ebdSchin return -1;
104da2e3ebdSchin s = t;
105da2e3ebdSchin }
106da2e3ebdSchin }
107da2e3ebdSchin else
108da2e3ebdSchin m = n;
109da2e3ebdSchin for (; n <= m; n += i)
110da2e3ebdSchin set[n] = 1;
111da2e3ebdSchin if (*s != ',')
112da2e3ebdSchin break;
113da2e3ebdSchin s++;
114da2e3ebdSchin }
115da2e3ebdSchin *e = s;
116da2e3ebdSchin return 1;
117da2e3ebdSchin }
118da2e3ebdSchin
119da2e3ebdSchin /*
12034f9b3eeSRoland Mainz * normalize <p,q> to power of 10 u in tm
12134f9b3eeSRoland Mainz */
12234f9b3eeSRoland Mainz
12334f9b3eeSRoland Mainz static void
powerize(Tm_t * tm,unsigned long p,unsigned long q,unsigned long u)12434f9b3eeSRoland Mainz powerize(Tm_t* tm, unsigned long p, unsigned long q, unsigned long u)
12534f9b3eeSRoland Mainz {
12634f9b3eeSRoland Mainz Time_t t = p;
12734f9b3eeSRoland Mainz
12834f9b3eeSRoland Mainz while (q > u)
12934f9b3eeSRoland Mainz {
13034f9b3eeSRoland Mainz q /= 10;
13134f9b3eeSRoland Mainz t /= 10;
13234f9b3eeSRoland Mainz }
13334f9b3eeSRoland Mainz while (q < u)
13434f9b3eeSRoland Mainz {
13534f9b3eeSRoland Mainz q *= 10;
13634f9b3eeSRoland Mainz t *= 10;
13734f9b3eeSRoland Mainz }
13834f9b3eeSRoland Mainz tm->tm_nsec += (int)(t % TMX_RESOLUTION);
13934f9b3eeSRoland Mainz tm->tm_sec += (int)(t / TMX_RESOLUTION);
14034f9b3eeSRoland Mainz }
14134f9b3eeSRoland Mainz
14234f9b3eeSRoland Mainz #define K1(c1) (c1)
14334f9b3eeSRoland Mainz #define K2(c1,c2) (((c1)<<8)|(c2))
14434f9b3eeSRoland Mainz #define K3(c1,c2,c3) (((c1)<<16)|((c2)<<8)|(c3))
14534f9b3eeSRoland Mainz #define K4(c1,c2,c3,c4) (((c1)<<24)|((c2)<<16)|((c3)<<8)|(c4))
14634f9b3eeSRoland Mainz
14734f9b3eeSRoland Mainz #define P_INIT(n) w = n; p = q = 0; u = (char*)s + 1
14834f9b3eeSRoland Mainz
14934f9b3eeSRoland Mainz /*
150da2e3ebdSchin * parse date expression in s and return Time_t value
151da2e3ebdSchin *
152da2e3ebdSchin * if non-null, e points to the first invalid sequence in s
153da2e3ebdSchin * now provides default values
154da2e3ebdSchin */
155da2e3ebdSchin
156da2e3ebdSchin Time_t
tmxdate(register const char * s,char ** e,Time_t now)157da2e3ebdSchin tmxdate(register const char* s, char** e, Time_t now)
158da2e3ebdSchin {
159da2e3ebdSchin register Tm_t* tm;
160da2e3ebdSchin register long n;
161da2e3ebdSchin register int w;
162da2e3ebdSchin unsigned long set;
163da2e3ebdSchin unsigned long state;
164da2e3ebdSchin unsigned long flags;
165da2e3ebdSchin Time_t fix;
166da2e3ebdSchin char* t;
167da2e3ebdSchin char* u;
16834f9b3eeSRoland Mainz const char* o;
169da2e3ebdSchin const char* x;
170da2e3ebdSchin char* last;
171da2e3ebdSchin char* type;
172da2e3ebdSchin int day;
173da2e3ebdSchin int dir;
174da2e3ebdSchin int dst;
175da2e3ebdSchin int zone;
176da2e3ebdSchin int c;
177da2e3ebdSchin int f;
178da2e3ebdSchin int i;
179da2e3ebdSchin int j;
180da2e3ebdSchin int k;
181da2e3ebdSchin int l;
182da2e3ebdSchin long m;
18334f9b3eeSRoland Mainz unsigned long p;
18434f9b3eeSRoland Mainz unsigned long q;
185da2e3ebdSchin Tm_zone_t* zp;
18634f9b3eeSRoland Mainz Tm_t ts;
187da2e3ebdSchin char skip[UCHAR_MAX + 1];
188da2e3ebdSchin
189da2e3ebdSchin /*
190da2e3ebdSchin * check DATEMSK first
191da2e3ebdSchin */
192da2e3ebdSchin
19334f9b3eeSRoland Mainz debug((error(-1, "AHA tmxdate 2009-03-06")));
194da2e3ebdSchin fix = tmxscan(s, &last, NiL, &t, now, 0);
195da2e3ebdSchin if (t && !*last)
196da2e3ebdSchin {
197da2e3ebdSchin if (e)
198da2e3ebdSchin *e = last;
199da2e3ebdSchin return fix;
200da2e3ebdSchin }
20134f9b3eeSRoland Mainz o = s;
202da2e3ebdSchin
203da2e3ebdSchin reset:
204da2e3ebdSchin
205da2e3ebdSchin /*
206da2e3ebdSchin * use now for defaults
207da2e3ebdSchin */
208da2e3ebdSchin
20934f9b3eeSRoland Mainz tm = tmxtm(&ts, now, NiL);
21034f9b3eeSRoland Mainz tm_info.date = tm->tm_zone;
211da2e3ebdSchin day = -1;
21234f9b3eeSRoland Mainz dir = 0;
213da2e3ebdSchin dst = TM_DST;
214da2e3ebdSchin set = state = 0;
215da2e3ebdSchin type = 0;
216da2e3ebdSchin zone = TM_LOCALZONE;
217da2e3ebdSchin skip[0] = 0;
218da2e3ebdSchin for (n = 1; n <= UCHAR_MAX; n++)
219da2e3ebdSchin skip[n] = isspace(n) || strchr("_,;@=|!^()[]{}", n);
220da2e3ebdSchin
221da2e3ebdSchin /*
222da2e3ebdSchin * get <weekday year month day hour minutes seconds ?[ds]t [ap]m>
223da2e3ebdSchin */
224da2e3ebdSchin
22534f9b3eeSRoland Mainz again:
226da2e3ebdSchin for (;;)
227da2e3ebdSchin {
228da2e3ebdSchin state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS);
229da2e3ebdSchin if ((set|state) & (YEAR|MONTH|DAY))
230da2e3ebdSchin skip['/'] = 1;
23134f9b3eeSRoland Mainz message((-1, "AHA#%d state=" FFMT " set=" FFMT, __LINE__, FLAGS(state), FLAGS(set)));
232da2e3ebdSchin for (;;)
233da2e3ebdSchin {
234da2e3ebdSchin if (*s == '.' || *s == '-' || *s == '+')
235da2e3ebdSchin {
236da2e3ebdSchin if (((set|state) & (YEAR|MONTH|HOUR|MINUTE|ZONE)) == (YEAR|MONTH|HOUR|MINUTE) && (i = tmgoff(s, &t, TM_LOCALZONE)) != TM_LOCALZONE)
237da2e3ebdSchin {
238da2e3ebdSchin zone = i;
239da2e3ebdSchin state |= ZONE;
240da2e3ebdSchin if (!*(s = t))
241da2e3ebdSchin break;
242da2e3ebdSchin }
243da2e3ebdSchin else if (*s == '+')
244da2e3ebdSchin break;
245da2e3ebdSchin }
246da2e3ebdSchin else if (!skip[*s])
247da2e3ebdSchin break;
248da2e3ebdSchin s++;
249da2e3ebdSchin }
250da2e3ebdSchin if (!*(last = (char*)s))
251da2e3ebdSchin break;
252da2e3ebdSchin if (*s == '#')
253da2e3ebdSchin {
254da2e3ebdSchin if (isdigit(*++s))
255da2e3ebdSchin {
256da2e3ebdSchin now = strtoull(s, &t, 0);
257da2e3ebdSchin sns:
258da2e3ebdSchin if (*(s = t) == '.')
259da2e3ebdSchin {
260da2e3ebdSchin fix = 0;
261da2e3ebdSchin m = 1000000000;
262da2e3ebdSchin while (isdigit(*++s))
263da2e3ebdSchin fix += (*s - '0') * (m /= 10);
264da2e3ebdSchin now = tmxsns(now, fix);
265da2e3ebdSchin }
266da2e3ebdSchin else if (now <= 0x7fffffff)
267da2e3ebdSchin now = tmxsns(now, 0);
268da2e3ebdSchin goto reset;
269da2e3ebdSchin }
270da2e3ebdSchin else if (*s++ == '#')
271da2e3ebdSchin {
272da2e3ebdSchin now = tmxtime(tm, zone);
273da2e3ebdSchin goto reset;
274da2e3ebdSchin }
275da2e3ebdSchin break;
276da2e3ebdSchin }
27734f9b3eeSRoland Mainz if ((*s == 'P' || *s == 'p') && (!isalpha(*(s + 1)) || (*(s + 1) == 'T' || *(s + 1) == 't') && !isalpha(*(s + 2))))
27834f9b3eeSRoland Mainz {
27934f9b3eeSRoland Mainz Tm_t otm;
28034f9b3eeSRoland Mainz
28134f9b3eeSRoland Mainz /*
28234f9b3eeSRoland Mainz * iso duration
28334f9b3eeSRoland Mainz */
28434f9b3eeSRoland Mainz
28534f9b3eeSRoland Mainz otm = *tm;
28634f9b3eeSRoland Mainz t = (char*)s;
28734f9b3eeSRoland Mainz m = 0;
28834f9b3eeSRoland Mainz P_INIT('Y');
28934f9b3eeSRoland Mainz do
29034f9b3eeSRoland Mainz {
29134f9b3eeSRoland Mainz c = *++s;
29234f9b3eeSRoland Mainz duration_next:
29334f9b3eeSRoland Mainz switch (c)
29434f9b3eeSRoland Mainz {
29534f9b3eeSRoland Mainz case 0:
29634f9b3eeSRoland Mainz m++;
29734f9b3eeSRoland Mainz if ((char*)s > u)
29834f9b3eeSRoland Mainz {
29934f9b3eeSRoland Mainz s--;
30034f9b3eeSRoland Mainz c = '_';
30134f9b3eeSRoland Mainz goto duration_next;
30234f9b3eeSRoland Mainz }
30334f9b3eeSRoland Mainz break;
30434f9b3eeSRoland Mainz case 'T':
30534f9b3eeSRoland Mainz case 't':
30634f9b3eeSRoland Mainz m++;
30734f9b3eeSRoland Mainz if ((char*)s > u)
30834f9b3eeSRoland Mainz {
30934f9b3eeSRoland Mainz s++;
31034f9b3eeSRoland Mainz c = 'D';
31134f9b3eeSRoland Mainz goto duration_next;
31234f9b3eeSRoland Mainz }
31334f9b3eeSRoland Mainz continue;
31434f9b3eeSRoland Mainz case 'Y':
31534f9b3eeSRoland Mainz case 'y':
31634f9b3eeSRoland Mainz m = 0;
31734f9b3eeSRoland Mainz if (q > 1)
31834f9b3eeSRoland Mainz tm->tm_sec += (365L*24L*60L*60L) * p / q;
31934f9b3eeSRoland Mainz else
32034f9b3eeSRoland Mainz tm->tm_year += p;
32134f9b3eeSRoland Mainz P_INIT('M');
32234f9b3eeSRoland Mainz continue;
32334f9b3eeSRoland Mainz case 'm':
32434f9b3eeSRoland Mainz if (!m)
32534f9b3eeSRoland Mainz m = 1;
32634f9b3eeSRoland Mainz /*FALLTHROUGH*/
32734f9b3eeSRoland Mainz case 'M':
32834f9b3eeSRoland Mainz switch (*(s + 1))
32934f9b3eeSRoland Mainz {
33034f9b3eeSRoland Mainz case 'I':
33134f9b3eeSRoland Mainz case 'i':
33234f9b3eeSRoland Mainz s++;
33334f9b3eeSRoland Mainz m = 1;
33434f9b3eeSRoland Mainz w = 'S';
33534f9b3eeSRoland Mainz break;
33634f9b3eeSRoland Mainz case 'O':
33734f9b3eeSRoland Mainz case 'o':
33834f9b3eeSRoland Mainz s++;
33934f9b3eeSRoland Mainz m = 0;
34034f9b3eeSRoland Mainz w = 'H';
34134f9b3eeSRoland Mainz break;
34234f9b3eeSRoland Mainz case 'S':
34334f9b3eeSRoland Mainz case 's':
34434f9b3eeSRoland Mainz s++;
34534f9b3eeSRoland Mainz m = 2;
34634f9b3eeSRoland Mainz w = 's';
34734f9b3eeSRoland Mainz break;
34834f9b3eeSRoland Mainz }
34934f9b3eeSRoland Mainz switch (m)
35034f9b3eeSRoland Mainz {
35134f9b3eeSRoland Mainz case 0:
35234f9b3eeSRoland Mainz m = 1;
35334f9b3eeSRoland Mainz if (q > 1)
35434f9b3eeSRoland Mainz tm->tm_sec += (3042L*24L*60L*60L) * p / q / 100L;
35534f9b3eeSRoland Mainz else
35634f9b3eeSRoland Mainz tm->tm_mon += p;
35734f9b3eeSRoland Mainz break;
35834f9b3eeSRoland Mainz case 1:
35934f9b3eeSRoland Mainz m = 2;
36034f9b3eeSRoland Mainz if (q > 1)
36134f9b3eeSRoland Mainz tm->tm_sec += (60L) * p / q;
36234f9b3eeSRoland Mainz else
36334f9b3eeSRoland Mainz tm->tm_min += p;
36434f9b3eeSRoland Mainz break;
36534f9b3eeSRoland Mainz default:
36634f9b3eeSRoland Mainz if (q > 1)
36734f9b3eeSRoland Mainz powerize(tm, p, q, 1000UL);
36834f9b3eeSRoland Mainz else
36934f9b3eeSRoland Mainz tm->tm_nsec += p * 1000000L;
37034f9b3eeSRoland Mainz break;
37134f9b3eeSRoland Mainz }
37234f9b3eeSRoland Mainz P_INIT(w);
37334f9b3eeSRoland Mainz continue;
37434f9b3eeSRoland Mainz case 'W':
37534f9b3eeSRoland Mainz case 'w':
37634f9b3eeSRoland Mainz m = 0;
37734f9b3eeSRoland Mainz if (q > 1)
37834f9b3eeSRoland Mainz tm->tm_sec += (7L*24L*60L*60L) * p / q;
37934f9b3eeSRoland Mainz else
38034f9b3eeSRoland Mainz tm->tm_mday += 7 * p;
38134f9b3eeSRoland Mainz P_INIT('D');
38234f9b3eeSRoland Mainz continue;
38334f9b3eeSRoland Mainz case 'D':
38434f9b3eeSRoland Mainz case 'd':
38534f9b3eeSRoland Mainz m = 0;
38634f9b3eeSRoland Mainz if (q > 1)
38734f9b3eeSRoland Mainz tm->tm_sec += (24L*60L*60L) * p / q;
38834f9b3eeSRoland Mainz else
38934f9b3eeSRoland Mainz tm->tm_mday += p;
39034f9b3eeSRoland Mainz P_INIT('H');
39134f9b3eeSRoland Mainz continue;
39234f9b3eeSRoland Mainz case 'H':
39334f9b3eeSRoland Mainz case 'h':
39434f9b3eeSRoland Mainz m = 1;
39534f9b3eeSRoland Mainz if (q > 1)
39634f9b3eeSRoland Mainz tm->tm_sec += (60L*60L) * p / q;
39734f9b3eeSRoland Mainz else
39834f9b3eeSRoland Mainz tm->tm_hour += p;
39934f9b3eeSRoland Mainz P_INIT('m');
40034f9b3eeSRoland Mainz continue;
40134f9b3eeSRoland Mainz case 'S':
40234f9b3eeSRoland Mainz case 's':
40334f9b3eeSRoland Mainz m = 2;
40434f9b3eeSRoland Mainz /*FALLTHROUGH*/
40534f9b3eeSRoland Mainz case ' ':
40634f9b3eeSRoland Mainz case '_':
40734f9b3eeSRoland Mainz case '\n':
40834f9b3eeSRoland Mainz case '\r':
40934f9b3eeSRoland Mainz case '\t':
41034f9b3eeSRoland Mainz case '\v':
41134f9b3eeSRoland Mainz if (q > 1)
41234f9b3eeSRoland Mainz powerize(tm, p, q, 1000000000UL);
41334f9b3eeSRoland Mainz else
41434f9b3eeSRoland Mainz tm->tm_sec += p;
41534f9b3eeSRoland Mainz P_INIT('U');
41634f9b3eeSRoland Mainz continue;
41734f9b3eeSRoland Mainz case 'U':
41834f9b3eeSRoland Mainz case 'u':
41934f9b3eeSRoland Mainz switch (*(s + 1))
42034f9b3eeSRoland Mainz {
42134f9b3eeSRoland Mainz case 'S':
42234f9b3eeSRoland Mainz case 's':
42334f9b3eeSRoland Mainz s++;
42434f9b3eeSRoland Mainz break;
42534f9b3eeSRoland Mainz }
42634f9b3eeSRoland Mainz m = 0;
42734f9b3eeSRoland Mainz if (q > 1)
42834f9b3eeSRoland Mainz powerize(tm, p, q, 1000000UL);
42934f9b3eeSRoland Mainz else
43034f9b3eeSRoland Mainz tm->tm_nsec += p * 1000L;
43134f9b3eeSRoland Mainz P_INIT('N');
43234f9b3eeSRoland Mainz continue;
43334f9b3eeSRoland Mainz case 'N':
43434f9b3eeSRoland Mainz case 'n':
43534f9b3eeSRoland Mainz switch (*(s + 1))
43634f9b3eeSRoland Mainz {
43734f9b3eeSRoland Mainz case 'S':
43834f9b3eeSRoland Mainz case 's':
43934f9b3eeSRoland Mainz s++;
44034f9b3eeSRoland Mainz break;
44134f9b3eeSRoland Mainz }
44234f9b3eeSRoland Mainz m = 0;
44334f9b3eeSRoland Mainz if (q > 1)
44434f9b3eeSRoland Mainz powerize(tm, p, q, 1000000000UL);
44534f9b3eeSRoland Mainz else
44634f9b3eeSRoland Mainz tm->tm_nsec += p;
44734f9b3eeSRoland Mainz P_INIT('Y');
44834f9b3eeSRoland Mainz continue;
44934f9b3eeSRoland Mainz case '.':
45034f9b3eeSRoland Mainz if (q)
45134f9b3eeSRoland Mainz goto exact;
45234f9b3eeSRoland Mainz q = 1;
45334f9b3eeSRoland Mainz continue;
45434f9b3eeSRoland Mainz case '-':
45534f9b3eeSRoland Mainz c = 'M';
45634f9b3eeSRoland Mainz u = (char*)s++;
45734f9b3eeSRoland Mainz while (*++u && *u != ':')
45834f9b3eeSRoland Mainz if (*u == '-')
45934f9b3eeSRoland Mainz {
46034f9b3eeSRoland Mainz c = 'Y';
46134f9b3eeSRoland Mainz break;
46234f9b3eeSRoland Mainz }
46334f9b3eeSRoland Mainz goto duration_next;
46434f9b3eeSRoland Mainz case ':':
46534f9b3eeSRoland Mainz c = 'm';
46634f9b3eeSRoland Mainz u = (char*)s++;
46734f9b3eeSRoland Mainz while (*++u)
46834f9b3eeSRoland Mainz if (*u == ':')
46934f9b3eeSRoland Mainz {
47034f9b3eeSRoland Mainz c = 'H';
47134f9b3eeSRoland Mainz break;
47234f9b3eeSRoland Mainz }
47334f9b3eeSRoland Mainz goto duration_next;
47434f9b3eeSRoland Mainz case '0':
47534f9b3eeSRoland Mainz case '1':
47634f9b3eeSRoland Mainz case '2':
47734f9b3eeSRoland Mainz case '3':
47834f9b3eeSRoland Mainz case '4':
47934f9b3eeSRoland Mainz case '5':
48034f9b3eeSRoland Mainz case '6':
48134f9b3eeSRoland Mainz case '7':
48234f9b3eeSRoland Mainz case '8':
48334f9b3eeSRoland Mainz case '9':
48434f9b3eeSRoland Mainz q *= 10;
48534f9b3eeSRoland Mainz p = p * 10 + (c - '0');
48634f9b3eeSRoland Mainz continue;
48734f9b3eeSRoland Mainz default:
48834f9b3eeSRoland Mainz exact:
48934f9b3eeSRoland Mainz *tm = otm;
49034f9b3eeSRoland Mainz s = (const char*)t + 1;
49134f9b3eeSRoland Mainz if (*t == 'p')
49234f9b3eeSRoland Mainz {
49334f9b3eeSRoland Mainz state |= HOLD|EXACT;
49434f9b3eeSRoland Mainz set &= ~(EXACT|LAST|NEXT|THIS);
49534f9b3eeSRoland Mainz set |= state & (EXACT|LAST|NEXT|THIS);
49634f9b3eeSRoland Mainz }
49734f9b3eeSRoland Mainz goto again;
49834f9b3eeSRoland Mainz }
49934f9b3eeSRoland Mainz break;
50034f9b3eeSRoland Mainz } while (c);
50134f9b3eeSRoland Mainz continue;
50234f9b3eeSRoland Mainz }
503da2e3ebdSchin f = -1;
504da2e3ebdSchin if (*s == '+')
505da2e3ebdSchin {
506da2e3ebdSchin while (isspace(*++s) || *s == '_');
507da2e3ebdSchin n = strtol(s, &t, 0);
508da2e3ebdSchin if (w = t - s)
509da2e3ebdSchin {
510da2e3ebdSchin for (s = t; skip[*s]; s++);
511da2e3ebdSchin state |= (f = n) ? NEXT : THIS;
512da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
513da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
514da2e3ebdSchin }
515da2e3ebdSchin else
516da2e3ebdSchin s = last;
517da2e3ebdSchin }
518da2e3ebdSchin if (!(state & CRON))
519da2e3ebdSchin {
520da2e3ebdSchin /*
521da2e3ebdSchin * check for cron date
522da2e3ebdSchin *
523da2e3ebdSchin * min hour day-of-month month day-of-week
524da2e3ebdSchin *
525da2e3ebdSchin * if it's cron then determine the next time
526da2e3ebdSchin * that satisfies the specification
527da2e3ebdSchin *
528da2e3ebdSchin * NOTE: the only spacing is ' '||'_'||';'
529da2e3ebdSchin */
530da2e3ebdSchin
531da2e3ebdSchin i = 0;
532da2e3ebdSchin n = *(t = (char*)s);
533da2e3ebdSchin for (;;)
534da2e3ebdSchin {
535da2e3ebdSchin if (n == '*')
536da2e3ebdSchin n = *++s;
537da2e3ebdSchin else if (!isdigit(n))
538da2e3ebdSchin break;
539da2e3ebdSchin else
540da2e3ebdSchin while ((n = *++s) == ',' || n == '-' || n == '/' || isdigit(n));
541da2e3ebdSchin if (n != ' ' && n != '_' && n != ';')
542da2e3ebdSchin {
543da2e3ebdSchin if (!n)
544da2e3ebdSchin i++;
545da2e3ebdSchin break;
546da2e3ebdSchin }
547da2e3ebdSchin i++;
548da2e3ebdSchin while ((n = *++s) == ' ' || n == '_');
549da2e3ebdSchin }
550da2e3ebdSchin if (i == 5)
551da2e3ebdSchin {
552da2e3ebdSchin Time_t tt;
553da2e3ebdSchin char hit[60];
5547c2fbfb3SApril Chin char mon[13];
555da2e3ebdSchin char day[7];
556da2e3ebdSchin
557da2e3ebdSchin state |= CRON;
558da2e3ebdSchin flags = 0;
559da2e3ebdSchin tm->tm_sec = 0;
560da2e3ebdSchin tm->tm_min++;
561da2e3ebdSchin tmfix(tm);
562da2e3ebdSchin
563da2e3ebdSchin /*
564da2e3ebdSchin * minute
565da2e3ebdSchin */
566da2e3ebdSchin
567da2e3ebdSchin if ((k = range(t, &t, hit, 0, 59)) < 0)
568da2e3ebdSchin break;
569da2e3ebdSchin if (k && !hit[i = tm->tm_min])
570da2e3ebdSchin {
571da2e3ebdSchin hit[i] = 1;
572da2e3ebdSchin do if (++i > 59)
573da2e3ebdSchin {
574da2e3ebdSchin i = 0;
575da2e3ebdSchin if (++tm->tm_hour > 59)
576da2e3ebdSchin {
577da2e3ebdSchin tm->tm_min = i;
578da2e3ebdSchin tmfix(tm);
579da2e3ebdSchin }
580da2e3ebdSchin } while (!hit[i]);
581da2e3ebdSchin tm->tm_min = i;
582da2e3ebdSchin }
583da2e3ebdSchin
584da2e3ebdSchin /*
585da2e3ebdSchin * hour
586da2e3ebdSchin */
587da2e3ebdSchin
588da2e3ebdSchin if ((k = range(t, &t, hit, 0, 23)) < 0)
589da2e3ebdSchin break;
590da2e3ebdSchin if (k && !hit[i = tm->tm_hour])
591da2e3ebdSchin {
592da2e3ebdSchin hit[i] = 1;
593da2e3ebdSchin do if (++i > 23)
594da2e3ebdSchin {
595da2e3ebdSchin i = 0;
596da2e3ebdSchin if (++tm->tm_mday > 28)
597da2e3ebdSchin {
598da2e3ebdSchin tm->tm_hour = i;
599da2e3ebdSchin tmfix(tm);
600da2e3ebdSchin }
601da2e3ebdSchin } while (!hit[i]);
602da2e3ebdSchin tm->tm_hour = i;
603da2e3ebdSchin }
604da2e3ebdSchin
605da2e3ebdSchin /*
606da2e3ebdSchin * day of month
607da2e3ebdSchin */
608da2e3ebdSchin
609da2e3ebdSchin if ((k = range(t, &t, hit, 1, 31)) < 0)
610da2e3ebdSchin break;
611da2e3ebdSchin if (k)
612da2e3ebdSchin flags |= DAY|MDAY;
613da2e3ebdSchin
614da2e3ebdSchin /*
615da2e3ebdSchin * month
616da2e3ebdSchin */
617da2e3ebdSchin
618da2e3ebdSchin if ((k = range(t, &t, mon, 1, 12)) < 0)
619da2e3ebdSchin break;
620da2e3ebdSchin if (k)
621da2e3ebdSchin flags |= MONTH;
622da2e3ebdSchin else
623da2e3ebdSchin for (i = 1; i <= 12; i++)
624da2e3ebdSchin mon[i] = 1;
625da2e3ebdSchin
626da2e3ebdSchin /*
627da2e3ebdSchin * day of week
628da2e3ebdSchin */
629da2e3ebdSchin
630da2e3ebdSchin if ((k = range(t, &t, day, 0, 6)) < 0)
631da2e3ebdSchin break;
632da2e3ebdSchin if (k)
633da2e3ebdSchin flags |= WDAY;
634da2e3ebdSchin s = t;
635da2e3ebdSchin if (flags & (MONTH|MDAY|WDAY))
636da2e3ebdSchin {
637da2e3ebdSchin fix = tmxtime(tm, zone);
63834f9b3eeSRoland Mainz tm = tmxtm(tm, fix, tm->tm_zone);
639da2e3ebdSchin i = tm->tm_mon + 1;
640da2e3ebdSchin j = tm->tm_mday;
641da2e3ebdSchin k = tm->tm_wday;
642da2e3ebdSchin for (;;)
643da2e3ebdSchin {
644da2e3ebdSchin if (!mon[i])
645da2e3ebdSchin {
646da2e3ebdSchin if (++i > 12)
647da2e3ebdSchin {
648da2e3ebdSchin i = 1;
649da2e3ebdSchin tm->tm_year++;
650da2e3ebdSchin }
651da2e3ebdSchin tm->tm_mon = i - 1;
652da2e3ebdSchin tm->tm_mday = 1;
653da2e3ebdSchin tt = tmxtime(tm, zone);
654da2e3ebdSchin if (tt < fix)
655da2e3ebdSchin goto done;
65634f9b3eeSRoland Mainz tm = tmxtm(tm, tt, tm->tm_zone);
657da2e3ebdSchin i = tm->tm_mon + 1;
658da2e3ebdSchin j = tm->tm_mday;
659da2e3ebdSchin k = tm->tm_wday;
660da2e3ebdSchin continue;
661da2e3ebdSchin }
662da2e3ebdSchin if (flags & (MDAY|WDAY))
663da2e3ebdSchin {
664da2e3ebdSchin if ((flags & (MDAY|WDAY)) == (MDAY|WDAY))
665da2e3ebdSchin {
666da2e3ebdSchin if (hit[j] && day[k])
667da2e3ebdSchin break;
668da2e3ebdSchin }
669da2e3ebdSchin else if ((flags & MDAY) && hit[j])
670da2e3ebdSchin break;
671da2e3ebdSchin else if ((flags & WDAY) && day[k])
672da2e3ebdSchin break;
673da2e3ebdSchin if (++j > 28)
674da2e3ebdSchin {
675da2e3ebdSchin tm->tm_mon = i - 1;
676da2e3ebdSchin tm->tm_mday = j;
67734f9b3eeSRoland Mainz tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
678da2e3ebdSchin i = tm->tm_mon + 1;
679da2e3ebdSchin j = tm->tm_mday;
680da2e3ebdSchin k = tm->tm_wday;
681da2e3ebdSchin }
682da2e3ebdSchin else if ((flags & WDAY) && ++k > 6)
683da2e3ebdSchin k = 0;
684da2e3ebdSchin }
685da2e3ebdSchin else if (flags & MONTH)
686da2e3ebdSchin break;
687da2e3ebdSchin }
688da2e3ebdSchin tm->tm_mon = i - 1;
689da2e3ebdSchin tm->tm_mday = j;
690da2e3ebdSchin tm->tm_wday = k;
691da2e3ebdSchin }
692da2e3ebdSchin continue;
693da2e3ebdSchin }
694da2e3ebdSchin s = t;
695da2e3ebdSchin }
696da2e3ebdSchin n = -1;
697da2e3ebdSchin if (isdigit(*s))
698da2e3ebdSchin {
699da2e3ebdSchin n = strtol(s, &t, 10);
700da2e3ebdSchin if ((w = t - s) && *t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && isdigit(*(t + 3)))
701da2e3ebdSchin {
702da2e3ebdSchin now = n;
703da2e3ebdSchin goto sns;
704da2e3ebdSchin }
7057c2fbfb3SApril Chin if ((*t == 'T' || *t == 't') && ((set|state) & (YEAR|MONTH|DAY)) == (YEAR|MONTH) && isdigit(*(t + 1)))
7067c2fbfb3SApril Chin t++;
707da2e3ebdSchin u = t + (*t == '-');
708da2e3ebdSchin if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1)))
709da2e3ebdSchin {
710da2e3ebdSchin if (w == 4)
711da2e3ebdSchin {
712da2e3ebdSchin if ((n -= 1900) < TM_WINDOW)
713da2e3ebdSchin break;
714da2e3ebdSchin }
715da2e3ebdSchin else if (n < TM_WINDOW)
716da2e3ebdSchin n += 100;
717da2e3ebdSchin m = n;
7187c2fbfb3SApril Chin n = strtol(++u, &t, 10);
7197c2fbfb3SApril Chin if ((i = (t - u)) < 2 || i > 3)
720da2e3ebdSchin break;
7217c2fbfb3SApril Chin if (i == 3)
7227c2fbfb3SApril Chin {
7237c2fbfb3SApril Chin k = n % 10;
7247c2fbfb3SApril Chin n /= 10;
7257c2fbfb3SApril Chin }
7267c2fbfb3SApril Chin else if (*t != '-')
727da2e3ebdSchin k = 1;
7287c2fbfb3SApril Chin else if (*++t && dig1(t, k) < 1 || k > 7)
729da2e3ebdSchin break;
7307c2fbfb3SApril Chin if (n < 0 || n > 53)
7317c2fbfb3SApril Chin break;
7327c2fbfb3SApril Chin if (k == 7)
733da2e3ebdSchin k = 0;
734da2e3ebdSchin tm->tm_year = m;
7357c2fbfb3SApril Chin tmweek(tm, 2, n, k);
736da2e3ebdSchin set |= YEAR|MONTH|DAY;
7377c2fbfb3SApril Chin s = t;
738da2e3ebdSchin continue;
739da2e3ebdSchin }
7407c2fbfb3SApril Chin else if (w == 6 || w == 8 && (n / 1000000) > 12)
741da2e3ebdSchin {
7427c2fbfb3SApril Chin t = (char*)s;
743da2e3ebdSchin flags = 0;
7447c2fbfb3SApril Chin if (w == 8 || w == 6 && *u != 'T' && *u != 't')
745da2e3ebdSchin {
7467c2fbfb3SApril Chin dig4(t, m);
747da2e3ebdSchin if ((m -= 1900) < TM_WINDOW)
748da2e3ebdSchin break;
749da2e3ebdSchin }
750da2e3ebdSchin else
751da2e3ebdSchin {
7527c2fbfb3SApril Chin dig2(t, m);
753da2e3ebdSchin if (m < TM_WINDOW)
754da2e3ebdSchin m += 100;
755da2e3ebdSchin }
756da2e3ebdSchin flags |= YEAR;
7577c2fbfb3SApril Chin if (dig2(t, l) <= 0 || l > 12)
758da2e3ebdSchin break;
759da2e3ebdSchin flags |= MONTH;
7607c2fbfb3SApril Chin if (*t != 'T' && *t != 't' || !isdigit(*++t))
7617c2fbfb3SApril Chin {
7627c2fbfb3SApril Chin if (w == 6)
7637c2fbfb3SApril Chin goto save_yymm;
7647c2fbfb3SApril Chin if (dig2(t, k) < 1 || k > 31)
765da2e3ebdSchin break;
7667c2fbfb3SApril Chin flags |= DAY;
7677c2fbfb3SApril Chin goto save_yymmdd;
7687c2fbfb3SApril Chin }
7697c2fbfb3SApril Chin n = strtol(s = t, &t, 0);
770da2e3ebdSchin if ((t - s) < 2)
771da2e3ebdSchin break;
772da2e3ebdSchin if (dig2(s, j) > 24)
773da2e3ebdSchin break;
774da2e3ebdSchin if ((t - s) < 2)
775da2e3ebdSchin {
776da2e3ebdSchin if ((t - s) == 1 || *t++ != '-')
777da2e3ebdSchin break;
778da2e3ebdSchin n = strtol(s = t, &t, 0);
779da2e3ebdSchin if ((t - s) < 2)
780da2e3ebdSchin break;
781da2e3ebdSchin }
782da2e3ebdSchin if (dig2(s, i) > 59)
783da2e3ebdSchin break;
784da2e3ebdSchin flags |= HOUR|MINUTE;
785da2e3ebdSchin if ((t - s) == 2)
786da2e3ebdSchin {
787da2e3ebdSchin if (dig2(s, n) > (59 + TM_MAXLEAP))
788da2e3ebdSchin break;
789da2e3ebdSchin flags |= SECOND;
790da2e3ebdSchin }
791da2e3ebdSchin else if (t - s)
792da2e3ebdSchin break;
793da2e3ebdSchin else
794da2e3ebdSchin n = 0;
795da2e3ebdSchin p = 0;
796da2e3ebdSchin if (*t == '.')
797da2e3ebdSchin {
798da2e3ebdSchin q = 1000000000;
799da2e3ebdSchin while (isdigit(*++t))
800da2e3ebdSchin p += (*t - '0') * (q /= 10);
801da2e3ebdSchin set |= NSEC;
802da2e3ebdSchin }
803da2e3ebdSchin if (n > (59 + TM_MAXLEAP))
804da2e3ebdSchin break;
805da2e3ebdSchin goto save;
806da2e3ebdSchin }
807da2e3ebdSchin else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0)
808da2e3ebdSchin {
8097c2fbfb3SApril Chin message((-1, "AHA#%d n=%d", __LINE__, n));
810da2e3ebdSchin ordinal:
8117c2fbfb3SApril Chin if (n)
8127c2fbfb3SApril Chin n--;
8137c2fbfb3SApril Chin message((-1, "AHA#%d n=%d", __LINE__, n));
8147c2fbfb3SApril Chin state |= ((f = n) ? NEXT : THIS)|ORDINAL;
815da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
816da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
817da2e3ebdSchin for (s = t; skip[*s]; s++);
818da2e3ebdSchin if (isdigit(*s))
819da2e3ebdSchin {
8207c2fbfb3SApril Chin if (n = strtol(s, &t, 10))
8217c2fbfb3SApril Chin n--;
822da2e3ebdSchin s = t;
823da2e3ebdSchin if (*s == '_')
824da2e3ebdSchin s++;
825da2e3ebdSchin }
826da2e3ebdSchin else
827da2e3ebdSchin n = -1;
82834f9b3eeSRoland Mainz dir = f;
82934f9b3eeSRoland Mainz message((-1, "AHA#%d f=%d n=%d state=" FFMT, __LINE__, f, n, FLAGS(state)));
830da2e3ebdSchin }
831da2e3ebdSchin else
832da2e3ebdSchin {
833da2e3ebdSchin 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))
834da2e3ebdSchin {
835da2e3ebdSchin /*
836da2e3ebdSchin * various { date(1) touch(1) } formats
837da2e3ebdSchin *
838da2e3ebdSchin * [[cc]yy[mm]]ddhhmm[.ss[.nn...]]
839da2e3ebdSchin * [cc]yyjjj
840da2e3ebdSchin * hhmm[.ss[.nn...]]
841da2e3ebdSchin */
842da2e3ebdSchin
843da2e3ebdSchin flags = 0;
844da2e3ebdSchin if (state & CCYYMMDDHHMMSS)
845da2e3ebdSchin break;
846da2e3ebdSchin state |= CCYYMMDDHHMMSS;
847da2e3ebdSchin p = 0;
8487c2fbfb3SApril Chin if ((i == 7 || i == 5) && (!*t || *t == 'Z' || *t == 'z'))
849da2e3ebdSchin {
850da2e3ebdSchin if (i == 7)
851da2e3ebdSchin {
852da2e3ebdSchin dig4(s, m);
853da2e3ebdSchin if ((m -= 1900) < TM_WINDOW)
854da2e3ebdSchin break;
855da2e3ebdSchin }
856da2e3ebdSchin else if (dig2(s, m) < TM_WINDOW)
857da2e3ebdSchin m += 100;
858da2e3ebdSchin dig3(s, k);
859da2e3ebdSchin l = 1;
860da2e3ebdSchin j = 0;
861da2e3ebdSchin i = 0;
862da2e3ebdSchin n = 0;
863da2e3ebdSchin flags |= MONTH;
864da2e3ebdSchin }
865da2e3ebdSchin else if (i & 1)
866da2e3ebdSchin break;
867da2e3ebdSchin else
868da2e3ebdSchin {
869da2e3ebdSchin u = t;
870da2e3ebdSchin if (i == 12)
871da2e3ebdSchin {
872da2e3ebdSchin x = s;
873da2e3ebdSchin dig2(x, m);
874da2e3ebdSchin if (m <= 12)
875da2e3ebdSchin {
876da2e3ebdSchin u -= 4;
877da2e3ebdSchin i -= 4;
878da2e3ebdSchin x = s + 8;
879da2e3ebdSchin dig4(x, m);
880da2e3ebdSchin }
881da2e3ebdSchin else
882da2e3ebdSchin dig4(s, m);
88334f9b3eeSRoland Mainz if (m < 1969 || m >= 3000)
88434f9b3eeSRoland Mainz break;
885da2e3ebdSchin m -= 1900;
886da2e3ebdSchin }
887da2e3ebdSchin else if (i == 10)
888da2e3ebdSchin {
889da2e3ebdSchin x = s;
890da2e3ebdSchin 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))
891da2e3ebdSchin dig2(s, m);
892da2e3ebdSchin else
893da2e3ebdSchin {
894da2e3ebdSchin u -= 2;
895da2e3ebdSchin i -= 2;
896da2e3ebdSchin x = s + 8;
897da2e3ebdSchin dig2(x, m);
898da2e3ebdSchin }
899da2e3ebdSchin if (m < TM_WINDOW)
900da2e3ebdSchin m += 100;
901da2e3ebdSchin }
902da2e3ebdSchin else
903da2e3ebdSchin m = tm->tm_year;
904da2e3ebdSchin if ((u - s) < 8)
905da2e3ebdSchin l = tm->tm_mon + 1;
906da2e3ebdSchin else if (dig2(s, l) <= 0 || l > 12)
907da2e3ebdSchin break;
908da2e3ebdSchin else
909da2e3ebdSchin flags |= MONTH;
910da2e3ebdSchin if ((u - s) < 6)
911da2e3ebdSchin k = tm->tm_mday;
912da2e3ebdSchin else if (dig2(s, k) < 1 || k > 31)
913da2e3ebdSchin break;
914da2e3ebdSchin else
915da2e3ebdSchin flags |= DAY;
916da2e3ebdSchin if ((u - s) < 4)
917da2e3ebdSchin break;
918da2e3ebdSchin if (dig2(s, j) > 24)
919da2e3ebdSchin break;
920da2e3ebdSchin if (dig2(s, i) > 59)
921da2e3ebdSchin break;
922da2e3ebdSchin flags |= HOUR|MINUTE;
923da2e3ebdSchin if ((u - s) == 2)
924da2e3ebdSchin {
925da2e3ebdSchin dig2(s, n);
926da2e3ebdSchin flags |= SECOND;
927da2e3ebdSchin }
928da2e3ebdSchin else if (u - s)
929da2e3ebdSchin break;
930da2e3ebdSchin else if (*t != '.')
931da2e3ebdSchin n = 0;
932da2e3ebdSchin else
933da2e3ebdSchin {
934da2e3ebdSchin n = strtol(t + 1, &t, 10);
935da2e3ebdSchin flags |= SECOND;
936da2e3ebdSchin if (*t == '.')
937da2e3ebdSchin {
938da2e3ebdSchin q = 1000000000;
939da2e3ebdSchin while (isdigit(*++t))
940da2e3ebdSchin p += (*t - '0') * (q /= 10);
941da2e3ebdSchin set |= NSEC;
942da2e3ebdSchin }
943da2e3ebdSchin }
944da2e3ebdSchin if (n > (59 + TM_MAXLEAP))
945da2e3ebdSchin break;
946da2e3ebdSchin }
947da2e3ebdSchin save:
948da2e3ebdSchin tm->tm_hour = j;
949da2e3ebdSchin tm->tm_min = i;
950da2e3ebdSchin tm->tm_sec = n;
951da2e3ebdSchin tm->tm_nsec = p;
9527c2fbfb3SApril Chin save_yymmdd:
9537c2fbfb3SApril Chin tm->tm_mday = k;
9547c2fbfb3SApril Chin save_yymm:
9557c2fbfb3SApril Chin tm->tm_mon = l - 1;
9567c2fbfb3SApril Chin tm->tm_year = m;
957da2e3ebdSchin s = t;
958da2e3ebdSchin set |= flags;
959da2e3ebdSchin continue;
960da2e3ebdSchin }
961da2e3ebdSchin for (s = t; skip[*s]; s++);
962da2e3ebdSchin if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY))
963da2e3ebdSchin {
964da2e3ebdSchin c = *s;
965da2e3ebdSchin if ((state & HOUR) || n > 24)
966da2e3ebdSchin break;
967da2e3ebdSchin while (isspace(*++s) || *s == '_');
968da2e3ebdSchin if (!isdigit(*s))
969da2e3ebdSchin break;
970da2e3ebdSchin i = n;
971da2e3ebdSchin n = strtol(s, &t, 10);
972da2e3ebdSchin for (s = t; isspace(*s) || *s == '_'; s++);
973da2e3ebdSchin if (n > 59)
974da2e3ebdSchin break;
975da2e3ebdSchin j = n;
976da2e3ebdSchin m = 0;
977da2e3ebdSchin if (*s == c)
978da2e3ebdSchin {
979da2e3ebdSchin while (isspace(*++s) || *s == '_');
980da2e3ebdSchin if (!isdigit(*s))
981da2e3ebdSchin break;
982da2e3ebdSchin n = strtol(s, &t, 10);
983da2e3ebdSchin s = t;
984da2e3ebdSchin if (n > (59 + TM_MAXLEAP))
985da2e3ebdSchin break;
986da2e3ebdSchin set |= SECOND;
987da2e3ebdSchin while (isspace(*s))
988da2e3ebdSchin s++;
989da2e3ebdSchin if (*s == '.')
990da2e3ebdSchin {
991da2e3ebdSchin q = 1000000000;
992da2e3ebdSchin while (isdigit(*++s))
993da2e3ebdSchin m += (*s - '0') * (q /= 10);
994da2e3ebdSchin set |= NSEC;
995da2e3ebdSchin }
996da2e3ebdSchin }
997da2e3ebdSchin else
998da2e3ebdSchin n = 0;
999da2e3ebdSchin set |= HOUR|MINUTE;
1000da2e3ebdSchin skip[':'] = 1;
1001da2e3ebdSchin k = tm->tm_hour;
1002da2e3ebdSchin tm->tm_hour = i;
1003da2e3ebdSchin l = tm->tm_min;
1004da2e3ebdSchin tm->tm_min = j;
1005da2e3ebdSchin tm->tm_sec = n;
1006da2e3ebdSchin tm->tm_nsec = m;
1007da2e3ebdSchin while (isspace(*s))
1008da2e3ebdSchin s++;
1009da2e3ebdSchin switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2))
1010da2e3ebdSchin {
1011da2e3ebdSchin case TM_MERIDIAN:
1012da2e3ebdSchin s = t;
1013da2e3ebdSchin if (i == 12)
1014da2e3ebdSchin tm->tm_hour = i = 0;
1015da2e3ebdSchin break;
1016da2e3ebdSchin case TM_MERIDIAN+1:
1017da2e3ebdSchin if (i < 12)
1018da2e3ebdSchin tm->tm_hour = i += 12;
1019da2e3ebdSchin break;
1020da2e3ebdSchin }
1021da2e3ebdSchin if (f >= 0 || (state & (LAST|NEXT)))
1022da2e3ebdSchin {
10237c2fbfb3SApril Chin message((-1, "AHA#%d f=%d i=%d j=%d k=%d l=%d", __LINE__, f, i, j, k, l));
1024da2e3ebdSchin state &= ~HOLD;
1025da2e3ebdSchin if (f < 0)
1026da2e3ebdSchin {
1027da2e3ebdSchin if (state & LAST)
1028da2e3ebdSchin f = -1;
1029da2e3ebdSchin else if (state & NEXT)
1030da2e3ebdSchin f = 1;
1031da2e3ebdSchin else
1032da2e3ebdSchin f = 0;
1033da2e3ebdSchin }
1034da2e3ebdSchin if (f > 0)
1035da2e3ebdSchin {
1036da2e3ebdSchin if (i > k || i == k && j > l)
1037da2e3ebdSchin f--;
1038da2e3ebdSchin }
1039da2e3ebdSchin else if (i < k || i == k && j < l)
1040da2e3ebdSchin f++;
1041da2e3ebdSchin if (f > 0)
1042da2e3ebdSchin {
1043da2e3ebdSchin tm->tm_hour += f * 24;
1044da2e3ebdSchin while (tm->tm_hour >= 24)
1045da2e3ebdSchin {
1046da2e3ebdSchin tm->tm_hour -= 24;
1047da2e3ebdSchin tm->tm_mday++;
1048da2e3ebdSchin }
1049da2e3ebdSchin }
1050da2e3ebdSchin else if (f < 0)
1051da2e3ebdSchin {
1052da2e3ebdSchin tm->tm_hour += f * 24;
1053da2e3ebdSchin while (tm->tm_hour < 24)
1054da2e3ebdSchin {
1055da2e3ebdSchin tm->tm_hour += 24;
1056da2e3ebdSchin tm->tm_mday--;
1057da2e3ebdSchin }
1058da2e3ebdSchin }
1059da2e3ebdSchin }
1060da2e3ebdSchin continue;
1061da2e3ebdSchin }
1062da2e3ebdSchin }
1063da2e3ebdSchin }
1064da2e3ebdSchin for (;;)
1065da2e3ebdSchin {
1066da2e3ebdSchin if (*s == '-' || *s == '+')
1067da2e3ebdSchin {
1068da2e3ebdSchin 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))))
1069da2e3ebdSchin break;
1070da2e3ebdSchin s++;
1071da2e3ebdSchin }
1072da2e3ebdSchin else if (skip[*s])
1073da2e3ebdSchin s++;
1074da2e3ebdSchin else
1075da2e3ebdSchin break;
1076da2e3ebdSchin }
107734f9b3eeSRoland Mainz if (isalpha(*s))
107834f9b3eeSRoland Mainz {
107934f9b3eeSRoland Mainz if (n > 0)
108034f9b3eeSRoland Mainz {
108134f9b3eeSRoland Mainz x = s;
108234f9b3eeSRoland Mainz q = *s++;
108334f9b3eeSRoland Mainz if (isalpha(*s))
108434f9b3eeSRoland Mainz {
108534f9b3eeSRoland Mainz q <<= 8;
108634f9b3eeSRoland Mainz q |= *s++;
108734f9b3eeSRoland Mainz if (isalpha(*s))
108834f9b3eeSRoland Mainz {
108934f9b3eeSRoland Mainz if (tmlex(s, &t, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES, NiL, 0) >= 0)
109034f9b3eeSRoland Mainz s = t;
109134f9b3eeSRoland Mainz if (isalpha(*s))
109234f9b3eeSRoland Mainz {
109334f9b3eeSRoland Mainz q <<= 8;
109434f9b3eeSRoland Mainz q |= *s++;
109534f9b3eeSRoland Mainz if (isalpha(*s))
109634f9b3eeSRoland Mainz {
109734f9b3eeSRoland Mainz q <<= 8;
109834f9b3eeSRoland Mainz q |= *s++;
109934f9b3eeSRoland Mainz if (isalpha(*s))
110034f9b3eeSRoland Mainz q = 0;
110134f9b3eeSRoland Mainz }
110234f9b3eeSRoland Mainz }
110334f9b3eeSRoland Mainz }
110434f9b3eeSRoland Mainz }
110534f9b3eeSRoland Mainz switch (q)
110634f9b3eeSRoland Mainz {
110734f9b3eeSRoland Mainz case K1('y'):
110834f9b3eeSRoland Mainz case K1('Y'):
110934f9b3eeSRoland Mainz case K2('y','r'):
111034f9b3eeSRoland Mainz case K2('Y','R'):
111134f9b3eeSRoland Mainz tm->tm_year += n;
111234f9b3eeSRoland Mainz set |= YEAR;
111334f9b3eeSRoland Mainz continue;
111434f9b3eeSRoland Mainz case K1('M'):
111534f9b3eeSRoland Mainz case K2('m','o'):
111634f9b3eeSRoland Mainz case K2('M','O'):
111734f9b3eeSRoland Mainz tm->tm_mon += n;
111834f9b3eeSRoland Mainz set |= MONTH;
111934f9b3eeSRoland Mainz continue;
112034f9b3eeSRoland Mainz case K1('w'):
112134f9b3eeSRoland Mainz case K1('W'):
112234f9b3eeSRoland Mainz case K2('w','k'):
112334f9b3eeSRoland Mainz case K2('W','K'):
112434f9b3eeSRoland Mainz tm->tm_mday += n * 7;
112534f9b3eeSRoland Mainz set |= DAY;
112634f9b3eeSRoland Mainz continue;
112734f9b3eeSRoland Mainz case K1('d'):
112834f9b3eeSRoland Mainz case K1('D'):
112934f9b3eeSRoland Mainz case K2('d','a'):
113034f9b3eeSRoland Mainz case K2('d','y'):
113134f9b3eeSRoland Mainz case K2('D','A'):
113234f9b3eeSRoland Mainz case K2('D','Y'):
113334f9b3eeSRoland Mainz tm->tm_mday += n;
113434f9b3eeSRoland Mainz set |= DAY;
113534f9b3eeSRoland Mainz continue;
113634f9b3eeSRoland Mainz case K1('h'):
113734f9b3eeSRoland Mainz case K1('H'):
113834f9b3eeSRoland Mainz case K2('h','r'):
113934f9b3eeSRoland Mainz case K2('H','R'):
114034f9b3eeSRoland Mainz tm->tm_hour += n;
114134f9b3eeSRoland Mainz set |= HOUR;
114234f9b3eeSRoland Mainz continue;
114334f9b3eeSRoland Mainz case K1('m'):
114434f9b3eeSRoland Mainz case K2('m','n'):
114534f9b3eeSRoland Mainz case K2('M','N'):
114634f9b3eeSRoland Mainz tm->tm_min += n;
114734f9b3eeSRoland Mainz set |= MINUTE;
114834f9b3eeSRoland Mainz continue;
114934f9b3eeSRoland Mainz case K1('s'):
115034f9b3eeSRoland Mainz case K2('s','c'):
115134f9b3eeSRoland Mainz case K1('S'):
115234f9b3eeSRoland Mainz case K2('S','C'):
115334f9b3eeSRoland Mainz tm->tm_sec += n;
115434f9b3eeSRoland Mainz set |= SECOND;
115534f9b3eeSRoland Mainz continue;
115634f9b3eeSRoland Mainz case K2('m','s'):
115734f9b3eeSRoland Mainz case K3('m','s','c'):
115834f9b3eeSRoland Mainz case K4('m','s','e','c'):
115934f9b3eeSRoland Mainz case K2('M','S'):
116034f9b3eeSRoland Mainz case K3('M','S','C'):
116134f9b3eeSRoland Mainz case K4('M','S','E','C'):
116234f9b3eeSRoland Mainz tm->tm_nsec += n * 1000000L;
116334f9b3eeSRoland Mainz continue;
116434f9b3eeSRoland Mainz case K1('u'):
116534f9b3eeSRoland Mainz case K2('u','s'):
116634f9b3eeSRoland Mainz case K3('u','s','c'):
116734f9b3eeSRoland Mainz case K4('u','s','e','c'):
116834f9b3eeSRoland Mainz case K1('U'):
116934f9b3eeSRoland Mainz case K2('U','S'):
117034f9b3eeSRoland Mainz case K3('U','S','C'):
117134f9b3eeSRoland Mainz case K4('U','S','E','C'):
117234f9b3eeSRoland Mainz tm->tm_nsec += n * 1000L;
117334f9b3eeSRoland Mainz continue;
117434f9b3eeSRoland Mainz case K2('n','s'):
117534f9b3eeSRoland Mainz case K3('n','s','c'):
117634f9b3eeSRoland Mainz case K4('n','s','e','c'):
117734f9b3eeSRoland Mainz case K2('N','S'):
117834f9b3eeSRoland Mainz case K3('N','S','C'):
117934f9b3eeSRoland Mainz case K4('N','S','E','C'):
118034f9b3eeSRoland Mainz tm->tm_nsec += n;
118134f9b3eeSRoland Mainz continue;
118234f9b3eeSRoland Mainz }
118334f9b3eeSRoland Mainz s = x;
118434f9b3eeSRoland Mainz }
118534f9b3eeSRoland Mainz if (n < 1000)
1186da2e3ebdSchin {
1187da2e3ebdSchin if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0)
1188da2e3ebdSchin {
1189da2e3ebdSchin s = t;
1190da2e3ebdSchin switch (tm_data.lex[j])
1191da2e3ebdSchin {
1192da2e3ebdSchin case TM_EXACT:
1193da2e3ebdSchin state |= HOLD|EXACT;
1194da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
1195da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
1196da2e3ebdSchin continue;
1197da2e3ebdSchin case TM_LAST:
1198da2e3ebdSchin state |= HOLD|LAST;
1199da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
1200da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
1201da2e3ebdSchin continue;
1202da2e3ebdSchin case TM_THIS:
1203da2e3ebdSchin state |= HOLD|THIS;
1204da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
1205da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
1206da2e3ebdSchin n = 0;
1207da2e3ebdSchin continue;
1208da2e3ebdSchin case TM_NEXT:
1209da2e3ebdSchin /*
1210da2e3ebdSchin * disambiguate english "last ... in"
1211da2e3ebdSchin */
1212da2e3ebdSchin
1213da2e3ebdSchin if (!((state|set) & LAST))
1214da2e3ebdSchin {
1215da2e3ebdSchin state |= HOLD|NEXT;
1216da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
1217da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
1218da2e3ebdSchin continue;
1219da2e3ebdSchin }
1220da2e3ebdSchin /*FALLTHROUGH*/
1221da2e3ebdSchin case TM_FINAL:
1222da2e3ebdSchin state |= HOLD|THIS|FINAL;
1223da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
1224da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS|FINAL);
1225da2e3ebdSchin continue;
122634f9b3eeSRoland Mainz case TM_WORK:
122734f9b3eeSRoland Mainz message((-1, "AHA#%d WORK", __LINE__));
122834f9b3eeSRoland Mainz state |= WORK;
122934f9b3eeSRoland Mainz set |= DAY;
123034f9b3eeSRoland Mainz if (state & LAST)
123134f9b3eeSRoland Mainz {
123234f9b3eeSRoland Mainz state &= ~LAST;
123334f9b3eeSRoland Mainz set &= ~LAST;
123434f9b3eeSRoland Mainz state |= FINAL;
123534f9b3eeSRoland Mainz set |= FINAL;
123634f9b3eeSRoland Mainz }
123734f9b3eeSRoland Mainz goto clear_hour;
1238da2e3ebdSchin case TM_ORDINAL:
1239da2e3ebdSchin j += TM_ORDINALS - TM_ORDINAL;
12407c2fbfb3SApril Chin message((-1, "AHA#%d j=%d", __LINE__, j));
1241da2e3ebdSchin /*FALLTHROUGH*/
1242da2e3ebdSchin case TM_ORDINALS:
1243da2e3ebdSchin n = j - TM_ORDINALS + 1;
12447c2fbfb3SApril Chin message((-1, "AHA#%d n=%d", __LINE__, n));
1245da2e3ebdSchin goto ordinal;
1246da2e3ebdSchin case TM_MERIDIAN:
1247da2e3ebdSchin if (f >= 0)
1248da2e3ebdSchin f++;
1249da2e3ebdSchin else if (state & LAST)
1250da2e3ebdSchin f = -1;
1251da2e3ebdSchin else if (state & THIS)
1252da2e3ebdSchin f = 1;
1253da2e3ebdSchin else if (state & NEXT)
1254da2e3ebdSchin f = 2;
1255da2e3ebdSchin else
1256da2e3ebdSchin f = 0;
1257da2e3ebdSchin if (n > 0)
1258da2e3ebdSchin {
1259da2e3ebdSchin if (n > 24)
1260da2e3ebdSchin goto done;
1261da2e3ebdSchin tm->tm_hour = n;
1262da2e3ebdSchin }
1263da2e3ebdSchin for (k = tm->tm_hour; k < 0; k += 24);
1264da2e3ebdSchin k %= 24;
1265da2e3ebdSchin if (j == TM_MERIDIAN)
1266da2e3ebdSchin {
1267da2e3ebdSchin if (k == 12)
1268da2e3ebdSchin tm->tm_hour -= 12;
1269da2e3ebdSchin }
1270da2e3ebdSchin else if (k < 12)
1271da2e3ebdSchin tm->tm_hour += 12;
1272da2e3ebdSchin if (n > 0)
1273da2e3ebdSchin goto clear_min;
1274da2e3ebdSchin continue;
1275da2e3ebdSchin case TM_DAY_ABBREV:
1276da2e3ebdSchin j += TM_DAY - TM_DAY_ABBREV;
1277da2e3ebdSchin /*FALLTHROUGH*/
1278da2e3ebdSchin case TM_DAY:
1279da2e3ebdSchin case TM_PARTS:
1280da2e3ebdSchin case TM_HOURS:
1281da2e3ebdSchin state |= set & (EXACT|LAST|NEXT|THIS);
1282da2e3ebdSchin if (!(state & (LAST|NEXT|THIS)))
1283da2e3ebdSchin for (;;)
1284da2e3ebdSchin {
1285da2e3ebdSchin while (skip[*s])
1286da2e3ebdSchin s++;
1287da2e3ebdSchin if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0)
1288da2e3ebdSchin {
1289da2e3ebdSchin s = t;
1290da2e3ebdSchin if (k <= 2)
1291da2e3ebdSchin state |= LAST;
1292da2e3ebdSchin else if (k <= 5)
1293da2e3ebdSchin state |= THIS;
1294da2e3ebdSchin else if (k <= 8)
1295da2e3ebdSchin state |= NEXT;
1296da2e3ebdSchin else
1297da2e3ebdSchin state |= EXACT;
1298da2e3ebdSchin }
1299da2e3ebdSchin else
1300da2e3ebdSchin {
1301da2e3ebdSchin state |= (n > 0) ? NEXT : THIS;
1302da2e3ebdSchin break;
1303da2e3ebdSchin }
1304da2e3ebdSchin set &= ~(EXACT|LAST|NEXT|THIS);
1305da2e3ebdSchin set |= state & (EXACT|LAST|NEXT|THIS);
1306da2e3ebdSchin }
1307da2e3ebdSchin /*FALLTHROUGH*/
1308da2e3ebdSchin case TM_DAYS:
130934f9b3eeSRoland Mainz message((-1, "AHA#%d n=%d j=%d f=%d state=" FFMT, __LINE__, n, j, f, FLAGS(state)));
1310da2e3ebdSchin if (n == -1)
1311da2e3ebdSchin {
1312da2e3ebdSchin /*
1313da2e3ebdSchin * disambiguate english "second"
1314da2e3ebdSchin */
1315da2e3ebdSchin
1316da2e3ebdSchin if (j == TM_PARTS && f == -1)
1317da2e3ebdSchin {
13187c2fbfb3SApril Chin state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/
1319da2e3ebdSchin n = 2;
1320da2e3ebdSchin goto ordinal;
1321da2e3ebdSchin }
1322da2e3ebdSchin n = 1;
1323da2e3ebdSchin }
13247c2fbfb3SApril Chin
13257c2fbfb3SApril Chin /*
13267c2fbfb3SApril Chin * disambiguate "last" vs. { "previous" "final" }
13277c2fbfb3SApril Chin */
13287c2fbfb3SApril Chin
13297c2fbfb3SApril Chin while (isspace(*s))
13307c2fbfb3SApril Chin s++;
13317c2fbfb3SApril Chin message((-1, "AHA#%d disambiguate LAST s='%s'", __LINE__, s));
133234f9b3eeSRoland Mainz 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)
13337c2fbfb3SApril Chin {
13347c2fbfb3SApril Chin s = t;
13357c2fbfb3SApril Chin if (state & LAST)
13367c2fbfb3SApril Chin {
13377c2fbfb3SApril Chin state &= ~LAST;
13387c2fbfb3SApril Chin set &= ~LAST;
13397c2fbfb3SApril Chin state |= FINAL;
13407c2fbfb3SApril Chin set |= FINAL;
13417c2fbfb3SApril Chin message((-1, "AHA#%d LAST => FINAL", __LINE__));
13427c2fbfb3SApril Chin }
13437c2fbfb3SApril Chin else
13447c2fbfb3SApril Chin state &= ~(THIS|NEXT);
13457c2fbfb3SApril Chin }
13467c2fbfb3SApril Chin message((-1, "AHA#%d disambiguate LAST k=%d", __LINE__, k));
1347da2e3ebdSchin if (state & LAST)
1348da2e3ebdSchin n = -n;
1349da2e3ebdSchin else if (!(state & NEXT))
1350da2e3ebdSchin n--;
1351da2e3ebdSchin m = (f > 0) ? f * n : n;
135234f9b3eeSRoland Mainz 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)));
1353da2e3ebdSchin switch (j)
1354da2e3ebdSchin {
1355da2e3ebdSchin case TM_DAYS+0:
1356da2e3ebdSchin tm->tm_mday--;
1357da2e3ebdSchin set |= DAY;
1358da2e3ebdSchin goto clear_hour;
1359da2e3ebdSchin case TM_DAYS+1:
1360da2e3ebdSchin set |= DAY;
1361da2e3ebdSchin goto clear_hour;
1362da2e3ebdSchin case TM_DAYS+2:
1363da2e3ebdSchin tm->tm_mday++;
1364da2e3ebdSchin set |= DAY;
1365da2e3ebdSchin goto clear_hour;
1366da2e3ebdSchin case TM_PARTS+0:
1367da2e3ebdSchin set |= SECOND;
1368da2e3ebdSchin if ((m < 0 ? -m : m) > (365L*24L*60L*60L))
1369da2e3ebdSchin {
1370da2e3ebdSchin now = tmxtime(tm, zone) + tmxsns(m, 0);
1371da2e3ebdSchin goto reset;
1372da2e3ebdSchin }
1373da2e3ebdSchin tm->tm_sec += m;
1374da2e3ebdSchin goto clear_nsec;
1375da2e3ebdSchin case TM_PARTS+1:
1376da2e3ebdSchin tm->tm_min += m;
1377da2e3ebdSchin set |= MINUTE;
1378da2e3ebdSchin goto clear_sec;
1379da2e3ebdSchin case TM_PARTS+2:
1380da2e3ebdSchin tm->tm_hour += m;
1381da2e3ebdSchin set |= MINUTE;
1382da2e3ebdSchin goto clear_min;
1383da2e3ebdSchin case TM_PARTS+3:
138434f9b3eeSRoland Mainz message((-1, "AHA#%d DAY m=%d n=%d%s", __LINE__, m, n, (state & LAST) ? " LAST" : ""));
138534f9b3eeSRoland Mainz if ((state & (LAST|NEXT|THIS)) == LAST)
138634f9b3eeSRoland Mainz tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year));
138734f9b3eeSRoland Mainz else if (state & ORDINAL)
138834f9b3eeSRoland Mainz tm->tm_mday = m + 1;
138934f9b3eeSRoland Mainz else
1390da2e3ebdSchin tm->tm_mday += m;
139134f9b3eeSRoland Mainz if (!(set & (FINAL|WORK)))
1392da2e3ebdSchin set |= HOUR;
1393da2e3ebdSchin goto clear_hour;
1394da2e3ebdSchin case TM_PARTS+4:
139534f9b3eeSRoland Mainz tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1396da2e3ebdSchin tm->tm_mday += 7 * m - tm->tm_wday + 1;
1397da2e3ebdSchin set |= DAY;
1398da2e3ebdSchin goto clear_hour;
1399da2e3ebdSchin case TM_PARTS+5:
1400da2e3ebdSchin tm->tm_mon += m;
1401da2e3ebdSchin set |= MONTH;
1402da2e3ebdSchin goto clear_mday;
1403da2e3ebdSchin case TM_PARTS+6:
1404da2e3ebdSchin tm->tm_year += m;
1405da2e3ebdSchin goto clear_mon;
1406da2e3ebdSchin case TM_HOURS+0:
1407da2e3ebdSchin tm->tm_mday += m;
1408da2e3ebdSchin set |= DAY;
1409da2e3ebdSchin goto clear_hour;
1410da2e3ebdSchin case TM_HOURS+1:
1411da2e3ebdSchin tm->tm_mday += m;
1412da2e3ebdSchin tm->tm_hour = 6;
1413da2e3ebdSchin set |= HOUR;
1414da2e3ebdSchin goto clear_min;
1415da2e3ebdSchin case TM_HOURS+2:
1416da2e3ebdSchin tm->tm_mday += m;
1417da2e3ebdSchin tm->tm_hour = 12;
1418da2e3ebdSchin set |= HOUR;
1419da2e3ebdSchin goto clear_min;
1420da2e3ebdSchin case TM_HOURS+3:
1421da2e3ebdSchin tm->tm_mday += m;
1422da2e3ebdSchin tm->tm_hour = 18;
1423da2e3ebdSchin set |= HOUR;
1424da2e3ebdSchin goto clear_min;
1425da2e3ebdSchin }
14267c2fbfb3SApril Chin if (m >= 0 && (state & ORDINAL))
14277c2fbfb3SApril Chin tm->tm_mday = 1;
142834f9b3eeSRoland Mainz tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1429da2e3ebdSchin day = j -= TM_DAY;
143034f9b3eeSRoland Mainz if (!dir)
1431da2e3ebdSchin dir = m;
14327c2fbfb3SApril Chin message((-1, "AHA#%d j=%d m=%d", __LINE__, j, m));
1433da2e3ebdSchin j -= tm->tm_wday;
14347c2fbfb3SApril Chin 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));
1435da2e3ebdSchin if (state & (LAST|NEXT|THIS))
1436da2e3ebdSchin {
14377c2fbfb3SApril Chin if (state & ORDINAL)
14387c2fbfb3SApril Chin {
14397c2fbfb3SApril Chin while (isspace(*s))
14407c2fbfb3SApril Chin s++;
14417c2fbfb3SApril Chin if (isdigit(*s) || tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0) >= 0)
14427c2fbfb3SApril Chin {
14437c2fbfb3SApril Chin state &= ~(LAST|NEXT|THIS);
14447c2fbfb3SApril Chin goto clear_hour;
14457c2fbfb3SApril Chin }
14467c2fbfb3SApril Chin }
1447da2e3ebdSchin if (j < 0)
1448da2e3ebdSchin j += 7;
1449da2e3ebdSchin }
1450da2e3ebdSchin else if (j > 0)
1451da2e3ebdSchin j -= 7;
145234f9b3eeSRoland Mainz 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)));
1453da2e3ebdSchin set |= DAY;
145434f9b3eeSRoland Mainz if (set & (FINAL|WORK))
1455da2e3ebdSchin goto clear_hour;
14567c2fbfb3SApril Chin else if (state & (LAST|NEXT|THIS))
14577c2fbfb3SApril Chin {
14587c2fbfb3SApril Chin if (f >= 0)
14597c2fbfb3SApril Chin day = -1;
14607c2fbfb3SApril Chin else if (m > 0 && (state & (NEXT|YEAR|MONTH)) == NEXT && j >= 0)
14617c2fbfb3SApril Chin m--;
14627c2fbfb3SApril Chin tm->tm_mday += j + m * 7;
14637c2fbfb3SApril Chin set &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/
14647c2fbfb3SApril Chin state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/
14657c2fbfb3SApril Chin if (!(state & EXACT))
14667c2fbfb3SApril Chin goto clear_hour;
14677c2fbfb3SApril Chin }
1468da2e3ebdSchin continue;
1469da2e3ebdSchin case TM_MONTH_ABBREV:
1470da2e3ebdSchin j += TM_MONTH - TM_MONTH_ABBREV;
1471da2e3ebdSchin /*FALLTHROUGH*/
1472da2e3ebdSchin case TM_MONTH:
1473da2e3ebdSchin if (state & MONTH)
1474da2e3ebdSchin goto done;
1475da2e3ebdSchin state |= MONTH;
1476da2e3ebdSchin i = tm->tm_mon;
1477da2e3ebdSchin tm->tm_mon = j - TM_MONTH;
1478da2e3ebdSchin if (n < 0)
1479da2e3ebdSchin {
1480da2e3ebdSchin while (skip[*s])
1481da2e3ebdSchin s++;
1482da2e3ebdSchin if (isdigit(*s))
1483da2e3ebdSchin {
1484da2e3ebdSchin n = strtol(s, &t, 10);
1485da2e3ebdSchin if (n <= 31 && *t != ':')
1486da2e3ebdSchin s = t;
1487da2e3ebdSchin else
1488da2e3ebdSchin n = -1;
1489da2e3ebdSchin }
1490da2e3ebdSchin }
1491da2e3ebdSchin if (n >= 0)
1492da2e3ebdSchin {
1493da2e3ebdSchin if (n > 31)
1494da2e3ebdSchin goto done;
1495da2e3ebdSchin state |= DAY|MDAY;
1496da2e3ebdSchin tm->tm_mday = n;
1497da2e3ebdSchin if (f > 0)
1498da2e3ebdSchin tm->tm_year += f;
1499da2e3ebdSchin }
1500da2e3ebdSchin if (state & (LAST|NEXT|THIS))
1501da2e3ebdSchin {
1502da2e3ebdSchin n = i;
1503da2e3ebdSchin goto rel_month;
1504da2e3ebdSchin }
1505da2e3ebdSchin continue;
1506da2e3ebdSchin case TM_UT:
1507da2e3ebdSchin if (state & ZONE)
1508da2e3ebdSchin goto done;
1509da2e3ebdSchin state |= ZONE;
1510da2e3ebdSchin zone = tmgoff(s, &t, 0);
1511da2e3ebdSchin s = t;
1512da2e3ebdSchin continue;
1513da2e3ebdSchin case TM_DT:
1514da2e3ebdSchin if (!dst)
1515da2e3ebdSchin goto done;
1516da2e3ebdSchin if (!(state & ZONE))
1517da2e3ebdSchin {
151834f9b3eeSRoland Mainz dst = tm->tm_zone->dst;
151934f9b3eeSRoland Mainz zone = tm->tm_zone->west;
1520da2e3ebdSchin }
1521da2e3ebdSchin zone += tmgoff(s, &t, dst);
1522da2e3ebdSchin s = t;
1523da2e3ebdSchin dst = 0;
1524da2e3ebdSchin state |= ZONE;
1525da2e3ebdSchin continue;
1526da2e3ebdSchin case TM_NOISE:
1527da2e3ebdSchin continue;
1528da2e3ebdSchin }
1529da2e3ebdSchin }
1530da2e3ebdSchin if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst)))
1531da2e3ebdSchin {
1532da2e3ebdSchin s = t;
1533da2e3ebdSchin zone = zp->west + dst;
1534da2e3ebdSchin tm_info.date = zp;
1535da2e3ebdSchin state |= ZONE;
15367c2fbfb3SApril Chin if (n < 0)
1537da2e3ebdSchin continue;
1538da2e3ebdSchin }
15397c2fbfb3SApril Chin else if (!type && (zp = tmtype(s, &t)))
1540da2e3ebdSchin {
1541da2e3ebdSchin s = t;
1542da2e3ebdSchin type = zp->type;
15437c2fbfb3SApril Chin if (n < 0)
1544da2e3ebdSchin continue;
1545da2e3ebdSchin }
1546da2e3ebdSchin state |= BREAK;
1547da2e3ebdSchin }
154834f9b3eeSRoland Mainz }
1549da2e3ebdSchin else if (*s == '/')
1550da2e3ebdSchin {
155134f9b3eeSRoland Mainz if (!(state & (YEAR|MONTH)) && n >= 1969 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12)
1552da2e3ebdSchin {
1553da2e3ebdSchin state |= YEAR;
1554da2e3ebdSchin tm->tm_year = n - 1900;
1555da2e3ebdSchin s = t;
1556da2e3ebdSchin i--;
1557da2e3ebdSchin }
1558da2e3ebdSchin else
1559da2e3ebdSchin {
1560da2e3ebdSchin if ((state & MONTH) || n <= 0 || n > 31)
1561da2e3ebdSchin break;
1562da2e3ebdSchin if (isalpha(*++s))
1563da2e3ebdSchin {
1564da2e3ebdSchin if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0)
1565da2e3ebdSchin break;
1566da2e3ebdSchin if (i >= TM_MONTH)
1567da2e3ebdSchin i -= TM_MONTH;
1568da2e3ebdSchin s = t;
1569da2e3ebdSchin }
1570da2e3ebdSchin else
1571da2e3ebdSchin {
1572da2e3ebdSchin i = n - 1;
1573da2e3ebdSchin n = strtol(s, &t, 10);
1574da2e3ebdSchin s = t;
1575da2e3ebdSchin if (n <= 0 || n > 31)
1576da2e3ebdSchin break;
1577da2e3ebdSchin if (*s == '/' && !isdigit(*(s + 1)))
1578da2e3ebdSchin break;
1579da2e3ebdSchin }
1580da2e3ebdSchin state |= DAY;
1581da2e3ebdSchin tm->tm_mday = n;
1582da2e3ebdSchin }
1583da2e3ebdSchin state |= MONTH;
1584da2e3ebdSchin n = tm->tm_mon;
1585da2e3ebdSchin tm->tm_mon = i;
1586da2e3ebdSchin if (*s == '/')
1587da2e3ebdSchin {
1588da2e3ebdSchin n = strtol(++s, &t, 10);
1589da2e3ebdSchin w = t - s;
1590da2e3ebdSchin s = t;
1591da2e3ebdSchin if (*s == '/' || *s == ':' || *s == '-' || *s == '_')
1592da2e3ebdSchin s++;
1593da2e3ebdSchin }
1594da2e3ebdSchin else
1595da2e3ebdSchin {
1596da2e3ebdSchin if (state & (LAST|NEXT|THIS))
1597da2e3ebdSchin {
1598da2e3ebdSchin rel_month:
1599da2e3ebdSchin if (state & LAST)
1600da2e3ebdSchin tm->tm_year -= (tm->tm_mon < n) ? 0 : 1;
1601da2e3ebdSchin else
1602da2e3ebdSchin tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0);
1603da2e3ebdSchin if (state & MDAY)
1604da2e3ebdSchin goto clear_hour;
16057c2fbfb3SApril Chin set &= ~(LAST|NEXT|THIS); /*AHA*/
16067c2fbfb3SApril Chin state &= ~(LAST|NEXT|THIS); /*AHA*/
1607da2e3ebdSchin goto clear_mday;
1608da2e3ebdSchin }
1609da2e3ebdSchin continue;
1610da2e3ebdSchin }
1611da2e3ebdSchin }
1612da2e3ebdSchin if (n < 0 || w > 4)
1613da2e3ebdSchin break;
1614da2e3ebdSchin if (w == 4)
1615da2e3ebdSchin {
161634f9b3eeSRoland Mainz if ((state & YEAR) || n < 1969 || n >= 3000)
1617da2e3ebdSchin break;
1618da2e3ebdSchin state |= YEAR;
1619da2e3ebdSchin tm->tm_year = n - 1900;
1620da2e3ebdSchin }
1621da2e3ebdSchin else if (w == 3)
1622da2e3ebdSchin {
1623da2e3ebdSchin if (state & (MONTH|MDAY|WDAY))
1624da2e3ebdSchin break;
1625da2e3ebdSchin state |= MONTH|DAY|MDAY;
1626da2e3ebdSchin tm->tm_mon = 0;
1627da2e3ebdSchin tm->tm_mday = n;
1628da2e3ebdSchin }
1629da2e3ebdSchin else if (w == 2 && !(state & YEAR))
1630da2e3ebdSchin {
1631da2e3ebdSchin state |= YEAR;
1632da2e3ebdSchin if (n < TM_WINDOW)
1633da2e3ebdSchin n += 100;
1634da2e3ebdSchin tm->tm_year = n;
1635da2e3ebdSchin }
1636da2e3ebdSchin else if (!(state & MONTH) && n >= 1 && n <= 12)
1637da2e3ebdSchin {
1638da2e3ebdSchin state |= MONTH;
1639da2e3ebdSchin tm->tm_mon = n - 1;
1640da2e3ebdSchin }
1641da2e3ebdSchin else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31)
1642da2e3ebdSchin {
1643da2e3ebdSchin state |= DAY|MDAY|WDAY;
1644da2e3ebdSchin tm->tm_mday = n;
1645da2e3ebdSchin }
1646da2e3ebdSchin else
1647da2e3ebdSchin break;
1648da2e3ebdSchin if (state & BREAK)
1649da2e3ebdSchin {
1650da2e3ebdSchin last = t;
1651da2e3ebdSchin break;
1652da2e3ebdSchin }
1653da2e3ebdSchin continue;
1654da2e3ebdSchin clear_mon:
1655da2e3ebdSchin if ((set|state) & (EXACT|MONTH))
1656da2e3ebdSchin continue;
1657da2e3ebdSchin tm->tm_mon = 0;
1658da2e3ebdSchin clear_mday:
1659da2e3ebdSchin set |= MONTH;
1660da2e3ebdSchin if ((set|state) & (EXACT|DAY|HOUR))
1661da2e3ebdSchin continue;
1662da2e3ebdSchin tm->tm_mday = 1;
1663da2e3ebdSchin clear_hour:
16647c2fbfb3SApril Chin message((-1, "AHA#%d DAY", __LINE__));
1665da2e3ebdSchin set |= DAY;
1666da2e3ebdSchin if ((set|state) & (EXACT|HOUR))
1667da2e3ebdSchin continue;
1668da2e3ebdSchin tm->tm_hour = 0;
1669da2e3ebdSchin clear_min:
1670da2e3ebdSchin set |= HOUR;
1671da2e3ebdSchin if ((set|state) & (EXACT|MINUTE))
1672da2e3ebdSchin continue;
1673da2e3ebdSchin tm->tm_min = 0;
1674da2e3ebdSchin clear_sec:
1675da2e3ebdSchin set |= MINUTE;
1676da2e3ebdSchin if ((set|state) & (EXACT|SECOND))
1677da2e3ebdSchin continue;
1678da2e3ebdSchin tm->tm_sec = 0;
1679da2e3ebdSchin clear_nsec:
1680da2e3ebdSchin set |= SECOND;
1681da2e3ebdSchin if ((set|state) & (EXACT|NSEC))
1682da2e3ebdSchin continue;
1683da2e3ebdSchin tm->tm_nsec = 0;
1684da2e3ebdSchin }
1685da2e3ebdSchin done:
1686da2e3ebdSchin if (day >= 0 && !(state & (MDAY|WDAY)))
1687da2e3ebdSchin {
168834f9b3eeSRoland Mainz message((-1, "AHA#%d day=%d dir=%d state=" FFMT, __LINE__, day, dir, FLAGS(state)));
1689*3e14f97fSRoger A. Faulkner tmfix(tm);
16907c2fbfb3SApril Chin m = dir;
1691da2e3ebdSchin if (state & MONTH)
1692da2e3ebdSchin tm->tm_mday = 1;
1693da2e3ebdSchin else if (m < 0)
1694da2e3ebdSchin m++;
169534f9b3eeSRoland Mainz tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1696da2e3ebdSchin j = day - tm->tm_wday;
1697da2e3ebdSchin if (j < 0)
1698da2e3ebdSchin j += 7;
1699da2e3ebdSchin tm->tm_mday += j + m * 7;
1700da2e3ebdSchin if (state & FINAL)
1701da2e3ebdSchin 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);
1702da2e3ebdSchin }
1703da2e3ebdSchin else if (day < 0 && (state & FINAL) && (set & DAY))
1704*3e14f97fSRoger A. Faulkner {
1705*3e14f97fSRoger A. Faulkner tmfix(tm);
1706da2e3ebdSchin tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year));
1707*3e14f97fSRoger A. Faulkner }
170834f9b3eeSRoland Mainz if (state & WORK)
170934f9b3eeSRoland Mainz {
171034f9b3eeSRoland Mainz tm->tm_mday = (set & FINAL) ? (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))) : 1;
171134f9b3eeSRoland Mainz tmfix(tm);
171234f9b3eeSRoland Mainz message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__, tm->tm_mday, tm->tm_wday));
171334f9b3eeSRoland Mainz if (tm->tm_wday == 0 && (j = 1) || tm->tm_wday == 6 && (j = 2))
171434f9b3eeSRoland Mainz {
171534f9b3eeSRoland Mainz if ((tm->tm_mday + j) > (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))))
171634f9b3eeSRoland Mainz j -= 3;
171734f9b3eeSRoland Mainz tm->tm_mday += j;
171834f9b3eeSRoland Mainz }
171934f9b3eeSRoland Mainz }
172034f9b3eeSRoland Mainz now = tmxtime(tm, zone);
172134f9b3eeSRoland Mainz if (tm->tm_year <= 70 && tmxsec(now) > 31536000)
172234f9b3eeSRoland Mainz {
172334f9b3eeSRoland Mainz now = 0;
172434f9b3eeSRoland Mainz last = (char*)o;
172534f9b3eeSRoland Mainz }
1726da2e3ebdSchin if (e)
1727da2e3ebdSchin *e = last;
172834f9b3eeSRoland Mainz return now;
1729da2e3ebdSchin }
1730