rsc | bc7cb1a | 2003-11-23 18:04:47 +0000 | [diff] [blame] | 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 | Biobuf in; |
| 18 | int debug, matchyear; |
| 19 | |
| 20 | Date *dates(Date**, Tm*); |
| 21 | void upper2lower(char*, char*, int); |
| 22 | void *alloc(unsigned int); |
| 23 | |
| 24 | void |
| 25 | main(int argc, char *argv[]) |
| 26 | { |
| 27 | int i, fd, ahead; |
| 28 | long now; |
| 29 | char *line; |
| 30 | Tm *tm; |
| 31 | Date *first, *last, *d; |
| 32 | char buf[1024]; |
| 33 | |
| 34 | ahead = 0; |
| 35 | ARGBEGIN{ |
| 36 | case 'y': |
| 37 | matchyear = 1; |
| 38 | break; |
| 39 | case 'd': |
| 40 | debug = 1; |
| 41 | break; |
| 42 | case 'p': |
| 43 | ahead = atoi(ARGF()); |
| 44 | break; |
| 45 | default: |
| 46 | fprint(2, "usage: calendar [-y] [-d] [files ...]\n"); |
| 47 | exits("usage"); |
| 48 | }ARGEND; |
| 49 | |
| 50 | /* make a list of dates */ |
| 51 | now = time(0); |
| 52 | tm = localtime(now); |
| 53 | last = nil; |
| 54 | first = dates(&last, tm); |
| 55 | now += Secondsperday; |
| 56 | tm = localtime(now); |
| 57 | dates(&last, tm); |
| 58 | if(tm->wday == 6){ |
| 59 | now += Secondsperday; |
| 60 | tm = localtime(now); |
| 61 | dates(&last, tm); |
| 62 | } |
| 63 | if(tm->wday == 0){ |
| 64 | now += Secondsperday; |
| 65 | tm = localtime(now); |
| 66 | dates(&last, tm); |
| 67 | } |
| 68 | if(ahead){ |
| 69 | now = time(0); |
| 70 | now += ahead * Secondsperday; |
| 71 | tm = localtime(now); |
| 72 | dates(&last, 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), |
rsc | c8b6342 | 2005-01-13 04:49:19 +0000 | [diff] [blame] | 78 | "%s/lib/calendar", getenv("HOME")); |
rsc | bc7cb1a | 2003-11-23 18:04:47 +0000 | [diff] [blame] | 79 | else |
| 80 | strcpy(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=first; 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 | |
| 118 | /* |
| 119 | * Generate two Date structures. First has month followed by day; |
| 120 | * second has day followed by month. Link them into list after |
| 121 | * last, and return the first. |
| 122 | */ |
| 123 | Date* |
| 124 | dates(Date **last, Tm *tm) |
| 125 | { |
| 126 | Date *first; |
| 127 | Date *nd; |
| 128 | char mo[128], buf[128]; |
| 129 | |
| 130 | if(utflen(months[tm->mon]) > 3) |
| 131 | snprint(mo, sizeof mo, "%3.3s(%s)?", |
| 132 | months[tm->mon], months[tm->mon]+3); |
| 133 | else |
| 134 | snprint(mo, sizeof mo, "%3.3s", months[tm->mon]); |
| 135 | if (matchyear) |
| 136 | snprint(buf, sizeof buf, |
| 137 | "(^| |\t)((%s( |\t)+)|(%d/))%d( |\t|$)(((%d|%d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))", |
| 138 | mo, tm->mon+1, tm->mday, tm->year+1900, tm->year%100); |
| 139 | else |
| 140 | snprint(buf, sizeof buf, |
| 141 | "(^| |\t)((%s( |\t)+)|(%d/))%d( |\t|$)", |
| 142 | mo, tm->mon+1, tm->mday); |
| 143 | if(debug) |
| 144 | print("%s\n", buf); |
| 145 | |
| 146 | first = alloc(sizeof(Date)); |
| 147 | if(*last) |
| 148 | (*last)->next = first; |
| 149 | first->p = regcomp(buf); |
| 150 | |
| 151 | if (matchyear) |
| 152 | snprint(buf, sizeof buf, |
| 153 | "(^| |\t)%d( |\t)+(%s)( |\t|$)(((%d|%d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))", |
| 154 | tm->mday, mo, tm->year+1900, tm->year%100); |
| 155 | else |
| 156 | snprint(buf, sizeof buf, |
| 157 | "(^| |\t)%d( |\t)+(%s)( |\t|$)", |
| 158 | tm->mday, mo); |
| 159 | if(debug) |
| 160 | print("%s\n", buf); |
| 161 | nd = alloc(sizeof(Date)); |
| 162 | nd->p = regcomp(buf); |
| 163 | nd->next = 0; |
| 164 | first->next = nd; |
| 165 | *last = nd; |
| 166 | |
| 167 | return first; |
| 168 | } |
| 169 | |
| 170 | /* |
| 171 | * Copy 'from' to 'to', converting to lower case |
| 172 | */ |
| 173 | void |
| 174 | upper2lower(char *to, char *from, int len) |
| 175 | { |
| 176 | while(--len>0 && *from!='\0') |
rsc | 1c171e3 | 2005-07-19 18:00:07 +0000 | [diff] [blame] | 177 | *to++ = tolower((uchar)*from++); |
rsc | bc7cb1a | 2003-11-23 18:04:47 +0000 | [diff] [blame] | 178 | *to = 0; |
| 179 | } |
| 180 | |
| 181 | /* |
| 182 | * Call malloc and check for errors |
| 183 | */ |
| 184 | void* |
| 185 | alloc(unsigned int n) |
| 186 | { |
| 187 | void *p; |
| 188 | |
| 189 | p = malloc(n); |
| 190 | if(p == 0){ |
| 191 | fprint(2, "calendar: malloc failed: %r\n"); |
| 192 | exits("malloc"); |
| 193 | } |
| 194 | return p; |
| 195 | } |