DIRECTORY
Ascii USING[SP, TAB, CR],
BasicTime USING[Period, Now, Update, GMT],
Booting USING[RollbackProc, RegisterProcs],
Convert USING[CardFromRope, TimeFromRope, Error],
FS USING[Error, StreamOpen],
IO USING[STREAM, GetChar, Close, PutRope, EndOfStream],
Process USING[Pause, SecondsToTicks, Detach],
Rope USING[ROPE, Concat, FromChar, Equal, Match],
ViewerClasses USING[Viewer],
ViewerEvents USING[RegisterEventProc, ViewerEvent],
ViewerIO USING[CreateViewerStreams],
ViewerOps USING[BlinkIcon, DestroyViewer],
ViewerTools USING[MakeNewTextViewer];
Reminder: CEDAR MONITOR
IMPORTS BasicTime, Booting, Convert, FS,
IO, Process, Rope,
ViewerEvents, ViewerIO, ViewerOps, ViewerTools
= BEGIN OPEN Ascii, Rope, ViewerClasses, ViewerEvents, ViewerOps;
Event: TYPE = REF EventObj;
EventObj:
TYPE =
RECORD[text:
ROPE,
timeRope: ROPE,
timeToStartNotification: BasicTime.GMT,
newStartTime: BOOL ← TRUE,
repetitionInterval: INT ← 0,
duration: INT ← 0,
viewer: Viewer ← NIL];
ParameterClass: TYPE = {message, repeat, duration--minutes--, until, time};
eventList: LIST OF Event ← NIL;
FormatError: ERROR = CODE;
Construct:
ENTRY Booting.RollbackProc =
{
ENABLE
UNWIND =>
NULL;
fileStream: IO.STREAM ← NIL;
timeRope: ROPE ← NIL;
{ -- for EXITS clause
IF eventList #
NIL
THEN
FOR el:
LIST
OF Event ← eventList, el.rest
UNTIL el =
NIL
DO
IF el.first.viewer #
NIL
AND
NOT el.first.viewer.destroyed
THEN DestroyViewer[el.first.viewer];
ENDLOOP;
eventList ← NIL;
fileStream ← FS.StreamOpen["Reminders.txt" ! FS.Error => GOTO noReminderFile];
DO
time: BasicTime.GMT;
text: ROPE;
class: ParameterClass;
repetitionInterval: INT ← 0;
duration: INT ← 0;
timeRope ← ReadTimeRope[fileStream];
IF timeRope = NIL THEN EXIT;
time ← Convert.TimeFromRope[timeRope
! Convert.Error => GOTO timeRopeFormatError];
[class, text] ← ReadParameter[fileStream ! FormatError => GOTO formatError];
UNTIL class = message
DO
SELECT class
FROM
repeat =>
IF Equal[s1: text, s2: "HOURLY", case:
FALSE]
THEN {repetitionInterval ← LONG[60*60]}
ELSE IF Equal[s1: text, s2: "DAILY", case: FALSE]
THEN {repetitionInterval ← LONG[60*60]*24}
ELSE IF Equal[s1: text, s2: "WEEKLY", case: FALSE]
THEN {repetitionInterval ← LONG[60*60]*24*7}
ELSE IF Equal[s1: text, s2: "YEARLY", case: FALSE]
THEN {repetitionInterval ← LONG[60*60]*24*7*52}
ELSE GOTO formatError;
duration => duration ← Convert.CardFromRope[text]*60;
until =>
duration
← BasicTime.Period[
to: Convert.TimeFromRope[text
! Convert.Error => GOTO formatError],
from: time];
ENDCASE;
[class, text] ← ReadParameter[fileStream ! FormatError => GOTO formatError];
ENDLOOP;
{
latest: BasicTime.GMT ← time;
IF repetitionInterval > 0
THEN
WHILE BasicTime.Period[from: latest, to: BasicTime.Now[]] >= repetitionInterval
DO latest ← BasicTime.Update[latest, repetitionInterval] ENDLOOP;
eventList ←
CONS[
NEW[EventObj ← [timeToStartNotification: latest,
timeRope: timeRope,
text: text,
repetitionInterval: repetitionInterval,
duration: duration]],
eventList];
};
ENDLOOP;
fileStream.Close[];
EXITS
formatError => {
out: IO.STREAM ← ViewerIO.CreateViewerStreams["Reminder Error"].out;
eventList ← NIL;
out.PutRope["Reminder: Format error in Reminders.txt\n"];
};
timeRopeFormatError => {
out: IO.STREAM ← ViewerIO.CreateViewerStreams["Reminder Error"].out;
eventList ← NIL;
out.PutRope["Reminder: Unintelligible time: "];
out.PutRope[timeRope];
out.PutRope["\n"];
};
noReminderFile => {
out: IO.STREAM ← ViewerIO.CreateViewerStreams["Reminder Error"].out;
eventList ← NIL;
out.PutRope["Reminder: Can't find the file named Reminders.txt\n"];
};
};