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