Unit Crt WriteLn in Threads bzw. Externe Programme

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
JD55
Beiträge: 5
Registriert: Fr 29. Mai 2020, 15:41

Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von JD55 »

Hallo,
erstmal einen netten Gruß an alle. Ich habe mich angemeldet da ich einiges mit FreePascal Programmiere. Was mir gefällt ist die unabhängikeit von Plattformen. Meistens schreibe ich Unix Programme. Das war es eigentlich schon zu meiner Person.

Nun zu meiner Frage. Ich habe eine Konsolen anwendung geschrieben wo ich auch gerne Farbigen Text ausgeben möchte. Das klappt auch einwandfrei. Ich habe nur ein Problem wenn ich mit WriteLn entweder aus einem Thread oder aus einem anderen Programm was ich mit fpsystem aufrufe Text ausgebe. Der ist immer "schief". Das heisst er macht nur ein LF und kein CR. Dadurch stehen die ausgaben nicht untereinander.
Da ich auch Externe Programme aufrufe die ich nicht geschrieben habe, kann ich es in diesen Programmen nicht ändern. Binde ich Crt nicht ein und verzichte auf Farben ist wieder alles richtig.
System ist Debian.

Was mache ich da falsch?

Vielen dank im Voraus

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von Mathias »

Verstehe ich dich richtig, du schreibst in :D deinem Programm mit der Unit Crt. Und gleichzeitig schreibt ein externes in die gleiche Konsole ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

JD55
Beiträge: 5
Registriert: Fr 29. Mai 2020, 15:41

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von JD55 »

Ja, mein Programm ruft unter anderem Externe Programme auf. Und die ausgaben möchte ich natürlich auch sehen. Oder wenn man etwas in einem Thread ausgibt.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von Mathias »

Normalerweise verwendet Unixsystem nur ein LF. Was ich mir in deinem Fall vorstellen kann, das die Unit Crt die Konsole auf CR-LF umstellt.
Versuche mal anstelle von Writeln(blabla) ein Write(blabla, #10).
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von Warf »

Soweit ich weiß macht die CRT Unit internes buffering (was sonst vom OS übernommen wird) und ich hab grade mal drüber geschaut, sie ist nicht Thread-Safe.

D.h. WriteLn aufrufe aus verschiedenen Threads ohne lock, wenn du die CRT unit benutzt kann ganz schön in die Hose gehen.

Wenn es dir nur um Farben geht, mittlerweile kann selbst der Windows Terminal emulator Escape Codes. Du kannst also ganz einfach sowas bauen:

Code: Alles auswählen

program Test;

{$Mode ObjFPC}{$H+}

uses
  SysUtils;

type
  TConsoleColor = (ccBlack = 0, ccRed, ccGreen, ccYellow, ccBlue, ccMagenta, ccCyan, ccWhite);

function Colored(const str: String; color: TConsoleColor): String;
begin
  Result := Format(#27'[3%dm%s'#27'[1;49m', [ord(color), str]);
end;

begin
  Writeln(Colored('Hello ', ccRed), Colored('World!', ccYellow));
end.
Für sowas simples wie reiner Farbiger output ist die CRT unit ein bisschen mit kanonen auf spatzen schießen

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von Mathias »

So nebenbei setzt unter Linux die Unit Crt die Farben auch mit Escape-Sequenzen.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
  TextAttr := 4;
  WriteLn('Hello World');
  TextAttr := 25;
  WriteLn('Hello World');
end; 
Dieser Code spuckt folgendes aus:

Code: Alles auswählen

[0;1;34;44mHello World
[0;31mHello World
[0;1;34;44mHello World
[0;31mHello World
[0;1;34;44mHello World
[0;31mHello World
[0;1;34;44mHello World
[0;31mHello World
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von Warf »

Mathias hat geschrieben:
Fr 29. Mai 2020, 22:03
So nebenbei setzt unter Linux die Unit Crt die Farben auch mit Escape-Sequenzen.
Jo, ist auch der "standard" weg unter Unix systemen. Kompliziert wirds erst bei älteren Windows systemen, denn dort werden die Farben über API aufrufe gesetzt, weshabl bis zum neuen Windows 10 Terminal Project (ein Projekt bei dem Microsoft versucht ein benutzbares Terminal in Windows hinzubekommen) es ein echter Krampf war das einzustellen.

Da Windows 7 mittlerweile von Microsoft allerdings für Tot erklärt wurde, muss man sich nicht mehr die Mühe machen und kann direkt auf die Escape sequenzen gehen, die jetzt überall funktionieren.

Das gesagt, habe ich grade erst gesehen, auf windows muss man bei programm start einmal mit nem API call die escape sequenzen "aktivieren". Hier ist ein C code dazu: https://solarianprogrammer.com/2019/04/ ... terminals/

Code: Alles auswählen

17 void setupConsole(void) {
  DWORD outMode = 0;
  stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);

  if(stdoutHandle == INVALID_HANDLE_VALUE) {
    exit(GetLastError());
  }

  if(!GetConsoleMode(stdoutHandle, &outMode)) {
    exit(GetLastError());
  }

  outModeInit = outMode;

  // Enable ANSI escape codes
  outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;

  if(!SetConsoleMode(stdoutHandle, outMode)) {
    exit(GetLastError());
  }	
}
Sollte mit der Windows Unit vergleichbar umzusetzen sein.

Die CRT Unit macht halt extrem viel und ist ziemlich komplex (modeliert intern den Status des gesammten Terminals um den Cursor zu verfolgen und so späße) und weil sie noch die Oldschool windows API funktionen benutzt für das Terminal zu Setzen (statt ansi escape sequences), ist es damit relativ lahm wenn du sehr viele farbänderungen und so hast. Außerdem durch das eigene Buffern der Unit, verhält sich WriteLn und die Read Funktionen plötzlich anders, und low-level funktionen wie getChar oder so funktionieren gar nicht mehr.

CRT macht vieles einfach (z.b. fenster informationen wie größe, cursor position, etc.), aber kann auch zu sehr speziellen Problemen führen. Daher bin ich der Meinung, wenn man nicht die komplexe funktionalität von CRT braucht und nur einen kleinen teil der Funktionaltiät haben will, ist es meist besser einfach diesen kleinen teil selbst zu bauen.

Schönes beispiel dafür ist auch wenn man eine zeile überschreiben will (z.b. bei nem downloader will man nen progressbar updaten). Das geht mit CRT (hat glaub ich ne funkion clearline oder so), aber es geht viel einfacher so:

Code: Alles auswählen

WriteLn(#13, SomeString);
Ohne den ganzen CRT kram

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von Mathias »

Unter dos musste man ansii.sys installieren, ansonsten war nix mit Escape.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

JD55
Beiträge: 5
Registriert: Fr 29. Mai 2020, 15:41

Re: Unit Crt WriteLn in Threads bzw. Externe Programme

Beitrag von JD55 »

Danke für die Tips und Hilfe. Ich werde es probieren.

Antworten