OberonCore https://forum.oberoncore.ru/ |
|
Отладочная консоль https://forum.oberoncore.ru/viewtopic.php?f=2&t=296 |
Страница 1 из 1 |
Автор: | Илья Ермаков [ Вторник, 22 Август, 2006 13:38 ] |
Заголовок сообщения: | Отладочная консоль |
Выкладываю полезный модуль - отладочное консольное окно. Очень полезно для ввода/вывода из ядра и других мест, где тот же StdLog неприменим... Испольуется просто - при загрузке модуля автоматически откроется консольное окно. Вывод можно перенаправить в файл. Код: MODULE Terminal;
(** Console input / output (useful for low-level debugging) Author: Ilya Ermakov **) IMPORT WinApi, S := SYSTEM; CONST charCode* = -1; decimal* = 10; hexadecimal* = -2; roman* = -3; digitspace* = 08FX; showBase* = TRUE; hideBase* = FALSE; minLongIntRev = "8085774586302733229"; (* reversed string of -MIN(LONGINT) *) ln = 0DX + 0AX; VAR in, out: WinApi.HANDLE; res, n: INTEGER; buf: ARRAY 1024 OF SHORTCHAR; digits: ARRAY 17 OF SHORTCHAR; cs: WinApi.CRITICAL_SECTION; PROCEDURE BeginAtomic* ; BEGIN WinApi.EnterCriticalSection(cs) END BeginAtomic; PROCEDURE EndAtomic* ; BEGIN WinApi.LeaveCriticalSection(cs) END EndAtomic; PROCEDURE IntToString (x: LONGINT; OUT s: ARRAY OF SHORTCHAR); VAR j, k: INTEGER; ch: SHORTCHAR; a: ARRAY 32 OF SHORTCHAR; 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] := SHORT(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; PROCEDURE StringToInt (IN s: ARRAY OF SHORTCHAR; OUT x: INTEGER; OUT res: INTEGER); CONST hexLimit = MAX(INTEGER) DIV 8 + 1; VAR i, j, k, digits: INTEGER; ch, top: CHAR; neg: BOOLEAN; base: INTEGER; BEGIN res := 0; i := 0; ch := s[0]; WHILE (ch # 0X) & (ch <= " ") OR (ch = 8BX) OR (ch = 8FX) OR (ch = 0A0X) DO (* ignore leading blanks *) INC(i); ch := s[i] END; j := i; top := "0"; WHILE (ch # 0X) & (ch # "H") & (ch # "X") & (ch # "%") DO IF ch > top THEN top := ch END; INC(j); ch := s[j] END; IF (ch = "H") OR (ch = "X") THEN x := 0; ch := s[i]; IF ("0" <= ch) & (ch <= "9") OR ("A" <= ch) & (ch <= "F") THEN WHILE ch = "0" DO INC(i); ch := s[i] END; digits := 0; WHILE (res = 0) & (("0" <= ch) & (ch <= "9") OR ("A" <= ch) & (ch <= "F")) DO IF ch < "A" THEN k := ORD(ch) - ORD("0") ELSE k := ORD(ch) - ORD("A") + 10 END; IF digits < 8 THEN x := x MOD hexLimit; IF x >= hexLimit DIV 2 THEN x := x - hexLimit END; x := x * 16 + k; INC(i); ch := s[i] ELSE res := 1 END; INC(digits) END; IF res = 0 THEN IF (ch # "H") & (ch # "X") OR (s[i+1] # 0X) THEN res := 2 END END ELSE res := 2 END ELSE IF ch = "%" THEN INC(j); ch := s[j]; base := 0; IF ("0" <= ch) & (ch <= "9") THEN k := ORD(ch) - ORD("0"); REPEAT base := base * 10 + k; INC(j); ch := s[j]; k := ORD(ch) - ORD("0") UNTIL (ch < "0") OR (ch > "9") OR (base > (MAX(INTEGER) - k) DIV 10); IF ("0" <= ch) & (ch <= "9") THEN base := 0 END END ELSE base := 10 END; IF (base < 2) OR (base > 16) THEN res := 2 ELSIF (base <= 10) & (ORD(top) < base + ORD("0")) OR (base > 10) & (ORD(top) < base - 10 + ORD("A")) THEN x := 0; ch := s[i]; neg := FALSE; IF ch = "-" THEN INC(i); ch := s[i]; neg := TRUE ELSIF ch = "+" THEN INC(i); ch := s[i] END; WHILE (ch # 0X) & (ch <= " ") DO INC(i); ch := s[i] END; IF ("0" <= ch) & (ch <= "9") OR ("A" <= ch) & (ch <= "F") THEN IF ch <= "9" THEN k := ORD(ch) - ORD("0") ELSE k := ORD(ch) - ORD("A") + 10 END; WHILE (("0" <= ch) & (ch <= "9") OR ("A" <= ch) & (ch <= "F")) & (res = 0) DO IF x >= (MIN(INTEGER) + (base - 1) + k) DIV base THEN x := x * base - k; INC(i); ch := s[i]; IF ch <= "9" THEN k := ORD(ch) - ORD("0") ELSE k := ORD(ch) - ORD("A") + 10 END ELSE res := 1 END END ELSE res := 2 END; IF res = 0 THEN IF ~neg THEN IF x > MIN(INTEGER) THEN x := -x ELSE res := 1 END END; IF (ch # 0X) & (ch # "%") THEN res := 2 END END ELSE res := 2 END END END StringToInt; PROCEDURE IntToStringForm (x: LONGINT; form, minWidth: INTEGER; fillCh: SHORTCHAR; showBase: BOOLEAN; OUT s: ARRAY OF SHORTCHAR); VAR base, i, j, k, si: INTEGER; mSign: BOOLEAN; a: ARRAY 128 OF SHORTCHAR; c1, c5, c10: SHORTCHAR; BEGIN ASSERT((form = charCode) OR (form = hexadecimal) OR (form = roman) OR ((form >= 2) & (form <= 16)), 20); ASSERT(minWidth >= 0, 22); IF form = charCode THEN base := 16 ELSIF form = hexadecimal THEN base := 16 ELSE base := form END; IF form = roman THEN ASSERT((x > 0) & (x < 3999), 21); base := 1000; i := 0; mSign := FALSE; WHILE (base > 0) & (x > 0) DO IF base = 1 THEN c1 := "I"; c5 := "V"; c10 := "X" ELSIF base = 10 THEN c1 := "X"; c5 := "L"; c10 := "C" ELSIF base = 100 THEN c1 := "C"; c5 := "D"; c10 := "M" ELSE c1 := "M" END; k := SHORT(x DIV base); x := x MOD base; IF k IN {4, 9} THEN a[i] := c1; INC(i) END; IF k IN {4 .. 8} THEN a[i] := c5; INC(i) END; IF k = 9 THEN a[i] := c10; INC(i) ELSIF k IN {1 .. 3, 6 .. 8} THEN j := k MOD 5; REPEAT a[i] := c1; INC(i); DEC(j) UNTIL j = 0 END; base := base DIV 10 END ELSIF (form = hexadecimal) OR (form = charCode) THEN i := 0; mSign := FALSE; IF showBase THEN DEC(minWidth) END; REPEAT a[i] := digits[x MOD base]; x := x DIV base; INC(i) UNTIL (x = 0) OR (x = -1) OR (i = LEN(a)); IF x = -1 THEN fillCh := "F" END ELSE IF x < 0 THEN i := 0; mSign := TRUE; DEC(minWidth); REPEAT IF x MOD base = 0 THEN a[i] := digits[0]; x := x DIV base ELSE a[i] := digits[base - x MOD base]; x := x DIV base + 1 END; INC(i) UNTIL (x = 0) OR (i = LEN(a)) ELSE i := 0; mSign := FALSE; REPEAT a[i] := digits[x MOD base]; x := x DIV base; INC(i) UNTIL (x = 0) OR (i = LEN(a)) END; IF showBase THEN DEC(minWidth); IF base < 10 THEN DEC(minWidth) ELSE DEC(minWidth,2) END END END; si := 0; IF mSign & (fillCh = "0") & (si < LEN(s)) THEN s[si] := "-"; INC(si); mSign := FALSE END; WHILE minWidth > i DO IF si < LEN(s) THEN s[si] := fillCh; INC(si) END; DEC(minWidth) END; IF mSign & (si < LEN(s)) THEN s[si] := "-"; INC(si) END; IF form = roman THEN j := 0; WHILE j < i DO IF si < LEN(s) THEN s[si] := a[j]; INC(si) END; INC(j) END ELSE REPEAT DEC(i); IF si < LEN(s) THEN s[si] := a[i]; INC(si) END UNTIL i = 0 END; IF showBase & (form # roman) THEN IF (form = charCode) & (si < LEN(s)) THEN s[si] := "X"; INC(si) ELSIF (form = hexadecimal) & (si < LEN(s)) THEN s[si] := "H"; INC(si) ELSIF (form < 10) & (si < LEN(s)-1) THEN s[si] := "%"; s[si+1] := digits[base]; INC(si, 2) ELSIF (si < LEN(s) - 2) THEN s[si] := "%"; s[si+1] := digits[base DIV 10]; s[si+2] := digits[base MOD 10]; INC(si, 3) END END; IF si < LEN(s) THEN s[si] := 0X ELSE HALT(23) END END IntToStringForm; PROCEDURE String* (IN s: ARRAY OF SHORTCHAR); BEGIN res := WinApi.WriteFile(out, S.ADR(s), LEN(s$), n, NIL) END String; PROCEDURE Int* (x: LONGINT); VAR s: ARRAY 16 OF SHORTCHAR; BEGIN IntToString(x, s); res := WinApi.WriteFile(out, S.ADR(s), LEN(s$), n, NIL) END Int; PROCEDURE Hex* (x: LONGINT); VAR s: ARRAY 16 OF SHORTCHAR; BEGIN IntToStringForm(x, hexadecimal, 0, " ", TRUE, s); res := WinApi.WriteFile(out, S.ADR(s), LEN(s$), n, NIL) END Hex; PROCEDURE IntForm* (x: LONGINT; form, minWidth: INTEGER; fillCh: SHORTCHAR; showBase: BOOLEAN); VAR s: ARRAY 16 OF SHORTCHAR; BEGIN IntToStringForm(x, form, minWidth, fillCh, showBase, s); res := WinApi.WriteFile(out, S.ADR(s), LEN(s$), n, NIL) END IntForm; PROCEDURE Char* (c: SHORTCHAR); BEGIN res := WinApi.WriteFile(out, S.ADR(c), 1, n, NIL) END Char; PROCEDURE Ln* ; BEGIN res := WinApi.WriteFile(out, S.ADR(ln), LEN(ln), n, NIL) END Ln; PROCEDURE ReadString* (OUT s: ARRAY OF SHORTCHAR); BEGIN res := WinApi.ReadFile(in, S.ADR(buf), LEN(buf), n, NIL); s := buf$ END ReadString; PROCEDURE ReadInt* (x: INTEGER); BEGIN res := WinApi.ReadFile(in, S.ADR(buf), LEN(buf), n, NIL); StringToInt(buf, x, res) END ReadInt; PROCEDURE ReadLn* ; VAR s: ARRAY 16 OF SHORTCHAR; BEGIN ReadString(s) END ReadLn; PROCEDURE AllocConsole; VAR res: INTEGER; BEGIN res := WinApi.AllocConsole(); res := WinApi.SetConsoleCP(1251) END AllocConsole; PROCEDURE OpenStdOut; BEGIN AllocConsole; out := WinApi.CreateFile("CONOUT$", WinApi.GENERIC_READ + WinApi.GENERIC_WRITE, {}, NIL, WinApi.OPEN_EXISTING, {}, 0); res := WinApi.GetLastError() END OpenStdOut; PROCEDURE OpenStdIn; BEGIN AllocConsole; in := WinApi.CreateFile("CONIN$", WinApi.GENERIC_READ + WinApi.GENERIC_WRITE, {}, NIL, WinApi.OPEN_EXISTING, {}, 0) END OpenStdIn; PROCEDURE AssignOutput* (IN file: ARRAY OF CHAR); VAR res: INTEGER; BEGIN IF file # "" THEN out := WinApi.CreateFileW(file, WinApi.GENERIC_WRITE, WinApi.FILE_SHARE_READ + WinApi.FILE_SHARE_WRITE, NIL, WinApi.CREATE_ALWAYS, {}, 0); (* res := WinApi.SetFilePointer(out, 0, NIL, WinApi.FILE_END) *) ELSE OpenStdOut END END AssignOutput; BEGIN WinApi.InitializeCriticalSection(cs); digits := "0123456789ABCDEF"; IF out = 0 THEN OpenStdOut END; OpenStdIn END Terminal. |
Автор: | Александр Ильин [ Суббота, 23 Сентябрь, 2006 23:10 ] |
Заголовок сообщения: | |
Интересно, что при закрытии окна консоли закрывается и основное приложение. Это как-то можно обойти? Не то чтобы мешает, просто неожиданно и несколько странно. |
Автор: | Илья Ермаков [ Воскресенье, 24 Сентябрь, 2006 02:00 ] |
Заголовок сообщения: | |
К сожалению, обойти это никак нельзя - при создании консоли Винда привязывает ее к процессу как главное окно, при закрытии которого процесс завершается... Memento more |
Автор: | Илья Ермаков [ Суббота, 25 Ноябрь, 2006 21:32 ] |
Заголовок сообщения: | |
Вот дополнение к модулю Terminal - модуль трассировки, позволяющий в определенной контрольной точке вывести в консоль цепь активаций процедур, которая прошла через эту точку. Пользоваться просто - в начале интересующих процедур пишем вызов - Trace.EntryPoint. Настраивать глубину просмотра активаций можно вызовом Trace.SetDepth. По умолчанию = 3. Код: MODULE Trace;
IMPORT Kernel, T := Terminal, S := SYSTEM, WinApi; CONST FP = 5; VAR depth: INTEGER; PROCEDURE EntryPoint* ; VAR fp: INTEGER; ret: ARRAY 64 OF INTEGER; name: ARRAY 64 OF ARRAY 256 OF SHORTCHAR; mod: Kernel.Module; n, i: INTEGER; ref, end: INTEGER; s: Kernel.Name; BEGIN S.GETREG(FP, fp); FOR n := 0 TO depth-1 DO S.GET(fp+4, ret[n]); S.GET(fp, fp) END; mod := Kernel.modList; n := 0; WHILE (mod # NIL) & (n < depth) DO FOR i := 0 TO depth-1 DO IF( mod.code < ret[i]) & (ret[i] < mod.code + mod.csize) THEN name[i] := mod.name$; ref := mod.refs; REPEAT Kernel.GetRefProc(ref, end, s) UNTIL (end = 0) OR (ret[i]-mod.code < end); IF ret[i]-mod.code < end THEN name[i] := name[i] + "." + s END; INC(n) END END; mod := mod.next END; T.BeginAtomic; T.Int(WinApi.GetCurrentThreadId()); T.String(": "); FOR i := 0 TO depth-1 DO T.String(name[i]); T.String(" << ") END; T.Ln; T.EndAtomic END EntryPoint; PROCEDURE SetDepth* (d: INTEGER); BEGIN ASSERT(d < 64, 20); depth := d END SetDepth; BEGIN depth := 3 END Trace. |
Автор: | Info21 [ Воскресенье, 26 Ноябрь, 2006 01:44 ] |
Заголовок сообщения: | |
Илья Ермаков писал(а): Memento more
Memento mori. |
Автор: | Илья Ермаков [ Воскресенье, 26 Ноябрь, 2006 11:37 ] |
Заголовок сообщения: | |
Зело слаб в латыни |
Автор: | FromOGU [ Вторник, 28 Ноябрь, 2006 17:09 ] |
Заголовок сообщения: | FromOGU |
Илья Ермаков писал(а): К сожалению, обойти это никак нельзя - при создании консоли Винда привязывает ее к процессу как главное окно, при закрытии которого процесс завершается... Memento more
Извратно, но можно. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |