Added all of the MH sources, including RCS files, in
[mmh] / 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 }