Recent

Author Topic: [SOLVED] TProcess doesn't output Carriage Returns before linebreaks  (Read 736 times)

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
I've been having this strange issue since ive moved to using readkey to get user input on console. I have not modified anything regarding the usage of TProcess and i write a CRLF after every press of enter. I'm not quite sure why this could be happening and have no clue what information is necessary.

Here is my unit where I get the user Input (also please excuse some of the messiness in my code, i will clean it up when im done with this issue :):
Code: Pascal  [Select][+][-]
  1. {$mode fpc}
  2. unit uInteractiveMode;
  3.  
  4. { uInteractiveMode.pp ; Interactive Shell for DEASH }
  5. { author: Marie Eckert                              }
  6.  
  7. {$H+}
  8.  
  9. interface
  10.   uses Crt, Dos,
  11. {$IF defined(UNIX)}
  12.        BaseUnix,
  13. {$ENDIF}
  14.        SysUtils, StrUtils, Types, uDEASHConsts, uHelpers, uInternalProcs,
  15.        uXDebug, uScriptEngine, uPathResolve, uTypes;
  16.  
  17.   procedure LaunchShell;
  18.  
  19.   const
  20.     { INPUT ACTIONS }
  21.     IA_ENTER  = 0;
  22.     IA_CLEFT  = 1;
  23.     IA_CRIGHT = 2;
  24.  
  25.   var
  26.     history          : TextFile;
  27.   {$IF defined(UNIX)}
  28.     sig_int_handler  : PSigActionRec;
  29.     sig_quit_handler : PSigActionRec;
  30.   {$ENDIF}
  31.     should_quit      : Boolean;
  32. implementation
  33. {$IF defined(UNIX)}
  34.   procedure HandleSigInterrupt(sig: cint); cdecl;
  35.   begin
  36.   end;
  37.  
  38.   procedure HandleSigQuit(sig: cint); cdecl;
  39.   begin
  40.     should_quit := True;
  41.   end;
  42.  
  43.   procedure InstallSignals;
  44.   begin
  45.     debugwriteln('Installing SIGINT handler...');
  46.     new(sig_int_handler);
  47.     sig_int_handler^.sa_Handler := SigActionHandler(@HandleSigInterrupt);
  48.     fillchar(sig_int_handler^.Sa_Mask, sizeof(sig_int_handler^.sa_mask),#0);
  49.     sig_int_handler^.Sa_Flags := 0;
  50.  
  51.   {$IF defined(LINUX)}
  52.     sig_int_handler^.Sa_Restorer:=Nil;
  53.   {$ENDIF}
  54.  
  55.     if fpSigAction(SIGINT, sig_int_handler, nil) <> 0 then
  56.     begin
  57.       deasherror('Error while installing SIGINT handler: '
  58.                     + IntToStr(fpgeterrno) + '.');
  59.       halt(1);
  60.     end;
  61.  
  62.     debugwriteln('Installing SIGQUIT handler...');
  63.     new(sig_quit_handler);
  64.     sig_quit_handler^.sa_Handler := SigActionHandler(@HandleSigQuit);
  65.     fillchar(sig_quit_handler^.Sa_Mask, sizeof(sig_quit_handler^.sa_mask), #0);
  66.     sig_quit_handler^.Sa_Flags := 0;
  67.  
  68.   {$IF defined(LINUX)}
  69.     sig_quit_handler^.Sa_Restorer:=Nil;
  70.   {$ENDIF}
  71.  
  72.     if fpSigAction(SIGQUIT, sig_quit_handler, nil) <> 0 then
  73.     begin
  74.       deasherror('Error while installing SIGQUIT handler: '
  75.                     + IntToStr(fpgeterrno) + '.');
  76.       halt(1);
  77.     end;
  78.   end;
  79. {$ENDIF}
  80.  
  81.   procedure HandleKeypress(AKey: Char; var AInputBuff: String;
  82.                             var AAction: Integer);
  83.   begin
  84.     if AKey = #0 then AKey := readkey;
  85.  
  86.     case Integer(AKey) of
  87.     13: AAction := IA_ENTER;
  88.     else
  89.     begin
  90.       write(AKey);
  91.       AInputBuff := AInputBuff + AKey;
  92.     end; end;
  93.   end;
  94.  
  95.   procedure HandleInputAction(const AAction: Integer; var AInputBuff: String);
  96.   begin
  97.     case AAction of
  98.     IA_ENTER: write(#13#10);
  99.     end;
  100.   end;
  101.  
  102.   procedure LaunchShell;
  103.   var
  104.     eval_result: TEvalResult;
  105.     script: TScript;
  106.     inbuff: String;
  107.     action: Integer;
  108.     rchar: Char;
  109.   begin
  110.     should_quit := False;
  111.  
  112.     debugwriteln('Launching shell');
  113.   {$IF defined(LINUX)}
  114.     InstallSignals;
  115.   {$ENDIF}
  116.     DoScriptExec(ResolveEnvsInPath('$HOME/.deashrc'));
  117.  
  118.     script.scriptpath := ResolveEnvsInPath('$HOME/.deash_history');
  119.     script.exited := False;
  120.     script.nline := 1;
  121.     script.incomment := False;
  122.     SetLength(script.codeblocks, 1);
  123.     script.codeblocks[0] := BLOCKTYPE_NONE;
  124.     script.registering_proc := -1;
  125.  
  126.     Assign(history, script.scriptpath);
  127.     if not FileExists(script.scriptpath) then
  128.       ReWrite(history)
  129.     else
  130.       Append(history);
  131.  
  132.     while not script.exited and not should_quit do
  133.     begin
  134.       write('deash ', GetCurrentDir(), '> ');
  135.  
  136.       inbuff := '';
  137.       repeat
  138.         action := -1;
  139.         if eof() then
  140.         begin
  141.           should_quit := True;
  142.           break;
  143.         end;
  144.  
  145.         rchar := readkey;
  146.         HandleKeypress(rchar, inbuff, action);
  147.         HandleInputAction(action, inbuff);
  148.       until (action = IA_ENTER) or should_quit;
  149.  
  150.       if should_quit then break;
  151.  
  152.       script.cline := inbuff;
  153.       write(history, script.cline);
  154.  
  155.       if script.cline = 'debug_cbtrace' then
  156.         DoInternalCmd(script.cline, [], script)
  157.       else
  158.         eval_result := Eval(script);
  159.  
  160.       script.nline := script.nline + 1;
  161.     end;
  162.  
  163.     Close(history);
  164.   end;
  165. end.
  166.  

And here is the unit which handles Process Execution:
Code: Pascal  [Select][+][-]
  1. {$mode fpc}
  2. unit uExecutor;
  3.  
  4. { uExectuor.pp ; Invoke execution handler for deash }
  5. { Author: Marie Eckert                              }
  6.  
  7. interface
  8.   uses Classes, StrUtils, SysUtils, Types, Process, uDEASHConsts, uHelpers;
  9.  
  10.   type
  11.     TInvoke = record
  12.       invoketype : Integer;
  13.       location   : String;
  14.       parameters : TStringDynArray;
  15.     end;
  16.  
  17.     TInvokeResult = record
  18.       code: Integer;
  19.       message: String;
  20.     end;
  21.  
  22.   function ExecBin(const ABinaryLocation: String; const AParameters: TStringDynArray): TInvokeResult;
  23.  
  24.   const
  25.     BUF_SIZE = 2048;
  26. implementation
  27.   function ExecBin(const ABinaryLocation: String; const AParameters: TStringDynArray): TInvokeResult;
  28.   var
  29.     process: TProcess;
  30.     parameter: String;
  31.   begin
  32.     ExecBin.code := 0;
  33.     ExecBin.message := '';
  34.  
  35.     writeln;
  36.     process := TProcess.Create(nil);
  37.     process.executable := ABinaryLocation;
  38.     for parameter in AParameters do
  39.       process.parameters.add(parameter);
  40.  
  41.     process.options := [poPassInput];
  42.     process.execute;
  43.  
  44.     while process.running do
  45.     begin
  46.     end;
  47.  
  48.     process.free;
  49.   end;
  50. end.
  51.  

Also here is sample output of what happens:
Code: Text  [Select][+][-]
  1.  
  2.       /\               USER marie@thinkarch
  3.                                                 /  \                OS "Arch Linux"
  4.                                                                                        /\   \             PKGS 1409
  5.                                                                                                                       /      \          KERNEL 6.2.12-arch1-1
  6.                                                                                                                                                                /   ,,   \          SHELL /bin/bash
  7.                          /   |  |  -\        UPTIME 43 minutes
  8.                                                               /_-''    ''-_\          CPU Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
  9.                                                                                                                                                           MEM 4958528 / 65486528 kB
  10.  
  11.  
  12. I hope those containment parameters are still nominal.
  13.                                                       deash /home/felix/workspace/deash>
  14.  
« Last Edit: April 28, 2023, 05:32:19 pm by MMarie »
i use arch btw

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12653
  • FPC developer.
Re: TProcess doesn't output Carriage Returns before linebreaks
« Reply #1 on: April 28, 2023, 11:59:39 am »
TProcess is just relays binary data. It doesn't implement any text level filtering. Maybe Crt eats it as it intercepts stdin and -out

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: TProcess doesn't output Carriage Returns before linebreaks
« Reply #2 on: April 28, 2023, 01:04:20 pm »
I've tried this fix i found in https://forum.lazarus.freepascal.org/index.php?topic=44149.0 where I just reassign output to '', but this completly strips the return carriage, so i think the only valid options are:
  1. Create my own interception which forces a CR before a LF
  2. Copy Crt to my inc/ directory and patch out the reassignment

I'm not totally happy with both options. Is there another unit that has a readkey equivalent which does not redirect stdout?
i use arch btw

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12653
  • FPC developer.
Re: TProcess doesn't output Carriage Returns before linebreaks
« Reply #3 on: April 28, 2023, 01:54:36 pm »
Maybe ncrt works for you.

Afaik some forms of input/output trapping puts the console in raw mode, with different lf characteristics.

Fred vS

  • Hero Member
  • *****
  • Posts: 3785
    • StrumPract is the musicians best friend
Re: TProcess doesn't output Carriage Returns before linebreaks
« Reply #4 on: April 28, 2023, 01:56:33 pm »
Hello.

Maybe you will have more luck using keyboard unit ( vs crt ):

Here one of the example: https://forum.lazarus.freepascal.org/index.php/topic,57682.msg429176.html#msg429176
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: TProcess doesn't output Carriage Returns before linebreaks
« Reply #5 on: April 28, 2023, 05:13:59 pm »
Hello.

Maybe you will have more luck using keyboard unit ( vs crt ):

Here one of the example: https://forum.lazarus.freepascal.org/index.php/topic,57682.msg429176.html#msg429176

It works with the keyboard unit, thanks :) Only was a bit confused in the beginning because I didnt realise that i'd have to call DoneKeyboard before i start writing to stdout again…
i use arch btw

 

TinyPortal © 2005-2018