fpc/ide/gdbmiproc.pas
2016-09-05 13:09:31 +00:00

157 lines
3.3 KiB
ObjectPascal

{
Copyright (c) 2015 by Nikolay Nikolov
This unit implements a class, which launches gdb in GDB/MI mode
and allows sending textual commands to it and receiving the response
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
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.
**********************************************************************}
unit GDBMIProc;
{$MODE objfpc}{$H+}
{$I globdir.inc}
interface
uses
SysUtils, Classes, Process;
type
TGDBProcess = class
private
FProcess: TProcess;
FDebugLog: TextFile;
function IsAlive: Boolean;
procedure GDBWrite(const S: string);
procedure DebugLn(const S: string);
procedure DebugErrorLn(const S: string);
public
constructor Create;
destructor Destroy; override;
function GDBReadLn: string;
procedure GDBWriteLn(const S: string);
property Alive: Boolean read IsAlive;
end;
var
GdbProgramName: string = 'gdb';
implementation
uses
fputils;
var
DebugLogEnabled: Boolean = False;
function TGDBProcess.IsAlive: Boolean;
begin
Result := Assigned(FProcess) and FProcess.Running;
end;
function TGDBProcess.GDBReadLn: string;
var
C: Char;
begin
Result := '';
while FProcess.Running do
begin
FProcess.Output.Read(C, 1);
{$ifdef windows}
{ On windows we expect both #13#10 and #10 }
if C = #13 then
begin
FProcess.Output.Read(C, 1);
if C <> #10 then
{ #13 not followed by #10, what should we do? }
Result := Result + #13;
end;
{$endif windows}
if C = #10 then
begin
DebugLn(Result);
exit;
end;
Result := Result + C;
end;
end;
constructor TGDBProcess.Create;
begin
if DebugLogEnabled then
begin
AssignFile(FDebugLog, 'gdblog.txt');
Rewrite(FDebugLog);
CloseFile(FDebugLog);
end;
FProcess := TProcess.Create(nil);
FProcess.Options := [poUsePipes, poStdErrToOutput];
if (ExeExt<>'') and (pos(ExeExt,LowerCaseStr(GdbProgramName))=0) then
FProcess.Executable := GdbProgramName+ExeExt
else
FProcess.Executable := GdbProgramName;
FProcess.Parameters.Add('--interpreter=mi');
try
FProcess.Execute;
except
on e: Exception do
begin
DebugErrorLn('Could not start GDB: ' + e.Message);
FreeAndNil(FProcess);
end;
end;
end;
destructor TGDBProcess.Destroy;
begin
FProcess.Free;
inherited Destroy;
end;
procedure TGDBProcess.DebugLn(const S: string);
begin
if DebugLogEnabled then
begin
Append(FDebugLog);
Writeln(FDebugLog, S);
CloseFile(FDebugLog);
end;
end;
procedure TGDBProcess.DebugErrorLn(const S: string);
begin
DebugLn('ERROR: ' + S);
end;
procedure TGDBProcess.GDBWrite(const S: string);
begin
FProcess.Input.Write(S[1], Length(S));
end;
procedure TGDBProcess.GDBWriteln(const S: string);
begin
if not IsAlive then
begin
DebugErrorLn('Trying to send command to a dead GDB: ' + S);
exit;
end;
DebugLn(S);
GDBWrite(S + #10);
end;
begin
if GetEnvironmentVariable('FPIDE_GDBLOG') = '1' then
DebugLogEnabled := True;
if GetEnvironmentVariable('FPIDE_GDBPROG') <> '' then
GdbProgramName := GetEnvironmentVariable('FPIDE_GDBPROG');
end.