Difference between revisions of "Console"
Jump to navigation
Jump to search
Josef templ (talk | contribs) (Created page with "For logging within the BlackBox framework, in particular the text subsystem, or for logging in very low-level modules the standard BlackBox logging facilities (Log, StdLog) ca...") |
Josef templ (talk | contribs) (improved version) |
||
| Line 4: | Line 4: | ||
It attaches a Windows Console window to the BlackBox process and outputs the log to the Console window. | It attaches a Windows Console window to the BlackBox process and outputs the log to the Console window. | ||
In order to make it easy to detect new output it adds a line number at the left. | In order to make it easy to detect new output it adds a line number at the left. | ||
In order to increase readability it supports indentation of the output. | |||
Non-ASCII characters are converted to the underlying Windows default code page. | |||
<pre>MODULE Console; | <pre>MODULE Console; | ||
(* low level logging to console window; supports switching on and off and indentation. | |||
if used in Kernel (or other linked module) don't forget to link a new .exe file *) | |||
IMPORT WinApi, SYSTEM; | IMPORT WinApi, SYSTEM; | ||
VAR res, stdOut, lineNr: INTEGER; | VAR | ||
res, stdOut, lineNr, indent, offAtLineNr: INTEGER; | |||
on: BOOLEAN; | |||
indentStr: ARRAY 10 OF CHAR; | |||
(* sets a non-default indent string, default is " " *) | |||
PROCEDURE SetIndentString*(IN s: ARRAY OF CHAR); | |||
BEGIN | |||
indentStr := s$ | |||
END SetIndentString; | |||
(* turn logging on; default *) | |||
PROCEDURE On*; | |||
BEGIN | |||
offAtLineNr := -1; | |||
on := TRUE | |||
END On; | |||
(* turn logging on for the specified number of lines *) | |||
PROCEDURE OnFor*(nofLines: INTEGER); | |||
BEGIN | |||
offAtLineNr := lineNr + nofLines; | |||
on := TRUE | |||
END OnFor; | |||
(* turn logging off *) | |||
PROCEDURE Off*; | |||
BEGIN | |||
on := FALSE | |||
END Off; | |||
(* increment indentation level *) | |||
PROCEDURE Indent*; | |||
BEGIN | |||
INC(indent) | |||
END Indent; | |||
(* decrement indentation level *) | |||
PROCEDURE Undent*; | |||
BEGIN | |||
DEC(indent) | |||
END Undent; | |||
(* output null terminated string; converted to Windows default code page *) | |||
PROCEDURE String*(IN s: ARRAY OF CHAR); | PROCEDURE String*(IN s: ARRAY OF CHAR); | ||
VAR | VAR buf: ARRAY 10000 OF SHORTCHAR; | ||
BEGIN | BEGIN | ||
IF on & (s # "") THEN | |||
res := WinApi.WideCharToMultiByte(WinApi.CP_OEMCP, {}, s, LEN(s$), buf, LEN(buf), NIL, NIL); | |||
IF ~((res > 0) & (res <= LEN(buf))) THEN | |||
buf := "*** error in Console.String ***"; res := LEN(buf$); | |||
END; | |||
res := WinApi.WriteFile(stdOut, SYSTEM.ADR(buf), res, NIL, NIL) | |||
END | |||
END String; | END String; | ||
| Line 34: | Line 87: | ||
END IntToString; | END IntToString; | ||
(* output integer as decimal number without any padding *) | |||
PROCEDURE Int*(x: INTEGER); | PROCEDURE Int*(x: INTEGER); | ||
VAR str: ARRAY 20 OF CHAR; sstr: ARRAY 20 OF SHORTCHAR; | VAR str: ARRAY 20 OF CHAR; sstr: ARRAY 20 OF SHORTCHAR; | ||
BEGIN | BEGIN | ||
IntToString(x, str); | IF on THEN | ||
IntToString(x, str); | |||
sstr := SHORT(str); | |||
res := WinApi.WriteFile(stdOut, SYSTEM.ADR(sstr), LEN(sstr$), NIL, NIL) | |||
END | |||
END Int; | END Int; | ||
PROCEDURE | (* outputs the line number and indentation level followed by repeated indentStr according to the indentation level *) | ||
BEGIN | PROCEDURE LinePrefix; | ||
END | VAR i: INTEGER; | ||
BEGIN | |||
Int(lineNr); String(":"); Int(indent); | |||
FOR i := 1 TO indent DO String(indentStr) END | |||
END LinePrefix; | |||
PROCEDURE Ln* | (* output line end and increment line number *) | ||
PROCEDURE Ln*; | |||
VAR crlf: ARRAY 2 OF SHORTCHAR; | VAR crlf: ARRAY 2 OF SHORTCHAR; | ||
BEGIN | BEGIN | ||
crlf[0] := 0DX; crlf[1] := 0AX; | IF on THEN | ||
crlf[0] := 0DX; crlf[1] := 0AX; | |||
res := WinApi.WriteFile(stdOut, SYSTEM.ADR(crlf), 2, NIL, NIL); | |||
INC(lineNr); LinePrefix; | |||
IF (offAtLineNr # -1) & (lineNr = offAtLineNr) THEN on := FALSE END | |||
END | |||
END Ln; | END Ln; | ||
| Line 57: | Line 121: | ||
res := WinApi.AllocConsole(); | res := WinApi.AllocConsole(); | ||
stdOut := WinApi.GetStdHandle(WinApi.STD_OUTPUT_HANDLE); | stdOut := WinApi.GetStdHandle(WinApi.STD_OUTPUT_HANDLE); | ||
lineNr := 1; indent := 1; indentStr := " "; On; | |||
LinePrefix | |||
END Console.</pre> | END Console.</pre> | ||
Revision as of 14:58, 21 February 2017
For logging within the BlackBox framework, in particular the text subsystem, or for logging in very low-level modules the standard BlackBox logging facilities (Log, StdLog) cannot be used.
The following module 'Console' can be used for that purpose. It attaches a Windows Console window to the BlackBox process and outputs the log to the Console window. In order to make it easy to detect new output it adds a line number at the left. In order to increase readability it supports indentation of the output. Non-ASCII characters are converted to the underlying Windows default code page.
MODULE Console;
(* low level logging to console window; supports switching on and off and indentation.
if used in Kernel (or other linked module) don't forget to link a new .exe file *)
IMPORT WinApi, SYSTEM;
VAR
res, stdOut, lineNr, indent, offAtLineNr: INTEGER;
on: BOOLEAN;
indentStr: ARRAY 10 OF CHAR;
(* sets a non-default indent string, default is " " *)
PROCEDURE SetIndentString*(IN s: ARRAY OF CHAR);
BEGIN
indentStr := s$
END SetIndentString;
(* turn logging on; default *)
PROCEDURE On*;
BEGIN
offAtLineNr := -1;
on := TRUE
END On;
(* turn logging on for the specified number of lines *)
PROCEDURE OnFor*(nofLines: INTEGER);
BEGIN
offAtLineNr := lineNr + nofLines;
on := TRUE
END OnFor;
(* turn logging off *)
PROCEDURE Off*;
BEGIN
on := FALSE
END Off;
(* increment indentation level *)
PROCEDURE Indent*;
BEGIN
INC(indent)
END Indent;
(* decrement indentation level *)
PROCEDURE Undent*;
BEGIN
DEC(indent)
END Undent;
(* output null terminated string; converted to Windows default code page *)
PROCEDURE String*(IN s: ARRAY OF CHAR);
VAR buf: ARRAY 10000 OF SHORTCHAR;
BEGIN
IF on & (s # "") THEN
res := WinApi.WideCharToMultiByte(WinApi.CP_OEMCP, {}, s, LEN(s$), buf, LEN(buf), NIL, NIL);
IF ~((res > 0) & (res <= LEN(buf))) THEN
buf := "*** error in Console.String ***"; res := LEN(buf$);
END;
res := WinApi.WriteFile(stdOut, SYSTEM.ADR(buf), res, NIL, NIL)
END
END String;
PROCEDURE IntToString(x: LONGINT; OUT s: ARRAY OF CHAR); (* copied from Strings *)
CONST minLongIntRev = "8085774586302733229";
VAR j, k: INTEGER; ch: CHAR; a: ARRAY 32 OF CHAR;
BEGIN
IF x # MIN(LONGINT) THEN
IF x < 0 THEN s[0] := "-"; k := 1; x := -x ELSE k := 0 END;
j := 0; REPEAT a[j] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(j) UNTIL x = 0
ELSE
a := minLongIntRev; s[0] := "-"; k := 1;
j := 0; WHILE a[j] # 0X DO INC(j) END
END;
ASSERT(k + j < LEN(s), 23);
REPEAT DEC(j); ch := a[j]; s[k] := ch; INC(k) UNTIL j = 0;
s[k] := 0X
END IntToString;
(* output integer as decimal number without any padding *)
PROCEDURE Int*(x: INTEGER);
VAR str: ARRAY 20 OF CHAR; sstr: ARRAY 20 OF SHORTCHAR;
BEGIN
IF on THEN
IntToString(x, str);
sstr := SHORT(str);
res := WinApi.WriteFile(stdOut, SYSTEM.ADR(sstr), LEN(sstr$), NIL, NIL)
END
END Int;
(* outputs the line number and indentation level followed by repeated indentStr according to the indentation level *)
PROCEDURE LinePrefix;
VAR i: INTEGER;
BEGIN
Int(lineNr); String(":"); Int(indent);
FOR i := 1 TO indent DO String(indentStr) END
END LinePrefix;
(* output line end and increment line number *)
PROCEDURE Ln*;
VAR crlf: ARRAY 2 OF SHORTCHAR;
BEGIN
IF on THEN
crlf[0] := 0DX; crlf[1] := 0AX;
res := WinApi.WriteFile(stdOut, SYSTEM.ADR(crlf), 2, NIL, NIL);
INC(lineNr); LinePrefix;
IF (offAtLineNr # -1) & (lineNr = offAtLineNr) THEN on := FALSE END
END
END Ln;
BEGIN
res := WinApi.AllocConsole();
stdOut := WinApi.GetStdHandle(WinApi.STD_OUTPUT_HANDLE);
lineNr := 1; indent := 1; indentStr := " "; On;
LinePrefix
END Console.