123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- MODULE EventsUtils; (** AUTHOR "staubesv"; PURPOSE "System events utilities"; *)
- (**
- * History:
- *
- * 07.03.2007 First release (staubesv)
- *)
- IMPORT
- Commands, Events, Streams, Files, Dates, Strings;
- CONST
- (** Result codes for system event operations *)
- Ok* = 0;
- Error* = 1;
- Uncomplete* = 3;
- EOF = 4;
- DateTimeFormat = "dd.mm.yyyy hh:nn:ss"; (* don't change or adapt DateTimeFromStream *)
- TYPE
- EventWrapper* = POINTER TO RECORD
- nextIndex- : LONGINT; (* index of next free place in events array *)
- events- : POINTER TO ARRAY OF Events.Event;
- next- : EventWrapper;
- END;
- TYPE
- EventContainer* = OBJECT(Events.Sink)
- VAR
- nofWrappers, nofEvents : LONGINT;
- (* stamps *)
- lastCleared, lastAdded : LONGINT;
- events, current : EventWrapper;
- maxNofWrappers, eventsPerWrapper : LONGINT;
- (* for polling *)
- 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;
- (** Returns the maximum number of event records this container can hold *)
- 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 : WORD);
- 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
- (* all done *)
- 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 : WORD);
- 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 : WORD);
- 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;
- (* date & time *)
- 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);
- (* type *)
- r.SkipWhitespace; r.String(str); IF (r.res # Streams.Ok) THEN msg := "Could not read type string"; RETURN; END;
- event.type := GetType(str);
- (* originator *)
- r.SkipWhitespace; r.String(event.originator); IF (r.res # Streams.Ok) THEN msg := "Could not read originator string"; RETURN; END;
- (* class, subclass & code *)
- 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;
- (* check validity of class/subclass/code *)
- 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));
- (* message *)
- 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); (** originator type class subclass code message ~ *)
- 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.
|