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