This is trigger.c in view mode; [Download] [Up]
/***************************************************************/ /* */ /* TRIGGER.C */ /* */ /* Routines for figuring out the trigger date of a reminder */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992, 1993, 1994 by David F. Skoll */ /* */ /***************************************************************/ #include "config.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #ifdef HAVE_MALLOC_H #include <malloc.h> #endif #include "types.h" #include "expr.h" #include "protos.h" #include "globals.h" #include "err.h" #define GOT_DAY 1 #define GOT_MON 2 #define GOT_YR 4 #define GOT_WD 8 static int JYear ARGS((int jul)); static int JMonth ARGS((int jul)); static int NextSimpleTrig ARGS((int startdate, Trigger *trig, int *err)); static int GetNextTriggerDate ARGS((Trigger *trig, int start, int *err, int *nextstart)); /***************************************************************/ /* */ /* NextSimpleTrig */ /* */ /* Compute the "simple" trigger date, taking into account */ /* ONLY the day of week, day, month and year components. */ /* Normally, returns -1 if the trigger has expired. As a */ /* special case, if D, M, Y [WD] are specified, returns the */ /* Julian date, regardless of whether it's expired. This is */ /* so that dates with a REP can be handled properly. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int NextSimpleTrig(int startdate, Trigger *trig, int *err) #else static int NextSimpleTrig(startdate, trig, err) int startdate; Trigger *trig; int *err; #endif { int typ = 0; int d, m, y, j, d2, m2, y2; *err = 0; FromJulian(startdate, &y, &m, &d); d2 = d; m2 = m; y2 = y; if (trig->d != NO_DAY) typ |= GOT_DAY; if (trig->m != NO_MON) typ |= GOT_MON; if (trig->y != NO_YR) typ |= GOT_YR; if (trig->wd != NO_WD) typ |= GOT_WD; switch(typ) { case 0: case GOT_WD: if (trig->wd != NO_WD) while(! (trig->wd & (1 << (startdate%7)))) startdate++; return startdate; case GOT_DAY: if (d > trig->d) { m++; if (m == 12) { m = 0; y++; } } while (trig->d > DaysInMonth(m, trig->y)) m++; j = Julian(y, m, trig->d); return j; case GOT_MON: if (m == trig->m) return startdate; else if (m > trig->m) return Julian(y+1, trig->m, 1); else return Julian(y, trig->m, 1); case GOT_YR: if (y == trig->y) return startdate; else if (y < trig->y) return Julian(trig->y, 0, 1); else return -1; case GOT_DAY+GOT_MON: if (m > trig->m || (m == trig->m && d > trig->d)) y++; if (trig->d > MonthDays[trig->m]) { *err = E_BAD_DATE; return -1; } /* Take care of Feb. 29 */ while (trig->d > DaysInMonth(trig->m, y)) y++; return Julian(y, trig->m, trig->d); case GOT_DAY+GOT_YR: if (y < trig->y) return Julian(trig->y, 0, trig->d); else if (y > trig->y) return -1; if (d > trig->d) { m++; if (m == 12) return -1; } while (trig->d > DaysInMonth(m, trig->y)) m++; return Julian(trig->y, m, trig->d); case GOT_MON+GOT_YR: if (y > trig->y || (y == trig->y && m > trig->m)) return -1; if (y < trig->y) return Julian(trig->y, trig->m, 1); if (m == trig->m) return startdate; return Julian(trig->y, trig->m, 1); case GOT_DAY+GOT_MON+GOT_YR: if (trig->d > DaysInMonth(trig->m, trig->y)) { *err = E_BAD_DATE; return -1; } return Julian(trig->y, trig->m, trig->d); case GOT_YR+GOT_WD: if (y > trig->y) return -1; if (y < trig->y) j = Julian(trig->y, 0, 1); else j = startdate; while(! (trig->wd & (1 << (j%7)))) j++; if (JYear(j) > trig->y) return -1; return j; case GOT_MON+GOT_WD: if (m == trig->m) { j = startdate; while(! (trig->wd & (1 << (j%7)))) j++; if (JMonth(j) == trig->m) return j; } if (m >= trig->m) j = Julian(y+1, trig->m, 1); else j = Julian(y, trig->m, 1); while(! (trig->wd & (1 << (j%7)))) j++; return j; /* Guaranteed to be within the month */ case GOT_DAY+GOT_WD: if (m !=0 || y > BASE) { m2 = m-1; if (m2 < 0) { y2 = y-1; m2 = 11; } /* If there are fewer days in previous month, no match */ if (trig->d <= DaysInMonth(m2, y2)) { j = Julian(y2, m2, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } } /* Try this month */ if (trig->d <= DaysInMonth(m, y)) { j = Julian(y, m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } /* Argh! Try next avail. month */ m2 = m+1; if (m2 > 11) { m2 = 0; y++; } while (trig->d > DaysInMonth(m2, y)) m2++; j = Julian(y, m2, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; case GOT_WD+GOT_YR+GOT_DAY: if (y > trig->y+1 || (y > trig->y && m>0)) return -1; if (y > trig->y) { j = Julian(trig->y, 11, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } else if (y < trig->y) { j = Julian(trig->y, 0, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; } else { /* Try last month */ if (m > 0) { m2 = m-1; while (trig->d > DaysInMonth(m2, trig->y)) m2--; j = Julian(trig->y, m2, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } } /* Try this month */ if (trig->d <= DaysInMonth(m, trig->y)) { j = Julian(trig->y, m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; } /* Must be next month */ if (m == 11) return -1; m++; while (trig->d > DaysInMonth(m, trig->d)) m++; j = Julian(trig->y, m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; case GOT_DAY+GOT_MON+GOT_WD: /* Move up to the first valid year */ while (trig->d > DaysInMonth(trig->m, y)) y++; /* Try this year */ j = Julian(y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; if (j >= startdate) return j; /* Must be next year */ y = y + 1; while (trig->d > DaysInMonth(trig->m, y)) y++; j = Julian(y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; case GOT_WD+GOT_MON+GOT_YR: if (y > trig->y || (y == trig->y && m > trig->m)) return -1; if (trig->y > y || (trig->y == y && trig->m > m)) { j = Julian(trig->y, trig->m, 1); while(! (trig->wd & (1 << (j%7)))) j++; return j; } else { j = startdate; while(! (trig->wd & (1 << (j%7)))) j++; FromJulian(j, &y2, &m2, &d2); if (m2 == trig->m) return j; else return -1; } case GOT_WD+GOT_DAY+GOT_MON+GOT_YR: j = Julian(trig->y, trig->m, trig->d); while(! (trig->wd & (1 << (j%7)))) j++; return j; default: Eprint("NextSimpleTrig %s %d", ErrMsg[E_SWERR], typ); *err = E_SWERR; return -1; } } /***************************************************************/ /* */ /* JMonth - Given a Julian date, what's the month? */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int JMonth(int jul) #else static int JMonth(jul) int jul; #endif { int y, m, d; FromJulian(jul, &y, &m, &d); return m; } /***************************************************************/ /* */ /* JYear - Given a Julian date, what's the year? */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int JYear(int jul) #else static int JYear(jul) int jul; #endif { int y, m, d; FromJulian(jul, &y, &m, &d); return y; } /***************************************************************/ /* */ /* GetNextTriggerDate */ /* */ /* Given a trigger, compute the next trigger date. */ /* */ /* Returns the Julian date of next trigger, -1 if */ /* expired, -2 if can't compute trigger date. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart) #else static int GetNextTriggerDate(trig, start, err, nextstart) Trigger *trig; int start; int *err; int *nextstart; #endif { int simple, mod; /* First: Have we passed the UNTIL date? */ if (trig->until != NO_UNTIL && trig->until < start) return -1; /* expired */ /* Next: If it's an "AFTER"-type skip, back up until we're at the start of a block of holidays */ if (trig->skip == AFTER_SKIP) while (IsOmitted(start-1, trig->localomit)) start--; /* Find the next simple trigger */ simple = NextSimpleTrig(start, trig, err); /* Problems? */ if (*err || (simple == -1)) return -1; /* Suggested starting point for next attempt */ *nextstart = simple+1; /* If there's a BACK, back up... */ if (trig->back != NO_BACK) { mod = trig->back; if (mod < 0) simple += mod; else while(mod) { simple--; if (!IsOmitted(simple, trig->localomit)) mod--; } } /* If there's a REP, calculate the next occurrence */ if (trig->rep != NO_REP) { if (simple < start) { mod = (start - simple) / trig->rep; simple = simple + mod * trig->rep; if (simple < start) simple += trig->rep; } } /* If it's a "BEFORE"-type skip, back up */ if (trig->skip == BEFORE_SKIP) while(IsOmitted(simple, trig->localomit)) simple--; /* If it's an "AFTER"-type skip, jump ahead */ if (trig->skip == AFTER_SKIP) while (IsOmitted(simple, trig->localomit)) simple++; /* Return the date */ return simple; } /***************************************************************/ /* */ /* ComputeTrigger */ /* */ /* The main function. Compute the next trigger date given */ /* today's date. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ComputeTrigger(int today, Trigger *trig, int *err) #else int ComputeTrigger(today, trig, err) int today; Trigger *trig; int *err; #endif { int nattempts = 0, start = today, nextstart, y, m, d, result; LastTrigValid = 0; /* Assume everything works */ *err = OK; /* But check for obvious problems... */ if (trig->localomit == 1 + 2 + 4 + 8 + 16 + 32 + 64) { *err = E_2MANY_LOCALOMIT; return -1; } if (trig->rep != NO_REP && (trig->d == NO_DAY || trig->m == NO_MON || trig->y == NO_YR)) { Eprint("%s", ErrMsg[E_REP_FULSPEC]); *err = E_REP_FULSPEC; return -1; } while (nattempts++ < TRIG_ATTEMPTS) { result = GetNextTriggerDate(trig, start, err, &nextstart); /* If there's an error, die immediately */ if (*err) return -1; if (result == -1) { if (DebugFlag & DB_PRTTRIG) { fprintf(ErrFp, "%s(%d): %s\n", FileName, LineNo, ErrMsg[E_EXPIRED]); } return -1; } /* If result is >= today, great! */ if (result >= today && (trig->skip != SKIP_SKIP || !IsOmitted(result, trig->localomit))) { LastTriggerDate = result; /* Save in global var */ LastTrigValid = 1; if (DebugFlag & DB_PRTTRIG) { FromJulian(result, &y, &m, &d); fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d\n", FileName, LineNo, DayName[result % 7], d, MonthName[m], y); } return result; } /* If it's a simple trigger, no point in rescanning */ if (trig->back == NO_BACK && trig->skip == NO_SKIP && trig->rep == NO_REP) { if (DebugFlag & DB_PRTTRIG) { fprintf(ErrFp, "%s(%d): %s\n", FileName, LineNo, ErrMsg[E_EXPIRED]); } if (result != -1) { LastTriggerDate = result; LastTrigValid = 1; } return -1; } /* Keep scanning... unless there's no point in doing it.*/ if (nextstart <= start) { if (result != -1) { LastTriggerDate = result; LastTrigValid = 1; } if (DebugFlag & DB_PRTTRIG) { fprintf(ErrFp, "%s(%d): %s\n", FileName, LineNo, ErrMsg[E_EXPIRED]); } return -1; } else start = nextstart; } /* We failed - too many attempts or trigger has expired*/ *err = E_CANT_TRIG; return -1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.