Errors.Mod 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. MODULE Errors; (** AUTHOR "staubesv"; PURPOSE "Error message interface"; *)
  2. (**
  3. * Interface to system-wide unique error codes. Can be used by application to retrieve textual representations
  4. * error codes.
  5. *
  6. * Notes:
  7. * - only for use withhin applications
  8. * - don't move this file to the system package, never use it from within modules in the system package
  9. *)
  10. IMPORT
  11. Modules, Streams, Commands, Strings, Files;
  12. CONST
  13. DefaultErrorMessageFile = "errors.txt";
  14. MaxLineLength = 256; (* Maximum length of line in error message file *)
  15. InitialCacheSize = 128;
  16. (* parser result codes *)
  17. Ok = 0;
  18. NotFound = 1;
  19. Error = 2;
  20. FileNotFound = 3;
  21. UnknownModule = "Unknown";
  22. TYPE
  23. ErrorMessage* = RECORD
  24. code : LONGINT;
  25. moduleName- : Modules.Name;
  26. text- : Strings.String; (* is never NIL *)
  27. END;
  28. ErrorMessages = POINTER TO ARRAY OF ErrorMessage;
  29. VAR
  30. cache : ErrorMessages;
  31. index : LONGINT;
  32. lastModuleName : Modules.Name;
  33. PROCEDURE GetErrorString(errorCode : WORD) : Strings.String;
  34. VAR message : ARRAY 128 OF CHAR; nbr : ARRAY 16 OF CHAR;
  35. BEGIN
  36. message := "Unknown error, res: ";
  37. Strings.IntToStr(errorCode, nbr); Strings.Append(message, nbr);
  38. RETURN Strings.NewString(message);
  39. END GetErrorString;
  40. (** Get error message for the specified error number. If no message can be found, a generic error message is generated *)
  41. PROCEDURE GetErrorMessage*(errorCode : WORD) : ErrorMessage;
  42. VAR errorMessage : ErrorMessage; res : WORD;
  43. BEGIN {EXCLUSIVE}
  44. res := -1;
  45. Get(errorCode, errorMessage, res);
  46. IF (res # Ok) THEN
  47. errorMessage.moduleName := UnknownModule;
  48. errorMessage.text := GetErrorString(errorCode);
  49. END;
  50. ASSERT(errorMessage.text # NIL);
  51. RETURN errorMessage;
  52. END GetErrorMessage;
  53. PROCEDURE ToStream*(errorCode : WORD; out : Streams.Writer);
  54. VAR errorMessage : ErrorMessage;
  55. BEGIN
  56. ASSERT(out # NIL);
  57. errorMessage := GetErrorMessage(errorCode);
  58. out.String(errorMessage.text^);
  59. out.String(" (");
  60. IF (errorMessage.moduleName # UnknownModule) THEN out.String(errorMessage.moduleName); out.String(":"); END;
  61. out.Int(errorCode, 0); out.String(")");
  62. out.Update;
  63. END ToStream;
  64. PROCEDURE ResizeCache;
  65. VAR newCache : ErrorMessages; i : LONGINT;
  66. BEGIN
  67. IF (cache # NIL) THEN
  68. NEW(newCache, 2*LEN(cache));
  69. FOR i := 0 TO LEN(cache)-1 DO newCache[i] := cache[i]; END;
  70. ELSE
  71. NEW(newCache, InitialCacheSize);
  72. END;
  73. cache := newCache;
  74. END ResizeCache;
  75. PROCEDURE Add(CONST errorMessage : ErrorMessage);
  76. BEGIN
  77. IF (cache = NIL) OR (index >= LEN(cache)) THEN ResizeCache; END;
  78. cache[index] := errorMessage;
  79. INC(index);
  80. END Add;
  81. PROCEDURE Get(number : WORD; VAR errorMessage : ErrorMessage; VAR res : WORD);
  82. VAR i : LONGINT;
  83. BEGIN
  84. IF (cache # NIL) THEN
  85. i := 0; WHILE (i < index) & (cache[i].code # number) DO INC(i); END;
  86. ELSE
  87. i := MAX(LONGINT);
  88. END;
  89. IF (i < index) THEN
  90. errorMessage := cache[i]; res := Ok;
  91. ELSE
  92. res := NotFound;
  93. END;
  94. END Get;
  95. PROCEDURE ParseLine(reader : Streams.Reader; VAR errorMessage : ErrorMessage; VAR res : WORD);
  96. VAR line : ARRAY MaxLineLength OF CHAR;
  97. BEGIN
  98. IF reader.GetInteger(errorMessage.code, FALSE) THEN
  99. reader.SkipWhitespace;
  100. reader.Ln(line);
  101. IF (reader.res = Ok) THEN
  102. errorMessage.text := Strings.NewString(line);
  103. END;
  104. END;
  105. res := reader.res;
  106. END ParseLine;
  107. PROCEDURE ParseFile(CONST filename : Files.FileName; VAR res : WORD);
  108. VAR file : Files.File; reader : Files.Reader; errorMessage : ErrorMessage; ch : CHAR;
  109. BEGIN
  110. file := Files.Old(filename);
  111. IF (file # NIL) THEN
  112. res := Ok;
  113. Files.OpenReader(reader, file, 0);
  114. WHILE (res = Ok) & (reader.res # Streams.EOF) DO
  115. ch := reader.Peek();
  116. IF (ch # "#") THEN
  117. ParseLine(reader, errorMessage, res);
  118. IF (res = Ok) THEN
  119. IF (errorMessage.code MOD 100 # 0) THEN
  120. errorMessage.moduleName := lastModuleName;
  121. Add(errorMessage);
  122. ELSE
  123. COPY(errorMessage.text^, lastModuleName);
  124. END;
  125. END;
  126. ELSE
  127. reader.SkipLn; (* skip line comment *)
  128. END;
  129. END;
  130. IF (reader.res = Streams.Ok) OR (reader.res = Streams.EOF) THEN res := Ok; ELSE res := Error; END;
  131. ELSE
  132. res := FileNotFound;
  133. END;
  134. END ParseFile;
  135. (** Load and parse a error message file. *)
  136. PROCEDURE Open*(context : Commands.Context); (** [filename] ~ *)
  137. VAR filename : Files.FileName; res : WORD;
  138. BEGIN {EXCLUSIVE}
  139. index := 0; cache := NIL;
  140. context.arg.SkipWhitespace; context.arg.String(filename);
  141. IF (filename = "") THEN COPY(DefaultErrorMessageFile, filename); END;
  142. context.out.String("Errors: Loading error messages from file "); context.out.String(filename);
  143. context.out.String(" ... "); context.out.Update;
  144. ParseFile(filename, res);
  145. IF (res = Ok) THEN
  146. context.out.Int(index, 0); context.out.String(" messages loaded.");
  147. ELSE
  148. context.out.String("failed, res: "); context.out.Int(res, 0);
  149. END;
  150. context.out.Ln;
  151. END Open;
  152. (** Show the error message for the optionally specified error number. If no number is specified,
  153. show all loaded error messages. This procedure is primarly for testing purposes. *)
  154. PROCEDURE Show*(context : Commands.Context); (** [error number] ~ *)
  155. CONST Tab = 09X;
  156. VAR number, i : LONGINT; errorMessage : ErrorMessage;
  157. BEGIN
  158. IF context.arg.GetInteger(number, FALSE) THEN
  159. errorMessage := GetErrorMessage(number);
  160. context.out.String("Error message for number "); context.out.Int(number, 0); context.out.String(": ");
  161. context.out.String("Module: "); context.out.String(errorMessage.moduleName);
  162. context.out.String(", Text: "); context.out.String(errorMessage.text^);
  163. ELSE
  164. context.out.String("Errors: ");
  165. IF (index > 0) THEN
  166. context.out.Int(index, 0); context.out.String(" error messages loaded: "); context.out.Ln;
  167. BEGIN {EXCLUSIVE}
  168. FOR i := 0 TO index-1 DO
  169. context.out.Int(cache[i].code, 0); context.out.Char(Tab);
  170. context.out.String(cache[i].text^);
  171. context.out.String(" ("); context.out.String(cache[i].moduleName); context.out.String(")");
  172. context.out.Ln;
  173. END;
  174. END;
  175. ELSE
  176. context.out.String("No error messages loaded.");
  177. END;
  178. END;
  179. context.out.Ln;
  180. END Show;
  181. BEGIN
  182. index := 0;
  183. lastModuleName := "";
  184. END Errors.
  185. Errors.Open ~
  186. Errors.Show 1505~
  187. Errors.Show~
  188. System.Free Errors ~