1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
27 * Time_t conversion support
29 * scan date expression in s using format
30 * if non-null, e points to the first invalid sequence in s
31 * if non-null, f points to the first unused format char
32 * t provides default values
55 #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)
57 #define INDEX(m,x) (((n)>=((x)-(m)))?((n)-=((x)-(m))):(n))
59 #define NUMBER(d,m,x) do \
63 while (s < (const char*)(u + d) && *s >= '0' && *s <= '9') \
64 n = n * 10 + *s++ - '0'; \
65 if (u == (char*)s || n < m || n > x) \
70 * generate a Time_t from tm + set
74 gen(register Tm_t
* tm
, register Set_t
* set
)
81 tm
->tm_year
= set
->year
;
84 if (set
->year
< 0 && set
->mon
< tm
->tm_mon
)
86 tm
->tm_mon
= set
->mon
;
87 if (set
->yday
< 0 && set
->mday
< 0)
88 tm
->tm_mday
= set
->mday
= 1;
94 tmweek(tm
, set
->weektype
, set
->week
, set
->wday
);
98 else if (set
->yday
>= 0)
103 tm
->tm_mday
= set
->yday
+ 1;
106 else if (set
->mday
>= 0)
107 tm
->tm_mday
= set
->mday
;
110 if (set
->hour
< tm
->tm_hour
&& set
->yday
< 0 && set
->mday
< 0 && set
->wday
< 0)
112 tm
->tm_hour
= set
->hour
;
113 tm
->tm_min
= (set
->min
>= 0) ? set
->min
: 0;
114 tm
->tm_sec
= (set
->sec
>= 0) ? set
->sec
: 0;
116 else if (set
->min
>= 0)
118 tm
->tm_min
= set
->min
;
119 tm
->tm_sec
= (set
->sec
>= 0) ? set
->sec
: 0;
121 else if (set
->sec
>= 0)
122 tm
->tm_sec
= set
->sec
;
123 if (set
->nsec
< 1000000000L)
124 tm
->tm_nsec
= set
->nsec
;
125 if (set
->meridian
> 0)
127 if (tm
->tm_hour
< 12)
130 else if (set
->meridian
== 0)
132 if (tm
->tm_hour
>= 12)
135 t
= tmxtime(tm
, set
->zone
);
139 tm
= tmxtm(tm
, t
, tm
->tm_zone
);
140 tm
->tm_mday
+= set
->yday
- tm
->tm_yday
;
142 else if (set
->wday
>= 0)
145 tm
= tmxtm(tm
, t
, tm
->tm_zone
);
146 if ((n
= set
->wday
- tm
->tm_wday
) < 0)
152 if (set
->nsec
< 1000000000L)
157 tm
= tmxtm(tm
, t
, tm
->tm_zone
);
159 tm
->tm_nsec
= set
->nsec
;
161 return z
? tmxtime(tm
, set
->zone
) : t
;
165 * the format scan workhorse
169 scan(register const char* s
, char** e
, const char* format
, char** f
, Time_t t
, long flags
)
187 char** sp
= &stack
[0];
194 tm
= tmxtm(&ts
, t
, NiL
);
195 pedantic
= (flags
& TM_PEDANTIC
) != 0;
198 if (!(d
= *format
++))
205 format
= (const char*)*--sp
;
212 else if (d
== '%' && (d
= *format
) && format
++ && d
!= '%')
219 hi
= pedantic
? TM_DAY
: TM_TIME
;
222 lo
= pedantic
? TM_DAY
: TM_DAY_ABBREV
;
225 if ((n
= tmlex(s
, &u
, tm_info
.format
+ lo
, hi
- lo
, NiL
, 0)) < 0)
228 INDEX(TM_DAY_ABBREV
, TM_DAY
);
233 lo
= TM_MONTH_ABBREV
;
234 hi
= pedantic
? TM_MONTH
: TM_DAY_ABBREV
;
237 lo
= pedantic
? TM_MONTH
: TM_MONTH_ABBREV
;
240 if ((n
= tmlex(s
, &u
, tm_info
.format
+ lo
, hi
- lo
, NiL
, 0)) < 0)
243 INDEX(TM_MONTH_ABBREV
, TM_MONTH
);
247 p
= "%a %b %e %T %Y";
251 set
.year
= (n
- 19) * 100 + tm
->tm_year
% 100;
254 if (pedantic
&& !isdigit(*s
))
306 NUMBER(9, 0, 999999999L);
310 if ((n
= tmlex(s
, &u
, tm_info
.format
+ TM_MERIDIAN
, TM_UT
- TM_MERIDIAN
, NiL
, 0)) < 0)
322 x
= strtoul(s
, &u
, 0);
325 tm
= tmxtm(tm
, tmxsns(x
, 0), tm
->tm_zone
);
357 p
= tm_info
.format
[TM_DATE
];
360 p
= tm_info
.format
[TM_TIME
];
369 NUMBER(4, 1969, 2100);
374 if (zp
= tmtype(s
, &u
))
384 if ((zp
= tmzone(s
, &u
, u
, &m
)))
387 set
.zone
= zp
->west
+ m
;
396 x
= tmxdate(s
, e
, t
);
397 if (s
== (const char*)*e
)
401 if (!*format
|| *format
== '%' && *(format
+ 1) == '|')
407 if (sp
>= &stack
[elementsof(stack
)])
409 *sp
++ = (char*)format
;
410 format
= (const char*)p
;
422 format
= (const char*)stack
[0];
426 if (!*s
&& *p
== '%' && *(p
+ 1) == '|')
427 format
+= strlen(format
);
430 if (*p
++ == '%' && *p
&& *p
++ == '|' && *p
)
432 format
= (const char*)p
;
447 while (isspace(*format
))
456 * *format==0 DATEMSK and tmxdate()
461 tmxscan(const char* s
, char** e
, const char* format
, char** f
, Time_t t
, long flags
)
469 static int initialized
;
470 static char** datemask
;
473 if (!format
|| !*format
)
482 if ((v
= getenv("DATEMSK")) && *v
&& (sp
= sfopen(NiL
, v
, "r")))
484 for (n
= 1; sfgetr(sp
, '\n', 0); n
++);
485 m
= sfseek(sp
, 0L, SEEK_CUR
);
486 if (p
= newof(0, char*, n
, m
))
488 sfseek(sp
, 0L, SEEK_SET
);
490 if (sfread(sp
, v
, m
) != m
)
502 if (!(v
= strchr(v
, '\n')))
514 x
= scan(s
, &q
, v
, &r
, t
, flags
);
527 return tmxdate(s
, e
, t
);
532 return scan(s
, e
, format
, f
, t
, flags
);