1 /*
2  * getabsdate - parse almost any absolute date getdate(3) can (& some it can't)
3  */
4 
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <string.h>
8 #include <time.h>
9 #include <sys/types.h>
10 #include <sys/timeb.h>
11 #include "dateconv.h"
12 #include "datetok.h"
13 #include "split.h"
14 
15 #define MAXDATEFIELDS 25
16 
17 /* imports */
18 extern int parsetime(register char *time, register struct tm *tm);
19 
20 /* forwards */
21 static int prsabsdate(char *timestr, struct timeb *now, register struct tm *tm, int *tzp);
22 
23 
24 
25 /* exports */
26 extern int dtok_numparsed;
27 
28 /*
29  * parse and convert absolute date in timestr (the normal interface)
30  */
31 time_t
getabsdate(timestr,now)32 getabsdate(timestr, now)
33 char *timestr;
34 struct timeb *now;
35 {
36 	int tz = 0;
37 	struct tm date;
38 
39 	return prsabsdate(timestr, now, &date, &tz) < 0? -1:
40 		dateconv(&date, tz);
41 }
42 
43 /*
44  * just parse the absolute date in timestr and get back a broken-out date.
45  */
46 static int
prsabsdate(timestr,now,tm,tzp)47 prsabsdate(timestr, now, tm, tzp)
48 char *timestr;
49 struct timeb *now;
50 register struct tm *tm;
51 int *tzp;
52 {
53 	register int nf;
54 	char *fields[MAXDATEFIELDS];
55 	static char delims[] = "- \t\n/,";
56 
57 	nf = split(timestr, fields, MAXDATEFIELDS, delims+1);
58 	if (nf > MAXDATEFIELDS)
59 		return -1;
60 	if (tryabsdate(fields, nf, now, tm, tzp) < 0) {
61 		register char *p = timestr;
62 
63 		/*
64 		 * could be a DEC-date; glue it all back together, split it
65 		 * with dash as a delimiter and try again.  Yes, this is a
66 		 * hack, but so are DEC-dates.
67 		 */
68 		while (--nf > 0) {
69 			while (*p++ != '\0')
70 				;
71 			p[-1] = ' ';
72 		}
73 		nf = split(timestr, fields, MAXDATEFIELDS, delims);
74 		if (nf > MAXDATEFIELDS)
75 			return -1;
76 		if (tryabsdate(fields, nf, now, tm, tzp) < 0)
77 			return -1;
78 	}
79 	return 0;
80 }
81 
82 /*
83  * try to parse pre-split timestr as an absolute date
84  */
85 int
tryabsdate(fields,nf,now,tm,tzp)86 tryabsdate(fields, nf, now, tm, tzp)
87 char *fields[];
88 int nf;
89 struct timeb *now;
90 register struct tm *tm;
91 int *tzp;
92 {
93 	register int i;
94 	register datetkn *tp;
95 	register long flg = 0, ty;
96 	int mer = HR24, bigval = -1;
97 	struct timeb ftz;
98 
99 	if (now == NULL) {		/* default to local time (zone) */
100 		now = &ftz;
101 		(void) ftime(now);
102 	}
103 	*tzp = now->timezone;
104 
105 	tm->tm_mday = tm->tm_mon = tm->tm_year = -1;	/* mandatory */
106 	tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
107 	tm->tm_isdst = 0;
108 	dtok_numparsed = 0;
109 
110 	for (i = 0; i < nf; i++) {
111 		if (fields[i][0] == '\0')
112 			continue;
113 		tp = datetoktype(fields[i], &bigval);
114 		ty = (1L << tp->type) & ~(1L << IGNORE);
115 		if (flg&ty)
116 			return -1;		/* repeated type */
117 		flg |= ty;
118 		switch (tp->type) {
119 		case YEAR:
120 			tm->tm_year = bigval;
121 
122 			/* convert 2-digit year 20xx to 1900 origin */
123 			if (tm->tm_year < 70) /* y2k */
124 				tm->tm_year += 100;
125 
126 			/* convert 4-digit year to 1900 origin */
127 			else if (tm->tm_year >= 1900)
128 				tm->tm_year -= 1900;
129 			break;
130 		case DAY:
131 			tm->tm_mday = bigval;
132 			break;
133 		case MONTH:
134 			tm->tm_mon = tp->value - 1; /* convert to zero-origin */
135 			break;
136 		case TIME:
137 			if (parsetime(fields[i], tm) < 0)
138 				return -1;
139 			break;
140 		case DTZ:
141 #if 0
142 			tm->tm_isdst++;
143 #endif
144 			/* FALLTHROUGH */
145 		case TZ:
146 			*tzp = FROMVAL(tp);
147 			break;
148 		case IGNORE:
149 			break;
150 		case AMPM:
151 			mer = tp->value;
152 			break;
153 		default:
154 			return -1;	/* bad token type: CANTHAPPEN */
155 		}
156 	}
157 	if (tm->tm_year == -1 || tm->tm_mon == -1 || tm->tm_mday == -1)
158 		return -1;		/* missing component */
159 	if (mer == PM)
160 		tm->tm_hour += 12;
161 	return 0;
162 }
163