summaryrefslogtreecommitdiffstats
path: root/libkholidays/parseholiday.y
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /libkholidays/parseholiday.y
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libkholidays/parseholiday.y')
-rw-r--r--libkholidays/parseholiday.y715
1 files changed, 715 insertions, 0 deletions
diff --git a/libkholidays/parseholiday.y b/libkholidays/parseholiday.y
new file mode 100644
index 000000000..fd03b11d2
--- /dev/null
+++ b/libkholidays/parseholiday.y
@@ -0,0 +1,715 @@
+%{
+/*
+ * deals with the holiday file. A yacc parser is used to parse the file.
+ * All the holidays of the specified year are calculated at once and stored
+ * in two arrays that have one entry for each day of the year. The day
+ * drawing routines just use the julian date to index into these arrays.
+ * There are two arrays because holidays can be printed either on a full
+ * line under the day number, or as a small line to the right of the day
+ * number. It's convenient to have both.
+ *
+ * parse_holidays(year, force) read the holiday file and evaluate
+ * all the holiday definitions for
+ * <year>. Sets holiday and sm_holiday
+ * arrays. If force is set, re-eval even
+ * if year is the same as last time.
+ *
+ * Taken from plan by Thomas Driemeyer <thomas@bitrot.de>
+ * Adapted for use in KOrganizer by Preston Brown <pbrown@kde.org> and
+ * Reinhold Kainhofer <reinhold@kainhofer.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <limits.h>
+
+/*** Macro definitions and constants ***/
+/*
+ * Before you mail and complain that the following macro is incorrect,
+ * please consider that this is one of the main battlegrounds of the
+ * Annual Usenet Flame Wars. 2000 is a leap year. Just trust me on this :-)
+ */
+
+#define ISLEAPYEAR(y) !((y)&3)
+#define JULIAN(m,d) (monthbegin[m] + (d)-1+((m)>1 && ISLEAPYEAR(parse_year)))
+#define LAST 999
+#define ANY 0
+#define BEFORE -1
+#define AFTER -2
+/**** Public forward declarations ****/
+char *parse_holidays(const char *holidays, int year, short force);
+
+/**** Private forward declarations ****/
+extern int kcallex(void); /* external lexical analyzer */
+static void kcalerror(const char *s);
+static time_t date_to_time(int day, int month, int year,
+ int *wkday, int *julian, int *weeknum);
+static time_t tm_to_time(struct tm *tm);
+static int day_from_name(char *str);
+static int day_from_easter(void);
+static int day_from_monthday(int month, int day);
+static int day_from_wday(int day, int wday, int num);
+static void monthday_from_day(int day, int *m, int *d, int *y);
+static int calc_easter(int year);
+static int calc_pascha(int year);
+static void setliteraldate(int month, int day, int off, int *ddup);
+static void seteaster(int off, int length, int pascha);
+static void setdate(int month, int day, int year, int off, int conditionaloff, int length);
+static void setwday(int num, int wday, int month, int off, int length);
+static void setdoff(int wday, int rel, int month, int day,
+ int year, int off, int length);
+/*** Variables and structures ***/
+static int m, d, y;
+int kcallineno; /* current line # being parsed */
+FILE *kcalin; /* file currently being processed */
+int yacc_small; /* small string or on its own line? */
+int yacc_stringcolor; /* color of holiday name text, 1..8 */
+char *yacc_string; /* holiday name text */
+int yacc_daycolor; /* color of day number, 1..8 */
+char *progname; /* argv[0] */
+int parse_year = -1; /* year being parsed, 0=1970..99=2069*/
+static const char *filename; /* holiday filename */
+static char errormsg[PATH_MAX+200];/* error message if any, or "" */
+static int easter_julian; /* julian date of Easter Sunday */
+static int pascha_julian; /* julian date of Pascha Sunday */
+static char *holiday_name; /* strdup'd yacc_string */
+short monthlen[12] = { 31, 28, 31, 30,
+ 31, 30, 31, 31,
+ 30, 31, 30, 31 };
+short monthbegin[12] = { 0, 31, 59, 90,
+ 120, 151, 181,
+ 212, 243, 273,
+ 304, 334 };
+
+/* struct holiday;*/
+struct holiday {
+ char *string; /* name of holiday, 0=not a holiday */
+ int color;
+ unsigned short dup; /* reference count */
+ struct holiday *next;
+};
+
+struct holiday holidays[366]; /* info for each day, separate for */
+/*struct holiday sm_holiday[366];*/ /* full-line texts under, and small */
+ /* texts next to day number */
+static int initialized=0;
+%}
+
+%union { int ival; char *sval; }
+%type <ival> color offset conditionaloffset length expr pexpr number month reldate wdaycondition
+%token <ival> NUMBER MONTH WDAY COLOR
+%token <sval> STRING
+%token IN PLUS MINUS SMALL CYEAR LEAPYEAR SHIFT IF
+%token LENGTH EASTER EQ NE LE GE LT GT PASCHA
+
+%left OR
+%left AND
+%right EQ NE LE GE LT GT
+%left '-' '+'
+%left '*' '/' '%'
+%nonassoc '!'
+%nonassoc UMINUS
+%left '?' ':'
+
+%start list
+
+%%
+list :
+ | list small color STRING color { yacc_stringcolor = $3;
+ yacc_string = $4;
+ yacc_daycolor = $5; }
+ entry { free(yacc_string); }
+ ;
+
+small : { yacc_small = 0; }
+ | SMALL { yacc_small = 1; }
+ ;
+
+ color : { $$ = 0; }
+ | COLOR { $$ = $1; }
+ ;
+
+entry : EASTER offset length { seteaster($2, $3, 0); }
+ | PASCHA offset length { seteaster($2, $3, 1); }
+ | date offset conditionaloffset length { setdate( m, d, y, $2, $3, $4);}
+ | WDAY offset length { setwday( 0, $1, 0, $2, $3);}
+ | pexpr WDAY offset length { setwday($1, $2, 0, $3, $4);}
+ | pexpr WDAY IN month offset length { setwday($1, $2, $4, $5, $6);}
+ | WDAY pexpr date offset length { setdoff($1, $2,m,d,y,$4,$5);}
+ ;
+
+ offset : { $$ = 0; }
+ | PLUS expr { $$ = $2; }
+ | MINUS expr { $$ = -$2; }
+ ;
+
+ conditionaloffset : { $$ = 0; }
+ | SHIFT wdaycondition IF wdaycondition { $$ = ($2<<8) | $4;printf("Shift to %i if %i\n", $2, $4); }
+ ;
+
+ wdaycondition : { $$ = 0; }
+ | WDAY { $$ = (1<<$1); }
+ | WDAY OR wdaycondition { $$ = (1<<$1) | $3; }
+ ;
+
+ length : { $$ = 1; }
+ | LENGTH expr { $$ = $2; }
+ ;
+
+ date : pexpr '.' month { m = $3; d = $1; y = 0; }
+ | pexpr '.' month '.' { m = $3; d = $1; y = 0; }
+ | pexpr '.' month '.' expr { m = $3; d = $1; y = $5; }
+ | month '/' pexpr { m = $1; d = $3; y = 0; }
+ | month '/' pexpr '/' pexpr { m = $1; d = $3; y = $5; }
+ | MONTH pexpr { m = $1; d = $2; y = 0; }
+ | MONTH pexpr pexpr { m = $1; d = $2; y = $3; }
+ | pexpr MONTH { m = $2; d = $1; y = 0; }
+ | pexpr MONTH pexpr { m = $2; d = $1; y = $3; }
+ | pexpr '.' MONTH pexpr { m = $3; d = $1; y = $4; }
+ | pexpr { monthday_from_day($1,
+ &m, &d, &y); }
+ ;
+
+ reldate : STRING { $$ = day_from_name($1); }
+ | EASTER { $$ = day_from_easter(); }
+ | pexpr '.' month { $$ = day_from_monthday
+ ($3, $1); }
+ | pexpr '.' month '.' { $$ = day_from_monthday
+ ($3, $1); }
+ | month '/' pexpr { $$ = day_from_monthday
+ ($1, $3); }
+ | pexpr MONTH { $$ = day_from_monthday
+ ($2, $1); }
+ | MONTH pexpr { $$ = day_from_monthday
+ ($1, $2); }
+ | WDAY pexpr pexpr { $$ = day_from_wday($3, $1,
+ $2 == -1 ? -1 : 0); }
+ | pexpr WDAY IN month { int day=day_from_monthday($4,1);
+ $$ = $1 == 999
+ ? day_from_wday(day+1,$2,-1)
+ : day_from_wday(day,$2,$1-1);}
+ ;
+
+ month : MONTH | pexpr;
+
+ expr : pexpr { $$ = $1; }
+ | expr OR expr { $$ = $1 || $3; }
+ | expr AND expr { $$ = $1 && $3; }
+ | expr EQ expr { $$ = $1 == $3; }
+ | expr NE expr { $$ = $1 != $3; }
+ | expr LE expr { $$ = $1 <= $3; }
+ | expr GE expr { $$ = $1 >= $3; }
+ | expr LT expr { $$ = $1 < $3; }
+ | expr GT expr { $$ = $1 > $3; }
+ | expr '+' expr { $$ = $1 + $3; }
+ | expr '-' expr { $$ = $1 - $3; }
+ | expr '*' expr { $$ = $1 * $3; }
+ | expr '/' expr { $$ = $3 ? $1 / $3 : 0; }
+ | expr '%' expr { $$ = $3 ? $1 % $3 : 0; }
+ | expr '?' expr ':' expr { $$ = $1 ? $3 : $5; }
+ | '!' expr { $$ = !$2; }
+ | '[' reldate ']' { $$ = $2; }
+ ;
+
+ pexpr : '(' expr ')' { $$ = $2; }
+ | number { $$ = $1; }
+ ;
+
+ number : NUMBER
+ | '-' NUMBER %prec UMINUS { $$ = -$2; }
+ | CYEAR { $$ = parse_year; }
+ | LEAPYEAR pexpr { $$ = !(($2) & 3); }
+ ;
+%%
+
+/*** Private Yacc callbacks and helper functions ***/
+static void kcalerror(const char *msg)
+{
+ fprintf(stderr, "%s: %s in line %d of %s\n", progname,
+ msg, kcallineno+1, filename);
+ if (!*errormsg)
+ snprintf(errormsg,sizeof(errormsg),
+ "Problem with holiday file %s:\n%.80s in line %d",
+ filename, msg, kcallineno+1);
+}
+
+static time_t date_to_time(int day, int month, int year,
+ int *wkday, int *julian, int *weeknum)
+{
+ struct tm tm;
+ time_t ttime;
+
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+ tm.tm_mday = day;
+ tm.tm_mon = month;
+ tm.tm_year = year;
+ ttime = tm_to_time(&tm);
+ if (wkday)
+ *wkday = tm.tm_wday;
+ if (julian)
+ *julian = tm.tm_yday;
+ if (weeknum)
+ *weeknum = 0
+ ? tm.tm_yday / 7
+ : tm.tm_yday ? ((tm.tm_yday - 1) /7) + 1 : 0;
+ return(ttime == -1 || day != tm.tm_mday ? 0 : ttime);
+}
+
+static time_t tm_to_time(struct tm *tm)
+{
+ time_t t; /* return value */
+
+ t = monthbegin[tm->tm_mon] /* full months */
+ + tm->tm_mday-1 /* full days */
+ + (!(tm->tm_year & 3) && tm->tm_mon > 1); /* leap day this year*/
+ tm->tm_yday = t;
+ t += 365 * (tm->tm_year - 70) /* full years */
+ + (tm->tm_year - 69)/4; /* past leap days */
+ tm->tm_wday = (t + 4) % 7;
+
+ t = t*86400 + tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;
+ if (tm->tm_mday > monthlen[tm->tm_mon] +
+ (!(tm->tm_year & 3) && tm->tm_mon == 1))
+ return((time_t)-1);
+ return(t);
+}
+
+/*
+ * set holiday by weekday (monday..sunday). The expression is
+ * "every <num>-th <wday> of <month> plus <off> days". num and month
+ * can be ANY or LAST.
+ */
+
+static void setwday(int num, int wday, int month, int off, int length)
+{
+ int min_month = 0, max_month = 11;
+ int min_num = 0, max_num = 4;
+ int mn, n, dy, l, mlen, wday1;
+ int ddup = 0;
+
+ if (month != ANY)
+ min_month = max_month = month-1;
+ if (month == LAST)
+ min_month = max_month = 11;
+ if (num != ANY)
+ min_num = max_num = num-1;
+
+ holiday_name = yacc_string;
+ for (mn=min_month; mn <= max_month; mn++) {
+ (void)date_to_time(1, mn, parse_year, &wday1, 0, 0);
+ dy = (wday-1 - (wday1-1) +7) % 7 + 1;
+ mlen = monthlen[mn] + (mn==1 && ISLEAPYEAR(parse_year));
+ if (num == LAST)
+ for (l=0; l < length; l++)
+ setliteraldate(mn, dy+28<=mlen ? dy+28 : dy+21,
+ off+l, &ddup);
+ else
+ for (dy+=min_num*7, n=min_num; n <= max_num; n++, dy+=7)
+ if (dy >= 1 && dy <= mlen)
+ for (l=0; l < length; l++)
+ setliteraldate(mn,dy,off+l,&ddup);
+ }
+}
+
+/*
+ * set holiday by weekday (monday..sunday) date offset. The expression is
+ * "every <wday> before/after <date> plus <off> days".
+ * (This routine contributed by Peter Littlefield <plittle@sofkin.ca>)
+ */
+
+static void setdoff(int wday, int rel, int month, int day,
+ int year, int off, int length)
+{
+ int min_month = 0, max_month = 11;
+ int min_day = 1, max_day = 31;
+ int mn, dy, nd, l, wday1;
+ int ddup = 0;
+
+ if (year != ANY) {
+ year %= 100;
+ if (year < 70) year += 100;
+ if (year != parse_year)
+ return;
+ }
+ if (month != ANY)
+ min_month = max_month = month-1;
+ if (month == LAST)
+ min_month = max_month = 11;
+ if (day != ANY)
+ min_day = max_day = day;
+
+ holiday_name = yacc_string;
+ for (mn=min_month; mn <= max_month; mn++)
+ if (day == LAST) {
+ (void)date_to_time(monthlen[mn], mn, parse_year,
+ &wday1, 0, 0);
+ nd = (((wday - wday1 + 7) % 7) -
+ ((rel == BEFORE) ? 7 : 0)) % 7;
+ for (l=0; l < length; l++)
+ setliteraldate(mn,monthlen[mn]+nd, off+l, &ddup);
+ } else
+ for (dy=min_day; dy <= max_day; dy++) {
+ (void)date_to_time(dy, mn, parse_year,
+ &wday1, 0, 0);
+ nd = (((wday - wday1 + 7) % 7) -
+ ((rel == BEFORE) ? 7 : 0)) % 7;
+ for (l=0; l < length; l++)
+ setliteraldate(mn, dy+nd, off+l, &ddup);
+ }
+}
+
+static int conditionalOffset( int day, int month, int year, int cond )
+{
+ int off = 0;
+ int wday = 0;
+ (void)date_to_time( day, month, year, &wday, 0, 0);
+ if ( wday == 0 ) { wday = 7; } /* sunday is 7, not 0 */
+ if ( cond & (1<<wday) ) {
+ /* condition matches -> higher 8 bits contain the possible days to shift to */
+ int to = (cond >> 8);
+ while ( !(to & (1<<((wday+off)%7))) && (off < 8) ) {
+ ++off;
+ }
+ }
+ if ( off >= 8 ) return 0;
+ else return off;
+}
+
+/*
+ * set holiday by date. Ignore holidays in the wrong year. The code is
+ * complicated by expressions such as "any/last/any" (every last day of
+ * the month).
+ */
+
+static void setdate(int month, int day, int year, int off, int conditionaloff, int length)
+{
+ int min_month = 0, max_month = 11;
+ int min_day = 1, max_day = 31;
+ int mn, dy, l;
+ int ddup = 0;
+
+ if (year != ANY) {
+ year %= 100;
+ if (year < 70) year += 100;
+ if (year != parse_year)
+ return;
+ }
+ if (month != ANY)
+ min_month = max_month = month-1;
+ if (month == LAST)
+ min_month = max_month = 11;
+ if (day != ANY)
+ min_day = max_day = day;
+
+ holiday_name = yacc_string;
+ /** TODO: Include the conditionaloff variable. */
+ /** The encoding of the conditional offset is:
+ 8 lower bits: conditions to shift (bit-register, bit 1=mon, ..., bit 7=sun)
+ 8 higher bits: weekday to shift to (bit-register, bit 1=mon, ..., bit 7=sun)
+ */
+ for (mn=min_month; mn <= max_month; mn++) {
+ if (day == LAST) {
+ int newoff = off + conditionalOffset( monthlen[mn], mn, parse_year, conditionaloff );
+ for (l=0; l < length; l++)
+ setliteraldate(mn, monthlen[mn], newoff+l, &ddup);
+ } else {
+ for (dy=min_day; dy <= max_day; dy++) {
+ int newoff = off + conditionalOffset( dy, mn, parse_year, conditionaloff );
+ for (l=0; l < length; l++)
+ setliteraldate(mn, dy, newoff+l, &ddup);
+ }
+ }
+ }
+}
+
+
+/*
+ * After the two routines above have removed ambiguities (ANY) and resolved
+ * weekday specifications, this routine registers the holiday in the holiday
+ * array. There are two of these, for full-line holidays (they take away one
+ * appointment line in the month calendar daybox) and "small" holidays, which
+ * appear next to the day number. If the day is already some other holiday,
+ * add a new item to the singly-linked list and insert the holiday there.
+ * <ddup> is information stored for parse_holidays(), it
+ * will free() the holiday name only if its dup field is 0 (because many
+ * string fields can point to the same string, which was allocated only once
+ * by the lexer, and should therefore only be freed once).
+ */
+
+static void setliteraldate(int month, int day, int off, int *ddup)
+{
+ int julian = JULIAN(month, day) + off;
+ /* struct holiday *hp = yacc_small ? &sm_holiday[julian]
+ : &holiday[julian]; */
+ struct holiday *hp = 0;
+
+ if (julian >= 0 && julian <= 365 ) {
+ hp = &holidays[julian];
+ if ( hp->string ) {
+ while (hp->next) { hp = hp->next; }
+ hp->next = malloc( sizeof(struct holiday)*2 );
+ hp = hp->next;
+ hp->next = 0;
+ }
+ if (!*ddup)
+ holiday_name = strdup(holiday_name);
+ hp->string = holiday_name;
+ hp->color = (yacc_stringcolor == 0) ? yacc_daycolor : yacc_stringcolor;
+ hp->dup = (*ddup)++;
+
+ }
+}
+
+
+/*
+ * set a holiday relative to Easter
+ */
+
+static void seteaster(int off, int length, int pascha /*0=Easter, 1=Pascha*/)
+{
+ int ddup = 0; /* flag for later free() */
+ int julian = (pascha ? pascha_julian : easter_julian) + off;
+ /* struct holiday *hp = yacc_small ? &sm_holiday[julian]
+ : &holidays[julian];*/
+ struct holiday *hp = 0;
+
+ holiday_name = yacc_string;
+ while (length-- > 0) {
+ if (julian >= 0 && julian <= 365 ) {
+ hp = &holidays[julian];
+ if ( hp->string ) {
+ while (hp->next) { hp = hp->next; }
+ hp->next = malloc( sizeof(struct holiday)*2 );
+ hp = hp->next;
+ hp->next = 0;
+ }
+ if (!ddup)
+ holiday_name = strdup(holiday_name);
+ hp->string = holiday_name;
+ hp->color = (yacc_stringcolor == 0) ? yacc_daycolor : yacc_stringcolor;
+ hp->dup = ddup++;
+ }
+ julian++;
+ }
+}
+
+
+/*
+ * calculate Easter Sunday as a julian date. I got this from Armin Liebl
+ * <liebla@informatik.tu-muenchen.de>, who got it from Knuth. I hope I got
+ * all this right...
+ */
+
+static int calc_easter(int year)
+{
+ int golden, cent, grcor, clcor, extra, epact, easter;
+
+ golden = (year/19)*(-19);
+ golden += year+1;
+ cent = year/100+1;
+ grcor = (cent*3)/(-4)+12;
+ clcor = ((cent-18)/(-25)+cent-16)/3;
+ extra = (year*5)/4+grcor-10;
+ epact = golden*11+20+clcor+grcor;
+ epact += (epact/30)*(-30);
+ if (epact<=0)
+ epact += 30;
+ if (epact==25) {
+ if (golden>11)
+ epact += 1;
+ } else {
+ if (epact==24)
+ epact += 1;
+ }
+ easter = epact*(-1)+44;
+ if (easter<21)
+ easter += 30;
+ extra += easter;
+ extra += (extra/7)*(-7);
+ extra *= -1;
+ easter += extra+7;
+ easter += 31+28+!(year&3)-1;
+ return(easter);
+}
+
+
+/*
+ * set a holiday relative to Pascha, which is the Christian Orthodox Easter.
+ * Algorithm provided by Efthimios Mavrogeorgiadis <emav@enl.auth.gr>.
+ * Changed 12.9.99 by Efthimios Mavrogeorgiadis <emav@enl.auth.gr>.
+ */
+
+static int calc_pascha(int year) /* Pascha in which year? */
+{
+ int a = year % 19;
+ int b = (19 * a + 15) % 30;
+ int c = (year + (year - (year % 4))/4 + b) % 7;
+ int dd = b - c;
+ int e = dd-3 - (2 - (year-(year%100))/100 + (year-(year%400))/400);
+ int f = (e - (e % 31))/31;
+ int day = e - 30 * f;
+ return(31 + 28+!(year&3) + 31 + (f ? 30 : 0) + day-1);
+}
+
+
+/*
+ * functions used for [] syntax: (Erwin Hugo Achermann <acherman@inf.ethz.ch>)
+ *
+ * day_from_name (str) gets day from symbolic name
+ * day_from_easter () gets day as easter sunday
+ * day_from_monthday (month, day) gets <day> from <month/day>
+ * day_from_wday (day, wday, num) gets num-th day (wday) after <day> day
+ * monthday_from_day (day, *m, *d, *y) gets month/day/cur_year from <day>
+ */
+
+static int day_from_name(char *str)
+{
+ int i;
+ char *name;
+
+ for (i=0; i < 366; i++) {
+ name = holidays[i].string;
+ if (name && !strcmp(str, name))
+ return(i);
+ }
+ return(-1);
+}
+
+
+static int day_from_easter(void)
+{
+ return(easter_julian);
+}
+
+
+static int day_from_monthday(int month, int day)
+{
+ if (month == 13)
+ return(365 + ISLEAPYEAR(parse_year));
+ return(JULIAN(month - 1, day));
+}
+
+
+static void monthday_from_day(int day, int *mn, int *dy, int *yr)
+{
+ int i, len;
+
+ *yr = parse_year;
+ *mn = 0;
+ *dy = 0;
+ if (day < 0)
+ return;
+ for (i=0; i < 12; i++) {
+ len = monthlen[i] + (i == 1 && ISLEAPYEAR(parse_year));
+ if (day < len) {
+ *mn = i + 1;
+ *dy = day + 1;
+ break;
+ }
+ day -= len;
+ }
+}
+
+
+static int day_from_wday(int day, int wday, int num)
+{
+ int wkday, yday, weeknum;
+
+ (void)date_to_time(1, 0, parse_year, &wkday, &yday, &weeknum);
+ day += (wday - wkday - day + 1001) % 7;
+ day += num * 7;
+ return (day);
+}
+
+static void initialize()
+{
+ register struct holiday *hp;
+ register int dy;
+ initialized = 1;
+ for (hp=holidays, dy=0; dy < 366; dy++, hp++)
+ {
+ hp->color = 0;
+ hp->dup = 0;
+ hp->string = 0;
+ hp->next = 0;
+ }
+}
+
+/*** Public Functions ***/
+/*
+ * parse the holiday text file, and set up the holiday arrays for a year.
+ * If year is -1, re-parse the last year parsed (this is used when the
+ * holiday file changes). If there is a CPP_PATH, check if the executable
+ * really exists, and if so, pipe the holioday files through it.
+ * Return an error message if an error occurred, 0 otherwise.
+ */
+
+char *parse_holidays(const char *holidayfile, int year, short force)
+{
+ register struct holiday *hp;
+ register int dy;
+ short piped = 0;
+ if (!initialized)
+ initialize();
+
+ if (year == parse_year && !force)
+ return(0);
+ if (year < 0)
+ year = parse_year;
+ parse_year = year;
+ easter_julian = calc_easter(year + 1900);
+ pascha_julian = calc_pascha(year + 1900);
+
+ for (hp=holidays, dy=0; dy < 366; dy++, hp++)
+ {
+ hp->color = 0;
+ if (hp->string) {
+ if (!hp->dup )
+ free(hp->string);
+ hp->string = 0;
+ }
+ {
+ struct holiday *nx = hp->next;
+ hp->next = 0;
+ while (nx) {
+ struct holiday *nxtmp;
+ if ( nx->string && !nx->dup ) {
+ free( nx->string );
+ }
+ nxtmp=nx;
+ nx = nxtmp->next;
+ free( nxtmp );
+ }
+ }
+ }
+ /* for (hp=sm_holiday, d=0; d < 366; d++, hp++)
+ if (hp->string) {
+ if (!hp->dup)
+ free(hp->string);
+ hp->string = 0;
+ }*/
+
+ filename = holidayfile;
+ if (access(filename, R_OK)) return(0);
+ kcalin = fopen(filename, "r");
+ if (!kcalin) return(0);
+ *errormsg = 0;
+ kcallineno = 0;
+ kcalparse();
+ if (piped) pclose(kcalin);
+ else fclose(kcalin);
+ if (*errormsg) return(errormsg);
+
+ return(0);
+}