xref: /plan9-contrib/sys/src/cmd/calendar.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <regexp.h>
5 #include <ctype.h>
6 
7 typedef struct Date	Date;
8 struct Date {
9 	Reprog *p;	/* an RE to match this date */
10 	Date *next;	/* pointer to next in list */
11 };
12 
13 enum{
14 	Secondsperday = 24*60*60
15 };
16 
17 Date *Base = nil;
18 Biobuf in;
19 int debug, matchyear;
20 
21 void dates(Tm*);
22 void upper2lower(char*, char*, int);
23 void *emalloc(unsigned int);
24 
25 void
26 main(int argc, char *argv[])
27 {
28 	int i, fd, ahead;
29 	long now;
30 	char *line;
31 	Tm *tm;
32 	Date *d;
33 	char buf[1024];
34 
35 	ahead = 0;
36 	ARGBEGIN{
37 	case 'y':
38 		matchyear = 1;
39 		break;
40 	case 'd':
41 		debug = 1;
42 		break;
43 	case 'p':
44 		ahead = atoi(ARGF());
45 		break;
46 	default:
47 		fprint(2, "usage: calendar [-dy] [-p days] [files ...]\n");
48 		exits("usage");
49 	}ARGEND;
50 
51 	/* make a list of dates */
52 	now = time(0);
53 	tm = localtime(now);
54 	dates(tm);
55 	now += Secondsperday;
56 	tm = localtime(now);
57 	dates(tm);
58 	if(tm->wday == 6){
59 		now += Secondsperday;
60 		tm = localtime(now);
61 		dates(tm);
62 	}
63 	if(tm->wday == 0){
64 		now += Secondsperday;
65 		tm = localtime(now);
66 		dates(tm);
67 	}
68 	if(ahead){
69 		now = time(0);
70 		now += ahead * Secondsperday;
71 		tm = localtime(now);
72 		dates(tm);
73 	}
74 
75 	for(i=0; i<argc || (i==0 && argc==0); i++){
76 		if(i==0 && argc==0)
77 			snprint(buf, sizeof buf,
78 				"/usr/%s/lib/calendar", getuser());
79 		else
80 			strecpy(buf, buf+sizeof buf, argv[i]);
81 		fd = open(buf, OREAD);
82 		if(fd<0 || Binit(&in, fd, OREAD)<0){
83 			fprint(2, "calendar: can't open %s: %r\n", buf);
84 			exits("open");
85 		}
86 
87 		/* go through the file */
88 		while(line = Brdline(&in, '\n')){
89 			line[Blinelen(&in) - 1] = 0;
90 			upper2lower(buf, line, sizeof buf);
91 			for(d=Base; d; d=d->next)
92 				if(regexec(d->p, buf, 0, 0)){
93 					print("%s\n", line);
94 					break;
95 				}
96 		}
97 		close(fd);
98 	}
99 	exits("");
100 }
101 
102 char *months[] =
103 {
104 	"january",
105 	"february",
106 	"march",
107 	"april",
108 	"may",
109 	"june",
110 	"july",
111 	"august",
112 	"september",
113 	"october",
114 	"november",
115 	"december"
116 };
117 char *nth[] = {
118 	"first",
119 	"seccond",
120 	"third",
121 	"fourth",
122 	"fifth"
123 };
124 char *days[] = {
125 	"sunday",
126 	"monday",
127 	"tuesday",
128 	"wednesday",
129 	"thursday",
130 	"friday",
131 	"saturday"
132 };
133 
134 /*
135  * Generate two Date structures.  First has month followed by day;
136  * second has day followed by month.  Link them into list after
137  * last, and return the first.
138  */
139 void
140 dates(Tm *tm)
141 {
142 	Date *nd;
143 	char mo[128], day[128], buf[128];
144 
145 	if(utflen(days[tm->wday]) > 3)
146 		snprint(day, sizeof day, "%3.3s(%s)?",
147 			days[tm->wday], days[tm->wday]+3);
148 	else
149 		snprint(day, sizeof day, "%3.3s", days[tm->wday]);
150 
151 	if(utflen(months[tm->mon]) > 3)
152 		snprint(mo, sizeof mo, "%3.3s(%s)?",
153 			months[tm->mon], months[tm->mon]+3);
154 	else
155 		snprint(mo, sizeof mo, "%3.3s", months[tm->mon]);
156 	if (matchyear)
157 		snprint(buf, sizeof buf,
158 			"^[\t ]*((%s( |\t)+)|(%d/))%d( |\t|$)(((%d|%d|%02d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))",
159 			mo, tm->mon+1, tm->mday, tm->year+1900, tm->year%100, tm->year%100);
160 	else
161 		snprint(buf, sizeof buf,
162 			"^[\t ]*((%s( |\t)+)|(%d/))%d( |\t|$)",
163 			mo, tm->mon+1, tm->mday);
164 	if(debug)
165 		print("%s\n", buf);
166 
167 	nd = emalloc(sizeof(Date));
168 	nd->p = regcomp(buf);
169 	nd->next = Base;
170 	Base = nd;
171 
172 	if (matchyear)
173 		snprint(buf, sizeof buf,
174 			"^[\t ]*%d( |\t)+(%s)( |\t|$)(((%d|%d|%02d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))",
175 			tm->mday, mo, tm->year+1900, tm->year%100, tm->year%100);
176 	else
177 		snprint(buf, sizeof buf,
178 			"^[\t ]*%d( |\t)+(%s)( |\t|$)",
179 			tm->mday, mo);
180 	if(debug)
181 		print("%s\n", buf);
182 	nd = emalloc(sizeof(Date));
183 	nd->p = regcomp(buf);
184 	nd->next = Base;
185 	Base = nd;
186 
187 	snprint(buf, sizeof buf, "^[\t ]*every[ \t]+%s", day);
188 	if(debug)
189 		print("%s\n", buf);
190 	nd = emalloc(sizeof(Date));
191 	nd->p = regcomp(buf);
192 	nd->next = Base;
193 	Base = nd;
194 
195 	snprint(buf, sizeof buf, "[\t ]*the[\t ]+%s[\t ]+%s", nth[tm->mday/7], day);
196 	if(debug)
197 		print("%s\n", buf);
198 	nd = emalloc(sizeof(Date));
199 	nd->p = regcomp(buf);
200 	nd->next = Base;
201 	Base = nd;
202 }
203 
204 /*
205  * Copy 'from' to 'to', converting to lower case
206  */
207 void
208 upper2lower(char *to, char *from, int len)
209 {
210 	while(--len>0 && *from!='\0')
211 		*to++ = tolower(*from++);
212 	*to = 0;
213 }
214 
215 /*
216  * Call malloc and check for errors
217  */
218 void*
219 emalloc(unsigned int n)
220 {
221 	void *p;
222 
223 	p = malloc(n);
224 	if(p == 0){
225 		fprint(2, "calendar: malloc failed: %r\n");
226 		exits("malloc");
227 	}
228 	return p;
229 }
230