Recent

Author Topic: [SOLVED] output redirection with unit crt inserts wrong char $0A and $0D in outp  (Read 1334 times)

Hartmut

  • Full Member
  • ***
  • Posts: 242
I use FPC 3.0.4 on Linux (Ubuntu 18.04). If you run the following code in a terminal console, you'll see 30 lines of 100 chars each:
Code: Pascal  [Select]
  1. program demo;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses crt;
  6.  
  7. var s: string[255];
  8.     i: integer;
  9.  
  10. begin
  11. s:=''; for i:=1 to 10 do  s:=s + '1234567890';
  12. for i:=1 to 30 do  writeln(i:2, ' ', s);
  13. end.  

But if you redirect the output like
Code: [Select]
demo > outfile.txtyou'll have 2 strange things in your file (see attached screenshot):
 - each line has wrongly inserted a Linefeed ($0A) after column 80
 - from line 13 on, each line is followed by an empty line, because it ends with $0A0D instead of $0A

On Windows this problem does not exist, only on Linux. I found out, that the "culprit" ist unit crt. If you omit unit crt, the problem disappears. But my "real program" uses a couple of units, which directly or indirectly use unit crt, so I can't avoid unit crt.

Question #1: is this a bug or "as designed"?

To avoid the problem I tried:
Code: Pascal  [Select]
  1. begin
  2. crt.WindMaxX:=2000;
  3. crt.WindMaxY:=dword(-1);
  4. s:=''; for i:=1 to 10 do  s:=s + '1234567890';
  5. for i:=1 to 30 do  writeln(i:2, ' ', s);
  6. end.

The redirected output now is correct, but now I get 2 Runtime errors:
Code: [Select]
hg6@i3300:~$ demo > outfile.txt
Runtime error 216 at $0805D8D4
  $0805D8D4
  $0806EC5D

Runtime error 216 at $0805D888
  $0805D888
  $0806EC5D
Runtime error 216 means "General Protection fault. The application tried to access invalid memory space." 
 
Question #2: does anybody know how to avoid these runtime errors or knows another way to avoid the $0A and $0D in the redirected output? Thanks in advance.
« Last Edit: February 05, 2019, 07:56:12 pm by Hartmut »

Hartmut

  • Full Member
  • ***
  • Posts: 242
to provide a 2nd screenshot I had to use this reply because of the maximum of 250 KB

dbannon

  • Hero Member
  • *****
  • Posts: 571
    • tomboy-ng, a rewrite of the classic Tomboy
I don't understand why crt is outputting a windows style line ending on Linux.

But maybe you could provide your own line ending, do -

write('stuff' + LineEnding);   

Davo
Lazarus 1.8, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng

valdir.marcos

  • Hero Member
  • *****
  • Posts: 724
I use FPC 3.0.4 on Linux (Ubuntu 18.04). If you run the following code in a terminal console, you'll see 30 lines of 100 chars each:
On Windows this problem does not exist, only on Linux. I found out, that the "culprit" ist unit crt. If you omit unit crt, the problem disappears. But my "real program" uses a couple of units, which directly or indirectly use unit crt, so I can't avoid unit crt.

Question #1: is this a bug or "as designed"?
 
Question #2: does anybody know how to avoid these runtime errors or knows another way to avoid the $0A and $0D in the redirected output? Thanks in advance.

I don't understand why crt is outputting a windows style line ending on Linux.
But maybe you could provide your own line ending, do -
write('stuff' + LineEnding);
Shouldn't this behaviour be reported as a bug?

Handoko

  • Hero Member
  • *****
  • Posts: 3041
  • My goal: build my own game engine using Lazarus
I think it is not bug.

- each line has wrongly inserted a Linefeed ($0A) after column 80
I remember in my old computer, the width of DOS text mode is 80. It seems the crt unit will automatically add chr($0A) when the output reach 80 characters from the left.

- from line 13 on, each line is followed by an empty line, because it ends with $0A0D instead of $0A
https://en.wikipedia.org/wiki/Text_mode#PC_common_text_modes

The common text mode for VGA is 80x25. OP's code generate 2 output lines for each single writeln. So when it reaches the line 13th, the total screen output is the line 26th. And the crt will automatically added an extra chr($0D).

The redirected output now is correct, but now I get 2 Runtime errors:
Code: [Select]
hg6@i3300:~$ demo > outfile.txt
Runtime error 216 at $0805D8D4
  $0805D8D4
  $0806EC5D

crt.WindMaxX:=2000;
crt.WindMaxY:=dword(-1);

I'm not familiar with WindMax, but it seems that the value must be below 80x25.

Question #2: does anybody know how to avoid these runtime errors or knows another way to avoid the $0A and $0D in the redirected output? Thanks in advance.

I remember I ever heard there are crt unit alternatives.

But why those behaviors don't appear on Windows? I don't know. Maybe it is OS depended.

--edit--

I checked the initialization code of crt unit. I can't understand but maybe you can understand and do a temporary redirect back to normal standard output when it writes to a file (if ParamCount > 0).

Code: Pascal  [Select]
  1. Initialization
  2. {$ifdef debugcrt}
  3.   Assign(DebugFile,'debug.txt');
  4.   ReWrite(DebugFile);
  5. {$endif}  
  6. { Redirect the standard output }
  7.   assigncrt(Output);
  8.   Rewrite(Output);
  9.   TextRec(Output).Handle:=StdOutputHandle;
  10.   assigncrt(Input);
  11.   Reset(Input);
  12.   TextRec(Input).Handle:=StdInputHandle;
  13. { Are we redirected to a file ? }
  14.   OutputRedir:= IsAtty(TextRec(Output).Handle)<>1;
  15. { does the input come from another console or from a file? }
  16.   InputRedir :=
  17.    (IsAtty(TextRec(Input).Handle)<>1) or
  18.    (not OutputRedir and
  19.     (TTYName(TextRec(Input).Handle) <> TTYName(TextRec(Output).Handle)));
  20. { Get Size of terminal and set WindMax to the window }
  21.   GetConsoleBuf;
  22.   WindMinX:=1;
  23.   WindMinY:=1;
  24.   WindMaxX:=ScreenWidth;
  25.   WindMaxY:=ScreenHeight;
  26.   WindMax:=((ScreenHeight-1) Shl 8)+(ScreenWidth-1);
  27. {Get Current X&Y or Reset to Home}
  28.   if OutputRedir then
  29.    begin
  30.      CurrX:=1;
  31.      CurrY:=1;
  32.    end
  33.   else
  34.    begin
  35.    { Set default Terminal Settings }
  36.      SetRawMode(True);
  37.    { Get current X,Y if not set already }
  38.      GetXY(CurrX,CurrY);
  39.      if (CurrX=0) then
  40.       begin
  41.         CurrX:=1;
  42.         CurrY:=1;
  43.         ttySendStr(#27'[H');
  44.       end;
  45.    {Reset Attribute (TextAttr=7 at startup)}
  46.       ttySendStr(#27'[m');
  47.     end;
« Last Edit: February 05, 2019, 05:08:37 am by Handoko »

GAN

  • Full Member
  • ***
  • Posts: 211
A String variable declared with a length specifier will always be a ShortString regardless of the compiler setting for String alias. http://wiki.freepascal.org/String

But this does not solve the problem.
Lazarus 1.6 FPC 3.0.0 Linux Mint Mate 17.2 x86_64 GTK-2
Zeos 7.1.3 - Sqlite 3.8.2

Foro Lazarus en español http://forum.lazarus.freepascal.org/index.php/board,73.0.html

Hartmut

  • Full Member
  • ***
  • Posts: 242
Thanks a lot to all for your numerous replies. I will answer them one by one. Please keep in mind, that the wronlgly inserted chars $0A and $0D only appear, when the output is redirected. Without redirection everything is ok. And the problem is only in Linux, not on Windows.

But maybe you could provide your own line ending, do -
write('stuff' + LineEnding);   
I tried it and it makes no difference.

Shouldn't this behaviour be reported as a bug?
That was my question...

I think it is not bug.

I remember in my old computer, the width of DOS text mode is 80. It seems the crt unit will automatically add chr($0A) when the output reach 80 characters from the left.
...
The common text mode for VGA is 80x25. OP's code generate 2 output lines for each single writeln. So when it reaches the line 13th, the total screen output is the line 26th. And the crt will automatically added an extra chr($0D).
This sounds convincing. But why does this behavior only occur when the output is redirected? And why not on Windows?

crt.WindMaxX:=2000;
crt.WindMaxY:=dword(-1);

I'm not familiar with WindMax, but it seems that the value must be below 80x25.
If this value must be below 80x25, then this could not be a solution for my problem. But WindMaxX and WindMaxY are of type dword. They replace the deprecated variable 'WindMax', which had type Word. So I can't believe hat they must be below 80x25.

I remember I ever heard there are crt unit alternatives.
My "real program" uses a couple of units, which directly or indirectly use unit crt, so I can't avoid unit crt.

I checked the initialization code of crt unit. I can't understand but maybe you can understand and do a temporary redirect back to normal standard output when it writes to a file (if ParamCount > 0).
Thank you for providing this code. I checked it, but as far as I understand, I see nothing which is wrong or could be adapted to solve my problem.

A String variable declared with a length specifier will always be a ShortString regardless of the compiler setting for String alias. http://wiki.freepascal.org/String
But this does not solve the problem.
That's true.

lucamar

  • Hero Member
  • *****
  • Posts: 1545
I'm not sure whether this will work but try doing

Code: [Select]
Assign(Output, ''); Rewrite(Output)
at the start of your program.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 1.8.4 & 2.0.2 w/FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

Hartmut

  • Full Member
  • ***
  • Posts: 242
I'm not sure whether this will work but try doing
Code: [Select]
Assign(Output, ''); Rewrite(Output)at the start of your program.

This works! Thank you very much for that idea, lucamar. Now my program starts like:

Code: Pascal  [Select]
  1. {$IFDEF LINUX}
  2. function ConOutRedirected: boolean;
  3.    {checks if Console Output was redirected}
  4.    begin
  5.    exit(termio.IsATTY(Output) = 0); // 0=redirected / 1=normal
  6.    end;
  7.  
  8. ...  
  9.  
  10. if ConOutRedirected then
  11.    begin Assign(Output, ''); Rewrite(Output); end;
  12. {$ENDIF}

lucamar

  • Hero Member
  • *****
  • Posts: 1545
It's an old TP/BP "trick" and since normally I don't use crt I wasn't sure it would work. Mighty glad it did :)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 1.8.4 & 2.0.2 w/FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.