Recent

Author Topic: GotoXy in terminal (crt) (Linux, FPC 3.2)  (Read 3562 times)

big_M

  • Jr. Member
  • **
  • Posts: 91
GotoXy in terminal (crt) (Linux, FPC 3.2)
« on: October 27, 2021, 12:21:26 pm »
Hi. Not sure if this is a bug of if I am missing something: To show the status of a calculation I want to repeatedly write over the same line in the terminal. To to that I use crt with the GotoXy function, however the result is buggy. Sometimes it works as expected, sometimes it doesn't. Here a test program:

Code: Pascal  [Select][+][-]
  1. program Repeat_WriteLn;
  2.  
  3. uses SysUtils, crt;
  4.  
  5. var i:integer;
  6.  
  7. begin
  8.  
  9.   for i:=1 to 1000 do
  10.   begin
  11.     writeLn('Line'+inttostr(i));
  12.   end;
  13.  
  14.   for i:=1 to 10000 do
  15.   begin
  16.     //GoToXy(lo(WindMin)+1,(hi(WindMax)));
  17.     GoToXy(WhereX,WhereY-1);
  18.     DelLine;
  19.     writeLn(inttostr(i));
  20.     sleep(100);
  21.   end;
  22. end.      

When running like this I expect it to go to line 1000 and overwrite it. However it goes somewhere to around the middle of the currently visible lines (depending on the size of the actual window of the terminal), or it creates new lines instead when the window is very small. So the result looks very erratic and (partly?) depends on the size of the terminal window. I tried this with xTerm and with Konsole with the same result. Sometimes however it also just works as expected (not with this test program so far, but in my actual program where I use this)

Any idea?
« Last Edit: October 27, 2021, 12:23:09 pm by big_M »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #1 on: October 27, 2021, 12:39:54 pm »
I don't think you can safely make any assumptions about positions larger than the konsole (etc.) window, and in practice you might find that resizing the window while it's running will give problems. (There's a unix-only signal when resizes happen, I don't believe that there's anything comparable for other OSes running text-mode programs).

The best workaround would probably be to move your program over to Lazarus and to output to a memo or grid... there are a few gotchas involved with keeping what you're looking at visible if extra lines are added etc., but by and large it works. You might find that you have to change things so that your computation starts on a button press or similar rather than from the program's main block, and you'll need to insert the /occasional/ Application.ProcessMessages in tight loops to make sure the GUI stays responsive.

The main reason that I'm posting this early with a bit of handwaving is to warn you that this is definitely an either/or situation: you either tinker with the Crt unit (which doesn't get much love these days) or you move to a GUI... don't try to mix them.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #2 on: October 27, 2021, 01:18:02 pm »
Ah, too bad. Thanks. You see a lot of linux programs that do this so I thought it should be easily doable. I guess that is a shortcoming then of pascal traditionally being very Windows oriented.

No, I can't move it to a GUI because the program should also be able to be executed by a server. For that purpose the status update would not be important anyway, but it would be nice to have when run manually. I think I will just leave it out then, unless someone knows an easy workaround.

ojz0r

  • Jr. Member
  • **
  • Posts: 58
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #3 on: October 27, 2021, 01:30:08 pm »
Maybe try something like this (just a speculation):

Code: Pascal  [Select][+][-]
  1. for i:=1 to 1000 do
  2. begin
  3.         GotoXY(1, i);
  4.         write('Line'+inttostr(i));
  5. end;
  6.  
  7. for i:=1 to 10000 do
  8. begin
  9.         GoToXy(1, WhereY);
  10.         write('                               '); // blank string to clear previous entry
  11.         GoToXy(1, WhereY);
  12.         write(inttostr(i));
  13.         sleep(100);
  14. end;
Just trying to learn.

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #4 on: October 27, 2021, 01:30:42 pm »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #5 on: October 27, 2021, 01:48:51 pm »
Ah, too bad. Thanks. You see a lot of linux programs that do this so I thought it should be easily doable. I guess that is a shortcoming then of pascal traditionally being very Windows oriented.

Speaking as a long-term Linux user, I can't immediately think of something that will update (say) line 1000 live unless the output is being handled with some sort of background paging buffer. I'd point in particular at top, which either redraws its entire output or updates the top one or two lines. I have to admit that I've never explored whether the escape sequences that control this sort of thing have a documented numeric limit... traditional terminals hence traditional escape sequences (in termcap/terminfo etc.) went up to around 25 lines plus sometimes an extra non-scrolling status line.

As for Pascal being Windows-oriented: that applies to the Delphi lineage obviously, but the FPC developers lean towards unix (predominantly Linux these days).

Quote
No, I can't move it to a GUI because the program should also be able to be executed by a server. For that purpose the status update would not be important anyway, but it would be nice to have when run manually. I think I will just leave it out then, unless someone knows an easy workaround.

Depends. You can attach to a background session using something like VLC, or you can run it using ssh with the graphical output tunelled. But for something like this you might be better off sending your status output to a socket, or in any event not updating your output until e.g. USR1 is sent to the process.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

ojz0r

  • Jr. Member
  • **
  • Posts: 58
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #6 on: October 27, 2021, 02:06:26 pm »
Okay i just tried my original code and that was a bit buggy..
However i tried it like this and it seems to work in my terminal atleast:

Code: Pascal  [Select][+][-]
  1. program main;
  2.  
  3. uses
  4.         crt,
  5.         sysutils;
  6.  
  7. var
  8.         i: integer;
  9.  
  10. begin
  11.         for i:=1 to 1000 do
  12.                 begin
  13.                 GotoXY(1, i);
  14.                 writeln('Line'+inttostr(i));
  15.         end;
  16.  
  17.         GoToXy(1, WhereY-1);
  18.        
  19.         for i:=1 to 1000 do
  20.         begin
  21.                 GoToXy(1, WhereY);
  22.                 write('                               '); // blank string to clear previous entry
  23.                 GoToXy(1, WhereY);
  24.                 write(inttostr(i));
  25.                 sleep(10);
  26.         end;
  27.         clrscr;
  28. end.

Ps. I changed the sleep and second for loop max value to limit the run time for testing.
Just trying to learn.

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #7 on: October 27, 2021, 02:43:10 pm »
Okay i just tried my original code and that was a bit buggy..
However i tried it like this and it seems to work in my terminal atleast:
Oh, thanks a lot ojz0r, this runs perfectly! (not really sure why it runs differently at all though)

Speaking as a long-term Linux user, I can't immediately think of something that will update (say) line 1000 live unless the output is being handled with some sort of background paging buffer. I'd point in particular at top, which either redraws its entire output or updates the top one or two lines. I have to admit that I've never explored whether the escape sequences that control this sort of thing have a documented numeric limit... traditional terminals hence traditional escape sequences (in termcap/terminfo etc.) went up to around 25 lines plus sometimes an extra non-scrolling status line.
Hm, seeing this often was maybe an overstatement, but what about apt-get? That updates the last line giving the download percentage etc. And I'm sure I came across other programs that did similar things, even with multiple lines.

Quote
Depends. You can attach to a background session using something like VLC, or you can run it using ssh with the graphical output tunelled. But for something like this you might be better off sending your status output to a socket, or in any event not updating your output until e.g. USR1 is sent to the process.
Hm, yeah, so far I just write every message in a log file. Other methods are beyond me tbh  :-[

« Last Edit: October 27, 2021, 02:52:24 pm by big_M »

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #8 on: October 27, 2021, 02:53:37 pm »
If you just want to continously update one line, use a CR Char
Code: Pascal  [Select][+][-]
  1. write('line 1', #13);
  2. Sleep(1000);
  3. write('line 2', #13);
  4. Sleep(1000);
  5. writeln('final line');

This is exactly what CR is made for, no external Unit needed

Besides this, I can always recommend laztermutils when writing console applications. It has some advantages over CRT and can do more stuff (but is restricted to stern escape sequences so only usable on current windows versions and modern Unix terminals)
« Last Edit: October 27, 2021, 02:57:33 pm by Warfley »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #9 on: October 27, 2021, 03:27:27 pm »
Hm, seeing this often was maybe an overstatement, but what about apt-get? That updates the last line giving the download percentage etc. And I'm sure I came across other programs that did similar things, even with multiple lines.

Yes, and as I said already: WITHIN THE BOUNDS OF THE TERMINAL.

Now again, as I think I've said, on unix (but not Windows) you can hook the WINCH signal so can detect when the size of the Window changes, I can't remember without checking what is made available about window size and scroll position (see e.g. the Lazarus IDE's debugger/test/watchconsolesize.pas file). And you'll find plenty of text programs which get confused when the window size changes, since in many cases they look for the window size in shell variables at startup and generally speaking there's no mechanism for these to be updated during execution.

Later: from the file I referred to above

Code: Pascal  [Select][+][-]
  1. procedure reportSize;
  2.  
  3. var
  4.   winSize: TWinSize;
  5.  
  6. begin
  7.   Write(signalCount, ': ');
  8.   FillChar(winSize, sizeof(winSize), 0);
  9.   if IsaTty(StdInputHandle) = 1 then
  10.     if fpioctl(StdInputHandle, TIOCGWINSZ, @winSize) >= 0 then
  11.       Write(winSize.ws_row, ' x ', winSize.ws_col);
  12.   WriteLn;
  13.   signalCount += 1
  14. end { reportSize } ;
  15.  
  16.  
  17. procedure winchHandler(sig: longint; {%H-}info: PSigInfo; {%H-}context: PSigContext); cdecl;
  18.  
  19. begin
  20.   case sig of
  21.     SIGWINCH: reportSize
  22.   otherwise
  23.   end
  24. end { winchHandler } ;
  25.  

...but if there were a corresponding ioctl for scroll position I'd probably have used it for demonstration purposes.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #10 on: October 27, 2021, 03:57:19 pm »
Sorry, no idea what you are on about...

All I said is that there are programs that can update a specific line. Just tested zypper. Updates last line properly regardless of the window/terminal size, resizing, amount of previous lines, or whether the last line is visible or not. That's all I want, and apparently that is possible. And so far ojz0r example works good enough for me. So please, no need to use your CAPSLOCK. Thank you
 

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #11 on: October 27, 2021, 04:14:03 pm »
Sorry, no idea what you are on about...

All I said is that there are programs that can update a specific line. Just tested zypper. Updates last line properly regardless of the window/terminal size, resizing, amount of previous lines, or whether the last line is visible or not. That's all I want, and apparently that is possible. And so far ojz0r example works good enough for me. So please, no need to use your CAPSLOCK. Thank you

Well finding the relevant bit of documentation is your problem then, since despite admitting that you don't understand what I'm trying to explain to you you're clearly under the impression that you know more about this stuff than I do.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #12 on: October 27, 2021, 04:23:57 pm »
Sorry, no idea what you are on about...

All I said is that there are programs that can update a specific line. Just tested zypper. Updates last line properly regardless of the window/terminal size, resizing, amount of previous lines, or whether the last line is visible or not. That's all I want, and apparently that is possible. And so far ojz0r example works good enough for me. So please, no need to use your CAPSLOCK. Thank you

Well finding the relevant bit of documentation is your problem then, since despite admitting that you don't understand what I'm trying to explain to you you're clearly under the impression that you know more about this stuff than I do.

MarkMLl

Sorry, but I really have no idea what gave you that impression. Clearly you have more knowlegde of this then me. I'm not sure why you all of a sudden have a very lecturing attitute

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #13 on: October 27, 2021, 04:57:08 pm »
OK, let's both try again. I think you've demonstrated that GotoXY() or whatever works for comparatively small cursor positions, i.e. within the bounds of something that approximated a physical terminal. (25 rows x 40 cols etc.).

I'm typing while trying to monitor a machine tool on a video feed...

Leaving aside for the moment that there might possibly be an ANSI sequence for the status line (line 26) at the bottom of the screen, and leaving aside that writing to a line which is /just/ off the bottom of the screen might have the expected result if the window is then resized.

Note what I said about there being the possibility of a backing store (buffer), and note what I said about the WINCH signal (normally written in caps since that's how it's defined in case-sensitive C). That leaves the possibility that if something is to be written /way/ offscreen (e.g. your line 1000) it will initially go to the backing store, and then will be drawn onto the screen when appropriately scrolled (note that for e.g. Konsole you can explicitly set the size of the backing store) or if the window is resized to be really big (or use an illegibly-tiny typeface).

When I was checking the terminal handling code earlier I found a note that the window size is held per-TTY by the kernel, but the kernel itself makes no use of that. There isn't anything equivalent for the scroll position, so it's down to Konsole etc. to make sense of that and pull stuff from the backing store when needed... an application program can't just ask the kernel for the window position (only for the size).

Generally speaking,  /something/ will make initial sizes available as shell variables:


COLORFGBG='0;15'
COLORTERM=truecolor
COLUMNS=187
...
LINES=63


but those are inherited when a program starts running, and there's no mechanism for something outside the program to update them. And that's why some things can end up in a mess if the geometry changes and they've not hooked WINCH... and this is a problem which affects plenty of programs.

And from what you've said it also affects the crt unit, but you're asking things from it that it was never intended to deliver.

Hope that clears up some of the ambiguities.

MarkMLl





MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #14 on: October 27, 2021, 06:32:52 pm »
Okay, thanks for bearing with me MarkMLI :)

I can't say I fully understand the problem, but at least I see a bit of the mechanics behind this. But if I understand this correctly, the program sends - let's say a line - to the terminal at the current cursor position, but the cursor position is only just defined within a limited bound (x,y number of cols/rows), so the terminal emulator then has to see where this line fits within it's buffer. And this can get messy, especially when the window gets resized, and therefor the number of cols and rows changes?

Anyway, it runs good enough now for me and I can live with a bit of quirkiness. The code that I posted just didn't work at all, and I was just wondering if this was supposed to work at all, or not. I didn't want to imply that it had to work with crt or anything.

 

TinyPortal © 2005-2018