comparison bday.c @ 8:19c1ad697022

beautifing :-)
author meillo@marmaro.de
date Tue, 18 Dec 2007 14:56:05 +0100
parents b6f4c7fba64a
children 4f48b4f86e3d
comparison
equal deleted inserted replaced
7:b6f4c7fba64a 8:19c1ad697022
1 /* 1 /*
2 birthday 2 bday
3 3
4 Birthday/Anniversary display on login 4 Birthday/Anniversary reminder
5 5
6 (c) 1996 AS Mortimer 6 (c) 1996 AS Mortimer
7 7 (c) 2007 markus schnalke <meillo@marmaro.de>
8 This program is free software; you can redistribute it and/or 8
9 modify it under the terms of the GNU General Public License as 9 This program is free software; you can redistribute it and/or
10 published by the Free Software Foundation; either version 2 of the 10 modify it under the terms of the GNU General Public License as
11 License, or (at your option) any later version. You may also 11 published by the Free Software Foundation; either version 2 of the
12 distribute it under the Artistic License, as comes with Perl. 12 License, or (at your option) any later version.
13 13
14 This program is distributed in the hope that it will be useful, 14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 17
18 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 21
22 You should also have recieved a copy of the Artistic license with 22 ===============================================================================
23 this program. 23
24 24 Input is read through standard input. For example: bday < ~/.birthdays
25 25 The input (file) has to have the following format:
26 We're getting there. At the moment, the file used by default is ~/.birthdays 26
27 under UNIX, or C:\PERSONAL\BDAYS.LST under DOS, but this can be overridden on 27 text=date flags
28 the command line. The file has the following format: 28
29 29 where:
30 name/event/whatever=date flags 30 date is yyyy-mm-dd
31 where: 31 flags is ONE or ZERO of
32 date is dd/mm, dd/mm/yy (assumes 20th century!) or dd/mm/yyyy 32 bd for a birthday (default)
33 flags is ONE or ZERO of 33 ann for an anniversary
34 o bd for a birthday (default) 34 ev for an event
35 o ann for an anniversary 35 and zero or more of
36 o ev for an event 36 w <n> to set the warn-in-advance time to n days (don't include the
37 and zero or more of 37 brackets! :)
38 o w <n> to set the warn-in-advance time to n days (don't include the 38 to <date>
39 brackets! :) 39 for <days>
40 o to <date> 40 to specify the length of time taken by an event, for example a holiday.
41 o for <days> 41
42 to specify the length of time taken by an event, for example a 42 Lines preceeded by # are treated as comments.
43 holiday. 43
44 44 Note: If you deviate from this format, I cannot guarantee anything about
45 Comment lines are preceeded by #. 45 it's behaviour. In most cases, it will just quietly ignore the error,
46 46 which probably isn't ideal behaviour. Oh, well.
47 Note: If you deviate from this format, I cannot guarantee anything about 47
48 it's behaviour. In most cases, it will just quietly ignore the error, 48 ===============================================================================
49 which probably isn't ideal behaviour. Oh, well.
50
51 2003/05/20: Automatic reallocation of output buffer in listsrings() by
52 Sebastian Schmidt <yath@yath.eu.org>.
53
54 */ 49 */
50
51
52 /* standard time to warn in advance, when no explicit w flag is given. */
53 #define DEF_WARN 14
55 54
56 55
57 #include <stdarg.h> 56 #include <stdarg.h>
58 #include <stdio.h> 57 #include <stdio.h>
59 #include <stdlib.h> 58 #include <stdlib.h>
62 #include <time.h> 61 #include <time.h>
63 #include <unistd.h> 62 #include <unistd.h>
64 63
65 64
66 65
67 /* standard time to warn in advance, when no explicit w flag is given. */
68 #define DEF_WARN 14
69
70 /* ========== Global constants and data types */ 66 /* ========== Global constants and data types */
71 67
72 68
73 /* month lengths etc */ 69 /* month lengths etc */
74
75 #define isleapyear(y) ((y)%4==0 && ((y)%100 != 0 || (y)%400 == 0)) 70 #define isleapyear(y) ((y)%4==0 && ((y)%100 != 0 || (y)%400 == 0))
76 const unsigned MLENDAT[]; 71 const unsigned MLENDAT[];
77 #define mlen(m,y) (MLENDAT[(m)-1] != -1 ? MLENDAT[(m)-1] : (isleapyear((y)) ? 29 : 28)) 72 #define mlen(m,y) (MLENDAT[(m)-1] != -1 ? MLENDAT[(m)-1] : (isleapyear((y)) ? 29 : 28))
78 #define before(a,b) ((a).month < (b).month || ((a).month == (b).month && (a).day < (b).day)) 73 #define before(a,b) ((a).month < (b).month || ((a).month == (b).month && (a).day < (b).day))
79 #define ydelta(a,b) ((int) (b).year - (a).year + before((a),(b))) 74 #define ydelta(a,b) ((int) (b).year - (a).year + before((a),(b)))
80 75
81 /* -------- modifier flags */ 76 /* -------- modifier flags */
82
83 #define F_MTYPE 0x07 77 #define F_MTYPE 0x07
84 #define F_TBIRTHDAY 1 78 #define F_TBIRTHDAY 1
85 #define F_TANNIVERSARY 2 79 #define F_TANNIVERSARY 2
86 #define F_TEVENT 3 80 #define F_TEVENT 3
87 81
89 #define F_MIMMEDIATE 0x24 83 #define F_MIMMEDIATE 0x24
90 #define F_WTIME_P 0x08 84 #define F_WTIME_P 0x08
91 #define F_FORDAYS 0x16 85 #define F_FORDAYS 0x16
92 #define F_TODATE 0x24 86 #define F_TODATE 0x24
93 87
94 struct _ftable {char *txt; unsigned flag;}; 88 struct _ftable {char* txt; unsigned flag;};
95 89
96 const struct _ftable FTABLE[]; 90 const struct _ftable FTABLE[];
97 91
98 struct date { 92 struct date {
99 unsigned day; 93 unsigned day;
100 unsigned month; 94 unsigned month;
101 unsigned year; 95 unsigned year;
102 }; 96 };
103 97
104 struct event { 98 struct event {
105 char *text; 99 char* text;
106 struct date date; 100 struct date date;
107 struct date enddate; 101 struct date enddate;
108 int warn; 102 int warn;
109 }; 103 };
110 104
112 106
113 /* ========== Global Variables */ 107 /* ========== Global Variables */
114 108
115 struct event* readlist(void); 109 struct event* readlist(void);
116 void gettoday(void); 110 void gettoday(void);
117 unsigned delta(struct date *); 111 unsigned delta(struct date*);
118 unsigned ddiff(struct date *D1, struct date *D2); 112 unsigned ddiff(struct date* D1, struct date* D2);
119 void liststrings(struct event* evl, prnfunc outf); 113 void liststrings(struct event* evl, prnfunc outf);
120 char *tdelta(struct date *d); 114 char* tdelta(struct date* d);
121 char *ttime(int yr, int mn, int wk, int dy); 115 char* ttime(int yr, int mn, int wk, int dy);
122 116 int skptok(int j, char* ptr);
123 int skptok(int j, char *ptr); 117 int evcmp(const void* e1, const void* e2);
124 int evcmp(const void *e1, const void *e2);
125 118
126 119
127 struct date today; 120 struct date today;
128 int iDWarn = DEF_WARN; 121 int iDWarn = DEF_WARN;
129 122
157 exit(1); 150 exit(1);
158 } 151 }
159 return value; 152 return value;
160 } 153 }
161 154
162
163 void* xrealloc (void* ptr, size_t size) { 155 void* xrealloc (void* ptr, size_t size) {
164 register void* value = realloc (ptr, size); 156 register void* value = realloc (ptr, size);
165 if (value == 0) { 157 if (value == 0) {
166 fprintf(stderr, "virtual memory exhausted\n"); 158 fprintf(stderr, "virtual memory exhausted\n");
167 exit(1); 159 exit(1);
168 } 160 }
169 return value; 161 return value;
170 } 162 }
171 163
164
172 /* ========== */ 165 /* ========== */
173
174 166
175 167
176 /* like strcat(), but lets the buffer automagically grow :-) 168 /* like strcat(), but lets the buffer automagically grow :-)
177 * (needs local variable "size" with the buffer size) */ 169 * (needs local variable "size" with the buffer size) */
178 #define append(where, what) do { \ 170 #define append(where, what) do { \
185 177
186 /* ========== */ 178 /* ========== */
187 179
188 /* returns delta(d) in days, weeks, months, etc 180 /* returns delta(d) in days, weeks, months, etc
189 * the returned buffer is malloc()ed, do not forget to free() it */ 181 * the returned buffer is malloc()ed, do not forget to free() it */
190 char *tdelta(struct date *d) { 182 char* tdelta(struct date* d) {
191 int dy, wk, mn, yr; 183 int dy, wk, mn, yr;
192 char *tmp; 184 char* tmp;
193 char *buf = xmalloc(128); 185 char* buf = xmalloc(128);
194 int size = 128; 186 int size = 128;
195 *buf = 0; 187 *buf = 0;
196 188
197 switch (delta(d)) { 189 switch (delta(d)) {
198 case 0: 190 case 0:
201 case 1: 193 case 1:
202 append(buf, "tomorrow"); 194 append(buf, "tomorrow");
203 return buf; 195 return buf;
204 default: 196 default:
205 /* like delta(), we ignore the year */ 197 /* like delta(), we ignore the year */
206 yr=-before(*d,today); 198 yr = -before(*d, today);
207 mn=d->month - today.month; 199 mn = d->month - today.month;
208 dy=d->day - today.day; 200 dy = d->day - today.day;
209 201
210 if (dy < 0) { 202 if (dy < 0) {
211 dy += mlen(today.month, today.year); 203 dy += mlen(today.month, today.year);
212 mn--; 204 mn--;
213 } 205 }
359 351
360 352
361 353
362 /* sort the events by the time before the next time they come up, putting those 354 /* sort the events by the time before the next time they come up, putting those
363 where the start has passed but we are still in the time-period first */ 355 where the start has passed but we are still in the time-period first */
364 int evcmp(const void *p1, const void *p2) { 356 int evcmp(const void* p1, const void* p2) {
365 struct event *e1=(struct event *)p1; 357 struct event* e1=(struct event*) p1;
366 struct event *e2=(struct event *)p2; 358 struct event* e2=(struct event*) p2;
367 unsigned d1,d2; 359 unsigned d1, d2;
368 360
369 /* if the delta for the enddate is less than that for the start date, then we 361 /* if the delta for the enddate is less than that for the start date, then we
370 have passed the start date but not yet the end date, and so we should 362 have passed the start date but not yet the end date, and so we should
371 display the enddate; otherwise, we should display the start date */ 363 display the enddate; otherwise, we should display the start date */
372 364
377 d2=delta(&(e2->date)); 369 d2=delta(&(e2->date));
378 if (e2->enddate.day && delta(&(e2->enddate)) < d2) 370 if (e2->enddate.day && delta(&(e2->enddate)) < d2)
379 d2=delta(&(e2->enddate)); 371 d2=delta(&(e2->enddate));
380 372
381 if (d1 < d2) return -1; 373 if (d1 < d2) return -1;
382 if (d1 > d2) return 1; 374 if (d1 > d2) return 1;
383 375
384 return strcmp(e1->text, e2->text); 376 return strcmp(e1->text, e2->text);
385 } 377 }
386 378
387 379
389 381
390 382
391 383
392 /* difference in days between two dates */ 384 /* difference in days between two dates */
393 /* it is assumed that D1 < D2, and so the result is always positive */ 385 /* it is assumed that D1 < D2, and so the result is always positive */
394 unsigned ddiff(struct date *D1, struct date *D2) { 386 unsigned ddiff(struct date* D1, struct date* D2) {
395 struct date d1,d2; 387 struct date d1, d2;
396 int dd,m; 388 int dd, m;
397 389
398 /* make working copies */ 390 /* make working copies */
399 d1=*D1; 391 d1 = *D1;
400 d2=*D2; 392 d2 = *D2;
401 393
402 /* sort out zero years */ 394 /* sort out zero years */
403 if (d1.year == 0 || d2.year==0) { 395 if (d1.year == 0 || d2.year==0) {
404 if (d1.year != d2.year) { 396 if (d1.year != d2.year) {
405 if (d1.year == 0) { 397 if (d1.year == 0) {
406 if (before(d1,d2)) 398 if (before(d1,d2))
407 d1.year=d2.year; 399 d1.year = d2.year;
408 else 400 else
409 d1.year=d2.year-1; 401 d1.year = d2.year - 1;
410 } else { 402 } else {
411 if (before(d1,d2)) 403 if (before(d1, d2))
412 d2.year=d1.year; 404 d2.year = d1.year;
413 else 405 else
414 d2.year=d1.year+1; 406 d2.year = d1.year + 1;
415 } 407 }
416 } else { /* both years zero */ 408 } else { /* both years zero */
417 if (before(d1,d2)) 409 if (before(d1, d2))
418 d1.year=d2.year=today.year; 410 d1.year = d2.year = today.year;
419 else { 411 else {
420 d1.year=today.year; 412 d1.year = today.year;
421 d2.year=d1.year+1; 413 d2.year = d1.year + 1;
422 } 414 }
423 } 415 }
424 } 416 }
425 417
426 /* now we can actually do the comparison ... */ 418 /* now we can actually do the comparison ... */
427 dd=0; 419 dd = 0;
428 420
429 /* to start with, we work in months */ 421 /* to start with, we work in months */
430 for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++) 422 for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++)
431 dd += mlen(((m-1)%12)+1, d1.year + m/12); 423 dd += mlen(((m-1)%12)+1, d1.year + m/12);
432 424
458 d.year = 1; 450 d.year = 1;
459 } else { 451 } else {
460 d.year = 0; 452 d.year = 0;
461 } 453 }
462 454
463 for (mn = today.month, dt=0; mn < d.month + 12*d.year; mn++) 455 for (mn = today.month, dt=0; mn < d.month + 12*d.year; mn++) {
464 dt += mlen(((mn-1)%12) + 1,today.year + mn/12); 456 dt += mlen(((mn-1)%12) + 1,today.year + mn/12);
457 }
465 458
466 dt -= today.day; 459 dt -= today.day;
467 dt += d.day; 460 dt += d.day;
468 461
469 return dt; 462 return dt;