This is dorem.c in view mode; [Download] [Up]
/***************************************************************/ /* */ /* 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, 1994 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)) { #ifdef OS2_POPUP if ( (r=TriggerReminder(p, &trig, &tim, jul, 0)) ) { #else if ( (r=TriggerReminder(p, &trig, &tim, jul)) ) { #endif 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 = DefaultPrio; 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 #ifdef OS2_POPUP PUBLIC int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul, int AsPopUp) #else /* ! OS2_POPUP */ PUBLIC int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul) #endif /* OS2_POPUP */ #else /* ! HAVE_PROTOS */ #ifdef OS2_POPUP int TriggerReminder(p, t, tim, jul, AsPopUp) ParsePtr p; Trigger *t; TimeTrig *tim; int jul; int AsPopUp; #else /* ! OS2_POPUP */ int TriggerReminder(p, t, tim, jul) ParsePtr p; Trigger *t; TimeTrig *tim; int jul; #endif /* OS2_POPUP */ #endif /* HAVE_PROTOS */ { 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 ((!MsgCommand && t->typ == MSG_TYPE) || t->typ == MSF_TYPE) { *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) { DoMsgCommand(MsgCommand, buf); } 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); #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(0) / 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; } /***************************************************************/ /* */ /* DoMsgCommand */ /* */ /* Execute the '-k' command, escaping shell chars in message. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void DoMsgCommand(char *cmd, char *msg) #else void DoMsgCommand(cmd, msg) char *cmd; char *msg; #endif { #ifdef WANT_SHELL_ESCAPING char buf[2*LINELEN+TOKSIZE]; char *s, *t; /* Escape shell characters in msg INCLUDING WHITESPACE! */ for (t=buf, s=msg; *s; s++) { if (isspace(*s) || strchr("\"'!$%^&*()|<>[]{}`~;?\\", *s)) *t++ = '\\'; *t++ = *s; } *t = 0; /* Use SubstBuffer -- not too safe, since no check for overflow... */ sprintf(SubstBuffer, cmd, buf); #else sprintf(SubstBuffer, cmd, msg); #endif /* WANT_SHELL_ESCAPING */ system(SubstBuffer); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.