[SOLVED] Horrible console output lazarus / 32-Linux ---------------------------------------------------------------------- lebao3105 · 2026-04-02 11:51 I was constantly trying to modify set of stdout+stderr attributes to my liking: 1. Map NL to CR-NL, as LineEnding on Linux and many other OSes is only NL 2. Disable mapping CR to NL 3. And maybe more if needed termios attributes and flags can be found here: https://www.man7.org/linux/man-pages/man3/termios.3.html The code is here: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var    { Where to write stuff into. }    OutputFile: Text;     { Handle to where to write stuff into. }    OutputHandle: cint = StdOutputHandle; { Check if Handle is a terminal. }fn isATerminal(Handle: cint): bool; retn screenClear;retn setOutputStream(toStdErr: bool);fn ANSIEscapeSequence(seq: string): string; // other unrelevant parts of the unit are not included implementation uses ... var    originalOuts: array[0..1] of termios;    // 0st index: stdout    // 1st index: stderr fn isATerminal(Handle: cint): bool;begin    return(isATTY(Handle) = 1);end; retn setOutputStream(toStdErr: bool);begin    if toStdErr then begin        OutputFile := stderr;        OutputHandle := StdErrorHandle;    end    else begin        OutputFile := stdout;      OutputHandle := StdOutputHandle;    end;end; retn modifyOutputHandle_Internal(for_stderr: bool);var    indx: int;    h: cint;    modi: termios;{$push} {$warn 5057 off} // Local variable seems to be not initializedbegin    if for_stderr then begin        indx := 1;        h := StdErrorHandle;    end    else begin        indx := 0;        h := StdOutputHandle;    end;     if not isATerminal(h) then        return;     if tcgetattr(h, originalOuts[indx]) = -1 then        return; // TODO: Do something   modi := originalOuts[indx];    modi.c_oflag := modi.c_oflag or ONLCR;    modi.c_oflag := modi.c_oflag or ONLRET;    modi.c_oflag := modi.c_oflag or ONOCR;    modi.c_oflag := modi.c_oflag and not OCRNL;     if tcsetattr(h, TCSANOW, modi) = -1 then        return; // TODO: Do somethingend;{$pop} retn restoreStdOut_Internal(for_stderr: bool);var    indx: int;    h: cint;begin    if for_stderr then begin      indx := 1;        h := StdErrorHandle;    end    else begin      indx := 0;        h := StdOutputHandle;    end;     if not isATerminal(h) then        return;        if tcsetattr(h, TCSANOW, originalOuts[indx]) = -1 then        return; // TODO: Do somethingend; retn screenClear;begin    if not isATerminal(OutputHandle) then        return;     write(OutputFile, ESC_KEY+'[2J');    write(OutputFile, ESC_KEY+'[H'); // move the cursor to the top-left cornerend; fn ANSIEscapeSequence(seq: string): string; inline;begin    if isATerminal(OutputHandle) then        return(seq);    return('');end; initialization InitKeyboard; modifyOutputHandle_Inte rnal({ for stderr }true);modifyOutputHandle_Internal(false); finalizat ion DoneKeyboard; Debug('Restoring default console attributes...', []);if modifiedStdIn and not disableRawStdIn then        Error('Failed to restore standard input attributes.', []); restoreStdOut_Internal({ for stderr }true);restoreStdOut_Internal(false); end.  Broken output can be seen using program's --help option. My program uses an array of TOption, which is: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type TOption = record        Long    : String;        Kind    : EOptKind;      Short   : Char;        Help    : string;         { Write the full help message of the option, which includes:          * Short and long variants;          * Value parameter name - if any and the option needs a value;          * Default option value - if any and the option needs a value;          * The option's help message.        }        fn WriteFullHelpMessage(defaultVal: string = ''; valParam: string = 'VALUE'): string;    end; fn TOption.WriteFullHelpMessage(defaultVal: string = ''; valParam: string = 'VALUE'): string;begin    if Short = #0 then        return;     Result += ANSI_CODE_BOLD;     if Long <> '' then        Result += ('--' + Long + '  ');        // TOption.Short must not be empty as it's used for command-    // line parsing task. However ARGAs are terminated with 0ed    // entry, which of course has its Short a #0. Already been    // handled above.    Result += ('-' + Short + ANSI_CODE_RESET);     if Kind <> EOptKind.FLAG then    begin      if Long <> '' then Result += '  ';        Result += valParam;       if defaultVal <> '' then            Result += (' = ' + defaultVal);     end;     Result += (LineEnding#9 + Help + LineEnding);end;  All TOption fields are not empty. The problem is that not only NL is still not CRNL (as LineEnding is a constant), but also garbage datas get printed and help messages get (re)printed for unknown reason (I think it's not related to this topic): Code: [Select]Asks for user input.                     M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                M=��RD�3=�4+@�AD�3=�4+@--message  -m  VALUE Custom message to show instead of Press any key/Enter to continue --hide-input  -t Hide inputs from the user --require-enter                -o will show characters from -k inside squared brackets, e.g [ynYn]. If no arguments are provided, the program will simply ask for a key press, quits with exit code 0. Otherwise will quit with the exit code set to the ASCII value of the input character.                                                                                    fatal: unrecognized option: -o                                                                                                                  debug: Restoring default console attributes... Removing stdout and stderr modifications on application start (modifyOutputHandle_Internal calls) failed to work. Are there any stdout/stderr modification from the RTL / C runtime that I do not know to happen on program start? Are my modifications actually correct? Should I manually override RTL's LineEnding to CRNL? Hours later I may produce a small reproduction. By the way, some compiler flags are used: Code: [Select]-dretn:=procedure -dfn:=function -dlong:=longint -dulong:=longword -dint:=integer -dbool:=boolean -dreturn:=exit Fix: To fix, use SetTextLineEnding: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SetTextLineEnding(stderr, #13#10);SetTextLineEnding(stdout, #13#10);  However this does NOT work if you use literal NL / UNIX LineEnding. ---------------------------------------------------------------------- lebao3105 · 2026-04-02 15:40 As promised here is the reproduce program. Oddly there are no garbage data being printed. No additional compiler flags needed. ---------------------------------------------------------------------- lebao3105 · 2026-04-02 15:50 Here is the modified test.pp in order to actually require no other compiler flags. ---------------------------------------------------------------------- Thaddy · 2026-04-02 16:30 That code is neither freepascal, nor delphi. IGN what dialect are you using? ---------------------------------------------------------------------- lebao3105 · 2026-04-02 16:44 Quote from: Thaddy on April 02, 2026, 06:30:59 pmThat code is neither freepascal, nor delphi. IGN what dialect are you using? Free Pascal? For the original code, I just put some compiler definitions. The lastest reproduce code however does not need any of them. ---------------------------------------------------------------------- lebao3105 · 2026-04-02 16:51 I figured out the cause of broken output indentations. It was... InitKeyboard. Oh dear... It literally set the console to use RAW mode.