comparison bday.c @ 15:032af48d590b

reformating of the source code
author markus schnalke <meillo@marmaro.de>
date Mon, 24 Feb 2014 17:46:57 +0100
parents a56120a4678f
children 79d22407a6be
comparison
equal deleted inserted replaced
14:a56120a4678f 15:032af48d590b
1 /* 1 /*
2 bday 2 bday -- Birthday/Anniversary reminder
3 3
4 Birthday/Anniversary reminder 4 (c) 2007,2014 markus schnalke <meillo@marmaro.de>
5 5 (c) 1994-1999 AS Mortimer
6 (c) 2007 markus schnalke <meillo@marmaro.de> 6
7 (c) 1994-1999 AS Mortimer 7 This program is free software; you can redistribute it and/or
8 8 modify it under the terms of the GNU General Public License as
9 This program is free software; you can redistribute it and/or 9 published by the Free Software Foundation; either version 2 of the
10 modify it under the terms of the GNU General Public License as 10 License, or (at your option) any later version. You may also
11 published by the Free Software Foundation; either version 2 of the 11 distribute it under the Artistic License, as comes with Perl.
12 License, or (at your option) any later version. You may also 12
13 distribute it under the Artistic License, as comes with Perl. 13 This program is distributed in the hope that it will be useful,
14 14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 This program is distributed in the hope that it will be useful, 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 but WITHOUT ANY WARRANTY; without even the implied warranty of 16
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17 You should have received a copy of the GNU General Public License
18 18 along with this program; if not, write to the Free Software
19 You should have received a copy of the GNU General Public License 19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 along with this program; if not, write to the Free Software 20
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 You should also have recieved a copy of the Artistic license with
22 22 this program.
23 You should also have recieved a copy of the Artistic license with 23
24 this program. 24 =====================================================================
25 25
26 =============================================================================== 26 Input is read through standard input. For example: bday < ~/.birthdays
27 27 The input (file) has to have the following format:
28 Input is read through standard input. For example: bday < ~/.birthdays 28
29 The input (file) has to have the following format: 29 text=date flags
30 30
31 text=date flags 31 where:
32 32 date is yyyy-mm-dd
33 where: 33 flags is ONE or ZERO of
34 date is yyyy-mm-dd 34 bd for a birthday (default)
35 flags is ONE or ZERO of 35 ann for an anniversary
36 bd for a birthday (default) 36 ev for an event
37 ann for an anniversary 37 and zero or more of
38 ev for an event 38 w <n> to set the warn-in-advance time to n days
39 and zero or more of 39 (don't include the brackets! :)
40 w <n> to set the warn-in-advance time to n days (don't include the 40 to <date>
41 brackets! :) 41 for <days>
42 to <date> 42 to specify the length of time taken by an
43 for <days> 43 event, for example a holiday.
44 to specify the length of time taken by an event, for example a holiday. 44
45 45 Lines preceeded by # are treated as comments.
46 Lines preceeded by # are treated as comments. 46
47 47 Note: If you deviate from this format, I cannot guarantee anything about
48 Note: If you deviate from this format, I cannot guarantee anything about 48 it's behaviour. In most cases, it will just quietly ignore the
49 it's behaviour. In most cases, it will just quietly ignore the error, 49 error, which probably isn't ideal behaviour. Oh, well.
50 which probably isn't ideal behaviour. Oh, well. 50
51 51 =====================================================================
52 ===============================================================================
53 */ 52 */
54 53
55 54
56 /* standard time to warn in advance, when no explicit w flag is given. */ 55 /* standard time to warn in advance, when no explicit w flag is given. */
57 #define DEF_WARN 14 56 #define DEF_WARN 14
92 struct _ftable {char* txt; unsigned flag;}; 91 struct _ftable {char* txt; unsigned flag;};
93 92
94 const struct _ftable FTABLE[]; 93 const struct _ftable FTABLE[];
95 94
96 struct date { 95 struct date {
97 unsigned day; 96 unsigned day;
98 unsigned month; 97 unsigned month;
99 unsigned year; 98 unsigned year;
100 }; 99 };
101 100
102 struct event { 101 struct event {
103 char* text; 102 char* text;
104 struct date date; 103 struct date date;
105 struct date enddate; 104 struct date enddate;
106 int warn; 105 int warn;
107 }; 106 };
108 107
109 typedef int (*prnfunc)(const char *); 108 typedef int (*prnfunc)(const char *);
110 109
111 /* ========== Global Variables */ 110 /* ========== Global Variables */
112 111
113 struct event* readlist(void); 112 struct event *readlist(void);
114 void gettoday(void); 113 void gettoday(void);
115 unsigned delta(struct date*); 114 unsigned delta(struct date *);
116 unsigned ddiff(struct date* D1, struct date* D2); 115 unsigned ddiff(struct date *D1, struct date *D2);
117 void liststrings(struct event* evl, prnfunc outf); 116 void liststrings(struct event *evl, prnfunc outf);
118 char* tdelta(struct date* d); 117 char *tdelta(struct date *d);
119 char* ttime(int yr, int mn, int wk, int dy); 118 char *ttime(int yr, int mn, int wk, int dy);
120 int skptok(int j, char* ptr); 119 int skptok(int j, char *ptr);
121 int evcmp(const void* e1, const void* e2); 120 int evcmp(const void *e1, const void *e2);
122 121
123 122
124 struct date today; 123 struct date today;
125 int iDWarn = DEF_WARN; 124 int iDWarn = DEF_WARN;
126 125
127 const unsigned MLENDAT[]={31,-1,31,30,31,30,31,31,30,31,30,31}; 126 const unsigned MLENDAT[] = {31,-1,31,30,31,30,31,31,30,31,30,31};
128 127
129 const struct _ftable FTABLE[] = { 128 const struct _ftable FTABLE[] = {
130 {"bd", F_TBIRTHDAY}, 129 {"bd", F_TBIRTHDAY},
131 {"ann",F_TANNIVERSARY}, 130 {"ann",F_TANNIVERSARY},
132 {"ev", F_TEVENT}, 131 {"ev", F_TEVENT},
140 139
141 140
142 141
143 142
144 /* 143 /*
145 xmalloc/xrealloc functions 144 xmalloc/xrealloc functions
146 Note: the x* functions are lifted straight from the GNU libc info docs 145 Note: the x* functions are lifted straight from the GNU libc info docs
147 $Id: xmalloc.c,v 1.2 1999/01/16 17:08:59 andy Exp $ 146 $Id: xmalloc.c,v 1.2 1999/01/16 17:08:59 andy Exp $
148 */ 147 */
149 148
150 void* xmalloc (size_t size) { 149 void *
151 register void* value = malloc (size); 150 xmalloc(size_t size)
151 {
152 register void *value = malloc (size);
152 if (value == 0) { 153 if (value == 0) {
153 fprintf(stderr, "virtual memory exhausted\n"); 154 fprintf(stderr, "virtual memory exhausted\n");
154 exit(1); 155 exit(1);
155 } 156 }
156 return value; 157 return value;
157 } 158 }
158 159
159 void* xrealloc (void* ptr, size_t size) { 160 void *
160 register void* value = realloc (ptr, size); 161 xrealloc(void *ptr, size_t size)
162 {
163 register void *value = realloc (ptr, size);
161 if (value == 0) { 164 if (value == 0) {
162 fprintf(stderr, "virtual memory exhausted\n"); 165 fprintf(stderr, "virtual memory exhausted\n");
163 exit(1); 166 exit(1);
164 } 167 }
165 return value; 168 return value;
167 170
168 171
169 /* ========== */ 172 /* ========== */
170 173
171 174
172 /* like strcat(), but lets the buffer automagically grow :-) 175 /*
173 * (needs local variable "size" with the buffer size) */ 176 like strcat(), but lets the buffer automagically grow :-)
177 (needs local variable "size" with the buffer size)
178 */
174 #define append(where, what) do { \ 179 #define append(where, what) do { \
175 if (strlen(what) > (size - strlen(where))) { \ 180 if (strlen(what) > (size - strlen(where))) { \
176 xrealloc(where, size + 128 + strlen(what)); \ 181 xrealloc(where, size + 128 + strlen(what)); \
177 size += 128 + strlen(what); \ 182 size += 128 + strlen(what); \
178 } \ 183 } \
179 strcat(where, what); \ 184 strcat(where, what); \
180 } while(0) 185 } while(0)
181 186
182 /* ========== */ 187 /* ========== */
183 188
184 /* returns delta(d) in days, weeks, months, etc 189 /*
185 * the returned buffer is malloc()ed, do not forget to free() it */ 190 returns delta(d) in days, weeks, months, etc
186 char* tdelta(struct date* d) { 191 the returned buffer is malloc()ed, do not forget to free() it
192 */
193 char *
194 tdelta(struct date *d)
195 {
187 int dy, wk, mn, yr; 196 int dy, wk, mn, yr;
188 char* tmp; 197 char *tmp;
189 char* buf = xmalloc(128); 198 char *buf = xmalloc(128);
190 int size = 128; 199 int size = 128;
200
191 *buf = 0; 201 *buf = 0;
192
193 switch (delta(d)) { 202 switch (delta(d)) {
194 case 0: 203 case 0:
195 append(buf, "today"); 204 append(buf, "today");
196 return buf; 205 return buf;
197 case 1: 206 case 1:
198 append(buf, "tomorrow"); 207 append(buf, "tomorrow");
199 return buf; 208 return buf;
200 default: 209 default:
201 /* like delta(), we ignore the year */ 210 /* like delta(), we ignore the year */
202 yr = -before(*d, today); 211 yr = -before(*d, today);
203 mn = d->month - today.month; 212 mn = d->month - today.month;
204 dy = d->day - today.day; 213 dy = d->day - today.day;
205 214
206 if (dy < 0) { 215 if (dy < 0) {
207 dy += mlen(today.month, today.year); 216 dy += mlen(today.month, today.year);
208 mn--; 217 mn--;
209 } 218 }
210 if (mn < 0) { 219 if (mn < 0) {
211 mn += 12; 220 mn += 12;
212 yr++; 221 yr++;
213 } 222 }
214 223
215 wk = (dy / 7); 224 wk = (dy / 7);
216 dy %= 7; 225 dy %= 7;
217 226
218 append(buf, "in "); 227 append(buf, "in ");
219 tmp = ttime(yr, mn, wk, dy); 228 tmp = ttime(yr, mn, wk, dy);
220 append(buf, tmp); 229 append(buf, tmp);
221 free(tmp); 230 free(tmp);
222 231
223 return buf; 232 return buf;
224 } 233 }
225 } 234 }
226 235
227 236
228 237
229 238
230 239
231 /* 240 /*
232 void donum(n,txt) { 241 void
233 do { 242 donum(n,txt)
234 if (n > 0) { 243 {
235 snprintf(tmp, sizeof(tmp), "%d", n); 244 if (n > 0) {
236 append(buf, tmp); 245 snprintf(tmp, sizeof(tmp), "%d", n);
237 append(buf, " " txt); 246 append(buf, tmp);
238 if (n != 1) 247 append(buf, " " txt);
239 append(buf, "s"); 248 if (n != 1)
240 terms--; 249 append(buf, "s");
241 if (orgterms > 1) { 250 terms--;
242 if (terms == 1) 251 if (orgterms > 1) {
243 append(buf, " and "); 252 if (terms == 1)
244 else if (terms > 1) 253 append(buf, " and ");
245 append(buf, ", "); 254 else if (terms > 1)
246 } 255 append(buf, ", ");
247 } 256 }
248 } while(0) 257 }
249 } 258 }
250 */ 259 */
251 260
252 261
253 #define donum(n,txt) do { \ 262 #define donum(n,txt) do { \
267 } \ 276 } \
268 } while(0) 277 } while(0)
269 278
270 279
271 /* returns allocated buffer, don't forget to free() */ 280 /* returns allocated buffer, don't forget to free() */
272 char* ttime(int yr, int mn, int wk, int dy) { 281 char *
273 char* buf = xmalloc(128); 282 ttime(int yr, int mn, int wk, int dy)
283 {
284 char *buf = xmalloc(128);
274 int size = 128; 285 int size = 128;
275 int terms, orgterms; 286 int terms, orgterms;
276 char tmp[128]; 287 char tmp[128];
277 288
278 *buf = 0; /* Initialize buffer */ 289 *buf = 0; /* Initialize buffer */
290 301
291 302
292 303
293 304
294 305
295 /* lists the birthdays in their string format, one by one, and passes the string to a function. */ 306 /*
296 void liststrings(struct event* evl, prnfunc outf) { 307 lists the birthdays in their string format, one by one, and passes
308 the string to a function.
309 */
310 void
311 liststrings(struct event *evl, prnfunc outf)
312 {
297 int i,j; 313 int i,j;
298 char *buf, *tmp; 314 char *buf, *tmp;
299 int size; 315 int size;
300 316
301 for (i = 0; evl[i].text != NULL; i++) { 317 for (i = 0; evl[i].text != NULL; i++) {
354 370
355 371
356 372
357 373
358 374
359 /* sort the events by the time before the next time they come up, putting those 375 /*
360 where the start has passed but we are still in the time-period first */ 376 sort the events by the time before the next time they come up,
361 int evcmp(const void* p1, const void* p2) { 377 putting those where the start has passed but we are still in the
362 struct event* e1=(struct event*) p1; 378 time-period first
363 struct event* e2=(struct event*) p2; 379 */
380 int
381 evcmp(const void *p1, const void *p2)
382 {
383 struct event *e1=(struct event *) p1;
384 struct event *e2=(struct event *) p2;
364 unsigned d1, d2; 385 unsigned d1, d2;
365 386
366 /* if the delta for the enddate is less than that for the start date, then we 387 /*
367 have passed the start date but not yet the end date, and so we should 388 if the delta for the enddate is less than that for the start
368 display the enddate; otherwise, we should display the start date */ 389 date, then we have passed the start date but not yet the end
390 date, and so we should display the enddate; otherwise, we
391 should display the start date
392 */
369 393
370 d1=delta(&(e1->date)); 394 d1=delta(&(e1->date));
371 if (e1->enddate.day && delta(&(e1->enddate)) < d1) 395 if (e1->enddate.day && delta(&(e1->enddate)) < d1)
372 d1=delta(&(e1->enddate)); 396 d1=delta(&(e1->enddate));
373 397
384 408
385 409
386 410
387 411
388 412
389 /* difference in days between two dates */ 413 /*
390 /* it is assumed that D1 < D2, and so the result is always positive */ 414 difference in days between two dates
391 unsigned ddiff(struct date* D1, struct date* D2) { 415 it is assumed that D1 < D2, and so the result is always positive
416 */
417 unsigned
418 ddiff(struct date *D1, struct date *D2)
419 {
392 struct date d1, d2; 420 struct date d1, d2;
393 int dd, m; 421 int dd, m;
394 422
395 /* make working copies */ 423 /* make working copies */
396 d1 = *D1; 424 d1 = *D1;
425 453
426 /* to start with, we work in months */ 454 /* to start with, we work in months */
427 for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++) 455 for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++)
428 dd += mlen(((m-1)%12)+1, d1.year + m/12); 456 dd += mlen(((m-1)%12)+1, d1.year + m/12);
429 457
430 /* and then we renormalise for the days within the months */ 458 /*
431 /* the first month was included in our calculations */ 459 and then we renormalise for the days within the months
460 the first month was included in our calculations
461 */
432 dd -= d1.day; 462 dd -= d1.day;
433 /* but the last one wasn't */ 463 /* but the last one wasn't */
434 dd += d2.day; 464 dd += d2.day;
435 465
436 return dd; 466 return dd;
441 471
442 472
443 473
444 474
445 475
446 /* actually until the next anniversary of ... */ 476 /*
447 unsigned delta(struct date *date) { 477 actually until the next anniversary of ...
478 */
479 unsigned
480 delta(struct date *date)
481 {
448 struct date d; 482 struct date d;
449 unsigned dt, mn; 483 unsigned dt, mn;
450 484
451 memcpy(&d, date, sizeof(struct date)); 485 memcpy(&d, date, sizeof(struct date));
452 486
470 504
471 505
472 506
473 507
474 508
475 void gettoday(void) { 509 void
510 gettoday(void)
511 {
476 struct tm *tm; 512 struct tm *tm;
477 time_t t; 513 time_t t;
478 514
479 time(&t); 515 time(&t);
480 tm = localtime(&t); 516 tm = localtime(&t);
490 526
491 527
492 528
493 529
494 530
495 struct event* readlist() { 531 struct event *
532 readlist()
533 {
496 int i, j, k, l, d; 534 int i, j, k, l, d;
497 struct event *evl; 535 struct event *evl;
498 char buf[1024], buf2[1024]; 536 char buf[1024], buf2[1024];
499 char *ptr; 537 char *ptr;
500 unsigned flags; 538 unsigned flags;
522 continue; 560 continue;
523 } 561 }
524 562
525 *(ptr++) = 0; 563 *(ptr++) = 0;
526 564
527 j = sscanf(ptr, "%u-%u-%u", &(evl[i].date.year), &(evl[i].date.month), &(evl[i].date.day)); 565 j = sscanf(ptr, "%u-%u-%u", &(evl[i].date.year),
566 &(evl[i].date.month), &(evl[i].date.day));
528 /* ... unless it wasn't read, in which case set it to zero */ 567 /* ... unless it wasn't read, in which case set it to zero */
529 if (j==2) { 568 if (j==2) {
530 evl[i].date.year = 0; 569 evl[i].date.year = 0;
531 } 570 }
532 571
544 while(j = skptok(j, ptr), ptr[j] != 0) { 583 while(j = skptok(j, ptr), ptr[j] != 0) {
545 for (k = 0; FTABLE[k].txt != NULL && strncmp(FTABLE[k].txt, ptr + j, strlen(FTABLE[k].txt)); k++) { 584 for (k = 0; FTABLE[k].txt != NULL && strncmp(FTABLE[k].txt, ptr + j, strlen(FTABLE[k].txt)); k++) {
546 } 585 }
547 586
548 switch (FTABLE[k].flag) { 587 switch (FTABLE[k].flag) {
549 case F_WTIME_P: /* w <n> -- sets warning time */ 588 case F_WTIME_P: /* w <n> -- sets warning time */
550 sscanf(ptr + j, "w %u", &(evl[i].warn)); 589 sscanf(ptr + j, "w %u", &(evl[i].warn));
551 break; 590 break;
552 case F_FORDAYS: /* for <days> -- sets the duration of the event */ 591 case F_FORDAYS: /* for <days> -- sets the duration of the event */
553 sscanf(ptr + j, "for %u", &d); 592 sscanf(ptr + j, "for %u", &d);
554 evl[i].enddate=evl[i].date; 593 evl[i].enddate=evl[i].date;
555 for (l = 1; l < d; l++) { 594 for (l = 1; l < d; l++) {
556 evl[i].enddate.day++; 595 evl[i].enddate.day++;
557 if (evl[i].enddate.day > mlen(evl[i].enddate.month, evl[i].enddate.year)) { 596 if (evl[i].enddate.day > mlen(evl[i].enddate.month, evl[i].enddate.year)) {
558 evl[i].enddate.month++; 597 evl[i].enddate.month++;
559 evl[i].enddate.day = 1; 598 evl[i].enddate.day = 1;
560 }
561 if (evl[i].enddate.month > 12) {
562 evl[i].enddate.year++;
563 evl[i].enddate.month = 1;
564 }
565 } 599 }
566 break; 600 if (evl[i].enddate.month > 12) {
567 case F_TODATE: /* to <date> -- sets the end date of the event */ 601 evl[i].enddate.year++;
568 l = sscanf(ptr + j, "to %u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day)); 602 evl[i].enddate.month = 1;
569 if (l == 2) {
570 evl[i].enddate.year = 0;
571 } 603 }
572 break; 604 }
573 case 0: 605 break;
574 break; 606 case F_TODATE: /* to <date> -- sets the end date of the event */
575 default: 607 l = sscanf(ptr + j, "to %u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day));
576 flags |= FTABLE[k].flag; 608 if (l == 2) {
577 break; 609 evl[i].enddate.year = 0;
610 }
611 break;
612 case 0:
613 break;
614 default:
615 flags |= FTABLE[k].flag;
616 break;
578 } 617 }
579 } 618 }
580 619
581 620
582 /* construct event text */ 621 /* construct event text */
630 669
631 670
632 671
633 672
634 673
635 int skptok(int j, char *ptr) { 674 int
675 skptok(int j, char *ptr)
676 {
636 for (; ptr[j] != 0 && ptr[j] != ' ' && ptr[j] != '\t' ; j++); 677 for (; ptr[j] != 0 && ptr[j] != ' ' && ptr[j] != '\t' ; j++);
637 for (; ptr[j] != 0 && (ptr[j] == ' ' || ptr[j] == '\t'); j++); 678 for (; ptr[j] != 0 && (ptr[j] == ' ' || ptr[j] == '\t'); j++);
638 679
639 return j; 680 return j;
640 } 681 }
642 683
643 684
644 685
645 686
646 687
647 int main(int argc, char* argv[]) { 688 int
648 689 main(int argc, char *argv[])
649 while (--argc > 0 && (*++argv)[0] == '-') { 690 {
691 while (--argc > 0 && (*++argv)[0] == '-') {
650 if (strcmp(argv[0], "-W") == 0) { 692 if (strcmp(argv[0], "-W") == 0) {
651 /* TODO: catch if no value given */ 693 /* TODO: catch if no value given */
652 iDWarn = atoi((++argv)[0]); 694 iDWarn = atoi((++argv)[0]);
653 argc--; 695 argc--;
654 } else { 696 } else {
657 } 699 }
658 } 700 }
659 701
660 liststrings(readlist(), puts); 702 liststrings(readlist(), puts);
661 703
662 return 0; 704 return 0;
663 } 705 }