diff --git a/src/dorem.c b/src/dorem.c index 2c9e90bb..9abb56bf 100644 --- a/src/dorem.c +++ b/src/dorem.c @@ -145,6 +145,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim) trig->priority = DefaultPrio; trig->sched[0] = 0; trig->warn[0] = 0; + trig->omitfunc[0] = 0; trig->tag[0] = 0; trig->passthru[0] = 0; tim->ttime = NO_TIME; @@ -266,6 +267,13 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim) if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday; return OK; + case T_OmitFunc: + r=ParseToken(s, &buf); + if (r) return r; + StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN); + DBufFree(&buf); + break; + case T_Warn: r=ParseToken(s, &buf); if(r) return r; @@ -551,7 +559,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type) int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul) { int r, y, m, d; - char PrioExpr[25]; + char PrioExpr[VAR_NAME_LEN+25]; char tmpBuf[64]; DynamicBuffer buf, calRow; DynamicBuffer pre_buf; @@ -795,9 +803,19 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul) jul = jul + t->delta; else { r = t->delta; - while(r && jul > JulianToday) { + int iter = 0; + int max = MaxSatIter; + if (max < r*2) max = r*2; + while(iter++ < max) { + if (!r || (jul <= JulianToday)) { + break; + } jul--; - if (!IsOmitted(jul, t->localomit)) r--; + if (!IsOmitted(jul, t->localomit, t->omitfunc)) r--; + } + if (iter > max) { + /* TODO: Somehow communicate error back to caller!! */ + return 0; } } } @@ -996,10 +1014,17 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int jul) if (JulianToday + v.v.val == jul) return 1; } else { int j = jul; - while (v.v.val) { + int iter = 0; + int max = MaxSatIter; + if (max < v.v.val * 2) max = v.v.val*2; + while(iter++ <= max) { j--; - if (!IsOmitted(j, t->localomit)) v.v.val++; + if (!IsOmitted(j, t->localomit, t->omitfunc)) v.v.val++; + if (!v.v.val) { + break; + } } + if (iter > max) return 0; if (j == JulianToday) return 1; } } diff --git a/src/funcs.c b/src/funcs.c index 7dc9e97f..380743f7 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -1302,7 +1302,7 @@ static int FIsomitted(void) { if (!HASDATE(ARG(0))) return E_BAD_TYPE; RetVal.type = INT_TYPE; - RetVal.v.val = IsOmitted(DATEPART(ARG(0)), 0); + RetVal.v.val = IsOmitted(DATEPART(ARG(0)), 0, NULL); return OK; } @@ -2478,7 +2478,7 @@ FNonomitted(void) ans = 0; while (d1 < d2) { - if (!IsOmitted(d1++, localomit)) { + if (!IsOmitted(d1++, localomit, NULL)) { ans++; } } diff --git a/src/omit.c b/src/omit.c index 737dbd97..4152f16d 100644 --- a/src/omit.c +++ b/src/omit.c @@ -20,6 +20,7 @@ #include "protos.h" #include "globals.h" #include "err.h" +#include "expr.h" static int BexistsIntArray (int array[], int num, int key); static void InsertIntoSortedArray (int *array, int num, int key); @@ -180,7 +181,7 @@ int PopOmitContext(ParsePtr p) /* Return non-zero if date is OMITted, zero if it is not. */ /* */ /***************************************************************/ -int IsOmitted(int jul, int localomit) +int IsOmitted(int jul, int localomit, char const *omitfunc) { int y, m, d; @@ -195,6 +196,23 @@ int IsOmitted(int jul, int localomit) if (BexistsIntArray(PartialOmitArray, NumPartialOmits, (m << 5) + d)) return 1; + /* Is it omitted because of omitfunc? */ + if (omitfunc && *omitfunc && UserFuncExists(omitfunc)) { + char expr[VAR_NAME_LEN + 32]; + char const *s; + int r; + Value v; + sprintf(expr, "%s('%04d-%02d-%02d')", + omitfunc, y, m, d); + s = expr; + r = EvalExpr(&s, &v); + if (!r) { + if (v.type == INT_TYPE && v.v.val != 0) { + return 1; + } + } + } + /* Not omitted */ return 0; } diff --git a/src/protos.h b/src/protos.h index dab94f6d..bf687398 100644 --- a/src/protos.h +++ b/src/protos.h @@ -75,7 +75,7 @@ int DoClear (ParsePtr p); int DestroyOmitContexts (void); int PushOmitContext (ParsePtr p); int PopOmitContext (ParsePtr p); -int IsOmitted (int jul, int localomit); +int IsOmitted (int jul, int localomit, char const *omitfunc); int DoOmit (ParsePtr p); int QueueReminder (ParsePtr p, Trigger *trig, TimeTrig *tim, char const *sched); void HandleQueuedReminders (void); diff --git a/src/token.c b/src/token.c index 1d2c51ca..ad071c6f 100644 --- a/src/token.c +++ b/src/token.c @@ -74,6 +74,7 @@ Token TokArray[] = { { "november", 3, T_Month, 10 }, { "october", 3, T_Month, 9 }, { "omit", 3, T_Omit, 0 }, + { "omitfunc", 8, T_OmitFunc, 0 }, { "once", 3, T_Once, 0 }, { "pop-omit-context", 3, T_Pop, 0 }, { "preserve", 8, T_Preserve, 0 }, diff --git a/src/trigger.c b/src/trigger.c index f8a3c454..2f61b264 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -294,8 +294,19 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart /* 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--; + if (trig->skip == AFTER_SKIP) { + int iter = 0; + while (iter++ <= MaxSatIter) { + if (!IsOmitted(start-1, trig->localomit, trig->omitfunc)) { + break; + } + start--; + } + if (iter > MaxSatIter) { + /* omitfunc must have returned "true" too often */ + return -2; + } + } /* Find the next simple trigger */ simple = NextSimpleTrig(start, trig, err); @@ -309,12 +320,23 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart /* 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 (mod < 0) { + simple += mod; + } + else { + int iter = 0; + int max = MaxSatIter; + if (max < mod*2) { + max = mod*2; } + while(iter++ <= max) { + if (!mod) { + break; + } + simple--; + if (!IsOmitted(simple, trig->localomit, trig->omitfunc)) mod--; + } + } } /* If there's a REP, calculate the next occurrence */ @@ -327,12 +349,32 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart } /* If it's a "BEFORE"-type skip, back up */ - if (trig->skip == BEFORE_SKIP) - while(IsOmitted(simple, trig->localomit)) simple--; + if (trig->skip == BEFORE_SKIP) { + int iter = 0; + while(iter++ <= MaxSatIter) { + if (!IsOmitted(simple, trig->localomit, trig->omitfunc)) { + break; + } + simple--; + } + if (iter > MaxSatIter) { + return -2; + } + } /* If it's an "AFTER"-type skip, jump ahead */ - if (trig->skip == AFTER_SKIP) - while (IsOmitted(simple, trig->localomit)) simple++; + if (trig->skip == AFTER_SKIP) { + int iter = 0; + while (iter++ <= MaxSatIter) { + if (!IsOmitted(simple, trig->localomit, trig->omitfunc)) { + break; + } + simple++; + } + if (iter > MaxSatIter) { + return -2; + } + } /* Return the date */ return simple; @@ -373,8 +415,8 @@ int ComputeTrigger(int today, Trigger *trig, int *err) *err = E_REP_FULSPEC; return -1; } - - + + while (nattempts++ < TRIG_ATTEMPTS) { result = GetNextTriggerDate(trig, start, err, &nextstart); @@ -390,7 +432,7 @@ int ComputeTrigger(int today, Trigger *trig, int *err) /* If result is >= today, great! */ if (result >= today && - (trig->skip != SKIP_SKIP || !IsOmitted(result, trig->localomit))) { + (trig->skip != SKIP_SKIP || !IsOmitted(result, trig->localomit, trig->omitfunc))) { LastTriggerDate = result; /* Save in global var */ LastTrigValid = 1; if (DebugFlag & DB_PRTTRIG) { @@ -421,7 +463,7 @@ int ComputeTrigger(int today, Trigger *trig, int *err) } if (trig->skip == SKIP_SKIP && - IsOmitted(result, trig->localomit) && + IsOmitted(result, trig->localomit, trig->omitfunc) && nextstart <= start && result >= start) { nextstart = result + 1; diff --git a/src/types.h b/src/types.h index eabd1c31..05c762bc 100644 --- a/src/types.h +++ b/src/types.h @@ -56,6 +56,7 @@ typedef struct { int priority; char sched[VAR_NAME_LEN+1]; /* Scheduling function */ char warn[VAR_NAME_LEN+1]; /* Warning function */ + char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */ char tag[TAG_LEN+1]; char passthru[PASSTHRU_LEN+1]; } Trigger; @@ -148,7 +149,8 @@ enum TokTypes T_Warn, T_Tag, T_Duration, - T_LongTime + T_LongTime, + T_OmitFunc }; /* The structure of a token */ diff --git a/tests/test.cmp b/tests/test.cmp index 90dc94a6..a88aced2 100644 --- a/tests/test.cmp +++ b/tests/test.cmp @@ -638,7 +638,7 @@ set a057 value("a05"+"6") "a05" + "6" => "a056" value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH" set a058 version() -version() => "03.01.06" +version() => "03.01.05" set a059 wkday(today()) today() => 1991-02-16 wkday(1991-02-16) => "Saturday" @@ -779,7 +779,7 @@ dump a048 "foo" a067 "INT" a039 "February" - a058 "03.01.06" + a058 "03.01.05" a077 "1992 92 " a049 21