bday
diff bdengine.c @ 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 | 9ec037775c38 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/bdengine.c Sun Dec 16 22:26:48 2007 +0100 1.3 @@ -0,0 +1,717 @@ 1.4 +/* 1.5 + birthday.c 1.6 + 1.7 + Birthday/Anniversary display on login 1.8 + 1.9 + (c) 1996 AS Mortimer 1.10 + 1.11 + This program is free software; you can redistribute it and/or 1.12 + modify it under the terms of the GNU General Public License as 1.13 + published by the Free Software Foundation; either version 2 of the 1.14 + License, or (at your option) any later version. You may also 1.15 + distribute it under the Artistic License, as comes with Perl. 1.16 + 1.17 + This program is distributed in the hope that it will be useful, 1.18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 1.20 + 1.21 + You should have received a copy of the GNU General Public License 1.22 + along with this program; if not, write to the Free Software 1.23 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.24 + 1.25 + You should also have recieved a copy of the Artistic license with 1.26 + this program. 1.27 + 1.28 + $Id: bdengine.c,v 1.14 2001/10/21 07:03:49 andy Exp $ 1.29 + 1.30 + We're getting there. At the moment, the file used by default is ~/.birthdays 1.31 + under UNIX, or C:\PERSONAL\BDAYS.LST under DOS, but this can be overridden on 1.32 + the command line. The file has the following format: 1.33 + 1.34 + name/event/whatever=date flags 1.35 + where: 1.36 + date is dd/mm, dd/mm/yy (assumes 20th century!) or dd/mm/yyyy 1.37 + flags is ONE or ZERO of 1.38 + o bd for a birthday (default) 1.39 + o bir for a birthday (exactly equivalent to `bd') 1.40 + o ann for an anniversary 1.41 + o ev for an event 1.42 + and zero or more of 1.43 + o w<n> to set the warn-in-advance time to n days (don't include the 1.44 + brackets! :) 1.45 + o to<date> 1.46 + o for<days> 1.47 + to specify the length of time taken by an event, for example a 1.48 + holiday. 1.49 + 1.50 + Comment lines are preceeded by #. 1.51 + 1.52 + Note: If you deviate from this format, I cannot guarantee anything about 1.53 + it's behaviour. In most cases, it will just quietly ignore the error, 1.54 + which probably isn't ideal behaviour. Oh, well. 1.55 + 1.56 + 2003/05/20: Automatic reallocation of output buffer in listsrings() by 1.57 + Sebastian Schmidt <yath@yath.eu.org>. 1.58 + 1.59 +*/ 1.60 + 1.61 + 1.62 + 1.63 +/* ========== */ 1.64 + 1.65 + 1.66 +#include <stdio.h> 1.67 +#include <stdarg.h> 1.68 +#include <stdlib.h> 1.69 +#include <string.h> 1.70 +#include <time.h> 1.71 + 1.72 +#include <sys/types.h> 1.73 +#include <unistd.h> 1.74 +#include <pwd.h> 1.75 + 1.76 +#include "birthday.h" 1.77 + 1.78 +/* ========== */ 1.79 + 1.80 + 1.81 + 1.82 +/* 1.83 + xmalloc/xrealloc functions, and fatal exit function 1.84 + Note: the x* functions are lifted straight from the GNU libc info docs 1.85 + $Id: xmalloc.c,v 1.2 1999/01/16 17:08:59 andy Exp $ 1.86 +*/ 1.87 + 1.88 +void *xmalloc (size_t size) { 1.89 + register void *value = malloc (size); 1.90 + if (value == 0) { 1.91 + fprintf(stderr, "virtual memory exhausted\n"); 1.92 + exit(1); 1.93 + } 1.94 + return value; 1.95 +} 1.96 + 1.97 + 1.98 +void *xrealloc (void *ptr, size_t size) { 1.99 + register void *value = realloc (ptr, size); 1.100 + if (value == 0) { 1.101 + fprintf(stderr, "virtual memory exhausted\n"); 1.102 + exit(1); 1.103 + } 1.104 + return value; 1.105 +} 1.106 + 1.107 +/* ========== */ 1.108 + 1.109 + 1.110 + 1.111 + 1.112 + 1.113 + 1.114 +int skptok(int j, char *ptr); 1.115 +int evcmp(const void *e1, const void *e2); 1.116 +char *deffname(void); 1.117 + 1.118 +struct event *dir_include(char *dir, char *parm); 1.119 + 1.120 +/* ========== Global variables */ 1.121 + 1.122 +struct date today; 1.123 +int iDWarn = DEF_WARN; 1.124 +int iMaxWarn = MAX_WARN; 1.125 +int iMinWarn = MIN_WARN; 1.126 + 1.127 +const unsigned MLENDAT[]={31,-1,31,30,31,30,31,31,30,31,30,31}; 1.128 + 1.129 +const struct _ftable FTABLE[] = { 1.130 + {"bir",F_TBIRTHDAY}, 1.131 + {"bd", F_TBIRTHDAY}, 1.132 + {"ann",F_TANNIVERSARY}, 1.133 + {"ev", F_TEVENT}, 1.134 + {"mes", F_TMESSAGE}, 1.135 + {"w", F_WTIME_P}, 1.136 + {"to", F_TODATE}, 1.137 + {"for", F_FORDAYS}, 1.138 + {NULL, 0} 1.139 +}; 1.140 + 1.141 + 1.142 +/* list of directives. These are entered in the file prefixed by '&'. The function should be declared as 1.143 + struct event *dir_func(char *directive, char *parameters); 1.144 + and should return a pointer to a NULL-terminated list of extra records, or NULL if there are none. 1.145 + This structure will allow us to dynamically add directives, if we wish to do so in the future. 1.146 + */ 1.147 + 1.148 +struct { 1.149 + const char *text; 1.150 + int len; 1.151 + struct event *(*func)(char*,char*); 1.152 +} directlist[] = { 1.153 + { "include", 0, dir_include }, 1.154 + { NULL, 0, NULL } 1.155 +}; 1.156 + 1.157 +/* ========== */ 1.158 + 1.159 + 1.160 + 1.161 + 1.162 +/* compare the first strlen(a) characters of a and b */ 1.163 +#define strbegcmp(a,b) strncmp(a,b,strlen(a)) 1.164 + 1.165 +/* like strcat(), but lets the buffer automagically grow :-) 1.166 + * (needs local variable "size" with the buffer size) */ 1.167 +#define append(where, what) do { \ 1.168 + if (strlen(what) > (size - strlen(where))) { \ 1.169 + xrealloc(where, size + 128 + strlen(what)); \ 1.170 + size += 128 + strlen(what); \ 1.171 + } \ 1.172 + strcat(where, what); \ 1.173 +} while(0) 1.174 + 1.175 +/* ========== */ 1.176 + 1.177 +/* returns delta(d) in days, weeks, months, etc 1.178 + * the returned buffer is malloc()ed, do not forget to free() it */ 1.179 +char *tdelta(struct date *d) { 1.180 + int dy, wk, mn, yr; 1.181 + char *tmp; 1.182 + char *buf = xmalloc(128); 1.183 + int size = 128; 1.184 + *buf = 0; 1.185 + 1.186 + switch (delta(d)) { 1.187 + case 0: 1.188 + append(buf, "today"); 1.189 + return buf; 1.190 + case 1: 1.191 + append(buf, "tomorrow"); 1.192 + return buf; 1.193 + default: 1.194 + /* like delta(), we ignore the year */ 1.195 + yr=-before(*d,today); 1.196 + mn=d->month - today.month; 1.197 + dy=d->day - today.day; 1.198 + 1.199 + if (dy < 0) { 1.200 + dy += mlen(today.month, today.year); 1.201 + mn--; 1.202 + } 1.203 + if (mn < 0) { 1.204 + mn += 12; 1.205 + yr++; 1.206 + } 1.207 + 1.208 + wk = (dy/7); 1.209 + dy%=7; 1.210 + 1.211 + append(buf, "in "); 1.212 + tmp = ttime(yr, mn, wk, dy); 1.213 + append(buf, tmp); 1.214 + free(tmp); 1.215 + 1.216 + if (*(buf + strlen(buf) - 1) == 's') 1.217 + append(buf, "'"); 1.218 + else 1.219 + append(buf, "'s"); 1.220 + 1.221 + append(buf, " time"); 1.222 + 1.223 + return buf; 1.224 + } 1.225 +} 1.226 + 1.227 + 1.228 + 1.229 + 1.230 + 1.231 +/* 1.232 +void donum(n,txt) { 1.233 + do { 1.234 + if (n > 0) { 1.235 + snprintf(tmp, sizeof(tmp), "%d", n); 1.236 + append(buf, tmp); 1.237 + append(buf, " " txt); 1.238 + if (n != 1) 1.239 + append(buf, "s"); 1.240 + terms--; 1.241 + if (orgterms > 1) { 1.242 + if (terms == 1) 1.243 + append(buf, " and "); 1.244 + else if (terms > 1) 1.245 + append(buf, ", "); 1.246 + } 1.247 + } 1.248 + } while(0) 1.249 +} 1.250 +*/ 1.251 + 1.252 + 1.253 +#define donum(n,txt) do { \ 1.254 + if (n > 0) { \ 1.255 + snprintf(tmp, sizeof(tmp), "%d", n); \ 1.256 + append(buf, tmp); \ 1.257 + append(buf, " " txt); \ 1.258 + if (n != 1) \ 1.259 + append(buf, "s"); \ 1.260 + terms--; \ 1.261 + if (orgterms > 1) { \ 1.262 + if (terms == 1) \ 1.263 + append(buf, " and "); \ 1.264 + else if (terms > 1) \ 1.265 + append(buf, ", "); \ 1.266 + } \ 1.267 + } \ 1.268 +} while(0) 1.269 + 1.270 + 1.271 +/* returns allocated buffer, don't forget to free() */ 1.272 +char* ttime(int yr, int mn, int wk, int dy) { 1.273 + char* buf = xmalloc(128); 1.274 + int size = 128; 1.275 + int terms, orgterms; 1.276 + char tmp[128]; 1.277 + 1.278 + *buf = 0; /* Initialize buffer */ 1.279 + terms = orgterms = (yr!=0) + (mn!=0) + (wk!=0) + (dy!=0); 1.280 + 1.281 + donum(yr, "year"); 1.282 + donum(mn, "month"); 1.283 + donum(wk, "week"); 1.284 + donum(dy, "day"); 1.285 + 1.286 + return buf; 1.287 +} 1.288 +#undef donum 1.289 + 1.290 + 1.291 + 1.292 + 1.293 + 1.294 + 1.295 +/* lists the birthdays in their string format, one by one, and passes the string 1.296 + to a function. */ 1.297 +void liststrings(struct event *evl, prnfunc outf) { 1.298 + int i,j; 1.299 + char *buf, *tmp; 1.300 + int size; 1.301 + 1.302 + for (i = 0; evl[i].text != NULL; i++) { 1.303 + buf = xmalloc(128); 1.304 + *buf = '\0'; 1.305 + size = 128; 1.306 + 1.307 + if (evl[i].warn == -1 && delta(&(evl[i].date))==0) { 1.308 + append(buf, evl[i].text); 1.309 + } else if (evl[i].enddate.day == 0) { 1.310 + if (delta(&(evl[i].date)) <= warnperiod(evl[i])) { 1.311 + append(buf, evl[i].text); 1.312 + append(buf, " "); 1.313 + tmp = tdelta(&(evl[i].date)); 1.314 + append(buf, tmp); 1.315 + free(tmp); 1.316 + } 1.317 + } else { 1.318 + if (delta(&(evl[i].date)) <= warnperiod(evl[i])) { 1.319 + append(buf, evl[i].text); 1.320 + append(buf, " for "); 1.321 + /* +1 because, if the difference between two dates is one day, 1.322 + then the length of an event on those days is two days */ 1.323 + j = ddiff(&(evl[i].date),&(evl[i].enddate)) + 1; 1.324 + tmp = ttime(0, 0, j/7, j%7); 1.325 + append(buf, tmp); 1.326 + free(tmp); 1.327 + append(buf, " "); 1.328 + tmp = tdelta(&(evl[i].date)); 1.329 + append(buf, tmp); 1.330 + } else if (delta(&(evl[i].enddate)) <= warnperiod(evl[i])) { 1.331 + append(buf, evl[i].text); 1.332 + append(buf, " "); 1.333 + j = delta(&(evl[i].enddate)); 1.334 + if (j) { 1.335 + append(buf, "for "); 1.336 + tmp = ttime(0, 0, j/7, j%7); 1.337 + append(buf, tmp); 1.338 + free(tmp); 1.339 + append(buf, " longer"); 1.340 + } else { 1.341 + append(buf, "finishes today"); 1.342 + } 1.343 + } 1.344 + } 1.345 + if (*buf) { 1.346 + append(buf, "."); 1.347 + outf(buf); 1.348 + } 1.349 + free(buf); 1.350 + } 1.351 +} 1.352 + 1.353 + 1.354 + 1.355 + 1.356 + 1.357 + 1.358 + 1.359 +char* deffname(void) { 1.360 +char buf[256]; 1.361 + 1.362 + strcpy(buf,getpwuid(getuid())->pw_dir); 1.363 + strcat(buf, "/" DEFAULT_FILE); 1.364 + 1.365 + return strdup(buf); 1.366 +} 1.367 + 1.368 + 1.369 + 1.370 + 1.371 + 1.372 + 1.373 +/* sort the events by the time before the next time they come up, putting those 1.374 + where the start has passed but we are still in the time-period first */ 1.375 +int evcmp(const void *p1, const void *p2) { 1.376 + struct event *e1=(struct event *)p1; 1.377 + struct event *e2=(struct event *)p2; 1.378 + unsigned d1,d2; 1.379 + 1.380 + /* if the delta for the enddate is less than that for the start date, then we 1.381 + have passed the start date but not yet the end date, and so we should 1.382 + display the enddate; otherwise, we should display the start date */ 1.383 + 1.384 + d1=delta(&(e1->date)); 1.385 + if (e1->enddate.day && delta(&(e1->enddate)) < d1) 1.386 + d1=delta(&(e1->enddate)); 1.387 + 1.388 + d2=delta(&(e2->date)); 1.389 + if (e2->enddate.day && delta(&(e2->enddate)) < d2) 1.390 + d2=delta(&(e2->enddate)); 1.391 + 1.392 + if (d1 < d2) return -1; 1.393 + if (d1 > d2) return 1; 1.394 + 1.395 + return strcmp(e1->text, e2->text); 1.396 +} 1.397 + 1.398 + 1.399 + 1.400 + 1.401 + 1.402 + 1.403 +/* difference in days between two dates */ 1.404 +/* it is assumed that D1 < D2, and so the result is always positive */ 1.405 +unsigned ddiff(struct date *D1, struct date *D2) { 1.406 + struct date d1,d2; 1.407 + int dd,m; 1.408 + 1.409 + /* make working copies */ 1.410 + d1=*D1; 1.411 + d2=*D2; 1.412 + 1.413 + /* sort out zero years */ 1.414 + if (d1.year == 0 || d2.year==0) { 1.415 + if (d1.year != d2.year) { 1.416 + if (d1.year == 0) { 1.417 + if (before(d1,d2)) 1.418 + d1.year=d2.year; 1.419 + else 1.420 + d1.year=d2.year-1; 1.421 + } else { 1.422 + if (before(d1,d2)) 1.423 + d2.year=d1.year; 1.424 + else 1.425 + d2.year=d1.year+1; 1.426 + } 1.427 + } else { /* both years zero */ 1.428 + if (before(d1,d2)) 1.429 + d1.year=d2.year=today.year; 1.430 + else { 1.431 + d1.year=today.year; 1.432 + d2.year=d1.year+1; 1.433 + } 1.434 + } 1.435 + } 1.436 + 1.437 + /* now we can actually do the comparison ... */ 1.438 + dd=0; 1.439 + 1.440 + /* to start with, we work in months */ 1.441 + for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++) 1.442 + dd += mlen(((m-1)%12)+1, d1.year + m/12); 1.443 + 1.444 + /* and then we renormalise for the days within the months */ 1.445 + /* the first month was included in our calculations */ 1.446 + dd -= d1.day; 1.447 + /* but the last one wasn't */ 1.448 + dd += d2.day; 1.449 + 1.450 + return dd; 1.451 +} 1.452 + 1.453 + 1.454 + 1.455 + 1.456 + 1.457 + 1.458 + 1.459 + 1.460 +/* actually until the next anniversary of ... */ 1.461 +unsigned delta(struct date *date) { 1.462 + struct date d; 1.463 + unsigned dt, mn; 1.464 + 1.465 + memcpy(&d, date, sizeof(struct date)); 1.466 + 1.467 + /* past the end of the year */ 1.468 + if (before(d, today)) { 1.469 + d.year = 1; 1.470 + } else { 1.471 + d.year = 0; 1.472 + } 1.473 + 1.474 + for (mn = today.month, dt=0; mn < d.month + 12*d.year; mn++) 1.475 + dt += mlen(((mn-1)%12) + 1,today.year + mn/12); 1.476 + 1.477 + dt -= today.day; 1.478 + dt += d.day; 1.479 + 1.480 + return dt; 1.481 +} 1.482 + 1.483 + 1.484 + 1.485 + 1.486 + 1.487 + 1.488 +void gettoday(void) { 1.489 + struct tm *tm; 1.490 + time_t t; 1.491 + 1.492 + time(&t); 1.493 + tm = localtime(&t); 1.494 + today.day = tm->tm_mday; 1.495 + today.month = tm->tm_mon + 1; /* 1-12 instead of 0-11 */ 1.496 + today.year = tm->tm_year; 1.497 + today.year += 1900; 1.498 +} 1.499 + 1.500 + 1.501 + 1.502 + 1.503 + 1.504 +struct event *readlist(char *fname) { 1.505 + FILE *file; 1.506 + int i,j,k,l,d; 1.507 + struct event *evl; 1.508 + char buf[1024], buf2[1024]; 1.509 + char *ptr; 1.510 + unsigned flags; 1.511 + struct event *nevl; 1.512 + /* initialise */ 1.513 + if (fname==NULL) { 1.514 + fname=deffname(); 1.515 + } 1.516 + 1.517 + gettoday(); 1.518 + 1.519 + if (fname[0] == '-' && fname[1] == 0) { 1.520 + /* read from stdin */ 1.521 + file=stdin; 1.522 + } else { 1.523 + /* now read it */ 1.524 + if((file=fopen(fname, "rt"))==NULL) { 1.525 + fprintf(stderr, "Unable to open file \"%s\"\n", fname); 1.526 + exit(1); 1.527 + } 1.528 + } 1.529 + 1.530 + 1.531 + for (i = 0, evl=NULL; fgets(buf, sizeof(buf), file) != NULL; i++) { 1.532 + evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); 1.533 + 1.534 + if (*buf == '#' || *buf == '\n') 1.535 + { 1.536 + i--; 1.537 + continue; 1.538 + } 1.539 + if (*buf == '&') { 1.540 + buf[strlen(buf)-1] = 0; 1.541 + if ((ptr=strchr(buf+1,' ')) == NULL && (ptr=strchr((buf+1),'\t')) == NULL) { 1.542 + ptr=(buf+1)+strlen((buf+1)); 1.543 + } 1.544 + 1.545 + *ptr++=0; 1.546 + nevl=NULL; 1.547 + k=0; 1.548 + for (j=0; directlist[j].text != NULL; j++) { 1.549 + if (directlist[j].len == 0) directlist[j].len = strlen(directlist[j].text); 1.550 + /* 1.551 + fprintf(stderr, "Checking against directive #%d, %s, which has length %d, against \"%s\" with length %d\n", 1.552 + j, directlist[j].text, directlist[j].len, buf+1, ptr-(buf+1)-1); 1.553 + */ 1.554 + if (directlist[j].len == ptr-(buf+1)-1 && !strncmp(directlist[j].text,(buf+1),directlist[j].len)) { 1.555 + nevl = directlist[j].func((buf+1),ptr); 1.556 + k=1; 1.557 + break; 1.558 + } 1.559 + } 1.560 + 1.561 + if (nevl != NULL) { 1.562 + for (j=0; nevl[j].text != NULL; j++); 1.563 + i+=j-1; 1.564 + evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); 1.565 + /* in fact, this loop reverses the order of the elements, but we're going to sort them later anyway. */ 1.566 + for (j=0; nevl[j].text != NULL; j++) 1.567 + evl[i-j]=nevl[j]; 1.568 + } 1.569 + if (!k) { 1.570 + fprintf(stderr, "Warning: unrecognised directive \"%s\" ignored.\n", (buf+1)); 1.571 + i--; 1.572 + } 1.573 + continue; 1.574 + } 1.575 + 1.576 + /* parse string in buf */ 1.577 + ptr = strrchr(buf, '='); /* allow '=' in text */ 1.578 + if(ptr==NULL) /* not a valid line, so ignore it! Cool, huh? */ 1.579 + { 1.580 + fprintf(stderr, "WARNING: Invalid line in input file:\n%s", buf); 1.581 + i--; 1.582 + continue; 1.583 + } 1.584 + 1.585 + *(ptr++) = 0; 1.586 + 1.587 + j = sscanf(ptr, "%u-%u-%u", &(evl[i].date.year), &(evl[i].date.month), &(evl[i].date.day)); 1.588 + /* if our year is only two digits, add 1900 to it ... */ 1.589 + if(evl[i].date.year < 100) evl[i].date.year+=1900; 1.590 + /* ... unless it wasn't read, in which case set it to zero */ 1.591 + if(j==2) evl[i].date.year=0; 1.592 + 1.593 + /* parse flags */ 1.594 + 1.595 + evl[i].warn=iDWarn; 1.596 + evl[i].enddate.day=evl[i].enddate.month=evl[i].enddate.year=0; 1.597 + 1.598 + flags=j=0; 1.599 + while(j = skptok(j, ptr),ptr[j]!=0) 1.600 + { 1.601 + for (k = 0; FTABLE[k].txt != NULL && strncmp(FTABLE[k].txt, ptr + j, strlen(FTABLE[k].txt)); k++); 1.602 + switch (FTABLE[k].flag) { 1.603 + case F_WTIME_P: /* w<n> -- sets warning time */ 1.604 + sscanf(ptr + j, "w %u", &(evl[i].warn)); 1.605 + break; 1.606 + case F_FORDAYS: /* for<days> -- sets the duration of the event */ 1.607 + sscanf(ptr + j, "for %d", &d); 1.608 + evl[i].enddate=evl[i].date; 1.609 + for (l=1; l < d; l++) { 1.610 + evl[i].enddate.day++; 1.611 + if (evl[i].enddate.day > mlen(evl[i].enddate.month, 1.612 + evl[i].enddate.year)) { 1.613 + evl[i].enddate.month++; 1.614 + evl[i].enddate.day=1; 1.615 + } 1.616 + if (evl[i].enddate.month > 12) { 1.617 + evl[i].enddate.year++; 1.618 + evl[i].enddate.month=1; 1.619 + } 1.620 + } 1.621 + break; 1.622 + case F_TODATE: 1.623 + l = sscanf(ptr + j, "to %u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day)); 1.624 + if (evl[i].enddate.year < 100) evl[i].enddate.year+=1900; 1.625 + if (l == 2) evl[i].enddate.year=0; 1.626 + break; 1.627 + case 0: 1.628 + break; 1.629 + default: 1.630 + flags|=FTABLE[k].flag; 1.631 + break; 1.632 + } 1.633 + } 1.634 + 1.635 + /* construct event text */ 1.636 + 1.637 + switch(flags & F_MTYPE) { 1.638 + case F_TBIRTHDAY: 1.639 + default: /* assume it's a birthday */ 1.640 + if (evl[i].date.year != 0) { 1.641 + int tmp_age=ydelta(evl[i].date, today); 1.642 + if (tmp_age!=1) { 1.643 + sprintf(buf2, "%s is %d years old", buf, tmp_age); 1.644 + } else { 1.645 + sprintf(buf2, "%s is %d year old", buf, tmp_age); 1.646 + } 1.647 + } else { 1.648 + sprintf(buf2, "%s has a birthday", buf); 1.649 + } 1.650 + break; 1.651 + case F_TANNIVERSARY: 1.652 + if (evl[i].date.year != 0) { 1.653 + sprintf(buf2, "%s %d years ago", buf, ydelta(evl[i].date, today)); 1.654 + } else { 1.655 + strcpy(buf2, buf); 1.656 + } 1.657 + break; 1.658 + case F_TEVENT: 1.659 + /* if a year was specified, and this warning isn't for it, ignore! */ 1.660 + if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0) && 1.661 + (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) { 1.662 + i--; 1.663 + continue; 1.664 + } 1.665 + strcpy(buf2, buf); 1.666 + break; 1.667 + case F_TMESSAGE: 1.668 + /* Like an event, except that it only comes up on the given date, and no text at all is appended */ 1.669 + if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0) && 1.670 + (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) { 1.671 + i--; 1.672 + continue; 1.673 + } 1.674 + strcpy(buf2, buf); 1.675 + evl[i].warn=-1; /* special code! */ 1.676 + break; 1.677 + } 1.678 + evl[i].text = strdup(buf2); 1.679 + } 1.680 + 1.681 + evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); 1.682 + evl[i].date.day=evl[i].date.month=evl[i].date.year=0; 1.683 + evl[i].text = (char *) NULL; 1.684 + 1.685 + fclose(file); 1.686 + free(fname); 1.687 + 1.688 + /* NB uses i from above */ 1.689 + qsort(evl, i, sizeof(struct event), evcmp); 1.690 + return evl; 1.691 +} 1.692 + 1.693 + 1.694 + 1.695 + 1.696 + 1.697 + 1.698 + 1.699 + 1.700 +int skptok(int j, char *ptr) { 1.701 + for (; ptr[j] != 0 && ptr[j] != ' ' && ptr[j] != '\t' ; j++); 1.702 + for (; ptr[j] != 0 && (ptr[j] == ' ' || ptr[j] == '\t'); j++); 1.703 + 1.704 + return j; 1.705 +} 1.706 + 1.707 + 1.708 + 1.709 + 1.710 + 1.711 + 1.712 +/* ---------------------------------------------------------------------- */ 1.713 +/* Functions to parse input file directives */ 1.714 +struct event *dir_include(char *dir, char *parm) { 1.715 + struct event *evl; 1.716 + 1.717 + evl=readlist(strdup(parm)); 1.718 + 1.719 + return evl; 1.720 +}