0
|
1 #include <stdio.h>
|
|
2 #include <sys/time.h>
|
|
3 #include <ctype.h>
|
|
4
|
|
5 /*
|
|
6 ** promptdate
|
|
7 ** prompt user for a date specification which can be quite minimal
|
|
8 ** and print it in a form suitable for parsing by MH
|
|
9 */
|
|
10
|
|
11 #define MAXLINE 128
|
|
12
|
|
13 char *mname[12] ={
|
|
14 "Jan","Feb","Mar","Apr","May","Jun",
|
|
15 "Jul","Aug","Sep","Oct","Nov","Dec"};
|
|
16 char *dname[7] ={
|
|
17 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
|
|
18 struct tm now;
|
|
19 int dayspast = 0;
|
|
20 int monthlen[2][12] ={
|
|
21 31,28,31,30,31,30,31,31,30,31,30,31,
|
|
22 31,29,31,30,31,30,31,31,30,31,30,31};
|
|
23 char *defaultformat = "%d %N %y 00:00";
|
|
24
|
|
25 main(argc, argv)
|
|
26 int argc;
|
|
27 char **argv;
|
|
28 {
|
|
29 register int c;
|
|
30 struct tm then;
|
|
31 extern int optind; /* defined in getopt */
|
|
32 extern char *optarg; /* defined in getopt */
|
|
33 int getopt();
|
|
34 long secsfr70();
|
|
35
|
|
36 while ((c = getopt (argc, argv, "f:")) != EOF)
|
|
37 {
|
|
38 switch (c)
|
|
39 {
|
|
40 case 'f':
|
|
41 defaultformat = optarg;
|
|
42 break;
|
|
43 default:
|
|
44 fprintf(stderr, "usage: %s [-f format] [datespec]\n", argv[0]);
|
|
45 exit (1);
|
|
46 }
|
|
47 }
|
|
48 argc -= optind;
|
|
49 argv += optind;
|
|
50
|
|
51 finddate(&now, dayspast = (int)(secsfr70()/86400L));
|
|
52
|
|
53 if (argc <= 0) /* get from user */
|
|
54 {
|
|
55 if (!promptdate(&then))
|
|
56 exit(1);
|
|
57 printdate(&then, defaultformat);
|
|
58 }
|
|
59 else /* get from command line */
|
|
60 {
|
|
61 if (!decodedate(argv[0], &then))
|
|
62 exit(1);
|
|
63 printdate(&then, defaultformat);
|
|
64 }
|
|
65 exit(0);
|
|
66 }
|
|
67
|
|
68 int promptdate(when)
|
|
69 struct tm *when;
|
|
70 {
|
|
71 char line[MAXLINE];
|
|
72 int decodedate();
|
|
73 char *gets();
|
|
74
|
|
75 for (;;)
|
|
76 {
|
|
77 fprintf(stderr, "When? ");
|
|
78 if (gets(line) == NULL)
|
|
79 {
|
|
80 fprintf(stderr, "\n");
|
|
81 return (0);
|
|
82 }
|
|
83 if (decodedate(line, when))
|
|
84 return (1);
|
|
85 }
|
|
86 /*NOTREACHED*/
|
|
87 }
|
|
88
|
|
89 int decodedate(line, when)
|
|
90 char *line;
|
|
91 struct tm *when;
|
|
92 /*
|
|
93 ** accept spec for date in several forms
|
|
94 ** legal are: sun,mon,tue,wed,thu,fri,sat,today,tomorrow,
|
|
95 ** <date><month>,+<relative number of days>
|
|
96 ** <month> should be alpha
|
|
97 ** upper case accepted too
|
|
98 */
|
|
99 {
|
|
100 char s[4];
|
|
101 register int i,targetdate;
|
|
102 int tem;
|
|
103 register char *lptr;
|
|
104
|
|
105 when->tm_year = now.tm_year;
|
|
106 when->tm_mon = now.tm_mon;
|
|
107 targetdate = dayspast;
|
|
108 for (lptr = line; isspace(*lptr); lptr++)
|
|
109 ;
|
|
110 if (isdigit(*lptr))
|
|
111 {
|
|
112 i = sscanf(lptr, "%d%3s%d", &when->tm_mday, s, &tem);
|
|
113 switch(i)
|
|
114 {
|
|
115 case 3:
|
|
116 when->tm_year = tem;
|
|
117 case 2:
|
|
118 fold(s);
|
|
119 when->tm_mon = monthofyear(s);
|
|
120 if (i == 3)
|
|
121 break;
|
|
122 if (when->tm_mday != 0 && when->tm_mon != 0 && daysfr70(when) < dayspast)
|
|
123 when->tm_year++;
|
|
124 break;
|
|
125 case 1:
|
|
126 if (when->tm_mday != 0 && when->tm_mday < now.tm_mday)
|
|
127 {
|
|
128 if (++when->tm_mon > 12)
|
|
129 {
|
|
130 when->tm_mon = 1;
|
|
131 when->tm_year++;
|
|
132 }
|
|
133 }
|
|
134 }
|
|
135 return (validate(when));
|
|
136 }
|
|
137 if (isalpha(*lptr))
|
|
138 {
|
|
139 sscanf(lptr, "%3s", s);
|
|
140 fold(s);
|
|
141 if ((tem = dayofweek(s)) >= 0)
|
|
142 targetdate += (tem -= now.tm_wday) <= 0 ? tem + 7 : tem;
|
|
143 else if (strcmp(s, "Tom") == 0)
|
|
144 targetdate++;
|
|
145 else if (strcmp(s, "Tod") == 0)
|
|
146 ;
|
|
147 else /* mistake */
|
|
148 return (0);
|
|
149 }
|
|
150 else if (*lptr == '+')
|
|
151 {
|
|
152 if (sscanf(++lptr, "%d", &tem) == 0 || tem < 0) /* mistake */
|
|
153 return (0);
|
|
154 targetdate += tem;
|
|
155 }
|
|
156 else /* mistake by default */
|
|
157 return (0);
|
|
158 finddate(when, targetdate);
|
|
159 return (when->tm_mday != 0);
|
|
160 }
|
|
161
|
|
162 int validate(datetm)
|
|
163 /*
|
|
164 ** check that a given date and month combination is legal
|
|
165 ** datetm->tm_year must hold the year in question
|
|
166 */
|
|
167 register struct tm *datetm;
|
|
168 {
|
|
169
|
|
170 return (datetm->tm_mday <= monthlen[leapyear(datetm->tm_year)]
|
|
171 [datetm->tm_mon] && datetm->tm_mday > 0);
|
|
172 }
|
|
173
|
|
174 finddate(datetm, df70)
|
|
175 /*
|
|
176 ** convert days from 1 jan 1970 to a date in struct datetm
|
|
177 */
|
|
178 register int df70;
|
|
179 register struct tm *datetm;
|
|
180 {
|
|
181 register struct tm *tdtm;
|
|
182 long longtime;
|
|
183 struct tm *gmtime();
|
|
184
|
|
185 longtime = df70 * 86400L;
|
|
186 tdtm = gmtime(&longtime);
|
|
187 datetm->tm_yday = tdtm->tm_yday;
|
|
188 datetm->tm_wday = tdtm->tm_wday;
|
|
189 datetm->tm_year = tdtm->tm_year + 1900;
|
|
190 datetm->tm_mon = tdtm->tm_mon;
|
|
191 datetm->tm_mday = tdtm->tm_mday;
|
|
192 datetm->tm_hour = tdtm->tm_hour;
|
|
193 datetm->tm_min = tdtm->tm_min;
|
|
194 datetm->tm_sec = tdtm->tm_sec;
|
|
195 }
|
|
196
|
|
197 fold(s)
|
|
198 /*
|
|
199 ** convert first character to uppercase
|
|
200 ** convert rest of string from uppercase to lower case
|
|
201 */
|
|
202 register char *s;
|
|
203 {
|
|
204 register char c;
|
|
205
|
|
206 if ((c = *s) != '\0')
|
|
207 *s++ += islower(c) ? 'A' - 'a' : 0;
|
|
208 while ((c = *s) != '\0')
|
|
209 *s++ += isupper(c) ? 'a' - 'A' : 0;
|
|
210 }
|
|
211
|
|
212 int leapyear(y)
|
|
213 /*
|
|
214 ** returns 1 if leapyear 0 otherwise
|
|
215 */
|
|
216 register int y;
|
|
217 {
|
|
218
|
|
219 return (((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0);
|
|
220 }
|
|
221
|
|
222 int daysfr70(datetm)
|
|
223 /*
|
|
224 ** returns the number of days from 1 Jan 1970
|
|
225 ** no checking for illegal date at all
|
|
226 */
|
|
227 register struct tm *datetm;
|
|
228 {
|
|
229 register int i, totdays;
|
|
230
|
|
231
|
|
232 totdays = 0;
|
|
233 for (i = 1970; i <= 2050 && i < datetm->tm_year; i++) /* prevent overflow */
|
|
234 totdays += 365 + leapyear(i);
|
|
235 for (i = 0; i < 12 && i < datetm->tm_mon; i++)
|
|
236 totdays += monthlen[leapyear(datetm->tm_year)][i];
|
|
237 totdays += datetm->tm_mday - 1;
|
|
238 return (totdays);
|
|
239 }
|
|
240
|
|
241 int monthofyear(s)
|
|
242 /*
|
|
243 ** returns month of year in numeric form when given
|
|
244 ** the first three letters
|
|
245 */
|
|
246 register char *s;
|
|
247 {
|
|
248 register int i;
|
|
249
|
|
250 fold(s);
|
|
251 for (i = 12; i-- && strcmp(s,mname[i]); )
|
|
252 ;
|
|
253 return (i);
|
|
254 }
|
|
255
|
|
256 int dayofweek(s)
|
|
257 /*
|
|
258 ** sunday = 0,...,saturday = 6, nomatch = -1
|
|
259 */
|
|
260 register char *s;
|
|
261 {
|
|
262 register int i;
|
|
263
|
|
264 fold(s);
|
|
265 for (i = 7; i-- && strcmp(s,dname[i]); )
|
|
266 ;
|
|
267 return (i);
|
|
268 }
|
|
269
|
|
270 printdate(date, format)
|
|
271 /*
|
|
272 ** print date in MH acceptable format
|
|
273 ** kludge - general formats are not implemented
|
|
274 */
|
|
275 struct tm *date;
|
|
276 char *format;
|
|
277 {
|
|
278 printf("%d %s %d 00:00\n",
|
|
279 date->tm_mday, mname[date->tm_mon], date->tm_year);
|
|
280 }
|
|
281
|
|
282 long secsfr70()
|
|
283 /*
|
|
284 ** This is system dependent
|
|
285 */
|
|
286 {
|
|
287 register int dst;
|
|
288 struct timeval tv;
|
|
289 struct timezone tz;
|
|
290 struct tm *localtime();
|
|
291
|
|
292 gettimeofday(&tv, &tz);
|
|
293 dst = localtime(&tv.tv_sec)->tm_isdst;
|
|
294 return (tv.tv_sec - tz.tz_minuteswest * 60 + (dst ? 3600 : 0));
|
|
295 }
|