Mercurial > bday
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:22b6e71de68e |
---|---|
1 /* | |
2 birthday.c | |
3 | |
4 Birthday/Anniversary display on login | |
5 | |
6 (c) 1996 AS Mortimer | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. You may also | |
12 distribute it under the Artistic License, as comes with Perl. | |
13 | |
14 This program is distributed in the hope that it will be useful, | |
15 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
17 | |
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 | |
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | |
22 You should also have recieved a copy of the Artistic license with | |
23 this program. | |
24 | |
25 $Id: bdengine.c,v 1.14 2001/10/21 07:03:49 andy Exp $ | |
26 | |
27 We're getting there. At the moment, the file used by default is ~/.birthdays | |
28 under UNIX, or C:\PERSONAL\BDAYS.LST under DOS, but this can be overridden on | |
29 the command line. The file has the following format: | |
30 | |
31 name/event/whatever=date flags | |
32 where: | |
33 date is dd/mm, dd/mm/yy (assumes 20th century!) or dd/mm/yyyy | |
34 flags is ONE or ZERO of | |
35 o bd for a birthday (default) | |
36 o bir for a birthday (exactly equivalent to `bd') | |
37 o ann for an anniversary | |
38 o ev for an event | |
39 and zero or more of | |
40 o w<n> to set the warn-in-advance time to n days (don't include the | |
41 brackets! :) | |
42 o to<date> | |
43 o for<days> | |
44 to specify the length of time taken by an event, for example a | |
45 holiday. | |
46 | |
47 Comment lines are preceeded by #. | |
48 | |
49 Note: If you deviate from this format, I cannot guarantee anything about | |
50 it's behaviour. In most cases, it will just quietly ignore the error, | |
51 which probably isn't ideal behaviour. Oh, well. | |
52 | |
53 2003/05/20: Automatic reallocation of output buffer in listsrings() by | |
54 Sebastian Schmidt <yath@yath.eu.org>. | |
55 | |
56 */ | |
57 | |
58 | |
59 | |
60 /* ========== */ | |
61 | |
62 | |
63 #include <stdio.h> | |
64 #include <stdarg.h> | |
65 #include <stdlib.h> | |
66 #include <string.h> | |
67 #include <time.h> | |
68 | |
69 #include <sys/types.h> | |
70 #include <unistd.h> | |
71 #include <pwd.h> | |
72 | |
73 #include "birthday.h" | |
74 | |
75 /* ========== */ | |
76 | |
77 | |
78 | |
79 /* | |
80 xmalloc/xrealloc functions, and fatal exit function | |
81 Note: the x* functions are lifted straight from the GNU libc info docs | |
82 $Id: xmalloc.c,v 1.2 1999/01/16 17:08:59 andy Exp $ | |
83 */ | |
84 | |
85 void *xmalloc (size_t size) { | |
86 register void *value = malloc (size); | |
87 if (value == 0) { | |
88 fprintf(stderr, "virtual memory exhausted\n"); | |
89 exit(1); | |
90 } | |
91 return value; | |
92 } | |
93 | |
94 | |
95 void *xrealloc (void *ptr, size_t size) { | |
96 register void *value = realloc (ptr, size); | |
97 if (value == 0) { | |
98 fprintf(stderr, "virtual memory exhausted\n"); | |
99 exit(1); | |
100 } | |
101 return value; | |
102 } | |
103 | |
104 /* ========== */ | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 int skptok(int j, char *ptr); | |
112 int evcmp(const void *e1, const void *e2); | |
113 char *deffname(void); | |
114 | |
115 struct event *dir_include(char *dir, char *parm); | |
116 | |
117 /* ========== Global variables */ | |
118 | |
119 struct date today; | |
120 int iDWarn = DEF_WARN; | |
121 int iMaxWarn = MAX_WARN; | |
122 int iMinWarn = MIN_WARN; | |
123 | |
124 const unsigned MLENDAT[]={31,-1,31,30,31,30,31,31,30,31,30,31}; | |
125 | |
126 const struct _ftable FTABLE[] = { | |
127 {"bir",F_TBIRTHDAY}, | |
128 {"bd", F_TBIRTHDAY}, | |
129 {"ann",F_TANNIVERSARY}, | |
130 {"ev", F_TEVENT}, | |
131 {"mes", F_TMESSAGE}, | |
132 {"w", F_WTIME_P}, | |
133 {"to", F_TODATE}, | |
134 {"for", F_FORDAYS}, | |
135 {NULL, 0} | |
136 }; | |
137 | |
138 | |
139 /* list of directives. These are entered in the file prefixed by '&'. The function should be declared as | |
140 struct event *dir_func(char *directive, char *parameters); | |
141 and should return a pointer to a NULL-terminated list of extra records, or NULL if there are none. | |
142 This structure will allow us to dynamically add directives, if we wish to do so in the future. | |
143 */ | |
144 | |
145 struct { | |
146 const char *text; | |
147 int len; | |
148 struct event *(*func)(char*,char*); | |
149 } directlist[] = { | |
150 { "include", 0, dir_include }, | |
151 { NULL, 0, NULL } | |
152 }; | |
153 | |
154 /* ========== */ | |
155 | |
156 | |
157 | |
158 | |
159 /* compare the first strlen(a) characters of a and b */ | |
160 #define strbegcmp(a,b) strncmp(a,b,strlen(a)) | |
161 | |
162 /* like strcat(), but lets the buffer automagically grow :-) | |
163 * (needs local variable "size" with the buffer size) */ | |
164 #define append(where, what) do { \ | |
165 if (strlen(what) > (size - strlen(where))) { \ | |
166 xrealloc(where, size + 128 + strlen(what)); \ | |
167 size += 128 + strlen(what); \ | |
168 } \ | |
169 strcat(where, what); \ | |
170 } while(0) | |
171 | |
172 /* ========== */ | |
173 | |
174 /* returns delta(d) in days, weeks, months, etc | |
175 * the returned buffer is malloc()ed, do not forget to free() it */ | |
176 char *tdelta(struct date *d) { | |
177 int dy, wk, mn, yr; | |
178 char *tmp; | |
179 char *buf = xmalloc(128); | |
180 int size = 128; | |
181 *buf = 0; | |
182 | |
183 switch (delta(d)) { | |
184 case 0: | |
185 append(buf, "today"); | |
186 return buf; | |
187 case 1: | |
188 append(buf, "tomorrow"); | |
189 return buf; | |
190 default: | |
191 /* like delta(), we ignore the year */ | |
192 yr=-before(*d,today); | |
193 mn=d->month - today.month; | |
194 dy=d->day - today.day; | |
195 | |
196 if (dy < 0) { | |
197 dy += mlen(today.month, today.year); | |
198 mn--; | |
199 } | |
200 if (mn < 0) { | |
201 mn += 12; | |
202 yr++; | |
203 } | |
204 | |
205 wk = (dy/7); | |
206 dy%=7; | |
207 | |
208 append(buf, "in "); | |
209 tmp = ttime(yr, mn, wk, dy); | |
210 append(buf, tmp); | |
211 free(tmp); | |
212 | |
213 if (*(buf + strlen(buf) - 1) == 's') | |
214 append(buf, "'"); | |
215 else | |
216 append(buf, "'s"); | |
217 | |
218 append(buf, " time"); | |
219 | |
220 return buf; | |
221 } | |
222 } | |
223 | |
224 | |
225 | |
226 | |
227 | |
228 /* | |
229 void donum(n,txt) { | |
230 do { | |
231 if (n > 0) { | |
232 snprintf(tmp, sizeof(tmp), "%d", n); | |
233 append(buf, tmp); | |
234 append(buf, " " txt); | |
235 if (n != 1) | |
236 append(buf, "s"); | |
237 terms--; | |
238 if (orgterms > 1) { | |
239 if (terms == 1) | |
240 append(buf, " and "); | |
241 else if (terms > 1) | |
242 append(buf, ", "); | |
243 } | |
244 } | |
245 } while(0) | |
246 } | |
247 */ | |
248 | |
249 | |
250 #define donum(n,txt) do { \ | |
251 if (n > 0) { \ | |
252 snprintf(tmp, sizeof(tmp), "%d", n); \ | |
253 append(buf, tmp); \ | |
254 append(buf, " " txt); \ | |
255 if (n != 1) \ | |
256 append(buf, "s"); \ | |
257 terms--; \ | |
258 if (orgterms > 1) { \ | |
259 if (terms == 1) \ | |
260 append(buf, " and "); \ | |
261 else if (terms > 1) \ | |
262 append(buf, ", "); \ | |
263 } \ | |
264 } \ | |
265 } while(0) | |
266 | |
267 | |
268 /* returns allocated buffer, don't forget to free() */ | |
269 char* ttime(int yr, int mn, int wk, int dy) { | |
270 char* buf = xmalloc(128); | |
271 int size = 128; | |
272 int terms, orgterms; | |
273 char tmp[128]; | |
274 | |
275 *buf = 0; /* Initialize buffer */ | |
276 terms = orgterms = (yr!=0) + (mn!=0) + (wk!=0) + (dy!=0); | |
277 | |
278 donum(yr, "year"); | |
279 donum(mn, "month"); | |
280 donum(wk, "week"); | |
281 donum(dy, "day"); | |
282 | |
283 return buf; | |
284 } | |
285 #undef donum | |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | |
292 /* lists the birthdays in their string format, one by one, and passes the string | |
293 to a function. */ | |
294 void liststrings(struct event *evl, prnfunc outf) { | |
295 int i,j; | |
296 char *buf, *tmp; | |
297 int size; | |
298 | |
299 for (i = 0; evl[i].text != NULL; i++) { | |
300 buf = xmalloc(128); | |
301 *buf = '\0'; | |
302 size = 128; | |
303 | |
304 if (evl[i].warn == -1 && delta(&(evl[i].date))==0) { | |
305 append(buf, evl[i].text); | |
306 } else if (evl[i].enddate.day == 0) { | |
307 if (delta(&(evl[i].date)) <= warnperiod(evl[i])) { | |
308 append(buf, evl[i].text); | |
309 append(buf, " "); | |
310 tmp = tdelta(&(evl[i].date)); | |
311 append(buf, tmp); | |
312 free(tmp); | |
313 } | |
314 } else { | |
315 if (delta(&(evl[i].date)) <= warnperiod(evl[i])) { | |
316 append(buf, evl[i].text); | |
317 append(buf, " for "); | |
318 /* +1 because, if the difference between two dates is one day, | |
319 then the length of an event on those days is two days */ | |
320 j = ddiff(&(evl[i].date),&(evl[i].enddate)) + 1; | |
321 tmp = ttime(0, 0, j/7, j%7); | |
322 append(buf, tmp); | |
323 free(tmp); | |
324 append(buf, " "); | |
325 tmp = tdelta(&(evl[i].date)); | |
326 append(buf, tmp); | |
327 } else if (delta(&(evl[i].enddate)) <= warnperiod(evl[i])) { | |
328 append(buf, evl[i].text); | |
329 append(buf, " "); | |
330 j = delta(&(evl[i].enddate)); | |
331 if (j) { | |
332 append(buf, "for "); | |
333 tmp = ttime(0, 0, j/7, j%7); | |
334 append(buf, tmp); | |
335 free(tmp); | |
336 append(buf, " longer"); | |
337 } else { | |
338 append(buf, "finishes today"); | |
339 } | |
340 } | |
341 } | |
342 if (*buf) { | |
343 append(buf, "."); | |
344 outf(buf); | |
345 } | |
346 free(buf); | |
347 } | |
348 } | |
349 | |
350 | |
351 | |
352 | |
353 | |
354 | |
355 | |
356 char* deffname(void) { | |
357 char buf[256]; | |
358 | |
359 strcpy(buf,getpwuid(getuid())->pw_dir); | |
360 strcat(buf, "/" DEFAULT_FILE); | |
361 | |
362 return strdup(buf); | |
363 } | |
364 | |
365 | |
366 | |
367 | |
368 | |
369 | |
370 /* sort the events by the time before the next time they come up, putting those | |
371 where the start has passed but we are still in the time-period first */ | |
372 int evcmp(const void *p1, const void *p2) { | |
373 struct event *e1=(struct event *)p1; | |
374 struct event *e2=(struct event *)p2; | |
375 unsigned d1,d2; | |
376 | |
377 /* if the delta for the enddate is less than that for the start date, then we | |
378 have passed the start date but not yet the end date, and so we should | |
379 display the enddate; otherwise, we should display the start date */ | |
380 | |
381 d1=delta(&(e1->date)); | |
382 if (e1->enddate.day && delta(&(e1->enddate)) < d1) | |
383 d1=delta(&(e1->enddate)); | |
384 | |
385 d2=delta(&(e2->date)); | |
386 if (e2->enddate.day && delta(&(e2->enddate)) < d2) | |
387 d2=delta(&(e2->enddate)); | |
388 | |
389 if (d1 < d2) return -1; | |
390 if (d1 > d2) return 1; | |
391 | |
392 return strcmp(e1->text, e2->text); | |
393 } | |
394 | |
395 | |
396 | |
397 | |
398 | |
399 | |
400 /* difference in days between two dates */ | |
401 /* it is assumed that D1 < D2, and so the result is always positive */ | |
402 unsigned ddiff(struct date *D1, struct date *D2) { | |
403 struct date d1,d2; | |
404 int dd,m; | |
405 | |
406 /* make working copies */ | |
407 d1=*D1; | |
408 d2=*D2; | |
409 | |
410 /* sort out zero years */ | |
411 if (d1.year == 0 || d2.year==0) { | |
412 if (d1.year != d2.year) { | |
413 if (d1.year == 0) { | |
414 if (before(d1,d2)) | |
415 d1.year=d2.year; | |
416 else | |
417 d1.year=d2.year-1; | |
418 } else { | |
419 if (before(d1,d2)) | |
420 d2.year=d1.year; | |
421 else | |
422 d2.year=d1.year+1; | |
423 } | |
424 } else { /* both years zero */ | |
425 if (before(d1,d2)) | |
426 d1.year=d2.year=today.year; | |
427 else { | |
428 d1.year=today.year; | |
429 d2.year=d1.year+1; | |
430 } | |
431 } | |
432 } | |
433 | |
434 /* now we can actually do the comparison ... */ | |
435 dd=0; | |
436 | |
437 /* to start with, we work in months */ | |
438 for (m=d1.month; m < d2.month + (d2.year-d1.year)*12; m++) | |
439 dd += mlen(((m-1)%12)+1, d1.year + m/12); | |
440 | |
441 /* and then we renormalise for the days within the months */ | |
442 /* the first month was included in our calculations */ | |
443 dd -= d1.day; | |
444 /* but the last one wasn't */ | |
445 dd += d2.day; | |
446 | |
447 return dd; | |
448 } | |
449 | |
450 | |
451 | |
452 | |
453 | |
454 | |
455 | |
456 | |
457 /* actually until the next anniversary of ... */ | |
458 unsigned delta(struct date *date) { | |
459 struct date d; | |
460 unsigned dt, mn; | |
461 | |
462 memcpy(&d, date, sizeof(struct date)); | |
463 | |
464 /* past the end of the year */ | |
465 if (before(d, today)) { | |
466 d.year = 1; | |
467 } else { | |
468 d.year = 0; | |
469 } | |
470 | |
471 for (mn = today.month, dt=0; mn < d.month + 12*d.year; mn++) | |
472 dt += mlen(((mn-1)%12) + 1,today.year + mn/12); | |
473 | |
474 dt -= today.day; | |
475 dt += d.day; | |
476 | |
477 return dt; | |
478 } | |
479 | |
480 | |
481 | |
482 | |
483 | |
484 | |
485 void gettoday(void) { | |
486 struct tm *tm; | |
487 time_t t; | |
488 | |
489 time(&t); | |
490 tm = localtime(&t); | |
491 today.day = tm->tm_mday; | |
492 today.month = tm->tm_mon + 1; /* 1-12 instead of 0-11 */ | |
493 today.year = tm->tm_year; | |
494 today.year += 1900; | |
495 } | |
496 | |
497 | |
498 | |
499 | |
500 | |
501 struct event *readlist(char *fname) { | |
502 FILE *file; | |
503 int i,j,k,l,d; | |
504 struct event *evl; | |
505 char buf[1024], buf2[1024]; | |
506 char *ptr; | |
507 unsigned flags; | |
508 struct event *nevl; | |
509 /* initialise */ | |
510 if (fname==NULL) { | |
511 fname=deffname(); | |
512 } | |
513 | |
514 gettoday(); | |
515 | |
516 if (fname[0] == '-' && fname[1] == 0) { | |
517 /* read from stdin */ | |
518 file=stdin; | |
519 } else { | |
520 /* now read it */ | |
521 if((file=fopen(fname, "rt"))==NULL) { | |
522 fprintf(stderr, "Unable to open file \"%s\"\n", fname); | |
523 exit(1); | |
524 } | |
525 } | |
526 | |
527 | |
528 for (i = 0, evl=NULL; fgets(buf, sizeof(buf), file) != NULL; i++) { | |
529 evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); | |
530 | |
531 if (*buf == '#' || *buf == '\n') | |
532 { | |
533 i--; | |
534 continue; | |
535 } | |
536 if (*buf == '&') { | |
537 buf[strlen(buf)-1] = 0; | |
538 if ((ptr=strchr(buf+1,' ')) == NULL && (ptr=strchr((buf+1),'\t')) == NULL) { | |
539 ptr=(buf+1)+strlen((buf+1)); | |
540 } | |
541 | |
542 *ptr++=0; | |
543 nevl=NULL; | |
544 k=0; | |
545 for (j=0; directlist[j].text != NULL; j++) { | |
546 if (directlist[j].len == 0) directlist[j].len = strlen(directlist[j].text); | |
547 /* | |
548 fprintf(stderr, "Checking against directive #%d, %s, which has length %d, against \"%s\" with length %d\n", | |
549 j, directlist[j].text, directlist[j].len, buf+1, ptr-(buf+1)-1); | |
550 */ | |
551 if (directlist[j].len == ptr-(buf+1)-1 && !strncmp(directlist[j].text,(buf+1),directlist[j].len)) { | |
552 nevl = directlist[j].func((buf+1),ptr); | |
553 k=1; | |
554 break; | |
555 } | |
556 } | |
557 | |
558 if (nevl != NULL) { | |
559 for (j=0; nevl[j].text != NULL; j++); | |
560 i+=j-1; | |
561 evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); | |
562 /* in fact, this loop reverses the order of the elements, but we're going to sort them later anyway. */ | |
563 for (j=0; nevl[j].text != NULL; j++) | |
564 evl[i-j]=nevl[j]; | |
565 } | |
566 if (!k) { | |
567 fprintf(stderr, "Warning: unrecognised directive \"%s\" ignored.\n", (buf+1)); | |
568 i--; | |
569 } | |
570 continue; | |
571 } | |
572 | |
573 /* parse string in buf */ | |
574 ptr = strrchr(buf, '='); /* allow '=' in text */ | |
575 if(ptr==NULL) /* not a valid line, so ignore it! Cool, huh? */ | |
576 { | |
577 fprintf(stderr, "WARNING: Invalid line in input file:\n%s", buf); | |
578 i--; | |
579 continue; | |
580 } | |
581 | |
582 *(ptr++) = 0; | |
583 | |
584 j = sscanf(ptr, "%u-%u-%u", &(evl[i].date.year), &(evl[i].date.month), &(evl[i].date.day)); | |
585 /* if our year is only two digits, add 1900 to it ... */ | |
586 if(evl[i].date.year < 100) evl[i].date.year+=1900; | |
587 /* ... unless it wasn't read, in which case set it to zero */ | |
588 if(j==2) evl[i].date.year=0; | |
589 | |
590 /* parse flags */ | |
591 | |
592 evl[i].warn=iDWarn; | |
593 evl[i].enddate.day=evl[i].enddate.month=evl[i].enddate.year=0; | |
594 | |
595 flags=j=0; | |
596 while(j = skptok(j, ptr),ptr[j]!=0) | |
597 { | |
598 for (k = 0; FTABLE[k].txt != NULL && strncmp(FTABLE[k].txt, ptr + j, strlen(FTABLE[k].txt)); k++); | |
599 switch (FTABLE[k].flag) { | |
600 case F_WTIME_P: /* w<n> -- sets warning time */ | |
601 sscanf(ptr + j, "w %u", &(evl[i].warn)); | |
602 break; | |
603 case F_FORDAYS: /* for<days> -- sets the duration of the event */ | |
604 sscanf(ptr + j, "for %d", &d); | |
605 evl[i].enddate=evl[i].date; | |
606 for (l=1; l < d; l++) { | |
607 evl[i].enddate.day++; | |
608 if (evl[i].enddate.day > mlen(evl[i].enddate.month, | |
609 evl[i].enddate.year)) { | |
610 evl[i].enddate.month++; | |
611 evl[i].enddate.day=1; | |
612 } | |
613 if (evl[i].enddate.month > 12) { | |
614 evl[i].enddate.year++; | |
615 evl[i].enddate.month=1; | |
616 } | |
617 } | |
618 break; | |
619 case F_TODATE: | |
620 l = sscanf(ptr + j, "to %u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day)); | |
621 if (evl[i].enddate.year < 100) evl[i].enddate.year+=1900; | |
622 if (l == 2) evl[i].enddate.year=0; | |
623 break; | |
624 case 0: | |
625 break; | |
626 default: | |
627 flags|=FTABLE[k].flag; | |
628 break; | |
629 } | |
630 } | |
631 | |
632 /* construct event text */ | |
633 | |
634 switch(flags & F_MTYPE) { | |
635 case F_TBIRTHDAY: | |
636 default: /* assume it's a birthday */ | |
637 if (evl[i].date.year != 0) { | |
638 int tmp_age=ydelta(evl[i].date, today); | |
639 if (tmp_age!=1) { | |
640 sprintf(buf2, "%s is %d years old", buf, tmp_age); | |
641 } else { | |
642 sprintf(buf2, "%s is %d year old", buf, tmp_age); | |
643 } | |
644 } else { | |
645 sprintf(buf2, "%s has a birthday", buf); | |
646 } | |
647 break; | |
648 case F_TANNIVERSARY: | |
649 if (evl[i].date.year != 0) { | |
650 sprintf(buf2, "%s %d years ago", buf, ydelta(evl[i].date, today)); | |
651 } else { | |
652 strcpy(buf2, buf); | |
653 } | |
654 break; | |
655 case F_TEVENT: | |
656 /* if a year was specified, and this warning isn't for it, ignore! */ | |
657 if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0) && | |
658 (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) { | |
659 i--; | |
660 continue; | |
661 } | |
662 strcpy(buf2, buf); | |
663 break; | |
664 case F_TMESSAGE: | |
665 /* Like an event, except that it only comes up on the given date, and no text at all is appended */ | |
666 if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0) && | |
667 (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) { | |
668 i--; | |
669 continue; | |
670 } | |
671 strcpy(buf2, buf); | |
672 evl[i].warn=-1; /* special code! */ | |
673 break; | |
674 } | |
675 evl[i].text = strdup(buf2); | |
676 } | |
677 | |
678 evl = (struct event *) xrealloc(evl, sizeof(struct event) * (i + 1)); | |
679 evl[i].date.day=evl[i].date.month=evl[i].date.year=0; | |
680 evl[i].text = (char *) NULL; | |
681 | |
682 fclose(file); | |
683 free(fname); | |
684 | |
685 /* NB uses i from above */ | |
686 qsort(evl, i, sizeof(struct event), evcmp); | |
687 return evl; | |
688 } | |
689 | |
690 | |
691 | |
692 | |
693 | |
694 | |
695 | |
696 | |
697 int skptok(int j, char *ptr) { | |
698 for (; ptr[j] != 0 && ptr[j] != ' ' && ptr[j] != '\t' ; j++); | |
699 for (; ptr[j] != 0 && (ptr[j] == ' ' || ptr[j] == '\t'); j++); | |
700 | |
701 return j; | |
702 } | |
703 | |
704 | |
705 | |
706 | |
707 | |
708 | |
709 /* ---------------------------------------------------------------------- */ | |
710 /* Functions to parse input file directives */ | |
711 struct event *dir_include(char *dir, char *parm) { | |
712 struct event *evl; | |
713 | |
714 evl=readlist(strdup(parm)); | |
715 | |
716 return evl; | |
717 } |