// Shell.pas - Zum Kontrollieren einer Bash in Linux
// Version: 1.0

// (c) 2009 by user _X_ (lazarusforum.de)
// Kontakt: laz_x(at)gmx.net

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License or version 3.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

unit shell;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, process, Controls, ExtCtrls;

type TShellEvent = procedure(Output: TStringlist) of Object;

type
  TShell = class(TComponent)
  private
    FShellCmd:     string;
    FShellProcess: TProcess;
    FReadTimer:    TIdleTimer;
    procedure ReadTimer(Sender: TObject);
  public
    constructor Create(AOwner: TComponent; Shell: string);
    destructor  Destroy();
    procedure SendCommand(cmd:string);
    OnOutput:      TShellEvent;
  public
    property ShellCmd: string read FShellCmd;
  end;

implementation

constructor TShell.Create(AOwner: TComponent; Shell: string);
begin
  inherited Create(AOwner);
  FShellCmd                 := Shell;

  FShellProcess             := TProcess.Create(AOwner);
  FShellProcess.CommandLine := Shell;
  FShellProcess.Options     := [poUsePipes, poNoConsole, poStdErrToOutPut];
  FShellProcess.Execute;

  FReadTimer                := TIdleTimer.Create(AOwner);
  FReadTimer.Interval       := 100;
  FReadTimer.Enabled        := true;
  FReadTimer.OnTimer        := @ReadTimer;
end;

destructor TShell.Destroy;
begin
  inherited Destroy();
  FShellProcess.Terminate(0);
  FShellProcess.Free;
  FReadTimer.Enabled := false;
  FReadTimer.Free;
end;

procedure TShell.ReadTimer(Sender: TObject);
var 
  NoMoreOutput: boolean;
  AStrlst:      TStringlist;

  procedure DoStuffForProcess(Process: TProcess; TheOutput: TStringlist);
  var
    Buffer: string;
    BytesAvailable: DWord;
    BytesRead:LongInt;
  begin
    if Process.Running then
    begin
      BytesAvailable := Process.Output.NumBytesAvailable;
      BytesRead := 0;
      while BytesAvailable>0 do
      begin
        SetLength(Buffer, BytesAvailable);
        BytesRead := Process.OutPut.Read(Buffer[1], BytesAvailable);
        TheOutput.Text := copy(Buffer,1, BytesRead);
        BytesAvailable := Process.Output.NumBytesAvailable;
        NoMoreOutput := false;
      end;
      if BytesRead>0 then
        if Assigned(onOutput) then begin onOutput(AStrlst); end;
    end;
  end;
begin
  repeat
    NoMoreOutput := true;
    AStrlst      := TStringlist.Create;
    DoStuffForProcess(FShellProcess, AStrlst);
    AStrlst.Free;
  until noMoreOutput;
end;

procedure TShell.SendCommand(cmd: string);
begin
  if FShellProcess.Running then begin
    cmd := cmd+#10;
    FShellProcess.Input.write(cmd[1], length(cmd));
  end;
end;

end.
