MODULE Errors;
IMPORT
Modules, Streams, Commands, Strings, Files;
CONST
DefaultErrorMessageFile = "errors.txt";
MaxLineLength = 256;
InitialCacheSize = 128;
Ok = 0;
NotFound = 1;
Error = 2;
FileNotFound = 3;
UnknownModule = "Unknown";
TYPE
ErrorMessage* = RECORD
code : LONGINT;
moduleName- : Modules.Name;
text- : Strings.String;
END;
ErrorMessages = POINTER TO ARRAY OF ErrorMessage;
VAR
cache : ErrorMessages;
index : LONGINT;
lastModuleName : Modules.Name;
PROCEDURE GetErrorString(errorCode : LONGINT) : Strings.String;
VAR message : ARRAY 128 OF CHAR; nbr : ARRAY 16 OF CHAR;
BEGIN
message := "Unknown error, res: ";
Strings.IntToStr(errorCode, nbr); Strings.Append(message, nbr);
RETURN Strings.NewString(message);
END GetErrorString;
PROCEDURE GetErrorMessage*(errorCode : LONGINT) : ErrorMessage;
VAR errorMessage : ErrorMessage; res : LONGINT;
BEGIN {EXCLUSIVE}
res := -1;
Get(errorCode, errorMessage, res);
IF (res # Ok) THEN
errorMessage.moduleName := UnknownModule;
errorMessage.text := GetErrorString(errorCode);
END;
ASSERT(errorMessage.text # NIL);
RETURN errorMessage;
END GetErrorMessage;
PROCEDURE ToStream*(errorCode : LONGINT; out : Streams.Writer);
VAR errorMessage : ErrorMessage;
BEGIN
ASSERT(out # NIL);
errorMessage := GetErrorMessage(errorCode);
out.String(errorMessage.text^);
out.String(" (");
IF (errorMessage.moduleName # UnknownModule) THEN out.String(errorMessage.moduleName); out.String(":"); END;
out.Int(errorCode, 0); out.String(")");
out.Update;
END ToStream;
PROCEDURE ResizeCache;
VAR newCache : ErrorMessages; i : LONGINT;
BEGIN
IF (cache # NIL) THEN
NEW(newCache, 2*LEN(cache));
FOR i := 0 TO LEN(cache)-1 DO newCache[i] := cache[i]; END;
ELSE
NEW(newCache, InitialCacheSize);
END;
cache := newCache;
END ResizeCache;
PROCEDURE Add(CONST errorMessage : ErrorMessage);
BEGIN
IF (cache = NIL) OR (index >= LEN(cache)) THEN ResizeCache; END;
cache[index] := errorMessage;
INC(index);
END Add;
PROCEDURE Get(number : LONGINT; VAR errorMessage : ErrorMessage; VAR res : LONGINT);
VAR i : LONGINT;
BEGIN
IF (cache # NIL) THEN
i := 0; WHILE (i < index) & (cache[i].code # number) DO INC(i); END;
ELSE
i := MAX(LONGINT);
END;
IF (i < index) THEN
errorMessage := cache[i]; res := Ok;
ELSE
res := NotFound;
END;
END Get;
PROCEDURE ParseLine(reader : Streams.Reader; VAR errorMessage : ErrorMessage; VAR res : LONGINT);
VAR line : ARRAY MaxLineLength OF CHAR;
BEGIN
IF reader.GetInteger(errorMessage.code, FALSE) THEN
reader.SkipWhitespace;
reader.Ln(line);
IF (reader.res = Ok) THEN
errorMessage.text := Strings.NewString(line);
END;
END;
res := reader.res;
END ParseLine;
PROCEDURE ParseFile(CONST filename : Files.FileName; VAR res : LONGINT);
VAR file : Files.File; reader : Files.Reader; errorMessage : ErrorMessage; ch : CHAR;
BEGIN
file := Files.Old(filename);
IF (file # NIL) THEN
res := Ok;
Files.OpenReader(reader, file, 0);
WHILE (res = Ok) & (reader.res # Streams.EOF) DO
ch := reader.Peek();
IF (ch # "#") THEN
ParseLine(reader, errorMessage, res);
IF (res = Ok) THEN
IF (errorMessage.code MOD 100 # 0) THEN
errorMessage.moduleName := lastModuleName;
Add(errorMessage);
ELSE
COPY(errorMessage.text^, lastModuleName);
END;
END;
ELSE
reader.SkipLn;
END;
END;
IF (reader.res = Streams.Ok) OR (reader.res = Streams.EOF) THEN res := Ok; ELSE res := Error; END;
ELSE
res := FileNotFound;
END;
END ParseFile;
PROCEDURE Open*(context : Commands.Context);
VAR filename : Files.FileName; res : LONGINT;
BEGIN {EXCLUSIVE}
index := 0; cache := NIL;
context.arg.SkipWhitespace; context.arg.String(filename);
IF (filename = "") THEN COPY(DefaultErrorMessageFile, filename); END;
context.out.String("Errors: Loading error messages from file "); context.out.String(filename);
context.out.String(" ... "); context.out.Update;
ParseFile(filename, res);
IF (res = Ok) THEN
context.out.Int(index, 0); context.out.String(" messages loaded.");
ELSE
context.out.String("failed, res: "); context.out.Int(res, 0);
END;
context.out.Ln;
END Open;
PROCEDURE Show*(context : Commands.Context);
CONST Tab = 09X;
VAR number, i : LONGINT; errorMessage : ErrorMessage;
BEGIN
IF context.arg.GetInteger(number, FALSE) THEN
errorMessage := GetErrorMessage(number);
context.out.String("Error message for number "); context.out.Int(number, 0); context.out.String(": ");
context.out.String("Module: "); context.out.String(errorMessage.moduleName);
context.out.String(", Text: "); context.out.String(errorMessage.text^);
ELSE
context.out.String("Errors: ");
IF (index > 0) THEN
context.out.Int(index, 0); context.out.String(" error messages loaded: "); context.out.Ln;
BEGIN {EXCLUSIVE}
FOR i := 0 TO index-1 DO
context.out.Int(cache[i].code, 0); context.out.Char(Tab);
context.out.String(cache[i].text^);
context.out.String(" ("); context.out.String(cache[i].moduleName); context.out.String(")");
context.out.Ln;
END;
END;
ELSE
context.out.String("No error messages loaded.");
END;
END;
context.out.Ln;
END Show;
BEGIN
index := 0;
lastModuleName := "";
END Errors.
Errors.Open ~
Errors.Show 1505~
Errors.Show~
SystemTools.Free Errors ~