xref: /plan9/sys/src/cmd/calendar.c (revision 7386956ab8f0263f8da0655d57bc42a48d63dd18)
1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include <regexp.h>
5219b2ee8SDavid du Colombier #include <ctype.h>
6219b2ee8SDavid du Colombier 
7219b2ee8SDavid du Colombier typedef struct Date	Date;
8219b2ee8SDavid du Colombier struct Date {
97dd7cddfSDavid du Colombier 	Reprog *p;	/* an RE to match this date */
107dd7cddfSDavid du Colombier 	Date *next;	/* pointer to next in list */
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier enum{
147dd7cddfSDavid du Colombier 	Secondsperday = 24*60*60
15219b2ee8SDavid du Colombier };
16219b2ee8SDavid du Colombier 
17f48db99cSDavid du Colombier Date *Base = nil;
18219b2ee8SDavid du Colombier Biobuf in;
1980ee5cbfSDavid du Colombier int debug, matchyear;
20219b2ee8SDavid du Colombier 
21f48db99cSDavid du Colombier void dates(Tm*);
22219b2ee8SDavid du Colombier void upper2lower(char*, char*, int);
23f48db99cSDavid du Colombier void *emalloc(unsigned int);
24219b2ee8SDavid du Colombier 
25219b2ee8SDavid du Colombier void
usage(void)26de8abbc9SDavid du Colombier usage(void)
27de8abbc9SDavid du Colombier {
28de8abbc9SDavid du Colombier 	fprint(2, "usage: calendar [-dy] [-p days] [files ...]\n");
29de8abbc9SDavid du Colombier 	exits("usage");
30de8abbc9SDavid du Colombier }
31de8abbc9SDavid du Colombier 
32de8abbc9SDavid du Colombier void
main(int argc,char * argv[])33219b2ee8SDavid du Colombier main(int argc, char *argv[])
34219b2ee8SDavid du Colombier {
353ff48bf5SDavid du Colombier 	int i, fd, ahead;
36219b2ee8SDavid du Colombier 	long now;
37219b2ee8SDavid du Colombier 	char *line;
38219b2ee8SDavid du Colombier 	Tm *tm;
39f48db99cSDavid du Colombier 	Date *d;
40219b2ee8SDavid du Colombier 	char buf[1024];
41219b2ee8SDavid du Colombier 
423ff48bf5SDavid du Colombier 	ahead = 0;
43219b2ee8SDavid du Colombier 	ARGBEGIN{
4480ee5cbfSDavid du Colombier 	case 'y':
4580ee5cbfSDavid du Colombier 		matchyear = 1;
4680ee5cbfSDavid du Colombier 		break;
47219b2ee8SDavid du Colombier 	case 'd':
48219b2ee8SDavid du Colombier 		debug = 1;
49219b2ee8SDavid du Colombier 		break;
503ff48bf5SDavid du Colombier 	case 'p':
51de8abbc9SDavid du Colombier 		ahead = atoi(EARGF(usage()));
523ff48bf5SDavid du Colombier 		break;
537dd7cddfSDavid du Colombier 	default:
54de8abbc9SDavid du Colombier 		usage();
55219b2ee8SDavid du Colombier 	}ARGEND;
56219b2ee8SDavid du Colombier 
57219b2ee8SDavid du Colombier 	/* make a list of dates */
58219b2ee8SDavid du Colombier 	now = time(0);
59219b2ee8SDavid du Colombier 	tm = localtime(now);
60f48db99cSDavid du Colombier 	dates(tm);
617dd7cddfSDavid du Colombier 	now += Secondsperday;
627dd7cddfSDavid du Colombier 	tm = localtime(now);
63f48db99cSDavid du Colombier 	dates(tm);
64219b2ee8SDavid du Colombier 	if(tm->wday == 6){
657dd7cddfSDavid du Colombier 		now += Secondsperday;
667dd7cddfSDavid du Colombier 		tm = localtime(now);
67f48db99cSDavid du Colombier 		dates(tm);
68219b2ee8SDavid du Colombier 	}
69219b2ee8SDavid du Colombier 	if(tm->wday == 0){
707dd7cddfSDavid du Colombier 		now += Secondsperday;
717dd7cddfSDavid du Colombier 		tm = localtime(now);
72f48db99cSDavid du Colombier 		dates(tm);
73219b2ee8SDavid du Colombier 	}
743ff48bf5SDavid du Colombier 	if(ahead){
753ff48bf5SDavid du Colombier 		now = time(0);
763ff48bf5SDavid du Colombier 		now += ahead * Secondsperday;
773ff48bf5SDavid du Colombier 		tm = localtime(now);
78f48db99cSDavid du Colombier 		dates(tm);
793ff48bf5SDavid du Colombier 	}
80219b2ee8SDavid du Colombier 
817dd7cddfSDavid du Colombier 	for(i=0; i<argc || (i==0 && argc==0); i++){
827dd7cddfSDavid du Colombier 		if(i==0 && argc==0)
834d44ba9bSDavid du Colombier 			snprint(buf, sizeof buf,
847dd7cddfSDavid du Colombier 				"/usr/%s/lib/calendar", getuser());
857dd7cddfSDavid du Colombier 		else
864d44ba9bSDavid du Colombier 			strecpy(buf, buf+sizeof buf, argv[i]);
877dd7cddfSDavid du Colombier 		fd = open(buf, OREAD);
887dd7cddfSDavid du Colombier 		if(fd<0 || Binit(&in, fd, OREAD)<0){
897dd7cddfSDavid du Colombier 			fprint(2, "calendar: can't open %s: %r\n", buf);
907dd7cddfSDavid du Colombier 			exits("open");
917dd7cddfSDavid du Colombier 		}
927dd7cddfSDavid du Colombier 
93219b2ee8SDavid du Colombier 		/* go through the file */
94219b2ee8SDavid du Colombier 		while(line = Brdline(&in, '\n')){
95219b2ee8SDavid du Colombier 			line[Blinelen(&in) - 1] = 0;
967dd7cddfSDavid du Colombier 			upper2lower(buf, line, sizeof buf);
97f48db99cSDavid du Colombier 			for(d=Base; d; d=d->next)
98219b2ee8SDavid du Colombier 				if(regexec(d->p, buf, 0, 0)){
99219b2ee8SDavid du Colombier 					print("%s\n", line);
100219b2ee8SDavid du Colombier 					break;
101219b2ee8SDavid du Colombier 				}
102219b2ee8SDavid du Colombier 		}
1037dd7cddfSDavid du Colombier 		close(fd);
1047dd7cddfSDavid du Colombier 	}
1057dd7cddfSDavid du Colombier 	exits("");
106219b2ee8SDavid du Colombier }
107219b2ee8SDavid du Colombier 
108219b2ee8SDavid du Colombier char *months[] =
109219b2ee8SDavid du Colombier {
110219b2ee8SDavid du Colombier 	"january",
111219b2ee8SDavid du Colombier 	"february",
112219b2ee8SDavid du Colombier 	"march",
113219b2ee8SDavid du Colombier 	"april",
114219b2ee8SDavid du Colombier 	"may",
115219b2ee8SDavid du Colombier 	"june",
116219b2ee8SDavid du Colombier 	"july",
117219b2ee8SDavid du Colombier 	"august",
118219b2ee8SDavid du Colombier 	"september",
119219b2ee8SDavid du Colombier 	"october",
120219b2ee8SDavid du Colombier 	"november",
121219b2ee8SDavid du Colombier 	"december"
122219b2ee8SDavid du Colombier };
123f48db99cSDavid du Colombier char *nth[] = {
124f48db99cSDavid du Colombier 	"first",
125*7386956aSDavid du Colombier 	"second",
126f48db99cSDavid du Colombier 	"third",
127f48db99cSDavid du Colombier 	"fourth",
128f48db99cSDavid du Colombier 	"fifth"
129f48db99cSDavid du Colombier };
130f48db99cSDavid du Colombier char *days[] = {
131f48db99cSDavid du Colombier 	"sunday",
132f48db99cSDavid du Colombier 	"monday",
133f48db99cSDavid du Colombier 	"tuesday",
134f48db99cSDavid du Colombier 	"wednesday",
135f48db99cSDavid du Colombier 	"thursday",
136f48db99cSDavid du Colombier 	"friday",
137f48db99cSDavid du Colombier 	"saturday"
138f48db99cSDavid du Colombier };
139219b2ee8SDavid du Colombier 
1407dd7cddfSDavid du Colombier /*
1417dd7cddfSDavid du Colombier  * Generate two Date structures.  First has month followed by day;
1427dd7cddfSDavid du Colombier  * second has day followed by month.  Link them into list after
1437dd7cddfSDavid du Colombier  * last, and return the first.
1447dd7cddfSDavid du Colombier  */
145f48db99cSDavid du Colombier void
dates(Tm * tm)146f48db99cSDavid du Colombier dates(Tm *tm)
147219b2ee8SDavid du Colombier {
148219b2ee8SDavid du Colombier 	Date *nd;
149f48db99cSDavid du Colombier 	char mo[128], day[128], buf[128];
150f48db99cSDavid du Colombier 
151f48db99cSDavid du Colombier 	if(utflen(days[tm->wday]) > 3)
152f48db99cSDavid du Colombier 		snprint(day, sizeof day, "%3.3s(%s)?",
153f48db99cSDavid du Colombier 			days[tm->wday], days[tm->wday]+3);
154f48db99cSDavid du Colombier 	else
155f48db99cSDavid du Colombier 		snprint(day, sizeof day, "%3.3s", days[tm->wday]);
156219b2ee8SDavid du Colombier 
15759cc4ca5SDavid du Colombier 	if(utflen(months[tm->mon]) > 3)
15859cc4ca5SDavid du Colombier 		snprint(mo, sizeof mo, "%3.3s(%s)?",
159219b2ee8SDavid du Colombier 			months[tm->mon], months[tm->mon]+3);
160219b2ee8SDavid du Colombier 	else
16159cc4ca5SDavid du Colombier 		snprint(mo, sizeof mo, "%3.3s", months[tm->mon]);
16280ee5cbfSDavid du Colombier 	if (matchyear)
16380ee5cbfSDavid du Colombier 		snprint(buf, sizeof buf,
164f48db99cSDavid du Colombier 			"^[\t ]*((%s( |\t)+)|(%d/))%d( |\t|$)(((%d|%d|%02d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))",
165f48db99cSDavid du Colombier 			mo, tm->mon+1, tm->mday, tm->year+1900, tm->year%100, tm->year%100);
16680ee5cbfSDavid du Colombier 	else
1677dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf,
168f48db99cSDavid du Colombier 			"^[\t ]*((%s( |\t)+)|(%d/))%d( |\t|$)",
1697dd7cddfSDavid du Colombier 			mo, tm->mon+1, tm->mday);
170219b2ee8SDavid du Colombier 	if(debug)
171219b2ee8SDavid du Colombier 		print("%s\n", buf);
1727dd7cddfSDavid du Colombier 
173f48db99cSDavid du Colombier 	nd = emalloc(sizeof(Date));
174f48db99cSDavid du Colombier 	nd->p = regcomp(buf);
175f48db99cSDavid du Colombier 	nd->next = Base;
176f48db99cSDavid du Colombier 	Base = nd;
177219b2ee8SDavid du Colombier 
17880ee5cbfSDavid du Colombier 	if (matchyear)
17980ee5cbfSDavid du Colombier 		snprint(buf, sizeof buf,
180f48db99cSDavid du Colombier 			"^[\t ]*%d( |\t)+(%s)( |\t|$)(((%d|%d|%02d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))",
181f48db99cSDavid du Colombier 			tm->mday, mo, tm->year+1900, tm->year%100, tm->year%100);
18280ee5cbfSDavid du Colombier 	else
1837dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf,
184f48db99cSDavid du Colombier 			"^[\t ]*%d( |\t)+(%s)( |\t|$)",
185219b2ee8SDavid du Colombier 			tm->mday, mo);
186219b2ee8SDavid du Colombier 	if(debug)
187219b2ee8SDavid du Colombier 		print("%s\n", buf);
188f48db99cSDavid du Colombier 	nd = emalloc(sizeof(Date));
189219b2ee8SDavid du Colombier 	nd->p = regcomp(buf);
190f48db99cSDavid du Colombier 	nd->next = Base;
191f48db99cSDavid du Colombier 	Base = nd;
192219b2ee8SDavid du Colombier 
193f48db99cSDavid du Colombier 	snprint(buf, sizeof buf, "^[\t ]*every[ \t]+%s", day);
194f48db99cSDavid du Colombier 	if(debug)
195f48db99cSDavid du Colombier 		print("%s\n", buf);
196f48db99cSDavid du Colombier 	nd = emalloc(sizeof(Date));
197f48db99cSDavid du Colombier 	nd->p = regcomp(buf);
198f48db99cSDavid du Colombier 	nd->next = Base;
199f48db99cSDavid du Colombier 	Base = nd;
200f48db99cSDavid du Colombier 
201*7386956aSDavid du Colombier 	snprint(buf, sizeof buf, "[\t ]*the[\t ]+%s[\t ]+%s", nth[(tm->mday-1)/7], day);
202f48db99cSDavid du Colombier 	if(debug)
203f48db99cSDavid du Colombier 		print("%s\n", buf);
204f48db99cSDavid du Colombier 	nd = emalloc(sizeof(Date));
205f48db99cSDavid du Colombier 	nd->p = regcomp(buf);
206f48db99cSDavid du Colombier 	nd->next = Base;
207f48db99cSDavid du Colombier 	Base = nd;
208219b2ee8SDavid du Colombier }
209219b2ee8SDavid du Colombier 
2107dd7cddfSDavid du Colombier /*
2117dd7cddfSDavid du Colombier  * Copy 'from' to 'to', converting to lower case
2127dd7cddfSDavid du Colombier  */
213219b2ee8SDavid du Colombier void
upper2lower(char * to,char * from,int len)2147dd7cddfSDavid du Colombier upper2lower(char *to, char *from, int len)
215219b2ee8SDavid du Colombier {
2167dd7cddfSDavid du Colombier 	while(--len>0 && *from!='\0')
2177dd7cddfSDavid du Colombier 		*to++ = tolower(*from++);
218219b2ee8SDavid du Colombier 	*to = 0;
219219b2ee8SDavid du Colombier }
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier /*
2227dd7cddfSDavid du Colombier  * Call malloc and check for errors
2237dd7cddfSDavid du Colombier  */
2247dd7cddfSDavid du Colombier void*
emalloc(unsigned int n)225f48db99cSDavid du Colombier emalloc(unsigned int n)
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier 	void *p;
2287dd7cddfSDavid du Colombier 
2297dd7cddfSDavid du Colombier 	p = malloc(n);
2307dd7cddfSDavid du Colombier 	if(p == 0){
2317dd7cddfSDavid du Colombier 		fprint(2, "calendar: malloc failed: %r\n");
2327dd7cddfSDavid du Colombier 		exits("malloc");
2337dd7cddfSDavid du Colombier 	}
2347dd7cddfSDavid du Colombier 	return p;
2357dd7cddfSDavid du Colombier }
236