mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-15 11:01:08 +08:00
369 lines
10 KiB
ObjectPascal
369 lines
10 KiB
ObjectPascal
{-------------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: uSimpleIDEDebugger.pas, released 2000-11-11.
|
|
|
|
The Original Code is part of the SimpleIDEDemo project, written by
|
|
Michael Hieke for the SynEdit component suite.
|
|
All Rights Reserved.
|
|
|
|
Contributors to the SynEdit project are listed in the Contributors.txt file.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of the
|
|
GNU General Public License Version 2 or later (the "GPL"), in which case
|
|
the provisions of the GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms
|
|
of the GPL and not to allow others to use your version of this file
|
|
under the MPL, indicate your decision by deleting the provisions above and
|
|
replace them with the notice and other provisions required by the GPL.
|
|
If you do not delete the provisions above, a recipient may use your version
|
|
of this file under either the MPL or the GPL.
|
|
|
|
$Id: uSimpleIDEDebugger.pas,v 1.2 2000/11/11 19:12:59 mghie Exp $
|
|
|
|
You may retrieve the latest version of this file at the SynEdit home page,
|
|
located at http://SynEdit.SourceForge.net
|
|
|
|
Known Issues:
|
|
-------------------------------------------------------------------------------}
|
|
|
|
unit uSimpleIDEDebugger;
|
|
|
|
{$I SynEdit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Classes;
|
|
|
|
type
|
|
TDebuggerState = (dsStopped, dsRunning, dsPaused);
|
|
|
|
TDebuggerLineInfo = (dlCurrentLine, dlBreakpointLine, dlExecutableLine);
|
|
TDebuggerLineInfos = set of TDebuggerLineInfo;
|
|
|
|
TBreakpointChangeEvent = procedure(Sender: TObject; ALine: integer) of object;
|
|
TDebuggerStateChangeEvent = procedure(Sender: TObject;
|
|
OldState, NewState: TDebuggerState) of object;
|
|
|
|
TSampleDebugger = class(TObject)
|
|
private
|
|
fBreakpoints: TList;
|
|
fCurrentLine: integer;
|
|
fDebuggerState: TDebuggerState;
|
|
fLineToStop: integer;
|
|
fNextInstruction: integer;
|
|
fWantedState: TDebuggerState;
|
|
fOnBreakpointChange: TBreakpointChangeEvent;
|
|
fOnCurrentLineChange: TNotifyEvent;
|
|
fOnStateChange: TDebuggerStateChangeEvent;
|
|
fOnYield: TNotifyEvent;
|
|
function CurrentLineIsBreakpoint: boolean;
|
|
procedure DoOnBreakpointChanged(ALine: integer);
|
|
procedure DoCurrentLineChanged;
|
|
procedure DoStateChange;
|
|
procedure DoYield;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function CanGotoCursor(ALine: integer): boolean;
|
|
function CanPause: boolean;
|
|
function CanRun: boolean;
|
|
function CanStep: boolean;
|
|
function CanStop: boolean;
|
|
procedure ClearAllBreakpoints;
|
|
function GetLineInfos(ALine: integer): TDebuggerLineInfos;
|
|
procedure GotoCursor(ALine: integer);
|
|
function HasBreakpoints: boolean;
|
|
function IsBreakpointLine(ALine: integer): boolean;
|
|
function IsExecutableLine(ALine: integer): boolean;
|
|
function IsRunning: boolean;
|
|
procedure Pause;
|
|
procedure Run;
|
|
procedure Step;
|
|
procedure Stop;
|
|
procedure ToggleBreakpoint(ALine: integer);
|
|
public
|
|
property CurrentLine: integer read fCurrentLine;
|
|
property OnBreakpointChange: TBreakpointChangeEvent read fOnBreakpointChange
|
|
write fOnBreakpointChange;
|
|
property OnCurrentLineChange: TNotifyEvent read fOnCurrentLineChange
|
|
write fOnCurrentLineChange;
|
|
property OnStateChange: TDebuggerStateChangeEvent read fOnStateChange
|
|
write fOnStateChange;
|
|
property OnYield: TNotifyEvent read fOnYield write fOnYield;
|
|
end;
|
|
|
|
const
|
|
SampleSource =
|
|
{ 1 } 'program Test;'#13#10 +
|
|
{ 2 } ''#13#10 +
|
|
{ 3 } 'procedure TestProc;'#13#10 +
|
|
{ 4 } 'begin'#13#10 +
|
|
{ 5 } ' DoNothing;'#13#10 +
|
|
{ 6 } 'end;'#13#10 +
|
|
{ 7 } ''#13#10 +
|
|
{ 8 } 'var'#13#10 +
|
|
{ 9 } ' i: integer;'#13#10 +
|
|
{ 10 } ''#13#10 +
|
|
{ 11 } 'begin'#13#10 +
|
|
{ 12 } ' while TRUE do'#13#10 +
|
|
{ 13 } ' TestProc;'#13#10 +
|
|
{ 14 } 'end.';
|
|
|
|
type
|
|
TSampleExecutableLine = record
|
|
Line: integer;
|
|
Delta: integer; // to change the array index
|
|
end;
|
|
|
|
const
|
|
SampleCode: array[0..7] of TSampleExecutableLine = (
|
|
(Line: 11; Delta: 1), (Line: 12; Delta: 1),
|
|
(Line: 13; Delta: 1), (Line: 4; Delta: 1),
|
|
(Line: 5; Delta: 1), (Line: 6; Delta: -4),
|
|
(Line: 14; Delta: 1), (Line: -1; Delta: 0));
|
|
ExecutableLines: array[0..6] of integer = (4, 5, 6, 11, 12, 13, 14);
|
|
|
|
implementation
|
|
|
|
{ TSampleDebugger }
|
|
|
|
constructor TSampleDebugger.Create;
|
|
begin
|
|
inherited Create;
|
|
fBreakpoints := TList.Create;
|
|
fCurrentLine := -1;
|
|
fDebuggerState := dsStopped;
|
|
fNextInstruction := Low(SampleCode);
|
|
end;
|
|
|
|
destructor TSampleDebugger.Destroy;
|
|
begin
|
|
fBreakpoints.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TSampleDebugger.CanGotoCursor(ALine: integer): boolean;
|
|
begin
|
|
Result := (fDebuggerState <> dsRunning) and IsExecutableLine(ALine);
|
|
end;
|
|
|
|
function TSampleDebugger.CanPause: boolean;
|
|
begin
|
|
Result := fDebuggerState = dsRunning;
|
|
end;
|
|
|
|
function TSampleDebugger.CanRun: boolean;
|
|
begin
|
|
Result := fDebuggerState <> dsRunning;
|
|
end;
|
|
|
|
function TSampleDebugger.CanStep: boolean;
|
|
begin
|
|
Result := fDebuggerState <> dsRunning;
|
|
end;
|
|
|
|
function TSampleDebugger.CanStop: boolean;
|
|
begin
|
|
Result := fDebuggerState <> dsStopped;
|
|
end;
|
|
|
|
function TSampleDebugger.CurrentLineIsBreakpoint: boolean;
|
|
begin
|
|
Result := (fCurrentLine = fLineToStop)
|
|
or ((fBreakpoints.Count > 0) and IsBreakpointLine(fCurrentLine));
|
|
end;
|
|
|
|
procedure TSampleDebugger.DoOnBreakpointChanged(ALine: integer);
|
|
begin
|
|
if Assigned(fOnBreakpointChange) then
|
|
fOnBreakpointChange(Self, ALine);
|
|
end;
|
|
|
|
procedure TSampleDebugger.DoCurrentLineChanged;
|
|
begin
|
|
if Assigned(fOnCurrentLineChange) then
|
|
fOnCurrentLineChange(Self);
|
|
end;
|
|
|
|
procedure TSampleDebugger.DoStateChange;
|
|
begin
|
|
if fDebuggerState <> fWantedState then begin
|
|
if fWantedState = dsStopped then
|
|
fCurrentLine := -1;
|
|
if Assigned(fOnStateChange) then
|
|
fOnStateChange(Self, fDebuggerState, fWantedState);
|
|
fDebuggerState := fWantedState;
|
|
if fWantedState <> dsRunning then
|
|
fLineToStop := -1;
|
|
DoCurrentLineChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TSampleDebugger.DoYield;
|
|
begin
|
|
if Assigned(fOnYield) then
|
|
fOnYield(Self);
|
|
end;
|
|
|
|
procedure TSampleDebugger.ClearAllBreakpoints;
|
|
begin
|
|
if fBreakpoints.Count > 0 then begin
|
|
fBreakpoints.Clear;
|
|
DoOnBreakpointChanged(-1);
|
|
end;
|
|
end;
|
|
|
|
function TSampleDebugger.GetLineInfos(ALine: integer): TDebuggerLineInfos;
|
|
begin
|
|
Result := [];
|
|
if ALine > 0 then begin
|
|
if ALine = fCurrentLine then
|
|
Include(Result, dlCurrentLine);
|
|
if IsExecutableLine(ALine) then
|
|
Include(Result, dlExecutableLine);
|
|
if IsBreakpointLine(ALine) then
|
|
Include(Result, dlBreakpointLine);
|
|
end;
|
|
end;
|
|
|
|
procedure TSampleDebugger.GotoCursor(ALine: integer);
|
|
begin
|
|
fLineToStop := ALine;
|
|
Run;
|
|
end;
|
|
|
|
function TSampleDebugger.HasBreakpoints: boolean;
|
|
begin
|
|
Result := fBreakpoints.Count > 0;
|
|
end;
|
|
|
|
function TSampleDebugger.IsBreakpointLine(ALine: integer): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := FALSE;
|
|
if ALine > 0 then begin
|
|
i := fBreakpoints.Count - 1;
|
|
while i >= 0 do begin
|
|
if integer(fBreakpoints[i]) = ALine then begin
|
|
Result := TRUE;
|
|
break;
|
|
end;
|
|
Dec(i);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSampleDebugger.IsExecutableLine(ALine: integer): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := FALSE;
|
|
if ALine > 0 then begin
|
|
i := High(ExecutableLines);
|
|
while i >= Low(ExecutableLines) do begin
|
|
if ALine = ExecutableLines[i] then begin
|
|
Result := TRUE;
|
|
break;
|
|
end;
|
|
Dec(i);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSampleDebugger.IsRunning: boolean;
|
|
begin
|
|
Result := fDebuggerState = dsRunning;
|
|
end;
|
|
|
|
procedure TSampleDebugger.Pause;
|
|
begin
|
|
if fDebuggerState = dsRunning then
|
|
fWantedState := dsPaused;
|
|
end;
|
|
|
|
procedure TSampleDebugger.Run;
|
|
var
|
|
dwTime: DWORD;
|
|
begin
|
|
fWantedState := dsRunning;
|
|
DoStateChange;
|
|
dwTime := GetTickCount + 100;
|
|
repeat
|
|
if GetTickCount >= dwTime then begin
|
|
DoYield;
|
|
dwTime := GetTickCount + 100;
|
|
end;
|
|
Step;
|
|
if fWantedState <> fDebuggerState then
|
|
DoStateChange;
|
|
until fDebuggerState <> dsRunning;
|
|
fLineToStop := -1;
|
|
end;
|
|
|
|
procedure TSampleDebugger.Step;
|
|
begin
|
|
if fDebuggerState = dsStopped then begin
|
|
fNextInstruction := Low(SampleCode);
|
|
fCurrentLine := SampleCode[fNextInstruction].Line;
|
|
fWantedState := dsPaused;
|
|
DoStateChange;
|
|
end else begin
|
|
Sleep(50);
|
|
fNextInstruction := fNextInstruction + SampleCode[fNextInstruction].Delta;
|
|
fCurrentLine := SampleCode[fNextInstruction].Line;
|
|
case fDebuggerState of
|
|
dsRunning:
|
|
begin
|
|
if CurrentLineIsBreakpoint then
|
|
fWantedState := dsPaused;
|
|
end;
|
|
else
|
|
DoCurrentLineChanged;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSampleDebugger.Stop;
|
|
begin
|
|
fWantedState := dsStopped;
|
|
DoStateChange;
|
|
end;
|
|
|
|
procedure TSampleDebugger.ToggleBreakpoint(ALine: integer);
|
|
var
|
|
SetBP: boolean;
|
|
i: integer;
|
|
begin
|
|
if ALine > 0 then begin
|
|
SetBP := TRUE;
|
|
for i := 0 to fBreakpoints.Count - 1 do begin
|
|
if integer(fBreakpoints[i]) = ALine then begin
|
|
fBreakpoints.Delete(i);
|
|
SetBP := FALSE;
|
|
break;
|
|
end else if integer(fBreakpoints[i]) > ALine then begin
|
|
fBreakpoints.Insert(i, pointer(ALine));
|
|
SetBP := FALSE;
|
|
break;
|
|
end;
|
|
end;
|
|
if SetBP then
|
|
fBreakpoints.Add(pointer(ALine));
|
|
DoOnBreakpointChanged(ALine);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|