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