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