1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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  * scan date expression in s using format
30da2e3ebdSchin  * if non-null, e points to the first invalid sequence in s
31da2e3ebdSchin  * if non-null, f points to the first unused format char
32da2e3ebdSchin  * t provides default values
33da2e3ebdSchin  */
34da2e3ebdSchin 
35da2e3ebdSchin #include <tmx.h>
36da2e3ebdSchin #include <ctype.h>
37da2e3ebdSchin 
38da2e3ebdSchin typedef struct
39da2e3ebdSchin {
40da2e3ebdSchin 	int32_t		nsec;
41da2e3ebdSchin 	int		year;
42da2e3ebdSchin 	int		mon;
43da2e3ebdSchin 	int		week;
44da2e3ebdSchin 	int		weektype;
45da2e3ebdSchin 	int		yday;
46da2e3ebdSchin 	int		mday;
47da2e3ebdSchin 	int		wday;
48da2e3ebdSchin 	int		hour;
49da2e3ebdSchin 	int		min;
50da2e3ebdSchin 	int		sec;
51da2e3ebdSchin 	int		meridian;
52da2e3ebdSchin 	int		zone;
53da2e3ebdSchin } Set_t;
54da2e3ebdSchin 
55da2e3ebdSchin #define CLEAR(s)	(s.year=s.mon=s.week=s.weektype=s.yday=s.mday=s.wday=s.hour=s.min=s.sec=s.meridian=(-1),s.nsec=1000000000L,s.zone=TM_LOCALZONE)
56da2e3ebdSchin 
57da2e3ebdSchin #define INDEX(m,x)	(((n)>=((x)-(m)))?((n)-=((x)-(m))):(n))
58da2e3ebdSchin 
59da2e3ebdSchin #define NUMBER(d,m,x)	do \
60da2e3ebdSchin 			{ \
61da2e3ebdSchin 				n = 0; \
62da2e3ebdSchin 				u = (char*)s; \
63da2e3ebdSchin 				while (s < (const char*)(u + d) && *s >= '0' && *s <= '9') \
64da2e3ebdSchin 					n = n * 10 + *s++ - '0'; \
65da2e3ebdSchin 				if (u == (char*)s || n < m || n > x) \
66da2e3ebdSchin 					goto next; \
67da2e3ebdSchin 			} while (0)
68da2e3ebdSchin 
69da2e3ebdSchin /*
70da2e3ebdSchin  * generate a Time_t from tm + set
71da2e3ebdSchin  */
72da2e3ebdSchin 
73da2e3ebdSchin static Time_t
gen(register Tm_t * tm,register Set_t * set)74da2e3ebdSchin gen(register Tm_t* tm, register Set_t* set)
75da2e3ebdSchin {
76da2e3ebdSchin 	register int	n;
7734f9b3eeSRoland Mainz 	int		z;
78da2e3ebdSchin 	Time_t		t;
79da2e3ebdSchin 
80da2e3ebdSchin 	if (set->year >= 0)
81da2e3ebdSchin 		tm->tm_year = set->year;
82da2e3ebdSchin 	if (set->mon >= 0)
83da2e3ebdSchin 	{
84da2e3ebdSchin 		if (set->year < 0 && set->mon < tm->tm_mon)
85da2e3ebdSchin 			tm->tm_year++;
86da2e3ebdSchin 		tm->tm_mon = set->mon;
87da2e3ebdSchin 		if (set->yday < 0 && set->mday < 0)
88da2e3ebdSchin 			tm->tm_mday = set->mday = 1;
89da2e3ebdSchin 	}
90da2e3ebdSchin 	if (set->week >= 0)
91da2e3ebdSchin 	{
92da2e3ebdSchin 		if (set->mon < 0)
93da2e3ebdSchin 		{
94da2e3ebdSchin 			tmweek(tm, set->weektype, set->week, set->wday);
95da2e3ebdSchin 			set->wday = -1;
96da2e3ebdSchin 		}
97da2e3ebdSchin 	}
98da2e3ebdSchin 	else if (set->yday >= 0)
99da2e3ebdSchin 	{
100da2e3ebdSchin 		if (set->mon < 0)
101da2e3ebdSchin 		{
102da2e3ebdSchin 			tm->tm_mon = 0;
103da2e3ebdSchin 			tm->tm_mday = set->yday + 1;
104da2e3ebdSchin 		}
105da2e3ebdSchin 	}
106da2e3ebdSchin 	else if (set->mday >= 0)
107da2e3ebdSchin 		tm->tm_mday = set->mday;
108da2e3ebdSchin 	if (set->hour >= 0)
109da2e3ebdSchin 	{
110da2e3ebdSchin 		if (set->hour < tm->tm_hour && set->yday < 0 && set->mday < 0 && set->wday < 0)
111da2e3ebdSchin 			tm->tm_mday++;
112da2e3ebdSchin 		tm->tm_hour = set->hour;
113da2e3ebdSchin 		tm->tm_min = (set->min >= 0) ? set->min : 0;
114da2e3ebdSchin 		tm->tm_sec = (set->sec >= 0) ? set->sec : 0;
115da2e3ebdSchin 	}
116da2e3ebdSchin 	else if (set->min >= 0)
117da2e3ebdSchin 	{
118da2e3ebdSchin 		tm->tm_min = set->min;
119da2e3ebdSchin 		tm->tm_sec = (set->sec >= 0) ? set->sec : 0;
120da2e3ebdSchin 	}
121da2e3ebdSchin 	else if (set->sec >= 0)
122da2e3ebdSchin 		tm->tm_sec = set->sec;
123da2e3ebdSchin 	if (set->nsec < 1000000000L)
124da2e3ebdSchin 		tm->tm_nsec = set->nsec;
125da2e3ebdSchin 	if (set->meridian > 0)
126da2e3ebdSchin 	{
127da2e3ebdSchin 		if (tm->tm_hour < 12)
128da2e3ebdSchin 			tm->tm_hour += 12;
129da2e3ebdSchin 	}
130da2e3ebdSchin 	else if (set->meridian == 0)
131da2e3ebdSchin 	{
132da2e3ebdSchin 		if (tm->tm_hour >= 12)
133da2e3ebdSchin 			tm->tm_hour -= 12;
134da2e3ebdSchin 	}
135da2e3ebdSchin 	t = tmxtime(tm, set->zone);
136da2e3ebdSchin 	if (set->yday >= 0)
137da2e3ebdSchin 	{
13834f9b3eeSRoland Mainz 		z = 1;
13934f9b3eeSRoland Mainz 		tm = tmxtm(tm, t, tm->tm_zone);
140da2e3ebdSchin 		tm->tm_mday += set->yday - tm->tm_yday;
141da2e3ebdSchin 	}
142da2e3ebdSchin 	else if (set->wday >= 0)
143da2e3ebdSchin 	{
14434f9b3eeSRoland Mainz 		z = 1;
14534f9b3eeSRoland Mainz 		tm = tmxtm(tm, t, tm->tm_zone);
146da2e3ebdSchin 		if ((n = set->wday - tm->tm_wday) < 0)
147da2e3ebdSchin 			n += 7;
148da2e3ebdSchin 		tm->tm_mday += n;
149da2e3ebdSchin 	}
15034f9b3eeSRoland Mainz 	else
15134f9b3eeSRoland Mainz 		z = 0;
152da2e3ebdSchin 	if (set->nsec < 1000000000L)
153da2e3ebdSchin 	{
15434f9b3eeSRoland Mainz 		if (!z)
15534f9b3eeSRoland Mainz 		{
15634f9b3eeSRoland Mainz 			z = 1;
15734f9b3eeSRoland Mainz 			tm = tmxtm(tm, t, tm->tm_zone);
15834f9b3eeSRoland Mainz 		}
159da2e3ebdSchin 		tm->tm_nsec = set->nsec;
160da2e3ebdSchin 	}
16134f9b3eeSRoland Mainz 	return z ? tmxtime(tm, set->zone) : t;
162da2e3ebdSchin }
163da2e3ebdSchin 
164da2e3ebdSchin /*
165da2e3ebdSchin  * the format scan workhorse
166da2e3ebdSchin  */
167da2e3ebdSchin 
168da2e3ebdSchin static Time_t
scan(register const char * s,char ** e,const char * format,char ** f,Time_t t,long flags)169da2e3ebdSchin scan(register const char* s, char** e, const char* format, char** f, Time_t t, long flags)
170da2e3ebdSchin {
171da2e3ebdSchin 	register int	d;
172da2e3ebdSchin 	register int	n;
173da2e3ebdSchin 	register char*	p;
174da2e3ebdSchin 	register Tm_t*	tm;
175da2e3ebdSchin 	const char*	b;
176da2e3ebdSchin 	char*		u;
177da2e3ebdSchin 	char*		stack[4];
178da2e3ebdSchin 	int		m;
179da2e3ebdSchin 	int		hi;
180da2e3ebdSchin 	int		lo;
181da2e3ebdSchin 	int		pedantic;
182da2e3ebdSchin 	Time_t		x;
183da2e3ebdSchin 	Set_t		set;
184da2e3ebdSchin 	Tm_zone_t*	zp;
18534f9b3eeSRoland Mainz 	Tm_t		ts;
186da2e3ebdSchin 
187da2e3ebdSchin 	char**		sp = &stack[0];
188da2e3ebdSchin 
189da2e3ebdSchin 	while (isspace(*s))
190da2e3ebdSchin 		s++;
191da2e3ebdSchin 	b = s;
192da2e3ebdSchin  again:
193da2e3ebdSchin 	CLEAR(set);
19434f9b3eeSRoland Mainz 	tm = tmxtm(&ts, t, NiL);
195da2e3ebdSchin 	pedantic = (flags & TM_PEDANTIC) != 0;
196da2e3ebdSchin 	for (;;)
197da2e3ebdSchin 	{
198da2e3ebdSchin 		if (!(d = *format++))
199da2e3ebdSchin 		{
200da2e3ebdSchin 			if (sp <= &stack[0])
201da2e3ebdSchin 			{
202da2e3ebdSchin 				format--;
203da2e3ebdSchin 				break;
204da2e3ebdSchin 			}
205da2e3ebdSchin 			format = (const char*)*--sp;
206da2e3ebdSchin 		}
207da2e3ebdSchin 		else if (!*s)
208da2e3ebdSchin 		{
209da2e3ebdSchin 			format--;
210da2e3ebdSchin 			break;
211da2e3ebdSchin 		}
212da2e3ebdSchin 		else if (d == '%' && (d = *format) && format++ && d != '%')
213da2e3ebdSchin 		{
214da2e3ebdSchin 		more:
215da2e3ebdSchin 			switch (d)
216da2e3ebdSchin 			{
217da2e3ebdSchin 			case 'a':
218da2e3ebdSchin 				lo = TM_DAY_ABBREV;
219da2e3ebdSchin 				hi = pedantic ? TM_DAY : TM_TIME;
220da2e3ebdSchin 				goto get_wday;
221da2e3ebdSchin 			case 'A':
222da2e3ebdSchin 				lo = pedantic ? TM_DAY : TM_DAY_ABBREV;
223da2e3ebdSchin 				hi = TM_TIME;
224da2e3ebdSchin 			get_wday:
225da2e3ebdSchin 				if ((n = tmlex(s, &u, tm_info.format + lo, hi - lo, NiL, 0)) < 0)
226da2e3ebdSchin 					goto next;
227da2e3ebdSchin 				s = u;
228da2e3ebdSchin 				INDEX(TM_DAY_ABBREV, TM_DAY);
229da2e3ebdSchin 				set.wday = n;
230da2e3ebdSchin 				continue;
231da2e3ebdSchin 			case 'b':
232da2e3ebdSchin 			case 'h':
233da2e3ebdSchin 				lo = TM_MONTH_ABBREV;
234da2e3ebdSchin 				hi = pedantic ? TM_MONTH : TM_DAY_ABBREV;
235da2e3ebdSchin 				goto get_mon;
236da2e3ebdSchin 			case 'B':
237da2e3ebdSchin 				lo = pedantic ? TM_MONTH : TM_MONTH_ABBREV;
238da2e3ebdSchin 				hi = TM_DAY_ABBREV;
239da2e3ebdSchin 			get_mon:
240da2e3ebdSchin 				if ((n = tmlex(s, &u, tm_info.format + lo, hi - lo, NiL, 0)) < 0)
241da2e3ebdSchin 					goto next;
242da2e3ebdSchin 				s = u;
243da2e3ebdSchin 				INDEX(TM_MONTH_ABBREV, TM_MONTH);
244da2e3ebdSchin 				set.mon = n;
245da2e3ebdSchin 				continue;
246da2e3ebdSchin 			case 'c':
247da2e3ebdSchin 				p = "%a %b %e %T %Y";
248da2e3ebdSchin 				break;
249da2e3ebdSchin 			case 'C':
250da2e3ebdSchin 				NUMBER(2, 19, 99);
251da2e3ebdSchin 				set.year = (n - 19) * 100 + tm->tm_year % 100;
252da2e3ebdSchin 				continue;
253da2e3ebdSchin 			case 'd':
254da2e3ebdSchin 				if (pedantic && !isdigit(*s))
255da2e3ebdSchin 					goto next;
256da2e3ebdSchin 				/*FALLTHROUGH*/
257da2e3ebdSchin 			case 'e':
258da2e3ebdSchin 				NUMBER(2, 1, 31);
259da2e3ebdSchin 				set.mday = n;
260da2e3ebdSchin 				continue;
261da2e3ebdSchin 			case 'D':
262da2e3ebdSchin 				p = "%m/%d/%y";
263da2e3ebdSchin 				break;
264da2e3ebdSchin 			case 'E':
265da2e3ebdSchin 			case 'O':
266da2e3ebdSchin 				if (*format)
267da2e3ebdSchin 				{
268da2e3ebdSchin 					d = *format++;
269da2e3ebdSchin 					goto more;
270da2e3ebdSchin 				}
271da2e3ebdSchin 				continue;
2727c2fbfb3SApril Chin 			case 'F':
2737c2fbfb3SApril Chin 				p = "%Y-%m-%d";
2747c2fbfb3SApril Chin 				break;
275da2e3ebdSchin 			case 'H':
276da2e3ebdSchin 			case 'k':
277da2e3ebdSchin 				NUMBER(2, 0, 23);
278da2e3ebdSchin 				set.hour = n;
279da2e3ebdSchin 				continue;
280da2e3ebdSchin 			case 'I':
281da2e3ebdSchin 			case 'l':
282da2e3ebdSchin 				NUMBER(2, 1, 12);
283da2e3ebdSchin 				set.hour = n;
284da2e3ebdSchin 				continue;
285da2e3ebdSchin 			case 'j':
286da2e3ebdSchin 				NUMBER(3, 1, 366);
287da2e3ebdSchin 				set.yday = n - 1;
288da2e3ebdSchin 				continue;
289da2e3ebdSchin 			case 'm':
290da2e3ebdSchin 				NUMBER(2, 1, 12);
291da2e3ebdSchin 				set.mon = n - 1;
292da2e3ebdSchin 				continue;
293da2e3ebdSchin 			case 'M':
294da2e3ebdSchin 				NUMBER(2, 0, 59);
295da2e3ebdSchin 				set.min = n;
296da2e3ebdSchin 				continue;
297da2e3ebdSchin 			case 'n':
298da2e3ebdSchin 				if (pedantic)
299da2e3ebdSchin 					while (*s == '\n')
300da2e3ebdSchin 						s++;
301da2e3ebdSchin 				else
302da2e3ebdSchin 					while (isspace(*s))
303da2e3ebdSchin 						s++;
304da2e3ebdSchin 				continue;
305da2e3ebdSchin 			case 'N':
306da2e3ebdSchin 				NUMBER(9, 0, 999999999L);
307da2e3ebdSchin 				set.nsec = n;
308da2e3ebdSchin 				continue;
309da2e3ebdSchin 			case 'p':
310da2e3ebdSchin 				if ((n = tmlex(s, &u, tm_info.format + TM_MERIDIAN, TM_UT - TM_MERIDIAN, NiL, 0)) < 0)
311da2e3ebdSchin 					goto next;
312da2e3ebdSchin 				set.meridian = n;
313da2e3ebdSchin 				s = u;
314da2e3ebdSchin 				continue;
315da2e3ebdSchin 			case 'r':
316da2e3ebdSchin 				p = "%I:%M:%S %p";
317da2e3ebdSchin 				break;
318da2e3ebdSchin 			case 'R':
319da2e3ebdSchin 				p = "%H:%M:%S";
320da2e3ebdSchin 				break;
321da2e3ebdSchin 			case 's':
322da2e3ebdSchin 				x = strtoul(s, &u, 0);
323da2e3ebdSchin 				if (s == u)
324da2e3ebdSchin 					goto next;
32534f9b3eeSRoland Mainz 				tm = tmxtm(tm, tmxsns(x, 0), tm->tm_zone);
326da2e3ebdSchin 				s = u;
327da2e3ebdSchin 				CLEAR(set);
328da2e3ebdSchin 				continue;
329da2e3ebdSchin 			case 'S':
330da2e3ebdSchin 				NUMBER(2, 0, 61);
331da2e3ebdSchin 				set.sec = n;
332da2e3ebdSchin 				continue;
333da2e3ebdSchin 			case 'u':
334da2e3ebdSchin 				NUMBER(2, 1, 7);
335da2e3ebdSchin 				set.wday = n % 7;
336da2e3ebdSchin 				continue;
337da2e3ebdSchin 			case 'U':
338da2e3ebdSchin 				NUMBER(2, 0, 52);
339da2e3ebdSchin 				set.week = n;
340da2e3ebdSchin 				set.weektype = 0;
341da2e3ebdSchin 				continue;
342da2e3ebdSchin 			case 'V':
343da2e3ebdSchin 				NUMBER(2, 1, 53);
344da2e3ebdSchin 				set.week = n;
345da2e3ebdSchin 				set.weektype = 2;
346da2e3ebdSchin 				continue;
347da2e3ebdSchin 			case 'w':
348da2e3ebdSchin 				NUMBER(2, 0, 6);
349da2e3ebdSchin 				set.wday = n;
350da2e3ebdSchin 				continue;
351da2e3ebdSchin 			case 'W':
352da2e3ebdSchin 				NUMBER(2, 0, 52);
353da2e3ebdSchin 				set.week = n;
354da2e3ebdSchin 				set.weektype = 1;
355da2e3ebdSchin 				continue;
356da2e3ebdSchin 			case 'x':
357da2e3ebdSchin 				p = tm_info.format[TM_DATE];
358da2e3ebdSchin 				break;
359da2e3ebdSchin 			case 'X':
360da2e3ebdSchin 				p = tm_info.format[TM_TIME];
361da2e3ebdSchin 				break;
362da2e3ebdSchin 			case 'y':
363da2e3ebdSchin 				NUMBER(2, 0, 99);
364da2e3ebdSchin 				if (n < TM_WINDOW)
365da2e3ebdSchin 					n += 100;
366da2e3ebdSchin 				set.year = n;
367da2e3ebdSchin 				continue;
368da2e3ebdSchin 			case 'Y':
369da2e3ebdSchin 				NUMBER(4, 1969, 2100);
370da2e3ebdSchin 				set.year = n - 1900;
371da2e3ebdSchin 				continue;
372da2e3ebdSchin 			case 'Z':
373da2e3ebdSchin 			case 'q':
374da2e3ebdSchin 				if (zp = tmtype(s, &u))
375da2e3ebdSchin 				{
376da2e3ebdSchin 					s = u;
377da2e3ebdSchin 					u = zp->type;
378da2e3ebdSchin 				}
379da2e3ebdSchin 				else
380da2e3ebdSchin 					u = 0;
381da2e3ebdSchin 				if (d == 'q')
382da2e3ebdSchin 					continue;
3835c16836eSToomas Soome 				/* FALLTHROUGH */
384da2e3ebdSchin 			case 'z':
385da2e3ebdSchin 				if ((zp = tmzone(s, &u, u, &m)))
386da2e3ebdSchin 				{
387da2e3ebdSchin 					s = u;
388da2e3ebdSchin 					set.zone = zp->west + m;
389da2e3ebdSchin 					tm_info.date = zp;
390da2e3ebdSchin 				}
391da2e3ebdSchin 				continue;
392da2e3ebdSchin 			case '|':
393da2e3ebdSchin 				s = b;
394da2e3ebdSchin 				goto again;
395da2e3ebdSchin 			case '&':
396da2e3ebdSchin 				x = gen(tm, &set);
397da2e3ebdSchin 				x = tmxdate(s, e, t);
398da2e3ebdSchin 				if (s == (const char*)*e)
399da2e3ebdSchin 					goto next;
400da2e3ebdSchin 				t = x;
401da2e3ebdSchin 				s = (const char*)*e;
402da2e3ebdSchin 				if (!*format || *format == '%' && *(format + 1) == '|')
403da2e3ebdSchin 					goto done;
404da2e3ebdSchin 				goto again;
405da2e3ebdSchin 			default:
406da2e3ebdSchin 				goto next;
407da2e3ebdSchin 			}
408da2e3ebdSchin 			if (sp >= &stack[elementsof(stack)])
409da2e3ebdSchin 				goto next;
410da2e3ebdSchin 			*sp++ = (char*)format;
411da2e3ebdSchin 			format = (const char*)p;
412da2e3ebdSchin 		}
413da2e3ebdSchin 		else if (isspace(d))
414da2e3ebdSchin 			while (isspace(*s))
415da2e3ebdSchin 				s++;
416da2e3ebdSchin 		else if (*s != d)
417da2e3ebdSchin 			break;
418da2e3ebdSchin 		else
419da2e3ebdSchin 			s++;
420da2e3ebdSchin 	}
421da2e3ebdSchin  next:
422da2e3ebdSchin 	if (sp > &stack[0])
423da2e3ebdSchin 		format = (const char*)stack[0];
424da2e3ebdSchin 	if (*format)
425da2e3ebdSchin 	{
426da2e3ebdSchin 		p = (char*)format;
427da2e3ebdSchin 		if (!*s && *p == '%' && *(p + 1) == '|')
428da2e3ebdSchin 			format += strlen(format);
429da2e3ebdSchin 		else
430da2e3ebdSchin 			while (*p)
431da2e3ebdSchin 				if (*p++ == '%' && *p && *p++ == '|' && *p)
432da2e3ebdSchin 				{
433da2e3ebdSchin 					format = (const char*)p;
434da2e3ebdSchin 					s = b;
435da2e3ebdSchin 					goto again;
436da2e3ebdSchin 				}
437da2e3ebdSchin 	}
438da2e3ebdSchin 	t = gen(tm, &set);
439da2e3ebdSchin  done:
440da2e3ebdSchin 	if (e)
441da2e3ebdSchin 	{
442da2e3ebdSchin 		while (isspace(*s))
443da2e3ebdSchin 			s++;
444da2e3ebdSchin 		*e = (char*)s;
445da2e3ebdSchin 	}
446da2e3ebdSchin 	if (f)
447da2e3ebdSchin 	{
448da2e3ebdSchin 		while (isspace(*format))
449da2e3ebdSchin 			format++;
450da2e3ebdSchin 		*f = (char*)format;
451da2e3ebdSchin 	}
452da2e3ebdSchin 	return t;
453da2e3ebdSchin }
454da2e3ebdSchin 
455da2e3ebdSchin /*
456da2e3ebdSchin  *  format==0	DATEMSK
457da2e3ebdSchin  * *format==0	DATEMSK and tmxdate()
458da2e3ebdSchin  * *format!=0	format
459da2e3ebdSchin  */
460da2e3ebdSchin 
461da2e3ebdSchin Time_t
tmxscan(const char * s,char ** e,const char * format,char ** f,Time_t t,long flags)462da2e3ebdSchin tmxscan(const char* s, char** e, const char* format, char** f, Time_t t, long flags)
463da2e3ebdSchin {
464da2e3ebdSchin 	register char*	v;
465da2e3ebdSchin 	register char**	p;
466da2e3ebdSchin 	char*		q;
467da2e3ebdSchin 	char*		r;
468da2e3ebdSchin 	Time_t		x;
469da2e3ebdSchin 
470da2e3ebdSchin 	static int	initialized;
471da2e3ebdSchin 	static char**	datemask;
472da2e3ebdSchin 
473da2e3ebdSchin 	tmlocale();
474da2e3ebdSchin 	if (!format || !*format)
475da2e3ebdSchin 	{
476da2e3ebdSchin 		if (!initialized)
477da2e3ebdSchin 		{
478da2e3ebdSchin 			register Sfio_t*	sp;
479da2e3ebdSchin 			register int		n;
480da2e3ebdSchin 			off_t			m;
481da2e3ebdSchin 
482da2e3ebdSchin 			initialized = 1;
483da2e3ebdSchin 			if ((v = getenv("DATEMSK")) && *v && (sp = sfopen(NiL, v, "r")))
484da2e3ebdSchin 			{
485da2e3ebdSchin 				for (n = 1; sfgetr(sp, '\n', 0); n++);
486da2e3ebdSchin 				m = sfseek(sp, 0L, SEEK_CUR);
487da2e3ebdSchin 				if (p = newof(0, char*, n, m))
488da2e3ebdSchin 				{
489da2e3ebdSchin 					sfseek(sp, 0L, SEEK_SET);
490da2e3ebdSchin 					v = (char*)(p + n);
491da2e3ebdSchin 					if (sfread(sp, v, m) != m)
492da2e3ebdSchin 					{
493da2e3ebdSchin 						free(p);
494da2e3ebdSchin 						p = 0;
495da2e3ebdSchin 					}
496da2e3ebdSchin 					else
497da2e3ebdSchin 					{
498da2e3ebdSchin 						datemask = p;
499da2e3ebdSchin 						v[m] = 0;
500da2e3ebdSchin 						while (*v)
501da2e3ebdSchin 						{
502da2e3ebdSchin 							*p++ = v;
503da2e3ebdSchin 							if (!(v = strchr(v, '\n')))
504da2e3ebdSchin 								break;
505da2e3ebdSchin 							*v++ = 0;
506da2e3ebdSchin 						}
507da2e3ebdSchin 						*p = 0;
508da2e3ebdSchin 					}
509da2e3ebdSchin 				}
510da2e3ebdSchin 			}
511da2e3ebdSchin 		}
512da2e3ebdSchin 		if (p = datemask)
513da2e3ebdSchin 			while (v = *p++)
514da2e3ebdSchin 			{
515da2e3ebdSchin 				x = scan(s, &q, v, &r, t, flags);
516da2e3ebdSchin 				if (!*q && !*r)
517da2e3ebdSchin 				{
518da2e3ebdSchin 					if (e)
519da2e3ebdSchin 						*e = q;
520da2e3ebdSchin 					if (f)
521da2e3ebdSchin 						*f = r;
522da2e3ebdSchin 					return x;
523da2e3ebdSchin 				}
524da2e3ebdSchin 			}
525da2e3ebdSchin 		if (f)
526da2e3ebdSchin 			*f = (char*)format;
527da2e3ebdSchin 		if (format)
528da2e3ebdSchin 			return tmxdate(s, e, t);
529da2e3ebdSchin 		if (e)
530da2e3ebdSchin 			*e = (char*)s;
531da2e3ebdSchin 		return 0;
532da2e3ebdSchin 	}
533da2e3ebdSchin 	return scan(s, e, format, f, t, flags);
534da2e3ebdSchin }
535