Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2020-07

Writeln() behaves differently on Windows and Linux, why?

17 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bo Berglund

I am writing a cross-platform program (console program, no GUI). I am using Lazarus 2.0.8 and FPC 3.0.4 on both Linux and Windows.

During sebugging I have put numerous writeln commands in the code to track what is happening.
I started on Windows and all worked just fine according to expectations.
Every new output generated a new line on the console with the printed text left aligned.

But then I moved the code over to Linux (Raspbian Buster) and strangely this happens:

Test line 1
Test line 2
Test line 3

and so on.
It looks exactly the same if I use a terminal window on the Linux system itself as it does if I connect to the Linux machine using PuTTY from Windows...

It seems like a writeln() in the code does actually not do a carriage return on the console, just a linefeed so the console continues at the column where the previous line ended.
The messages I print out are simple text strings either showing incoming data packets or just my comment.

Typical code:

  s := 'Status changed: ' + newstat + ' msg: ' + AStatusText;
  LogStd(s);
  Writeln(s);

In the log file this obviously does not happen...

What can cause this strange behaviour?

Bo Berglund Developer in Sweden

Reply by email

Alexander Grotewohl
to Bo Berglund

perhaps try 'reset' or 'stty sane' in the terminal before running your program?

are you using the crt or video units at all?

it sounds like your terminal has gotten fudged somehow

Alexander Grotewohl https://dcclost.com ________________________________
Earlier message 50 lines
From: fpc-pascal on behalf of Bo Berglund via fpc-pascal Sent: Thursday, July 9, 2020 12:01:42 PM To: Cc: Bo Berglund Subject: [fpc-pascal] Writeln() behaves differently on Windows and Linux, why? I am writing a cross-platform program (console program, no GUI). I am using Lazarus 2.0.8 and FPC 3.0.4 on both Linux and Windows. During sebugging I have put numerous writeln commands in the code to track what is happening. I started on Windows and all worked just fine according to expectations. Every new output generated a new line on the console with the printed text left aligned. But then I moved the code over to Linux (Raspbian Buster) and strangely this happens: Test line 1 Test line 2 Test line 3 and so on. It looks exactly the same if I use a terminal window on the Linux system itself as it does if I connect to the Linux machine using PuTTY from Windows... It seems like a writeln() in the code does actually not do a carriage return on the console, just a linefeed so the console continues at the column where the previous line ended. The messages I print out are simple text strings either showing incoming data packets or just my comment. Typical code: s := 'Status changed: ' + newstat + ' msg: ' + AStatusText; LogStd(s); Writeln(s); In the log file this obviously does not happen... What can cause this strange behaviour? -- Bo Berglund Developer in Sweden

Reply by email

Bo Berglund
to Alexander Grotewohl
Alexander Grotewohl wrote
perhaps try 'reset' or 'stty sane' in the terminal before running your program?

reset in PuTTY gives me a new resized empty screen, but works exactly the same afterwards.

are you using the crt or video units at all?

Yes, see below.

it sounds like your terminal has gotten fudged somehow

I am using crt in the lpr file just for the sake of being able to shut it down sensibly:

  try
    RemoteSrv.ClientPort := 23500; //Set port explicitly
    Logger.StdLog('Starting remote server on port: ' +
IntToStr(RemoteSrv.ClientPort));
    Writeln('Starting remote server on port: ' +
IntToStr(RemoteSrv.ClientPort));
    RemoteSrv.StartServer;
    Writeln('Server running, hit q to exit!');
    repeat
      ch := ReadKey;  <== NEEDS unit crt to read the keypress
    until ch='q'; {q}
    Writeln('Shutting down server');
    Logger.StdLog('Shutting down server');
    RemoteSrv.StopServer;
  finally
    RemoteSrv.Free;
  end;
  Writeln('Terminating program');

The messages put out from this code are all left aligned.

From then on the messages are stacked sideways but on a new line.

So when the server (it is a TCP/IP socket server) gets a client call this is written in the console by the writeln() executed inside the handler as I showed in my start message.

I have tried the Linux terminal on Raspbian Buster and from Windows PuTTY, both show the same strange behaviour.

If I run the program on Windows this does not happen (same code just compiled on Windows or Linux).

Bo Berglund Developer in Sweden

Reply by email

Michael Van Canneyt
to Bo Berglund
Bo Berglund wrote 42 lines
On Thu, 9 Jul 2020 16:25:50 +0000, Alexander Grotewohl wrote: > perhaps try 'reset' or 'stty sane' in the terminal before running your program? reset in PuTTY gives me a new resized empty screen, but works exactly the same afterwards. > are you using the crt or video units at all? Yes, see below. > > it sounds like your terminal has gotten fudged somehow > I am using crt in the lpr file just for the sake of being able to shut it down sensibly: try RemoteSrv.ClientPort := 23500; //Set port explicitly Logger.StdLog('Starting remote server on port: ' + IntToStr(RemoteSrv.ClientPort)); Writeln('Starting remote server on port: ' + IntToStr(RemoteSrv.ClientPort)); RemoteSrv.StartServer; Writeln('Server running, hit q to exit!'); repeat ch := ReadKey; <== NEEDS unit crt to read the keypress until ch='q'; {q} Writeln('Shutting down server'); Logger.StdLog('Shutting down server'); RemoteSrv.StopServer; finally RemoteSrv.Free; end; Writeln('Terminating program'); The messages put out from this code are all left aligned. From then on the messages are stacked sideways but on a new line. So when the server (it is a TCP/IP socket server) gets a client call this is written in the console by the writeln() executed inside the handler as I showed in my start message.

Is this done in a thread ? Since you're using indy, I suppose so.

The crt unit is not thread safe. The implementation on Windows and Linux is totally different, which may explain the difference you see.

Michael.

Reply by email

Rainer Stratmann
to Bo Berglund: I am writing a cross-platform program (console program, no GUI). I am using Lazarus 2.0.8…

I had exactly the same behaviour.

Some setterm commands solved it, if I remember correct.

setterm -blank 0
setterm -powersave off

I guess it was the first command.
You can try it.

Bo Berglund wrote 38 lines
I am writing a cross-platform program (console program, no GUI). I am using Lazarus 2.0.8 and FPC 3.0.4 on both Linux and Windows. During sebugging I have put numerous writeln commands in the code to track what is happening. I started on Windows and all worked just fine according to expectations. Every new output generated a new line on the console with the printed text left aligned. But then I moved the code over to Linux (Raspbian Buster) and strangely this happens: Test line 1 Test line 2 Test line 3 and so on. It looks exactly the same if I use a terminal window on the Linux system itself as it does if I connect to the Linux machine using PuTTY from Windows... It seems like a writeln() in the code does actually not do a carriage return on the console, just a linefeed so the console continues at the column where the previous line ended. The messages I print out are simple text strings either showing incoming data packets or just my comment. Typical code: s := 'Status changed: ' + newstat + ' msg: ' + AStatusText; LogStd(s); Writeln(s); In the log file this obviously does not happen... What can cause this strange behaviour?

Reply by email

Bo Berglund
to Rainer Stratmann
Rainer Stratmann wrote 5 lines
I had exactly the same behaviour. Some setterm commands solved it, if I remember correct. setterm -blank 0

Response was:
setterm: terminal xterm-256color does not support --blank

setterm -powersave off

Power save is not involved here...

I guess it was the first command. You can try it.
Bo Berglund Developer in Sweden

Reply by email

Bo Berglund
to Michael Van Canneyt: Is this done in a thread ? Since you're using indy, I suppose so. The crt unit is not…
Michael Van Canneyt wrote
Is this done in a thread ? Since you're using indy, I suppose so. The crt unit is not thread safe. The implementation on Windows and Linux is totally different, which may explain the difference you see.

Is there a way to check user keyboard input in the main program while action is being done in the server's threads?

The code I first tried did not need to use crt:

  repeat
    Read(ch);
  until (ch='q');

But it acts like Readln(), in that it requires the user to press 'q' followed by ENTER in order for the loop to break.

Then I used this but it needs the crt unit:

    repeat
      ch := ReadKey;
    until ch='q'; {q}

and now the user just needs to hit q without any follow-up ENTER.

Bo Berglund Developer in Sweden

Reply by email

Michael Van Canneyt
to Bo Berglund
Bo Berglund wrote 10 lines
On Thu, 9 Jul 2020 19:36:31 +0200 (CEST), Michael Van Canneyt wrote: > Is this done in a thread ? Since you're using indy, I suppose so. > > The crt unit is not thread safe. The implementation on Windows and Linux is > totally different, which may explain the difference you see. Is there a way to check user keyboard input in the main program while action is being done in the server's threads?

Sure, do a fpselect() on file descriptor 0.

Michael.

Reply by email

Tomas Hajny
to Michael Van Canneyt
Michael Van Canneyt wrote 15 lines
On Thu, 9 Jul 2020, Bo Berglund via fpc-pascal wrote: > On Thu, 9 Jul 2020 19:36:31 +0200 (CEST), Michael Van Canneyt > wrote: > >> Is this done in a thread ? Since you're using indy, I suppose so. >> >> The crt unit is not thread safe. The implementation on Windows and >> Linux is >> totally different, which may explain the difference you see. > > Is there a way to check user keyboard input in the main program while > action is being done in the server's threads? Sure, do a fpselect() on file descriptor 0.

You can use the unit Keyboard as well, which is cross-platform.

Tomas

Reply by email

Sven Barth
to Bo Berglund: On Thu, 9 Jul 2020 16:25:50 +0000, Alexander Grotewohl reset in PuTTY gives me a new…
Bo Berglund wrote 7 lines
On Thu, 9 Jul 2020 16:25:50 +0000, Alexander Grotewohl wrote: > it sounds like your terminal has gotten fudged somehow > I am using crt in the lpr file just for the sake of being able to shut it down sensibly:

It doesn't matter where the CRT unit is used. It hooks globally for the whole program.

Show quoted text 32 lines
try RemoteSrv.ClientPort := 23500; //Set port explicitly Logger.StdLog('Starting remote server on port: ' + IntToStr(RemoteSrv.ClientPort)); Writeln('Starting remote server on port: ' + IntToStr(RemoteSrv.ClientPort)); RemoteSrv.StartServer; Writeln('Server running, hit q to exit!'); repeat ch := ReadKey; <== NEEDS unit crt to read the keypress until ch='q'; {q} Writeln('Shutting down server'); Logger.StdLog('Shutting down server'); RemoteSrv.StopServer; finally RemoteSrv.Free; end; Writeln('Terminating program'); The messages put out from this code are all left aligned. From then on the messages are stacked sideways but on a new line. So when the server (it is a TCP/IP socket server) gets a client call this is written in the console by the writeln() executed inside the handler as I showed in my start message. I have tried the Linux terminal on Raspbian Buster and from Windows PuTTY, both show the same strange behaviour. If I run the program on Windows this does not happen (same code just compiled on Windows or Linux).

You could try to use CheckSynchronize(SomeLowTimeout) inside the main loop (together with KeyPressed before using ReadKey) and then do your other output in the Indy event handlers using TThread.Synchronize or TThread.Queue.

Regards,
Sven

Reply by email

Bo Berglund
to Tomas Hajny: You can use the unit Keyboard as well, which is cross-platform. Tomas
Tomas Hajny wrote
You can use the unit Keyboard as well, which is cross-platform.

I did as follows:

uses
  ...
  Keyboard,
  ...
begin
  ...
    repeat
      //ch := ReadKey; //ReadKey is not supported by Keyboard...
      Read(ch);
    until ch='q'; {q}
  ...
end.

Now what happened is that the display is back to normal without these missing carriage returns.

But I also must hit Enter after using the q key in order for the loop to break.

So Crt was the culprit for the messed up Writeln() output, but replacing it with Keyboard brought back the old keyboard read behaviour.

Removing Keyboard and Crt from uses does not change anything, but the display now is Keyboard is not needed it seems.
At least it does not add anything in this program.

So I will have to live with q<Enter> to break the loop...

Bo Berglund Developer in Sweden

Reply by email

Tomas Hajny
to Bo Berglund
Bo Berglund wrote 19 lines
On Thu, 09 Jul 2020 23:11:34 +0200, Tomas Hajny wrote: > You can use the unit Keyboard as well, which is cross-platform. I did as follows: uses ... Keyboard, ... begin ... repeat //ch := ReadKey; //ReadKey is not supported by Keyboard... Read(ch); until ch='q'; {q} ... end.

You added unit Keyboard to the uses clause, but you don't use it. ;-)

Show quoted text 15 lines
Now what happened is that the display is back to normal without these missing carriage returns. But I also must hit Enter after using the q key in order for the loop to break. So Crt was the culprit for the messed up Writeln() output, but replacing it with Keyboard brought back the old keyboard read behaviour. Removing Keyboard and Crt from uses does not change anything, but the display now is Keyboard is not needed it seems. At least it does not add anything in this program. So I will have to live with q<Enter> to break the loop...

Not necessarily.

----
uses

  Keyboard;
var
  K: TKeyEvent;
begin
  InitKeyboard;
  while char (TKeyRecord (K).KeyCode)  'q' do
   begin
    WriteLn (char (TKeyRecord (K).KeyCode));
    K := GetKeyEvent;
   end;
  DoneKeyboard;
end.
=========

The above is just a dirty hack without handling the pressed keys properly, but it hopefully shows the basics.

Tomas

Reply by email

Travis Siegel
to Tomas Hajny: You can use the unit Keyboard as well, which is cross-platform. Tomas
Tomas Hajny wrote 19 lines
On 2020-07-09 22:58, Michael Van Canneyt wrote: > On Thu, 9 Jul 2020, Bo Berglund via fpc-pascal wrote: > >> On Thu, 9 Jul 2020 19:36:31 +0200 (CEST), Michael Van Canneyt >> wrote: >> >>> Is this done in a thread ? Since you're using indy, I suppose so. >>> >>> The crt unit is not thread safe. The implementation on Windows and >>> Linux is >>> totally different, which may explain the difference you see. >> >> Is there a way to check user keyboard input in the main program while >> action is being done in the server's threads? > > Sure, do a fpselect() on file descriptor 0. You can use the unit Keyboard as well, which is cross-platform.

cross platform doesn't mean thread safe, which is the primary reason for *not* using crt unit.  I have no idea if keyboard is thread safe or not, and I've not seen anything in this discussion to answer that question either.

Is there sample code of server code so testing can be performed outside the discussion parameters? I have looked for years for client/server information for freepascal, and never found anything, then this discussion shows some code for running a server, where did that information come from? I'm apparently really bad on searching for said information.

Reply by email

Tomas Hajny
to Travis Siegel
Travis Siegel wrote 25 lines
On 7/9/2020 5:11 PM, Tomas Hajny wrote: > On 2020-07-09 22:58, Michael Van Canneyt wrote: >> On Thu, 9 Jul 2020, Bo Berglund via fpc-pascal wrote: >> >>> On Thu, 9 Jul 2020 19:36:31 +0200 (CEST), Michael Van Canneyt >>> wrote: >>> >>>> Is this done in a thread ? Since you're using indy, I suppose so. >>>> >>>> The crt unit is not thread safe. The implementation on Windows and >>>> Linux is >>>> totally different, which may explain the difference you see. >>> >>> Is there a way to check user keyboard input in the main program >>> while >>> action is being done in the server's threads? >> >> Sure, do a fpselect() on file descriptor 0. > > You can use the unit Keyboard as well, which is cross-platform. > cross platform doesn't mean thread safe, which is the primary reason for *not* using crt unit.  I have no idea if keyboard is thread safe or not, and I've not seen anything in this discussion to answer that question either.

The point is that unit Keyboard makes no changes to the console output (unlike unit Crt). Unit Crt provides special features allowing to perform output at a particular position of the console (which makes it less reliable in multi-threaded scenarios). Without this unit, standard simple I/O is used. No, it isn't guaranteed to be thread-safe per se, you should make sure to wait for finishing output from the first thread before you start writing in another, that's your responsibility, but there are ways for achieving that (as mentioned earlier in this thread).

Show quoted text 6 lines
Is there sample code of server code so testing can be performed outside the discussion parameters? I have looked for years for client/server information for freepascal, and never found anything, then this discussion shows some code for running a server, where did that information come from? I'm apparently really bad on searching for said information.

I'm not sure how we got from a multi-threaded application to client/server, but there are certainly examples of using FPC for both client and server in our SVN (see e.g. packages/fcl-net/examples/ and packages/fcl-web/examples/).

Toams

Reply by email

Bo Berglund
to Tomas Hajny

On Fri, 10 Jul 2020 01:26:24 +0200, Tomas Hajny
wrote:

Well I do not believe the problem I am seeing is because of thread safe or not.
This test server is just running the main thread (the program itself) where the detection of keyboard entry q is in a loop to make it possible to end execution in a controlled way.
Nothing is output to the console from this loop when the server is running, only after it is commanded to shut down following detection of q.
Additionally the TIdTCPServer is created and started prior to getting to the loop. This is for sure multi-threaded but by itself does not interact with the console.

And I am using a TCP client application to connect to the TCP server and it will send one message at a time to the server when connecting in order to read back the state information for display. This is done sequentially in a single thread on the client, so messages arrive in an orderly fashion.

Show quoted text 8 lines
The point is that unit Keyboard makes no changes to the console output (unlike unit Crt). Unit Crt provides special features allowing to perform output at a particular position of the console (which makes it less reliable in multi-threaded scenarios). Without this unit, standard simple I/O is used. No, it isn't guaranteed to be thread-safe per se, you should make sure to wait for finishing output from the first thread before you start writing in another, that's your responsibility, but there are ways for achieving that (as mentioned earlier in this thread).

Instead I think that this what you mention here is the real culprit. So Crt changes the way the console displays data on the screen as you describe and this screen position access is probably what I see as the messages from inside the server being output without the CR only using LF when executing the Writeln() command.

I posted here because I thought I had discovered a bug or that I had somehow mis-interpreted the way Writeln() works and could get an immediate advice concerning the cause of the problem.

It is not that important since this is just a test program evaluating the TCP server class I am building.
It would just be more convenient to stop the application using a single keypress than two, but ths only happens while I am testing.

So by removing the loop, I can just hit Enter and it shuts down:

    Writeln('Server running, hit Enter to exit!');
    //repeat
      Read(ch);
    //until ch='q'; {q}
    Writeln('Shutting down server');

Here I use the blocking Read(ch) instead and now Enter makes the code move on to the termination phase.
It will not be used at all in the production program...

But I really asked about the *difference* between Windows and Linux behaviour because on Windows the original code works fine without any screen mess.

Bo Berglund Developer in Sweden

Reply by email

Michael Van Canneyt
to Bo Berglund
Bo Berglund wrote 10 lines
On Fri, 10 Jul 2020 01:26:24 +0200, Tomas Hajny wrote: Here I use the blocking Read(ch) instead and now Enter makes the code move on to the termination phase. It will not be used at all in the production program... But I really asked about the *difference* between Windows and Linux behaviour because on Windows the original code works fine without any screen mess.

The crt unit has been in use for 25 years. It behaves as expected.

However, times change, terminals too, so who knows.

Before answering to you I wrote a small program that does what you do. Write to screen, wait for keypress. Write again to screen.

It behaves as expected: the next line is written flushed-left.

The only difference with your program is that mine does not use threads which also write to screen.

So the hypothesis that it is the threads that are messing up the terminal.

It can also be that Indy messes up the terminal but I consider this less likely.

Michael.

Reply by email

Tomas Hajny
to Bo Berglund: On Fri, 10 Jul 2020 01:26:24 +0200, Tomas Hajny Well I do not believe the problem I am…
Bo Berglund wrote 15 lines
On Fri, 10 Jul 2020 01:26:24 +0200, Tomas Hajny wrote: Well I do not believe the problem I am seeing is because of thread safe or not. This test server is just running the main thread (the program itself) where the detection of keyboard entry q is in a loop to make it possible to end execution in a controlled way. Nothing is output to the console from this loop when the server is running, only after it is commanded to shut down following detection of q. Additionally the TIdTCPServer is created and started prior to getting to the loop. This is for sure multi-threaded but by itself does not interact with the console.

If you want others to check the real reason, you should provide your compilable source so that others may try to reproduce and analyze the problem. Obviously, there may be other issues as well like particular setting of your terminal, etc.

.
.

Show quoted text 5 lines
Instead I think that this what you mention here is the real culprit. So Crt changes the way the console displays data on the screen as you describe and this screen position access is probably what I see as the messages from inside the server being output without the CR only using LF when executing the Writeln() command.

That could be, but please note that Crt.WriteLn has been used many times without issues by others, so if it doesn't work correctly in your case, it is probably related either to other parts of your program, or to particular settings and/or features of your terminal.

Show quoted text 10 lines
I posted here because I thought I had discovered a bug or that I had somehow mis-interpreted the way Writeln() works and could get an immediate advice concerning the cause of the problem. It is not that important since this is just a test program evaluating the TCP server class I am building. It would just be more convenient to stop the application using a single keypress than two, but ths only happens while I am testing. So by removing the loop, I can just hit Enter and it shuts down:

.
.

Here I use the blocking Read(ch) instead and now Enter makes the code move on to the termination phase. It will not be used at all in the production program...

Fine. I provided an alternative solution for checking a single keypress without using unit Crt, but it's obviously up to you whether you want or need to use it. BTW, both Crt.ReadKey and Keyboard.GetKeyEvent are blocking as well, but both Crt and Keyboard provide ways for non-blocking access as well (Crt.KeyPressed and Keyboard.PollKeyEvent).

But I really asked about the *difference* between Windows and Linux behaviour because on Windows the original code works fine without any screen mess.

The difference comes from different features and behaviour of console in Windows and Linux (especially from the lack of API access to more advanced features of the console - which, to be fair, is mostly due to the need to provide universal remote access to the console / terminal in the Unix world, which is not supported in the Windows world).

Tomas

Reply by email