home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************/
- /* */
- /* DOREM.C */
- /* */
- /* Contains routines for parsing reminders and evaluating */
- /* triggers. Also contains routines for parsing OMIT */
- /* commands. */
- /* */
- /* This file is part of REMIND. */
- /* Copyright (C) 1992, 1993 by David F. Skoll. */
- /* */
- /***************************************************************/
- #include "config.h"
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #ifdef HAVE_MALLOC_H
- #include <malloc.h>
- #endif
- #include "globals.h"
- #include "err.h"
- #include "types.h"
- #include "protos.h"
- #include "expr.h"
-
- PRIVATE int ParseTimeTrig ARGS ((ParsePtr s, TimeTrig *tim));
- PRIVATE int ParseLocalOmit ARGS ((ParsePtr s, Trigger *t));
- PRIVATE int ParseScanFrom ARGS ((ParsePtr s, Trigger *t));
- PRIVATE int ParsePriority ARGS ((ParsePtr s, Trigger *t));
- PRIVATE int ParseUntil ARGS ((ParsePtr s, Trigger *t));
-
- /***************************************************************/
- /* */
- /* DoRem */
- /* */
- /* Do the REM command. */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PUBLIC int DoRem(ParsePtr p)
- #else
- int DoRem(p)
- ParsePtr p;
- #endif
- {
-
- Trigger trig;
- TimeTrig tim;
- int r;
- int jul;
- char buf[TOKSIZE];
- Token tok;
-
- /* Parse the trigger date and time */
- if ( (r=ParseRem(p, &trig, &tim)) ) return r;
-
- if (trig.typ == NO_TYPE) return E_EOLN;
- if (trig.typ == SAT_TYPE) {
- r=DoSatRemind(&trig, &tim, p);
- if (r) return r;
- r=ParseToken(p, buf);
- if (r) return r;
- FindToken(buf, &tok);
- if (tok.type == T_Empty || tok.type == T_Comment) return OK;
- if (tok.type != T_RemType || tok.val == SAT_TYPE) return E_PARSE_ERR;
- trig.typ = tok.val;
- jul = LastTriggerDate;
- if (!LastTrigValid) return OK;
- } else {
- /* Calculate the trigger date */
- jul = ComputeTrigger(trig.scanfrom, &trig, &r);
- if (r) return r;
- }
-
- /* Queue the reminder, if necessary */
- #ifdef HAVE_QUEUED
- if (jul == JulianToday &&
- !(!IgnoreOnce &&
- trig.once != NO_ONCE &&
- FileAccessDate == JulianToday))
- QueueReminder(p, trig.typ, &tim, trig.sched);
- /* If we're in daemon mode, do nothing over here */
- if (Daemon) return OK;
- #endif
-
-
- if (ShouldTriggerReminder(&trig, &tim, jul)) {
- if ( (r=TriggerReminder(p, &trig, &tim, jul, 0)) ) {
- return r;
- }
- }
-
- return OK;
- }
-
- /***************************************************************/
- /* */
- /* ParseRem */
- /* */
- /* Given a parse pointer, parse line and fill in a */
- /* trigger structure. */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PUBLIC int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
- #else
- int ParseRem(s, trig, tim)
- ParsePtr s;
- Trigger *trig;
- TimeTrig *tim;
- #endif
- {
- register int r;
- Token tok;
-
- trig->y = NO_YR;
- trig->m = NO_MON;
- trig->d = NO_DAY;
- trig->wd = NO_WD;
- trig->back = NO_BACK;
- trig->delta = NO_DELTA;
- trig->until = NO_UNTIL;
- trig->rep = NO_REP;
- trig->localomit = NO_WD;
- trig->skip = NO_SKIP;
- trig->once = NO_ONCE;
- trig->typ = NO_TYPE;
- trig->scanfrom = NO_DATE;
- trig->priority = NO_PRIORITY;
- trig->sched[0] = 0;
- tim->ttime = NO_TIME;
- tim->delta = NO_DELTA;
- tim->rep = NO_REP;
-
- while(1) {
- /* Read space-delimited string */
- r = ParseToken(s, TokBuffer);
- if (r) return r;
-
- /* Figure out what we've got */
- FindToken(TokBuffer, &tok);
- switch(tok.type) {
- case T_WkDay:
- if (trig->wd & (1 << tok.val)) return E_WD_TWICE;
- trig->wd |= (1 << tok.val);
- break;
-
- case T_Month:
- if (trig->m != NO_MON) return E_MON_TWICE;
- trig->m = tok.val;
- break;
-
- case T_Skip:
- if (trig->skip != NO_SKIP) return E_SKIP_ERR;
- trig->skip = tok.val;
- break;
-
- case T_Priority:
- r=ParsePriority(s, trig);
- if (r) return r;
- break;
-
- case T_At:
- r=ParseTimeTrig(s, tim);
- if (r) return r;
- break;
-
- case T_Scanfrom:
- r=ParseScanFrom(s, trig);
- if (r) return r;
- break;
-
- case T_RemType:
- trig->typ = tok.val;
- if (s->isnested) return E_CANT_NEST_RTYPE;
- if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday;
- return OK;
-
- case T_Until:
- r=ParseUntil(s, trig);
- if (r) return r;
- break;
-
- case T_Year:
- if (trig->y != NO_YR) return E_YR_TWICE;
- trig->y = tok.val;
- break;
-
- case T_Day:
- if (trig->d != NO_DAY) return E_DAY_TWICE;
- trig->d = tok.val;
- break;
-
- case T_Rep:
- if (trig->rep != NO_REP) return E_REP_TWICE;
- trig->rep = tok.val;
- break;
-
- case T_Delta:
- if (trig->delta != NO_DELTA) return E_DELTA_TWICE;
- trig->delta = tok.val;
- break;
-
- case T_Back:
- if (trig->back != NO_BACK) return E_BACK_TWICE;
- trig->back = tok.val;
- break;
-
- case T_Once:
- if (trig->once != NO_ONCE) return E_ONCE_TWICE;
- trig->once = ONCE_ONCE;
- break;
-
- case T_Omit:
- r = ParseLocalOmit(s, trig);
- if (r) return r;
- break;
-
- case T_Empty:
- if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday;
- return OK;
-
- case T_Sched:
- r=ParseToken(s, TokBuffer);
- if(r) return r;
- StrnCpy(trig->sched, TokBuffer, VAR_NAME_LEN);
- break;
-
- default:
- Eprint("%s: %s", ErrMsg[E_UNKNOWN_TOKEN], TokBuffer);
- return E_UNKNOWN_TOKEN;
- }
- }
- }
-
- /***************************************************************/
- /* */
- /* ParseTimeTrig - parse the AT part of a timed reminder */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PRIVATE int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
- #else
- static int ParseTimeTrig(s, tim)
- ParsePtr s;
- TimeTrig *tim;
- #endif
- {
- Token tok;
- int r;
-
- while(1) {
- r = ParseToken(s, TokBuffer);
- if (r) return r;
- FindToken(TokBuffer, &tok);
- switch(tok.type) {
- case T_Time:
- tim->ttime = tok.val;
- break;
-
- case T_Delta:
- tim->delta = (tok.val > 0) ? tok.val : -tok.val;
- break;
-
- case T_Rep:
- tim->rep = tok.val;
- break;
-
- default:
- if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
- /* Save in global variable */
- LastTriggerTime = tim->ttime;
- PushToken(TokBuffer);
- return OK;
- }
- }
- }
-
- /***************************************************************/
- /* */
- /* ParseLocalOmit - parse the local OMIT portion of a */
- /* reminder. */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PRIVATE int ParseLocalOmit(ParsePtr s, Trigger *t)
- #else
- static int ParseLocalOmit(s, t)
- ParsePtr s;
- Trigger *t;
- #endif
- {
- Token tok;
- int r;
-
- while(1) {
- r = ParseToken(s, TokBuffer);
- if (r) return r;
- FindToken(TokBuffer, &tok);
- switch(tok.type) {
- case T_WkDay:
- t->localomit |= (1 << tok.val);
- break;
-
- default:
- PushToken(TokBuffer);
- return OK;
- }
- }
- }
-
- /***************************************************************/
- /* */
- /* ParseUntil - parse the UNTIL portion of a reminder */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PRIVATE int ParseUntil(ParsePtr s, Trigger *t)
- #else
- static int ParseUntil(s, t)
- ParsePtr s;
- Trigger *t;
- #endif
- {
- int y = NO_YR,
- m = NO_MON,
- d = NO_DAY;
-
- Token tok;
- int r;
-
- if (t->until != NO_UNTIL) return E_UNTIL_TWICE;
-
- while(1) {
- r = ParseToken(s, TokBuffer);
- if (r) return r;
- FindToken(TokBuffer, &tok);
- switch(tok.type) {
- case T_Year:
- if (y != NO_YR) {
- Eprint("UNTIL: %s", ErrMsg[E_YR_TWICE]);
- return E_YR_TWICE;
- }
- y = tok.val;
- break;
-
- case T_Month:
- if (m != NO_MON) {
- Eprint("UNTIL: %s", ErrMsg[E_MON_TWICE]);
- return E_MON_TWICE;
- }
- m = tok.val;
- break;
-
- case T_Day:
- if (d != NO_DAY) {
- Eprint("UNTIL: %s", ErrMsg[E_DAY_TWICE]);
- return E_DAY_TWICE;
- }
- d = tok.val;
- break;
-
- default:
- if (y == NO_YR || m == NO_MON || d == NO_DAY) {
- Eprint("UNTIL: %s", ErrMsg[E_INCOMPLETE]);
- return E_INCOMPLETE;
- }
- if (!DateOK(y, m, d)) return E_BAD_DATE;
- t->until = Julian(y, m, d);
- PushToken(TokBuffer);
- return OK;
- }
- }
- }
-
- /***************************************************************/
- /* */
- /* ParseScanFrom - parse the SCANFROM portion of a reminder */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PRIVATE int ParseScanFrom(ParsePtr s, Trigger *t)
- #else
- static int ParseScanFrom(s, t)
- ParsePtr s;
- Trigger *t;
- #endif
- {
- int y = NO_YR,
- m = NO_MON,
- d = NO_DAY;
-
- Token tok;
- int r;
-
- if (t->scanfrom != NO_DATE) return E_SCAN_TWICE;
-
- while(1) {
- r = ParseToken(s, TokBuffer);
- if (r) return r;
- FindToken(TokBuffer, &tok);
- switch(tok.type) {
- case T_Year:
- if (y != NO_YR) {
- Eprint("SCANFROM: %s", ErrMsg[E_YR_TWICE]);
- return E_YR_TWICE;
- }
- y = tok.val;
- break;
-
- case T_Month:
- if (m != NO_MON) {
- Eprint("SCANFROM: %s", ErrMsg[E_MON_TWICE]);
- return E_MON_TWICE;
- }
- m = tok.val;
- break;
-
- case T_Day:
- if (d != NO_DAY) {
- Eprint("SCANFROM: %s", ErrMsg[E_DAY_TWICE]);
- return E_DAY_TWICE;
- }
- d = tok.val;
- break;
-
- default:
- if (y == NO_YR || m == NO_MON || d == NO_DAY) {
- Eprint("SCANFROM: %s", ErrMsg[E_INCOMPLETE]);
- return E_INCOMPLETE;
- }
- if (!DateOK(y, m, d)) return E_BAD_DATE;
- t->scanfrom = Julian(y, m, d);
- PushToken(TokBuffer);
- return OK;
- }
- }
- }
- /***************************************************************/
- /* */
- /* TriggerReminder */
- /* */
- /* Trigger the reminder if it's a RUN or MSG type. */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PUBLIC int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul,
- int AsPopUp)
- #else
- int TriggerReminder(p, t, tim, jul, AsPopUp)
- ParsePtr p;
- Trigger *t;
- TimeTrig *tim;
- int jul;
- int AsPopUp
- #endif
- {
- int r, y, m, d;
- char PrioExpr[25];
- static char buf[LINELEN+TOKSIZE];
- char *s, *s2;
- Value v;
-
- if (t->typ == RUN_TYPE && RunDisabled) return E_RUN_DISABLED;
- if (t->typ == CAL_TYPE || t->typ == PS_TYPE || t->typ == PSF_TYPE)
- return OK;
-
- /* If it's a MSG-type reminder, and no -k option was used, issue the banner. */
- if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE)
- && !NumTriggered && !NextMode && !MsgCommand) {
- if (!DoSubstFromString(Banner, SubstBuffer, JulianToday, NO_TIME) && *SubstBuffer)
- #ifdef OS2_POPUP
- if (AsPopUp)
- PutlPopUp(SubstBuffer);
- else
- printf("%s\n", SubstBuffer);
- #else
- printf("%s\n", SubstBuffer);
- #endif
- }
-
- /* If it's NextMode, process as a CAL-type entry, and issue simple-calendar
- format. */
- if (NextMode) {
- if ( (r=DoSubst(p, SubstBuffer, t, tim, jul, CAL_MODE)) ) return r;
- if (!*SubstBuffer) return OK;
- FromJulian(jul, &y, &m, &d);
- #ifdef OS2_POPUP
- if (AsPopUp) {
- sprintf(buf, "%04d%c%02d%c%02d %s", y, DATESEP, m+1, DATESEP, d,
- SimpleTime(tim->ttime, NULL));
- StartPopUp();
- PutsPopUp(buf);
- PutlPopUp(SubstBuffer);
- }
- else
- printf("%04d%c%02d%c%02d %s%s\n", y, DATESEP, m+1, DATESEP, d,
- SimpleTime(tim->ttime, NULL),
- SubstBuffer);
- #else
- printf("%04d%c%02d%c%02d %s%s\n", y, DATESEP, m+1, DATESEP, d,
- SimpleTime(tim->ttime, NULL),
- SubstBuffer);
- #endif
- return OK;
- }
-
- /* Put the substituted string into the SubstBuffer */
- s2 = buf;
- *s2 = 0;
- if (UserFuncExists("msgprefix") == 1) {
- sprintf(PrioExpr, "msgprefix(%d)", t->priority);
- s = PrioExpr;
- r = EvalExpr(&s, &v);
- if (!r) {
- if (!DoCoerce(STR_TYPE, &v)) {
- sprintf(s2, "%s", v.v.str);
- s2 += strlen(s2);
- }
- DestroyValue(&v);
- }
- }
- if ( (r=DoSubst(p, s2, t, tim, jul, NORMAL_MODE)) ) return r;
- s2 += strlen(s2);
- if (UserFuncExists("msgsuffix") == 1) {
- sprintf(PrioExpr, "msgsuffix(%d)", t->priority);
- s = PrioExpr;
- r = EvalExpr(&s, &v);
- if (!r) {
- if (!DoCoerce(STR_TYPE, &v)) {
- sprintf(s2, "%s", v.v.str);
- s2 += strlen(s2);
- }
- DestroyValue(&v);
- }
- }
- #if 0
- #ifdef OS2_POPUP
- if (t->typ == MSF_TYPE) {
- #else
- if (t->typ == MSG_TYPE || t->typ == MSF_TYPE) {
- #endif
- #else
- if (t->typ == MSG_TYPE || t->typ == MSF_TYPE) {
- #endif
- *s2++ = '\n';
- }
- *s2 = 0;
-
- /* If we are sorting, just queue it up in the sort buffer */
- if (SortByDate) {
- if (InsertIntoSortBuffer(jul, tim->ttime, buf, t->typ, t->priority) == OK) {
- NumTriggered++;
- return OK;
- }
- }
-
- /* If we didn't insert the reminder into the sort buffer, issue the
- reminder now. */
- switch(t->typ) {
- case MSG_TYPE:
- if (MsgCommand) {
- sprintf(SubstBuffer, MsgCommand, buf);
- system(SubstBuffer);
- } else {
- #ifdef OS2_POPUP
- if (AsPopUp)
- PutlPopUp(buf);
- else
- printf("%s", buf);
- #else
- printf("%s", buf);
- #endif
- }
- break;
-
- case MSF_TYPE:
- #ifdef OS2_POPUP
- if (AsPopUp) {
- StartPopUp();
- FillParagraph(buf, 1);
- EndPopUp();
- }else{
- FillParagraph(buf, 0);
- }
- #else
- FillParagraph(buf, 0);
- #endif
- break;
-
- case RUN_TYPE:
- system(buf);
- break;
-
- default: /* Unknown/illegal type? */
- return E_SWERR;
- }
-
- NumTriggered++;
- return OK;
- }
-
- /***************************************************************/
- /* */
- /* ShouldTriggerReminder */
- /* */
- /* Return 1 if we should trigger a reminder, based on today's */
- /* date and the trigger. Return 0 if reminder should not be */
- /* triggered. */
- /* */
- /***************************************************************/
- #ifdef __TURBOC__
- #pragma argsused
- #endif
- #ifdef HAVE_PROTOS
- PUBLIC int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul)
- #else
- int ShouldTriggerReminder(t, tim, jul)
- Trigger *t;
- TimeTrig *tim;
- int jul;
- #endif
- {
- int r;
-
- /* Handle the ONCE modifier in the reminder. */
- if (!IgnoreOnce && t->once !=NO_ONCE && FileAccessDate == JulianToday)
- return 0;
-
- if (jul < JulianToday) return 0;
-
- /* Don't trigger timed reminders if DontIssueAts is true, and if the
- reminder is for today */
-
- #ifdef HAVE_QUEUED
- if (jul == JulianToday && DontIssueAts && tim->ttime != NO_TIME) return 0;
- #endif
-
- /* Don't trigger "old" timed reminders */
- /*** REMOVED...
- if (jul == JulianToday &&
- tim->ttime != NO_TIME &&
- tim->ttime < SystemTime() / 60) return 0;
- *** ...UNTIL HERE */
-
- /* If "infinite delta" option is chosen, always trigger future reminders */
- if (InfiniteDelta || NextMode) return 1;
-
- /* Move back by delta days, if any */
- if (t->delta != NO_DELTA) {
- if (t->delta < 0)
- jul = jul + t->delta;
- else {
- r = t->delta;
- while(r && jul > JulianToday) {
- jul--;
- if (!IsOmitted(jul, t->localomit)) r--;
- }
- }
- }
-
- /* Should we trigger the reminder? */
- return (jul <= JulianToday);
- }
-
- /***************************************************************/
- /* */
- /* DoSatRemind */
- /* */
- /* Do the "satisfying..." remind calculation. */
- /* */
- /***************************************************************/
- #ifdef __TURBOC__
- #pragma argsused
- #endif
- #ifdef HAVE_PROTOS
- PUBLIC int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
- #else
- int DoSatRemind(trig, tim, p)
- Trigger *trig;
- TimeTrig *tim;
- ParsePtr p;
- #endif
- {
- int iter, jul, r;
- Value v;
- char *s, *t;
-
- t = p->pos;
- iter = 0;
- jul = trig->scanfrom;
- while (iter++ < MaxSatIter) {
- jul = ComputeTrigger(jul, trig, &r);
- if (r) {
- if (r == E_CANT_TRIG) return OK; else return r;
- }
- s = p->pos;
- r = EvaluateExpr(p, &v);
- t = p->pos;
- if (r) return r;
- if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE;
- if (v.type == INT_TYPE && v.v.val) return OK;
- if (v.type == STR_TYPE && *v.v.str) return OK;
- p->pos = s;
- jul++;
- }
- p->pos = t;
- LastTrigValid = 0;
- return OK;
- }
-
- /***************************************************************/
- /* */
- /* ParsePriority - parse the PRIORITY portion of a reminder */
- /* */
- /***************************************************************/
- #ifdef HAVE_PROTOS
- PRIVATE int ParsePriority(ParsePtr s, Trigger *t)
- #else
- static int ParsePriority(s, t)
- ParsePtr s;
- Trigger *t;
- #endif
- {
- int p, r;
- char *u;
-
- r = ParseToken(s, TokBuffer);
- if(r) return r;
- u = TokBuffer;
-
- if (!isdigit(*u)) return E_EXPECTING_NUMBER;
- p = 0;
- while (isdigit(*u)) {
- p = p*10 + *u - '0';
- u++;
- }
- if (*u) return E_EXPECTING_NUMBER;
-
- /* Tricky! The only way p can be < 0 is if overflow occurred; thus,
- E2HIGH is indeed the appropriate error message. */
- if (p<0 || p>9999) return E_2HIGH;
- t->priority = p;
- return OK;
- }
-