bday
changeset 0:22b6e71de68e
initial commit; codebase from birthday; just the needed stuff; substituted getopt by own code
author | meillo@marmaro.de |
---|---|
date | Sun, 16 Dec 2007 22:26:48 +0100 |
parents | |
children | 8534f0e3a0db |
files | .hgignore Makefile bdengine.c birthday.c birthday.h |
diffstat | 5 files changed, 924 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Sun Dec 16 22:26:48 2007 +0100 1.3 @@ -0,0 +1,7 @@ 1.4 +syntax: glob 1.5 + 1.6 +*~ 1.7 +*.swp 1.8 + 1.9 +*.o 1.10 +bday
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Sun Dec 16 22:26:48 2007 +0100 2.3 @@ -0,0 +1,31 @@ 2.4 +###################################################################### 2.5 +# birthday. Reminder of birthdays and other events in the near future. 2.6 +# $Id: Makefile.in,v 1.3 2000/01/02 19:17:33 andy Exp $ 2.7 + 2.8 + 2.9 +CFLAGS=-O2 -Wall -Wstrict-prototypes 2.10 + 2.11 + 2.12 +SRC=birthday.c bdengine.c 2.13 +OBJ=$(SRC:.c=.o) 2.14 +EXE=bday 2.15 + 2.16 +all: ${EXE} 2.17 + 2.18 +${EXE}: $(OBJ) 2.19 + $(CC) $(LDFLAGS) $(OBJ) -o $@ 2.20 + 2.21 + 2.22 +install: birthday birthday.man 2.23 + mkdir -p $(DESTDIR)/usr/bin $(DESTDIR)/usr/share/man/man1 2.24 + cp ${EXE} $(DESTDIR)/usr/bin/${EXE} 2.25 + chmod 0755 $(DESTDIR)/usr/bin/${EXE} 2.26 + cp ${EXE}.man $(DESTDIR)/usr/share/man/man1/${EXE}.1 2.27 + chmod 0644 $(DESTDIR)/usr/share/man/man1/${EXE}.1 2.28 + 2.29 + 2.30 +clean: 2.31 + rm -f *.o 2.32 + 2.33 +realclean: clean 2.34 + rm -f ${EXE}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/bdengine.c Sun Dec 16 22:26:48 2007 +0100 3.3 @@ -0,0 +1,717 @@ 3.4 +/* 3.5 + birthday.c 3.6 + 3.7 + Birthday/Anniversary display on login 3.8 + 3.9 + (c) 1996 AS Mortimer 3.10 + 3.11 + This program is free software; you can redistribute it and/or 3.12 + modify it under the terms of the GNU General Public License as 3.13 + published by the Free Software Foundation; either version 2 of the 3.14 + License, or (at your option) any later version. You may also 3.15 + distribute it under the Artistic License, as comes with Perl. 3.16 + 3.17 + This program is distributed in the hope that it will be useful, 3.18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 3.19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 3.20 + 3.21 + You should have received a copy of the GNU General Public License 3.22 + along with this program; if not, write to the Free Software 3.23 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 3.24 + 3.25 + You should also have recieved a copy of the Artistic license with 3.26 + this program. 3.27 + 3.28 + $Id: bdengine.c,v 1.14 2001/10/21 07:03:49 andy Exp $ 3.29 + 3.30 + We're getting there. At the moment, the file used by default is ~/.birthdays 3.31 + under UNIX, or C:\PERSONAL\BDAYS.LST under DOS, but this can be overridden on 3.32 + the command line. The file has the following format: 3.33 + 3.34 + name/event/whatever=date flags 3.35 + where: 3.36 + date is dd/mm, dd/mm/yy (assumes 20th century!) or dd/mm/yyyy 3.37 + flags is ONE or ZERO of 3.38 + o bd for a birthday (default) 3.39 + o bir for a birthday (exactly equivalent to `bd') 3.40 + o ann for an anniversary 3.41 + o ev for an event 3.42 + and zero or more of 3.43 + o w<n> to set the warn-in-advance time to n days (don't include the 3.44 + brackets! :) 3.45 + o to<date> 3.46 + o for<days> 3.47 + to specify the length of time taken by an event, for example a 3.48 + holiday. 3.49 + 3.50 + Comment lines are preceeded by #. 3.51 + 3.52 + Note: If you deviate from this format, I cannot guarantee anything about 3.53 + it's behaviour. In most cases, it will just quietly ignore the error, 3.54 + which probably isn't ideal behaviour. Oh, well. 3.55 + 3.56 + 2003/05/20: Automatic reallocation of output buffer in listsrings() by 3.57 + Sebastian Schmidt <yath@yath.eu.org>. 3.58 + 3.59 +*/ 3.60 + 3.61 + 3.62 + 3.63 +/* ========== */ 3.64 + 3.65 + 3.66 +#include <stdio.h> 3.67 +#include <stdarg.h> 3.68 +#include <stdlib.h> 3.69 +#include <string.h> 3.70 +#include <time.h> 3.71 + 3.72 +#include <sys/types.h> 3.73 +#include <unistd.h> 3.74 +#include <pwd.h> 3.75 + 3.76 +#include "birthday.h" 3.77 + 3.78 +/* ========== */ 3.79 + 3.80 + 3.81 + 3.82 +/* 3.83 + xmalloc/xrealloc functions, and fatal exit function 3.84 + Note: the x* functions are lifted straight from the GNU libc info docs 3.85 + $Id: xmalloc.c,v 1.2 1999/01/16 17:08:59 andy Exp $ 3.86 +*/ 3.87 + 3.88 +void *xmalloc (size_t size) { 3.89 + register void *value = malloc (size); 3.90 + if (value == 0) { 3.91 + fprintf(stderr, "virtual memory exhausted\n"); 3.92 + exit(1); 3.93 + } 3.94 + return value; 3.95 +} 3.96 + 3.97 + 3.98 +void *xrealloc (void *ptr, size_t size) { 3.99 + register void *value = realloc (ptr, size); 3.100 + if (value == 0) { 3.101 + fprintf(stderr, "virtual memory exhausted\n"); 3.102 + exit(1); 3.103 + } 3.104 + return value; 3.105 +} 3.106 + 3.107 +/* ========== */ 3.108 + 3.109 + 3.110 + 3.111 + 3.112 + 3.113 + 3.114 +int skptok(int j, char *ptr); 3.115 +int evcmp(const void *e1, const void *e2); 3.116 +char *deffname(void); 3.117 + 3.118 +struct event *dir_include(char *dir, char *parm); 3.119 + 3.120 +/* ========== Global variables */ 3.121 + 3.122 +struct date today; 3.123 +int iDWarn = DEF_WARN; 3.124 +int iMaxWarn = MAX_WARN; 3.125 +int iMinWarn = MIN_WARN; 3.126 + 3.127 +const unsigned MLENDAT[]={31,-1,31,30,31,30,31,31,30,31,30,31}; 3.128 + 3.129 +const struct _ftable FTABLE[] = { 3.130 + {"bir",F_TBIRTHDAY}, 3.131 + {"bd", F_TBIRTHDAY}, 3.132 + {"ann",F_TANNIVERSARY}, 3.133 + {"ev", F_TEVENT}, 3.134 + {"mes", F_TMESSAGE}, 3.135 + {"w", F_WTIME_P}, 3.136 + {"to", F_TODATE}, 3.137 + {"for", F_FORDAYS}, 3.138 + {NULL, 0} 3.139 +}; 3.140 + 3.141 + 3.142 +/* list of directives. These are entered in the file prefixed by '&'. The function should be declared as 3.143 + struct event *dir_func(char *directive, char *parameters); 3.144 + and should return a pointer to a NULL-terminated list of extra records, or NULL if there are none. 3.145 + This structure will allow us to dynamically add directives, if we wish to do so in the future. 3.146 + */ 3.147 + 3.148 +struct { 3.149 + const char *text; 3.150 + int len; 3.151 + struct event *(*func)(char*,char*); 3.152 +} directlist[] = { 3.153 + { "include", 0, dir_include }, 3.154 + { NULL, 0, NULL } 3.155 +}; 3.156 + 3.157 +/* ========== */ 3.158 + 3.159 + 3.160 + 3.161 + 3.162 +/* compare the first strlen(a) characters of a and b */ 3.163 +#define strbegcmp(a,b) strncmp(a,b,strlen(a)) 3.164 + 3.165 +/* like strcat(), but lets the buffer automagically grow :-) 3.166 + * (needs local variable "size" with the buffer size) */ 3.167 +#define append(where, what) do { \ 3.168 + if (strlen(what) > (size - strlen(where))) { \ 3.169 + xrealloc(where, size + 128 + strlen(what)); \ 3.170 + size += 128 + strlen(what); \ 3.171 + } \ 3.172 + strcat(where, what); \ 3.173 +} while(0) 3.174 + 3.175 +/* ========== */ 3.176 + 3.177 +/* returns delta(d) in days, weeks, months, etc 3.178 + * the returned buffer is malloc()ed, do not forget to free() it */ 3.179 +char *tdelta(struct date *d) { 3.180 + int dy, wk, mn, yr; 3.181 + char *tmp; 3.182 + char *buf = xmalloc(128); 3.183 + int size = 128; 3.184 + *buf = 0; 3.185 + 3.186 + switch (delta(d)) { 3.187 + case 0: 3.188 + append(buf, "today"); 3.189 + return buf; 3.190 + case 1: 3.191 + append(buf, "tomorrow"); 3.192 + return buf; 3.193 + default: 3.194 + /* like delta(), we ignore the year */ 3.195 + yr=-before(*d,today); 3.196 + mn=d->month - today.month; 3.197 + dy=d->day - today.day; 3.198 + 3.199 + if (dy < 0) { 3.200 + dy += mlen(today.month, today.year); 3.201 + mn--; 3.202 + } 3.203 + if (mn < 0) { 3.204 + mn += 12; 3.205 + yr++; 3.206 + } 3.207 + 3.208 + wk = (dy/7); 3.209 + dy%=7; 3.210 + 3.211 + append(buf, "in "); 3.212 + tmp = ttime(yr, mn, wk, dy); 3.213 + append(buf, tmp); 3.214 + free(tmp); 3.215 + 3.216 + if (*(buf + strlen(buf) - 1) == 's') 3.217 + append(buf, "'"); 3.218 + else 3.219 + append(buf, "'s"); 3.220 + 3.221 + append(buf, " time"); 3.222 + 3.223 + return buf; 3.224 + } 3.225 +} 3.226 + 3.227 + 3.228 + 3.229 + 3.230 + 3.231 +/* 3.232 +void donum(n,txt) { 3.233 + do { 3.234 + if (n > 0) { 3.235 + snprintf(tmp, sizeof(tmp), "%d", n); 3.236 + append(buf, tmp); 3.237 + append(buf, " " txt); 3.238 + if (n != 1) 3.239 + append(buf, "s"); 3.240 + terms--; 3.241 + if (orgterms > 1) { 3.242 + if (terms == 1) 3.243 + append(buf, " and "); 3.244 + else if (terms > 1) 3.245 + append(buf, ", "); 3.246 + } 3.247 + } 3.248 + } while(0) 3.249 +} 3.250 +*/ 3.251 + 3.252 + 3.253 +#define donum(n,txt) do { \ 3.254 + if (n > 0) { \ 3.255 + snprintf(tmp, sizeof(tmp), "%d", n); \ 3.256 + append(buf, tmp); \ 3.257 + append(buf, " " txt); \ 3.258 + if (n != 1) \ 3.259 + append(buf, "s"); \ 3.260 + terms--; \ 3.261 + if (orgterms > 1) { \ 3.262 + if (terms == 1) \ 3.263 + append(buf, " and "); \ 3.264 + else if (terms > 1) \ 3.265 + append(buf, ", "); \ 3.266 + } \ 3.267 + } \ 3.268 +} while(0) 3.269 + 3.270 + 3.271 +/* returns allocated buffer, don't forget to free() */ 3.272 +char* ttime(int yr, int mn, int wk, int dy) { 3.273 + char* buf = xmalloc(128); 3.274 + int size = 128; 3.275 + int terms, orgterms; 3.276 + char tmp[128]; 3.277 + 3.278 + *buf = 0; /* Initialize buffer */ 3.279 + terms = orgterms = (yr!=0) + (mn!=0) + (wk!=0) + (dy!=0); 3.280 + 3.281 + donum(yr, "year"); 3.282 + donum(mn, "month"); 3.283 + donum(wk, "week"); 3.284 + donum(dy, "day"); 3.285 + 3.286 + return buf; 3.287 +} 3.288 +#undef donum 3.289 + 3.290 + 3.291 + 3.292 + 3.293 + 3.294 + 3.295 +/* lists the birthdays in their string format, one by one, and passes the string 3.296 + to a function. */ 3.297 +void liststrings(struct event *evl, prnfunc outf) { 3.298 + int i,j; 3.299 + char *buf, *tmp; 3.300 + int size; 3.301 + 3.302 + for (i = 0; evl[i].text != NULL; i++) { 3.303 + buf = xmalloc(128); 3.304 + *buf = '\0'; 3.305 + size = 128; 3.306 + 3.307 + if (evl[i].warn == -1 && delta(&(evl[i].date))==0) { 3.308 + append(buf, evl[i].text); 3.309 + } else if (evl[i].enddate.day == 0) { 3.310 + if (delta(&(evl[i].date)) <= warnperiod(evl[i])) { 3.311 + append(buf, evl[i].text); 3.312 + append(buf, " "); 3.313 + tmp = tdelta(&(evl[i].date)); 3.314 + append(buf, tmp); 3.315 + free(tmp); 3.316 + } 3.317 + } else { 3.318 + if (delta(&(evl[i].date)) <= warnperiod(evl[i])) { 3.319 + append(buf, evl[i].text); 3.320 + append(buf, " for "); 3.321 + /* +1 because, if the difference between two dates is one day, 3.322 + then the length of an event on those days is two days */ 3.323 + j = ddiff(&(evl[i].date),&(evl[i].enddate)) + 1; 3.324 + tmp = ttime(0, 0, j/7, j%7); 3.325 + append(buf, tmp); 3.326 + free(tmp); 3.327 + append(buf, " "); 3.328 + tmp = tdelta(&(evl[i].date)); 3.329 + append(buf, tmp); 3.330 + } else if (delta(&(evl[i].enddate)) <= warnperiod(evl[i])) { 3.331 + append(buf, evl[i].text); 3.332 + append(buf, " "); 3.333 + j = delta(&(evl[i].enddate)); 3.334 + if (j) { 3.335 + append(buf, "for "); 3.336 + tmp = ttime(0, 0, j/7, j%7); 3.337 + append(buf, tmp); 3.338 + free(tmp); 3.339 + append(buf, " longer"); 3.340 + } else { 3.341 + append(buf, "finishes today"); 3.342 + } 3.343 + } 3.344 + } 3.345 + if (*buf) { 3.346 + append(buf, "."); 3.347 + outf(buf); 3.348 + } 3.349 + free(buf); 3.350 + } 3.351 +} 3.352 + 3.353 + 3.354 + 3.355 + 3.356 + 3.357 + 3.358 + 3.359 +char* deffname(void) { 3.360 +char buf[256]; 3.361 + 3.362 + strcpy(buf,getpwuid(getuid())->pw_dir); 3.363 + strcat(buf, "/" DEFAULT_FILE); 3.364 + 3.365 + return strdup(buf); 3.366 +} 3.367 + 3.368 + 3.369 + 3.370 + 3.371 + 3.372 + 3.373 +/* sort the events by the time before the next time they come up, putting those 3.374 + where the start has passed but we are still in the time-period first */ 3.375 +int evcmp(const void *p1, const void *p2) { 3.376 + struct event *e1=(struct event *)p1; 3.377 + struct event *e2=(struct event *)p2; 3.378 + unsigned d1,d2; 3.379 + 3.380 + /* if the delta for the enddate is less than that for the start date, then we 3.381 + have passed the start date but not yet the end date, and so we should 3.382 + display the enddate; otherwise, we should display the start date */ 3.383 + 3.384 + d1=delta(&(e1->date)); 3.385 + if (e1->enddate.day && delta(&(e1->enddate)) < d1) 3.386 + d1=delta(&(e1->enddate)); 3.387 + 3.388 + d2=delta(&(e2->date)); 3.389 + if (e2->enddate.day && delta(&(e2->enddate)) < d2) 3.390 + d2=delta(&(e2->enddate)); 3.391 + 3.392 + if (d1 < d2) return -1; 3.393 + if (d1 > d2) return 1; 3.394 + 3.395 + return strcmp(e1->text, e2->text); 3.396 +} 3.397 + 3.398 + 3.399 + 3.400 + 3.401 + 3.402 + 3.403 +/* difference in days between two dates */ 3.404 +/* it is assumed that D1 < D2, and so the result is always positive */ 3.405 +unsigned ddiff(struct date *D1, struct date *D2) { 3.406 + struct date d1,d2; 3.407 + int dd,m; 3.408 + 3.409 + /* make working copies */ 3.410 + d1=*D1; 3.411 + d2=*D2; 3.412 + 3.413 + /* sort out zero years */ 3.414 + if (d1.year == 0 || d2.year==0) { 3.415 + if (d1.year != d2.year) { 3.416 + if (d1.year == 0) { 3.417 + if (before(d1,d2)) 3.418 + d1.year=d2.year; 3.419 + else 3.420 + d1.year=d2.year-1; 3.421 + } else { 3.422 + if (before(d1,d2)) 3.423 + d2.year=d1.year; 3.424 + else 3.425 + d2.year=d1.year+1; 3.426 + } 3.427 + } else { /* both years zero */ 3.428 + if (before(d1,d2)) 3.429 + d1.year=d2.year=today.year; 3.430 + else { 3.431 + d1.year=today.year; 3.432 + d2.year=d1.year+1; 3.433 + } 3.434 + } 3.435 + } 3.436 + 3.437 + /* now we can actually do the comparison ... */ 3.438 + dd=0; 3.439 + 3.440 + /* to start with, we work in months */ 3.441 + for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++) 3.442 + dd += mlen(((m-1)%12)+1, d1.year + m/12); 3.443 + 3.444 + /* and then we renormalise for the days within the months */ 3.445 + /* the first month was included in our calculations */ 3.446 + dd -= d1.day; 3.447 + /* but the last one wasn't */ 3.448 + dd += d2.day; 3.449 + 3.450 + return dd; 3.451 +} 3.452 + 3.453 + 3.454 + 3.455 + 3.456 + 3.457 + 3.458 + 3.459 + 3.460 +/* actually until the next anniversary of ... */ 3.461 +unsigned delta(struct date *date) { 3.462 + struct date d; 3.463 + unsigned dt, mn; 3.464 + 3.465 + memcpy(&d, date, sizeof(struct date)); 3.466 + 3.467 + /* past the end of the year */ 3.468 + if (before(d, today)) { 3.469 + d.year = 1; 3.470 + } else { 3.471 + d.year = 0; 3.472 + } 3.473 + 3.474 + for (mn = today.month, dt=0; mn < d.month + 12*d.year; mn++) 3.475 + dt += mlen(((mn-1)%12) + 1,today.year + mn/12); 3.476 + 3.477 + dt -= today.day; 3.478 + dt += d.day; 3.479 + 3.480 + return dt; 3.481 +} 3.482 + 3.483 + 3.484 + 3.485 + 3.486 + 3.487 + 3.488 +void gettoday(void) { 3.489 + struct tm *tm; 3.490 + time_t t; 3.491 + 3.492 + time(&t); 3.493 + tm = localtime(&t); 3.494 + today.day = tm->tm_mday; 3.495 + today.month = tm->tm_mon + 1; /* 1-12 instead of 0-11 */ 3.496 + today.year = tm->tm_year; 3.497 + today.year += 1900; 3.498 +} 3.499 + 3.500 + 3.501 + 3.502 + 3.503 + 3.504 +struct event *readlist(char *fname) { 3.505 + FILE *file; 3.506 + int i,j,k,l,d; 3.507 + struct event *evl; 3.508 + char buf[1024], buf2[1024]; 3.509 + char *ptr; 3.510 + unsigned flags; 3.511 + struct event *nevl; 3.512 + /* initialise */ 3.513 + if (fname==NULL) { 3.514 + fname=deffname(); 3.515 + } 3.516 + 3.517 + gettoday(); 3.518 + 3.519 + if (fname[0] == '-' && fname[1] == 0) { 3.520 + /* read from stdin */ 3.521 + file=stdin; 3.522 + } else { 3.523 + /* now read it */ 3.524 + if((file=fopen(fname, "rt"))==NULL) { 3.525 + fprintf(stderr, "Unable to open file \"%s\"\n", fname); 3.526 + exit(1); 3.527 + } 3.528 + } 3.529 + 3.530 + 3.531 + for (i = 0, evl=NULL; fgets(buf, sizeof(buf), file) != NULL; i++) { 3.532 + evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); 3.533 + 3.534 + if (*buf == '#' || *buf == '\n') 3.535 + { 3.536 + i--; 3.537 + continue; 3.538 + } 3.539 + if (*buf == '&') { 3.540 + buf[strlen(buf)-1] = 0; 3.541 + if ((ptr=strchr(buf+1,' ')) == NULL && (ptr=strchr((buf+1),'\t')) == NULL) { 3.542 + ptr=(buf+1)+strlen((buf+1)); 3.543 + } 3.544 + 3.545 + *ptr++=0; 3.546 + nevl=NULL; 3.547 + k=0; 3.548 + for (j=0; directlist[j].text != NULL; j++) { 3.549 + if (directlist[j].len == 0) directlist[j].len = strlen(directlist[j].text); 3.550 + /* 3.551 + fprintf(stderr, "Checking against directive #%d, %s, which has length %d, against \"%s\" with length %d\n", 3.552 + j, directlist[j].text, directlist[j].len, buf+1, ptr-(buf+1)-1); 3.553 + */ 3.554 + if (directlist[j].len == ptr-(buf+1)-1 && !strncmp(directlist[j].text,(buf+1),directlist[j].len)) { 3.555 + nevl = directlist[j].func((buf+1),ptr); 3.556 + k=1; 3.557 + break; 3.558 + } 3.559 + } 3.560 + 3.561 + if (nevl != NULL) { 3.562 + for (j=0; nevl[j].text != NULL; j++); 3.563 + i+=j-1; 3.564 + evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); 3.565 + /* in fact, this loop reverses the order of the elements, but we're going to sort them later anyway. */ 3.566 + for (j=0; nevl[j].text != NULL; j++) 3.567 + evl[i-j]=nevl[j]; 3.568 + } 3.569 + if (!k) { 3.570 + fprintf(stderr, "Warning: unrecognised directive \"%s\" ignored.\n", (buf+1)); 3.571 + i--; 3.572 + } 3.573 + continue; 3.574 + } 3.575 + 3.576 + /* parse string in buf */ 3.577 + ptr = strrchr(buf, '='); /* allow '=' in text */ 3.578 + if(ptr==NULL) /* not a valid line, so ignore it! Cool, huh? */ 3.579 + { 3.580 + fprintf(stderr, "WARNING: Invalid line in input file:\n%s", buf); 3.581 + i--; 3.582 + continue; 3.583 + } 3.584 + 3.585 + *(ptr++) = 0; 3.586 + 3.587 + j = sscanf(ptr, "%u-%u-%u", &(evl[i].date.year), &(evl[i].date.month), &(evl[i].date.day)); 3.588 + /* if our year is only two digits, add 1900 to it ... */ 3.589 + if(evl[i].date.year < 100) evl[i].date.year+=1900; 3.590 + /* ... unless it wasn't read, in which case set it to zero */ 3.591 + if(j==2) evl[i].date.year=0; 3.592 + 3.593 + /* parse flags */ 3.594 + 3.595 + evl[i].warn=iDWarn; 3.596 + evl[i].enddate.day=evl[i].enddate.month=evl[i].enddate.year=0; 3.597 + 3.598 + flags=j=0; 3.599 + while(j = skptok(j, ptr),ptr[j]!=0) 3.600 + { 3.601 + for (k = 0; FTABLE[k].txt != NULL && strncmp(FTABLE[k].txt, ptr + j, strlen(FTABLE[k].txt)); k++); 3.602 + switch (FTABLE[k].flag) { 3.603 + case F_WTIME_P: /* w<n> -- sets warning time */ 3.604 + sscanf(ptr + j, "w %u", &(evl[i].warn)); 3.605 + break; 3.606 + case F_FORDAYS: /* for<days> -- sets the duration of the event */ 3.607 + sscanf(ptr + j, "for %d", &d); 3.608 + evl[i].enddate=evl[i].date; 3.609 + for (l=1; l < d; l++) { 3.610 + evl[i].enddate.day++; 3.611 + if (evl[i].enddate.day > mlen(evl[i].enddate.month, 3.612 + evl[i].enddate.year)) { 3.613 + evl[i].enddate.month++; 3.614 + evl[i].enddate.day=1; 3.615 + } 3.616 + if (evl[i].enddate.month > 12) { 3.617 + evl[i].enddate.year++; 3.618 + evl[i].enddate.month=1; 3.619 + } 3.620 + } 3.621 + break; 3.622 + case F_TODATE: 3.623 + l = sscanf(ptr + j, "to %u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day)); 3.624 + if (evl[i].enddate.year < 100) evl[i].enddate.year+=1900; 3.625 + if (l == 2) evl[i].enddate.year=0; 3.626 + break; 3.627 + case 0: 3.628 + break; 3.629 + default: 3.630 + flags|=FTABLE[k].flag; 3.631 + break; 3.632 + } 3.633 + } 3.634 + 3.635 + /* construct event text */ 3.636 + 3.637 + switch(flags & F_MTYPE) { 3.638 + case F_TBIRTHDAY: 3.639 + default: /* assume it's a birthday */ 3.640 + if (evl[i].date.year != 0) { 3.641 + int tmp_age=ydelta(evl[i].date, today); 3.642 + if (tmp_age!=1) { 3.643 + sprintf(buf2, "%s is %d years old", buf, tmp_age); 3.644 + } else { 3.645 + sprintf(buf2, "%s is %d year old", buf, tmp_age); 3.646 + } 3.647 + } else { 3.648 + sprintf(buf2, "%s has a birthday", buf); 3.649 + } 3.650 + break; 3.651 + case F_TANNIVERSARY: 3.652 + if (evl[i].date.year != 0) { 3.653 + sprintf(buf2, "%s %d years ago", buf, ydelta(evl[i].date, today)); 3.654 + } else { 3.655 + strcpy(buf2, buf); 3.656 + } 3.657 + break; 3.658 + case F_TEVENT: 3.659 + /* if a year was specified, and this warning isn't for it, ignore! */ 3.660 + if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0) && 3.661 + (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) { 3.662 + i--; 3.663 + continue; 3.664 + } 3.665 + strcpy(buf2, buf); 3.666 + break; 3.667 + case F_TMESSAGE: 3.668 + /* Like an event, except that it only comes up on the given date, and no text at all is appended */ 3.669 + if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0) && 3.670 + (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) { 3.671 + i--; 3.672 + continue; 3.673 + } 3.674 + strcpy(buf2, buf); 3.675 + evl[i].warn=-1; /* special code! */ 3.676 + break; 3.677 + } 3.678 + evl[i].text = strdup(buf2); 3.679 + } 3.680 + 3.681 + evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); 3.682 + evl[i].date.day=evl[i].date.month=evl[i].date.year=0; 3.683 + evl[i].text = (char *) NULL; 3.684 + 3.685 + fclose(file); 3.686 + free(fname); 3.687 + 3.688 + /* NB uses i from above */ 3.689 + qsort(evl, i, sizeof(struct event), evcmp); 3.690 + return evl; 3.691 +} 3.692 + 3.693 + 3.694 + 3.695 + 3.696 + 3.697 + 3.698 + 3.699 + 3.700 +int skptok(int j, char *ptr) { 3.701 + for (; ptr[j] != 0 && ptr[j] != ' ' && ptr[j] != '\t' ; j++); 3.702 + for (; ptr[j] != 0 && (ptr[j] == ' ' || ptr[j] == '\t'); j++); 3.703 + 3.704 + return j; 3.705 +} 3.706 + 3.707 + 3.708 + 3.709 + 3.710 + 3.711 + 3.712 +/* ---------------------------------------------------------------------- */ 3.713 +/* Functions to parse input file directives */ 3.714 +struct event *dir_include(char *dir, char *parm) { 3.715 + struct event *evl; 3.716 + 3.717 + evl=readlist(strdup(parm)); 3.718 + 3.719 + return evl; 3.720 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/birthday.c Sun Dec 16 22:26:48 2007 +0100 4.3 @@ -0,0 +1,65 @@ 4.4 +/* 4.5 + birthday 4.6 + 4.7 + Birthday/Anniversary display on login 4.8 + 4.9 + (c) 1996 AS Mortimer 4.10 + 4.11 + This program is free software; you can redistribute it and/or 4.12 + modify it under the terms of the GNU General Public License as 4.13 + published by the Free Software Foundation; either version 2 of the 4.14 + License, or (at your option) any later version. You may also 4.15 + distribute it under the Artistic License, as comes with Perl. 4.16 + 4.17 + This program is distributed in the hope that it will be useful, 4.18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 4.19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 4.20 + 4.21 + You should have received a copy of the GNU General Public License 4.22 + along with this program; if not, write to the Free Software 4.23 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4.24 + 4.25 + You should also have recieved a copy of the Artistic license with 4.26 + this program. 4.27 + 4.28 + $Id: birthday.c,v 1.5 1999/04/25 14:01:29 andy Exp $ 4.29 +*/ 4.30 + 4.31 +#include <string.h> 4.32 +#include <stdio.h> 4.33 +#include <stdlib.h> 4.34 + 4.35 +#include "birthday.h" 4.36 + 4.37 + 4.38 +int main(int argc, char* argv[]) 4.39 +{ 4.40 + char* fname = NULL; 4.41 + struct event *evl; /* evl => event list */ 4.42 + char* opt = NULL; 4.43 + 4.44 + while (--argc > 0 && (*++argv)[0] == '-') { 4.45 + if (strcmp(argv[0], "-f") == 0) { 4.46 + fname = strdup((++argv)[0]); 4.47 + argc--; 4.48 + } else if (strcmp(argv[0], "-W") == 0) { 4.49 + iDWarn = atoi((++argv)[0]); 4.50 + argc--; 4.51 + } else if (strcmp(argv[0], "-M") == 0) { 4.52 + iMaxWarn = atoi((++argv)[0]); 4.53 + argc--; 4.54 + } else if (strcmp(argv[0], "-m") == 0) { 4.55 + iMinWarn = atoi((++argv)[0]); 4.56 + argc--; 4.57 + } else { 4.58 + fprintf(stderr, "unknown option %s\n", opt); 4.59 + exit(1); 4.60 + } 4.61 + } 4.62 + 4.63 + evl = readlist(fname); /* read and format entries */ 4.64 + 4.65 + liststrings(evl, puts); 4.66 + 4.67 + return 0; 4.68 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/birthday.h Sun Dec 16 22:26:48 2007 +0100 5.3 @@ -0,0 +1,104 @@ 5.4 +/* 5.5 + birthday 5.6 + 5.7 + Birthday/Anniversary display on login 5.8 + 5.9 + (c) 1996 AS Mortimer 5.10 + 5.11 + This program is free software; you can redistribute it and/or 5.12 + modify it under the terms of the GNU General Public License as 5.13 + published by the Free Software Foundation; either version 2 of the 5.14 + License, or (at your option) any later version. You may also 5.15 + distribute it under the Artistic License, as comes with Perl. 5.16 + 5.17 + This program is distributed in the hope that it will be useful, 5.18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 5.19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 5.20 + 5.21 + You should have received a copy of the GNU General Public License 5.22 + along with this program; if not, write to the Free Software 5.23 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 5.24 + 5.25 + You should also have recieved a copy of the Artistic license with 5.26 + this program. 5.27 + 5.28 + $Id: birthday.h,v 1.6 1999/04/25 14:01:29 andy Exp $ 5.29 +*/ 5.30 + 5.31 +/* ========== Configuration section */ 5.32 + 5.33 +#define DEFAULT_FILE ".birthdays" 5.34 + 5.35 +/* standard time to warn in advance, when no explicit w flag is given. */ 5.36 +#define DEF_WARN 21 5.37 +/* maximum time to warn in advance when no M flag is given */ 5.38 +#define MAX_WARN 500 /* ie, a year */ 5.39 +/* minimum time to warn in advance when no m flag */ 5.40 +#define MIN_WARN 0 5.41 + 5.42 +/* ========== Required includes */ 5.43 + 5.44 +#include <stdio.h> 5.45 + 5.46 +/* ========== Global constants and data types */ 5.47 + 5.48 + 5.49 +/* month lengths etc */ 5.50 + 5.51 +#define isleapyear(y) ((y)%4==0 && ((y)%100 != 0 || (y)%400 == 0)) 5.52 +extern const unsigned MLENDAT[]; 5.53 +#define mlen(m,y) (MLENDAT[(m)-1] != -1 ? MLENDAT[(m)-1] : (isleapyear((y)) ? 29 : 28)) 5.54 +#define before(a,b) ((a).month < (b).month || ((a).month == (b).month && (a).day < (b).day)) 5.55 +#define ydelta(a,b) ((int) (b).year - (a).year + before((a),(b))) 5.56 +#define warnperiod(ev) ((ev).warn<iMinWarn?iMinWarn:((ev).warn>iMaxWarn?iMaxWarn:(ev).warn)) 5.57 + 5.58 +/* -------- modifier flags */ 5.59 + 5.60 +#define F_MTYPE 0x07 5.61 +#define F_TBIRTHDAY 1 5.62 +#define F_TANNIVERSARY 2 5.63 +#define F_TEVENT 3 5.64 +#define F_TMESSAGE 4 5.65 + 5.66 +/* flags processed immediately on encountering */ 5.67 +#define F_MIMMEDIATE 0x24 5.68 +#define F_WTIME_P 0x08 5.69 +#define F_FORDAYS 0x16 5.70 +#define F_TODATE 0x24 5.71 + 5.72 +struct _ftable {char *txt; unsigned flag;}; 5.73 + 5.74 +extern const struct _ftable FTABLE[]; 5.75 + 5.76 +struct date { 5.77 + unsigned day; 5.78 + unsigned month; 5.79 + unsigned year; 5.80 +}; 5.81 + 5.82 +struct event { 5.83 + char *text; 5.84 + struct date date; 5.85 + struct date enddate; 5.86 + int warn; 5.87 +}; 5.88 + 5.89 +typedef int (*prnfunc)(const char *); 5.90 + 5.91 +/* ========== */ 5.92 + 5.93 +struct event *readlist(char *fname); 5.94 +void gettoday(void); 5.95 +unsigned delta(struct date *); 5.96 +unsigned ddiff(struct date *D1, struct date *D2); 5.97 +void liststrings(struct event *evl, prnfunc outf); 5.98 +char *tdelta(struct date *d); 5.99 +char *ttime(int yr, int mn, int wk, int dy); 5.100 + 5.101 +/* ========== Global Variables */ 5.102 + 5.103 +extern struct date today; 5.104 +extern int iDWarn; 5.105 +extern int iMaxWarn; 5.106 +extern int iMinWarn; 5.107 +