EventsUtils.Mod 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. MODULE EventsUtils; (** AUTHOR "staubesv"; PURPOSE "System events utilities"; *)
  2. (**
  3. * History:
  4. *
  5. * 07.03.2007 First release (staubesv)
  6. *)
  7. IMPORT
  8. Commands, Events, Streams, Files, Dates, Strings;
  9. CONST
  10. (** Result codes for system event operations *)
  11. Ok* = 0;
  12. Error* = 1;
  13. Uncomplete* = 3;
  14. EOF = 4;
  15. DateTimeFormat = "dd.mm.yyyy hh:nn:ss"; (* don't change or adapt DateTimeFromStream *)
  16. TYPE
  17. EventWrapper* = POINTER TO RECORD
  18. nextIndex- : LONGINT; (* index of next free place in events array *)
  19. events- : POINTER TO ARRAY OF Events.Event;
  20. next- : EventWrapper;
  21. END;
  22. TYPE
  23. EventContainer* = OBJECT(Events.Sink)
  24. VAR
  25. nofWrappers, nofEvents : LONGINT;
  26. (* stamps *)
  27. lastCleared, lastAdded : LONGINT;
  28. events, current : EventWrapper;
  29. maxNofWrappers, eventsPerWrapper : LONGINT;
  30. (* for polling *)
  31. PROCEDURE GetStamp*() : LONGINT;
  32. BEGIN
  33. RETURN lastAdded;
  34. END GetStamp;
  35. PROCEDURE GetEvents*(VAR nofEvents : LONGINT; VAR full : BOOLEAN; VAR lastCleared : LONGINT) : EventWrapper;
  36. BEGIN {EXCLUSIVE}
  37. nofEvents := SELF.nofEvents;
  38. full := nofEvents = maxNofWrappers * eventsPerWrapper;
  39. lastCleared := SELF.lastCleared;
  40. RETURN events;
  41. END GetEvents;
  42. PROCEDURE IsFull*() : BOOLEAN;
  43. BEGIN {EXCLUSIVE}
  44. RETURN nofEvents = maxNofWrappers * eventsPerWrapper;
  45. END IsFull;
  46. PROCEDURE Clear*;
  47. BEGIN {EXCLUSIVE}
  48. events.next := NIL; events.nextIndex := 0;
  49. current := events;
  50. nofWrappers := 1; nofEvents := 0;
  51. INC(lastCleared); INC(lastAdded);
  52. END Clear;
  53. (** Returns the maximum number of event records this container can hold *)
  54. PROCEDURE GetSize*() : LONGINT;
  55. BEGIN
  56. RETURN maxNofWrappers * eventsPerWrapper;
  57. END GetSize;
  58. PROCEDURE Handle*(event : Events.Event);
  59. VAR wrapper : EventWrapper;
  60. BEGIN {EXCLUSIVE}
  61. IF nofEvents = maxNofWrappers * eventsPerWrapper THEN RETURN; END;
  62. IF (current.nextIndex >= LEN(current.events)) THEN
  63. NEW(wrapper); NEW(wrapper.events, eventsPerWrapper); wrapper.nextIndex := 0;
  64. current.next := wrapper;
  65. current := wrapper;
  66. INC(nofWrappers);
  67. END;
  68. current.events[current.nextIndex] := event;
  69. INC(current.nextIndex);
  70. INC(nofEvents);
  71. INC(lastAdded);
  72. END Handle;
  73. PROCEDURE &Init*(maxNofWrappers, eventsPerWrapper : LONGINT);
  74. BEGIN
  75. SELF.maxNofWrappers := maxNofWrappers;
  76. SELF.eventsPerWrapper:= eventsPerWrapper;
  77. NEW(events); NEW(events.events, eventsPerWrapper); events.nextIndex := 0;
  78. current := events;
  79. nofWrappers := 1; nofEvents := 0;
  80. END Init;
  81. END EventContainer;
  82. PROCEDURE LoadFromFile*(CONST filename : ARRAY OF CHAR; VAR events : EventContainer; VAR msg : ARRAY OF CHAR; VAR res : WORD);
  83. VAR file : Files.File; r : Files.Reader; event : Events.Event; nofEvents : LONGINT;
  84. BEGIN
  85. file := Files.Old(filename);
  86. IF file # NIL THEN
  87. Files.OpenReader(r, file, 0);
  88. NEW(events, 1024, 1024);
  89. nofEvents := 0;
  90. WHILE (r.Available() > 0) & (r.res = Streams.Ok) DO
  91. FromStream(r, event, msg, res);
  92. IF (res = Ok) THEN
  93. INC(nofEvents);
  94. events.Handle(event);
  95. ELSIF (res = EOF) THEN
  96. (* all done *)
  97. ELSE
  98. IF (nofEvents = 0) THEN
  99. res := Error;
  100. ELSE
  101. res := Uncomplete;
  102. END;
  103. RETURN;
  104. END;
  105. END;
  106. res := Ok;
  107. ELSE
  108. msg := "File not found"; res := Error;
  109. END;
  110. END LoadFromFile;
  111. PROCEDURE StoreToFile*(CONST filename : ARRAY OF CHAR; events : EventContainer; VAR msg : ARRAY OF CHAR; VAR res : WORD);
  112. VAR
  113. file : Files.File; w : Files.Writer; wrapper : EventWrapper;
  114. nofEvents, lastCleared, i, idx : LONGINT; full : BOOLEAN;
  115. BEGIN
  116. file := Files.New(filename);
  117. IF file # NIL THEN
  118. Files.OpenWriter(w, file, 0);
  119. wrapper := events.GetEvents(nofEvents, full, lastCleared);
  120. IF nofEvents > 0 THEN
  121. i := 0;
  122. WHILE (i < nofEvents) DO
  123. IF i >= LEN(wrapper.events) THEN wrapper := wrapper.next; END;
  124. idx := i MOD LEN(wrapper.events);
  125. ToStream(w, wrapper.events[idx]);
  126. INC(i);
  127. END;
  128. Files.Register(file);
  129. res := Ok;
  130. ELSE
  131. msg := "Number of events must be greater than zero"; res := Error;
  132. END;
  133. ELSE
  134. msg := "Could not create file"; res := Error;
  135. END;
  136. END StoreToFile;
  137. PROCEDURE ToStream*(w : Streams.Writer; event : Events.Event);
  138. VAR dt : Dates.DateTime; str : ARRAY 64 OF CHAR;
  139. BEGIN
  140. ASSERT(w # NIL);
  141. dt := Dates.OberonToDateTime(event.date, event.time);
  142. Strings.FormatDateTime(DateTimeFormat, dt, str);
  143. w.String(str); w.String(" ");
  144. GetTypeString(event.type, str); w.String(str); w.String(" ");
  145. w.String('"'); w.String(event.originator); w.String('"');
  146. w.String(" ["); w.Int(event.class, 0); w.String(","); w.Int(event.subclass, 0); w.String(","); w.Int(event.code, 0); w.String('] "');
  147. w.String(event.message); w.String('"'); w.Ln;
  148. w.Update;
  149. END ToStream;
  150. PROCEDURE FromStream*(r : Streams.Reader; VAR event : Events.Event; VAR msg : ARRAY OF CHAR; VAR res : WORD);
  151. VAR dt : Dates.DateTime; str : Events.Message; ch : CHAR; class, subclass, code : LONGINT;
  152. PROCEDURE IsValid(value : LONGINT) : BOOLEAN;
  153. BEGIN
  154. RETURN (0 <= value) & (value <= MAX(SHORTINT));
  155. END IsValid;
  156. BEGIN
  157. ASSERT(r # NIL);
  158. res := Error;
  159. r.SkipWhitespace;
  160. IF r.Available() = 0 THEN res := EOF; RETURN; END;
  161. (* date & time *)
  162. IF ~DateTimeFromStream(r, dt) THEN
  163. ch := r.Peek();
  164. IF r.res = Streams.EOF THEN res := Ok; RETURN;
  165. ELSE
  166. msg := "Could not read datetime string"; RETURN;
  167. END;
  168. END;
  169. Dates.DateTimeToOberon(dt, event.date, event.time);
  170. (* type *)
  171. r.SkipWhitespace; r.String(str); IF (r.res # Streams.Ok) THEN msg := "Could not read type string"; RETURN; END;
  172. event.type := GetType(str);
  173. (* originator *)
  174. r.SkipWhitespace; r.String(event.originator); IF (r.res # Streams.Ok) THEN msg := "Could not read originator string"; RETURN; END;
  175. (* class, subclass & code *)
  176. r.SkipWhitespace;
  177. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # "[") THEN msg := "Expected opening bracket"; RETURN; END;
  178. r.Int(class, FALSE); IF (r.res # Streams.Ok) THEN msg := "Could not parse event class"; RETURN; END;
  179. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ",") THEN msg := "Expected ,"; RETURN; END;
  180. r.Int(subclass, FALSE); IF (r.res # Streams.Ok) THEN msg := "Could not parse event subclass"; RETURN; END;
  181. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ",") THEN msg := "Expected ,"; RETURN; END;
  182. r.Int(code, FALSE); IF (r.res # Streams.Ok) THEN msg := "Could not parse event code"; RETURN; END;
  183. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # "]") THEN msg := "Expected closing bracket"; RETURN; END;
  184. (* check validity of class/subclass/code *)
  185. IF ~IsValid(class) THEN msg := "Class must be in [0, 127]"; RETURN; END;
  186. IF ~IsValid(subclass) THEN msg := "Subclass must be in [0, 127]"; RETURN; END;
  187. IF ~IsValid(code) THEN msg := "Code must be in [0, 127]"; RETURN; END;
  188. event.class := SHORT(SHORT(class));
  189. event.subclass := SHORT(SHORT(subclass));
  190. event.code := SHORT(SHORT(code));
  191. (* message *)
  192. r.SkipWhitespace; r.String(event.message);
  193. IF (r.res # Streams.EOF) & (~r.EOLN()) THEN msg := "Expected end of line"; RETURN; END;
  194. res := Ok;
  195. END FromStream;
  196. PROCEDURE DateTimeFromStream(r : Streams.Reader; VAR dt : Dates.DateTime) : BOOLEAN;
  197. VAR ch : CHAR;
  198. BEGIN
  199. ASSERT(r # NIL);
  200. r.SkipWhitespace;
  201. r.Int(dt.day, FALSE);
  202. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ".") THEN RETURN FALSE; END;
  203. r.Int(dt.month, FALSE);
  204. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ".") THEN RETURN FALSE; END;
  205. r.Int(dt.year, FALSE);
  206. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # " ") THEN RETURN FALSE; END;
  207. r.Int(dt.hour, FALSE);
  208. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ":") THEN RETURN FALSE; END;
  209. r.Int(dt.minute, FALSE);
  210. r.Char(ch); IF (r.res # Streams.Ok) OR (ch # ":") THEN RETURN FALSE; END;
  211. r.Int(dt.second, FALSE);
  212. IF (r.res # Streams.Ok) THEN RETURN FALSE; END;
  213. RETURN Dates.ValidDateTime(dt);
  214. END DateTimeFromStream;
  215. PROCEDURE GetTypeString*(type : LONGINT; VAR string: ARRAY OF CHAR);
  216. VAR nbr : ARRAY 16 OF CHAR;
  217. BEGIN
  218. CASE type OF
  219. |Events.Unknown: string := "Unknown";
  220. |Events.Undefined: string := "Undefined";
  221. |Events.Information: string := "Information";
  222. |Events.Warning: string := "Warning";
  223. |Events.Error: string := "Error";
  224. |Events.Critical: string := "Critical";
  225. |Events.Alert: string := "Alert";
  226. |Events.Failure: string := "Failure";
  227. ELSE
  228. string := "Unknown ("; Strings.IntToStr(type, nbr); Strings.Append(string, nbr); Strings.Append(string, ")");
  229. END;
  230. END GetTypeString;
  231. PROCEDURE GetType*(CONST string : ARRAY OF CHAR) : SHORTINT;
  232. VAR type : SHORTINT;
  233. BEGIN
  234. IF string = "Unknown" THEN type := Events.Unknown;
  235. ELSIF string = "Undefined" THEN type := Events.Undefined;
  236. ELSIF string = "Information" THEN type := Events.Information;
  237. ELSIF string = "Warning" THEN type := Events.Warning;
  238. ELSIF string = "Error" THEN type := Events.Error;
  239. ELSIF string = "Critical" THEN type := Events.Critical;
  240. ELSIF string = "Alert" THEN type := Events.Alert;
  241. ELSIF string = "Failure" THEN type := Events.Failure;
  242. ELSE
  243. type := Events.Unknown;
  244. END;
  245. RETURN type;
  246. END GetType;
  247. PROCEDURE GenerateEvent*(context : Commands.Context); (** originator type class subclass code message ~ *)
  248. VAR event : Events.Event; value : LONGINT;
  249. BEGIN
  250. context.arg.SkipWhitespace; context.arg.String(event.originator);
  251. context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.type := SHORT(SHORT(value));
  252. context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.class := SHORT(SHORT(value));
  253. context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.subclass := SHORT(SHORT(value));
  254. context.arg.SkipWhitespace; context.arg.Int(value, FALSE); event.code := SHORT(SHORT(value));
  255. context.arg.SkipWhitespace; context.arg.String(event.message);
  256. Events.Add(event, FALSE);
  257. END GenerateEvent;
  258. END EventsUtils.