xref: /titanic_51/usr/src/lib/libast/common/tm/tmxdate.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
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