MODULE EventsUtils;
IMPORT
Commands, Events, Streams, Files, Dates, Strings;
CONST
Ok* = 0;
Error* = 1;
Uncomplete* = 3;
EOF = 4;
DateTimeFormat = "dd.mm.yyyy hh:nn:ss";
TYPE
EventWrapper* = POINTER TO RECORD
nextIndex- : LONGINT;
events- : POINTER TO ARRAY OF Events.Event;
next- : EventWrapper;
END;
TYPE
EventContainer* = OBJECT(Events.Sink)
VAR
nofWrappers, nofEvents : LONGINT;
lastCleared, lastAdded : LONGINT;
events, current : EventWrapper;
maxNofWrappers, eventsPerWrapper : LONGINT;
PROCEDURE GetStamp*() : LONGINT;
BEGIN
RETURN lastAdded;
END GetStamp;
PROCEDURE GetEvents*(VAR nofEvents : LONGINT; VAR full : BOOLEAN; VAR lastCleared : LONGINT) : EventWrapper;
BEGIN {EXCLUSIVE}
nofEvents := SELF.nofEvents;
full := nofEvents = maxNofWrappers * eventsPerWrapper;
lastCleared := SELF.lastCleared;
RETURN events;
END GetEvents;
PROCEDURE IsFull*() : BOOLEAN;
BEGIN {EXCLUSIVE}
RETURN nofEvents = maxNofWrappers * eventsPerWrapper;
END IsFull;
PROCEDURE Clear*;
BEGIN {EXCLUSIVE}
events.next := NIL; events.nextIndex := 0;
current := events;
nofWrappers := 1; nofEvents := 0;
INC(lastCleared); INC(lastAdded);
END Clear;
PROCEDURE GetSize*() : LONGINT;
BEGIN
RETURN maxNofWrappers * eventsPerWrapper;
END GetSize;
PROCEDURE Handle*(event : Events.Event);
VAR wrapper : EventWrapper;
BEGIN {EXCLUSIVE}
IF nofEvents = maxNofWrappers * eventsPerWrapper THEN RETURN; END;
IF (current.nextIndex >= LEN(current.events)) THEN
NEW(wrapper); NEW(wrapper.events, eventsPerWrapper); wrapper.nextIndex := 0;
current.next := wrapper;
current := wrapper;
INC(nofWrappers);
END;
current.events[current.nextIndex] := event;
INC(current.nextIndex);
INC(nofEvents);
INC(lastAdded);
END Handle;
PROCEDURE &Init*(maxNofWrappers, eventsPerWrapper : LONGINT);
BEGIN
SELF.maxNofWrappers := maxNofWrappers;
SELF.eventsPerWrapper:= eventsPerWrapper;
NEW(events); NEW(events.events, eventsPerWrapper); events.nextIndex := 0;
current := events;
nofWrappers := 1; nofEvents := 0;
END Init;
END EventContainer;
PROCEDURE LoadFromFile*(CONST filename : ARRAY OF CHAR; VAR events : EventContainer; VAR msg : ARRAY OF CHAR; VAR res : LONGINT);
VAR file : Files.File; r : Files.Reader; event : Events.Event; nofEvents : LONGINT;
BEGIN
file := Files.Old(filename);
IF file # NIL THEN
Files.OpenReader(r, file, 0);
NEW(events, 1024, 1024);
nofEvents := 0;
WHILE (r.Available() > 0) & (r.res = Streams.Ok) DO
FromStream(r, event, msg, res);
IF (res = Ok) THEN
INC(nofEvents);
events.Handle(event);
ELSIF (res = EOF) THEN
ELSE
IF (nofEvents = 0) THEN
res := Error;
ELSE
res := Uncomplete;
END;
RETURN;
END;
END;
res := Ok;
ELSE
msg := "File not found"; res := Error;
END;
END LoadFromFile;
PROCEDURE StoreToFile*(CONST filename : ARRAY OF CHAR; events : EventContainer; VAR msg : ARRAY OF CHAR; VAR res : LONGINT);
VAR
file : Files.File; w : Files.Writer; wrapper : EventWrapper;
nofEvents, lastCleared, i, idx : LONGINT; full : BOOLEAN;
BEGIN
file := Files.New(filename);
IF file # NIL THEN
Files.OpenWriter(w, file, 0);
wrapper := events.GetEvents(nofEvents, full, lastCleared);
IF nofEvents > 0 THEN
i := 0;
WHILE (i < nofEvents) DO
IF i >= LEN(wrapper.events) THEN wrapper := wrapper.next; END;
idx := i MOD LEN(wrapper.events);
ToStream(w, wrapper.events[idx]);
INC(i);
END;
Files.Register(file);
res := Ok;
ELSE
msg := "Number of events must be greater than zero"; res := Error;
END;
ELSE
msg := "Could not create file"; res := Error;
END;
END StoreToFile;
PROCEDURE ToStream*(w : Streams.Writer; event : Events.Event);
VAR dt : Dates.DateTime; str : ARRAY 64 OF CHAR;
BEGIN
ASSERT(w # NIL);
dt := Dates.OberonToDateTime(event.date, event.time);
Strings.FormatDateTime(DateTimeFormat, dt, str);
w.String(str); w.String(" ");
GetTypeString(event.type, str); w.String(str); w.String(" ");
w.String('"'); w.String(event.originator); w.String('"');
w.String(" ["); w.Int(event.class, 0); w.String(","); w.Int(event.subclass, 0); w.String(","); w.Int(event.code, 0); w.String('] "');
w.String(event.message); w.String('"'); w.Ln;
w.Update;
END ToStream;
PROCEDURE FromStream*(r : Streams.Reader; VAR event : Events.Event; VAR msg : ARRAY OF CHAR; VAR res : LONGINT);
VAR dt : Dates.DateTime; str : Events.Message; ch : CHAR; class, subclass, code : LONGINT;
PROCEDURE IsValid(value : LONGINT) : BOOLEAN;
BEGIN
RETURN (0 <= value) & (value <= MAX(SHORTINT));
END IsValid;
BEGIN
ASSERT(r # NIL);
res := Error;
r.SkipWhitespace;
IF r.Available() = 0 THEN res := EOF; RETURN; END;
IF ~DateTimeFromStream(r, dt) THEN
ch := r.Peek();
IF r.res = Streams.EOF THEN res := Ok; RETURN;
ELSE
msg := "Could not read datetime string"; RETURN;
END;
END;
Dates.DateTimeToOberon(dt, event.date, event.time);
r.SkipWhitespace; r.String(str); IF (r.res # Streams.Ok) THEN msg := "Could not read type string"; RETURN; END;
event.type := GetType(str);
r.SkipWhitespace; r.String(event.originator); IF (r.res # Streams.Ok) THEN msg := "Could not read originator string"; RETURN; END;
r.SkipWhitespace;
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # "[") THEN msg := "Expected opening bracket"; RETURN; END;
r.Int(class, FALSE); IF (r.res # Streams.Ok) THEN msg := "Could not parse event class"; RETURN; END;
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ",") THEN msg := "Expected ,"; RETURN; END;
r.Int(subclass, FALSE); IF (r.res # Streams.Ok) THEN msg := "Could not parse event subclass"; RETURN; END;
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ",") THEN msg := "Expected ,"; RETURN; END;
r.Int(code, FALSE); IF (r.res # Streams.Ok) THEN msg := "Could not parse event code"; RETURN; END;
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # "]") THEN msg := "Expected closing bracket"; RETURN; END;
IF ~IsValid(class) THEN msg := "Class must be in [0, 127]"; RETURN; END;
IF ~IsValid(subclass) THEN msg := "Subclass must be in [0, 127]"; RETURN; END;
IF ~IsValid(code) THEN msg := "Code must be in [0, 127]"; RETURN; END;
event.class := SHORT(SHORT(class));
event.subclass := SHORT(SHORT(subclass));
event.code := SHORT(SHORT(code));
r.SkipWhitespace; r.String(event.message);
IF (r.res # Streams.EOF) & (~r.EOLN()) THEN msg := "Expected end of line"; RETURN; END;
res := Ok;
END FromStream;
PROCEDURE DateTimeFromStream(r : Streams.Reader; VAR dt : Dates.DateTime) : BOOLEAN;
VAR ch : CHAR;
BEGIN
ASSERT(r # NIL);
r.SkipWhitespace;
r.Int(dt.day, FALSE);
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ".") THEN RETURN FALSE; END;
r.Int(dt.month, FALSE);
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ".") THEN RETURN FALSE; END;
r.Int(dt.year, FALSE);
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # " ") THEN RETURN FALSE; END;
r.Int(dt.hour, FALSE);
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ":") THEN RETURN FALSE; END;
r.Int(dt.minute, FALSE);
r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ":") THEN RETURN FALSE; END;
r.Int(dt.second, FALSE);
IF (r.res # Streams.Ok) THEN RETURN FALSE; END;
RETURN Dates.ValidDateTime(dt);
END DateTimeFromStream;
PROCEDURE GetTypeString*(type : LONGINT; VAR string: ARRAY OF CHAR);
VAR nbr : ARRAY 16 OF CHAR;
BEGIN
CASE type OF
|Events.Unknown: string := "Unknown";
|Events.Undefined: string := "Undefined";
|Events.Information: string := "Information";
|Events.Warning: string := "Warning";
|Events.Error: string := "Error";
|Events.Critical: string := "Critical";
|Events.Alert: string := "Alert";
|Events.Failure: string := "Failure";
ELSE
string := "Unknown ("; Strings.IntToStr(type, nbr); Strings.Append(string, nbr); Strings.Append(string, ")");
END;
END GetTypeString;
PROCEDURE GetType*(CONST string : ARRAY OF CHAR) : SHORTINT;
VAR type : SHORTINT;
BEGIN
IF string = "Unknown" THEN type := Events.Unknown;
ELSIF string = "Undefined" THEN type := Events.Undefined;
ELSIF string = "Information" THEN type := Events.Information;
ELSIF string = "Warning" THEN type := Events.Warning;
ELSIF string = "Error" THEN type := Events.Error;
ELSIF string = "Critical" THEN type := Events.Critical;
ELSIF string = "Alert" THEN type := Events.Alert;
ELSIF string = "Failure" THEN type := Events.Failure;
ELSE
type := Events.Unknown;
END;
RETURN type;
END GetType;
PROCEDURE GenerateEvent*(context : Commands.Context);
VAR event : Events.Event; value : LONGINT;
BEGIN
context.arg.SkipWhitespace; context.arg.String(event.originator);
context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.type := SHORT(SHORT(value));
context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.class := SHORT(SHORT(value));
context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.subclass := SHORT(SHORT(value));
context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.code := SHORT(SHORT(value));
context.arg.SkipWhitespace; context.arg.String(event.message);
Events.Add(event, FALSE);
END GenerateEvent;
END EventsUtils.