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