* src/debug/dbgbrwsr.prg
! fixed to not display last column out of browser area
* src/debug/dbghelp.prg
* src/debug/dbgmenu.prg
* src/debug/debugger.prg
* use strings to to locate help topics instead of hardcoded numeric
offsets
! added support for topic specification in "HELP" command - Cl*pper
compatibility
! allow to use FILE DOS (and F D shortcut) to activate OS Shell - Cl*pper
compatibility
* src/debug/dbgentry.c
! removed recent pseudo fix with memset() missing the last byte of
allocated memory area since e59993bdb1.
The original code was correct. In Harbour trailing 0 in all strings
is set inside functions creating string items.
* package/harbour.spec
+ added MXML library
* package/mpkg_rpm.sh
* respect HB_WITH_*=no and HB_WITH_*=local envvars
3620 lines
94 KiB
Plaintext
3620 lines
94 KiB
Plaintext
/*
|
|
* The Debugger
|
|
*
|
|
* Copyright 1999 Antonio Linares <alinares@fivetechsoft.com>
|
|
* Copyright 2003-2006 Phil Krylov <phil@newstar.rinet.ru>
|
|
* Copyright 2007 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
*
|
|
* 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
|
|
* (at your option) any later version, with one exception:
|
|
*
|
|
* 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, or (at your option)
|
|
* any later version.
|
|
*
|
|
* 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 software; see the file COPYING.txt. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site https://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
/* NOTE: Don't use SAY/DevOut()/DevPos() for screen output, otherwise
|
|
the debugger output may interfere with the applications output
|
|
redirection, and is also slower. [vszakats] */
|
|
|
|
#pragma -b-
|
|
|
|
#define HB_CLS_NOTOBJECT /* do not inherit from HBObject calss */
|
|
#include "hbclass.ch"
|
|
|
|
#include "hbdebug.ch" /* for "nMode" of __dbgEntry */
|
|
#include "hbgtinfo.ch"
|
|
#include "hbmemvar.ch"
|
|
|
|
#include "box.ch"
|
|
#include "getexit.ch"
|
|
#include "inkey.ch"
|
|
#include "setcurs.ch"
|
|
|
|
|
|
/* Information structure stored in DATA aCallStack */
|
|
#define CSTACK_MODULE 1 // module name (.prg file)
|
|
#define CSTACK_FUNCTION 2 // function name
|
|
#define CSTACK_LINE 3 // start line
|
|
#define CSTACK_LEVEL 4 // eval stack level of the function
|
|
#define CSTACK_LOCALS 5 // an array with local variables
|
|
#define CSTACK_STATICS 6 // an array with static variables
|
|
|
|
/* Information structure stored in aCallStack[ n ][ CSTACK_LOCALS ]
|
|
{ cLocalName, nLocalIndex, "Local", ProcName( 1 ), nLevel } */
|
|
#define VAR_NAME 1
|
|
#define VAR_POS 2
|
|
#define VAR_TYPE 3
|
|
#define VAR_LEVEL 4 // eval stack level of the function
|
|
|
|
/* Information structure stored in ::aWatch (watchpoints) */
|
|
#define WP_TYPE 1 // wp: watchpoint, tr: tracepoint
|
|
#define WP_EXPR 2 // source of an expression
|
|
|
|
/* Information structure stored in ::aModules */
|
|
#define MODULE_NAME 1
|
|
#define MODULE_STATICS 2
|
|
#define MODULE_GLOBALS 3
|
|
#define MODULE_EXTERNGLOBALS 4
|
|
|
|
/* The dimensions of the debugger window */
|
|
#define DEBUGGER_MINROW 0
|
|
#define DEBUGGER_MINCOL 0
|
|
#define DEBUGGER_MAXROW 22
|
|
#define DEBUGGER_MAXCOL 77
|
|
|
|
/* command window scroll history */
|
|
#define DEBUGGER_CMDHIST_SIZE 64
|
|
|
|
THREAD STATIC t_oDebugger
|
|
|
|
/* debugger entry point */
|
|
PROCEDURE __dbgEntry( nMode, uParam1, uParam2, uParam3, uParam4 )
|
|
|
|
LOCAL lStartup
|
|
|
|
SWITCH nMode
|
|
CASE HB_DBG_ACTIVATE
|
|
|
|
IF ( lStartup := ( t_oDebugger == NIL ) )
|
|
t_oDebugger := HBDebugger():New()
|
|
t_oDebugger:pInfo := uParam1
|
|
ENDIF
|
|
t_oDebugger:nProcLevel := uParam2
|
|
t_oDebugger:aCallStack := uParam3
|
|
t_oDebugger:aModules := uParam4
|
|
IF lStartup
|
|
IF t_oDebugger:lRunAtStartup
|
|
__dbgSetGo( uParam1 )
|
|
RETURN
|
|
ENDIF
|
|
ENDIF
|
|
t_oDebugger:lGo := .F.
|
|
t_oDebugger:Activate()
|
|
RETURN
|
|
|
|
CASE HB_DBG_GETENTRY
|
|
|
|
__dbgSetEntry()
|
|
|
|
ENDSWITCH
|
|
|
|
RETURN
|
|
|
|
CREATE CLASS HBDebugger
|
|
|
|
VAR pInfo
|
|
VAR aWindows INIT {}
|
|
VAR nCurrentWindow INIT 1
|
|
VAR oPullDown
|
|
|
|
VAR oWndCode
|
|
VAR oWndCommand
|
|
VAR oWndStack
|
|
VAR oWndVars
|
|
|
|
VAR oBrwText
|
|
VAR cPrgName
|
|
VAR oBrwStack
|
|
VAR oBrwVars
|
|
VAR aVars INIT {}
|
|
|
|
VAR nAppDispCount
|
|
|
|
VAR nAppDirCase
|
|
VAR nAppFileCase
|
|
VAR nAppTypeAhead
|
|
VAR nAppLastKey
|
|
|
|
VAR nMaxRow
|
|
VAR nMaxCol
|
|
|
|
VAR hUserWindow
|
|
VAR hDebuggerWindow
|
|
VAR lDebuggerWindowIsOpen INIT .F.
|
|
|
|
VAR aCallStack INIT {} // stack of procedures with debug info
|
|
VAR aProcStack INIT {} // stack of all procedures
|
|
VAR nProcLevel // procedure level where the debugger is currently
|
|
VAR aModules INIT {} // array of modules with static and GLOBAL variables
|
|
VAR aWatch INIT {}
|
|
VAR aColors INIT { "W+/BG", "N/BG", "R/BG", "N+/BG", "W+/B", "GR+/B", "W/B", "N/W", "R/W", "N/BG", "R/BG" }
|
|
|
|
VAR aHistCommands
|
|
VAR aLastCommands
|
|
VAR nCommand
|
|
VAR oGetCommand
|
|
|
|
VAR lAnimate INIT .F.
|
|
VAR lEnd INIT .F.
|
|
VAR lCaseSensitive INIT .F.
|
|
VAR lMonoDisplay INIT .F.
|
|
VAR lSortVars INIT .F.
|
|
|
|
VAR cSearchString INIT ""
|
|
VAR cPathForFiles
|
|
VAR cSettingsFileName INIT "init.cld"
|
|
VAR aPathDirs
|
|
|
|
VAR nTabWidth INIT 4
|
|
VAR nSpeed INIT 0
|
|
|
|
VAR lShowPublics INIT .F.
|
|
VAR lShowPrivates INIT .F.
|
|
VAR lShowStatics INIT .F.
|
|
VAR lShowLocals INIT .F.
|
|
VAR lShowGlobals INIT .F.
|
|
VAR lShowAllGlobals INIT .F.
|
|
VAR lAll INIT .F.
|
|
VAR lShowCallStack INIT .F.
|
|
VAR lGo // stores if GO was requested
|
|
VAR lActive INIT .F.
|
|
VAR lCBTrace INIT .T. // stores if codeblock tracing is allowed
|
|
VAR oBrwPnt
|
|
VAR oWndPnt
|
|
VAR lPPO INIT .F.
|
|
VAR lRunAtStartup INIT .T. // Clipper compatible
|
|
VAR lLineNumbers INIT .T.
|
|
VAR nHelpPage INIT 1
|
|
VAR nWaFocus INIT 1
|
|
VAR lWindowsAutoSized INIT .T.
|
|
|
|
METHOD New()
|
|
METHOD Activate()
|
|
|
|
METHOD All()
|
|
|
|
METHOD Animate() INLINE iif( ::lAnimate, ::Step(), NIL )
|
|
|
|
METHOD BarDisplay()
|
|
METHOD BuildCommandWindow()
|
|
METHOD BuildBrowseStack()
|
|
|
|
METHOD CallStackProcessKey( nKey )
|
|
METHOD ClrModal() INLINE iif( ::lMonoDisplay, "N/W, W+/W, W/N, W+/N", ;
|
|
"N/W, R/W, N/BG, R/BG" )
|
|
METHOD GetColors() INLINE iif( ! ::lMonoDisplay, ::aColors, { ;
|
|
"W+/N", "W+/N", "N/W", "N/W", ;
|
|
"N/W", "N/W", "W+/N", "N/W", ;
|
|
"W+/W", "W/N", "W+/N" } )
|
|
METHOD CodeblockTrace()
|
|
METHOD CodeWindowProcessKey( nKey )
|
|
METHOD Colors()
|
|
METHOD CommandWindowProcessKey( nKey )
|
|
METHOD CommandWindowDisplay( cLine, lCmd )
|
|
METHOD DoCommand( cCommand )
|
|
METHOD DoScript( cFileName )
|
|
METHOD EditColor( nColor, oBrwColors )
|
|
METHOD EditSet( nSet, oBrwSets )
|
|
METHOD EditVar( nVar )
|
|
METHOD Exit() INLINE ::lEnd := .T.
|
|
METHOD FindNext()
|
|
METHOD FindPrevious()
|
|
METHOD GetExprValue( xExpr, lValid )
|
|
METHOD GetSourceFiles()
|
|
METHOD ModuleMatch( cModuleName1, cModuleName2 )
|
|
|
|
METHOD Global()
|
|
|
|
METHOD Go()
|
|
METHOD GoToLine( nLine )
|
|
METHOD HandleEvent()
|
|
METHOD Hide()
|
|
METHOD HideCallStack()
|
|
METHOD HideVars()
|
|
METHOD InputBox( cMsg, uValue, bValid, lEditable )
|
|
METHOD Inspect( uValue, cValueName )
|
|
METHOD IsValidStopLine( cName, nLine )
|
|
METHOD ListBox( cCaption, aItems )
|
|
METHOD LoadColors()
|
|
METHOD LoadSettings()
|
|
METHOD LoadVars()
|
|
METHOD LoadCallStack()
|
|
|
|
METHOD Local()
|
|
|
|
METHOD Locate( nMode, cValue )
|
|
|
|
METHOD MonoDisplay()
|
|
METHOD NextWindow()
|
|
METHOD Open()
|
|
METHOD OpenMenu( cName )
|
|
METHOD OpenPPO()
|
|
METHOD Resume() INLINE ::ShowCodeLine( 1 )
|
|
METHOD OSShell()
|
|
METHOD PathForFiles( cPathForFiles )
|
|
|
|
METHOD PrevWindow()
|
|
METHOD Private()
|
|
METHOD Public()
|
|
METHOD Quit()
|
|
METHOD RefreshVars()
|
|
METHOD RestoreAppScreen()
|
|
METHOD RestoreAppState()
|
|
METHOD RestoreSettings( cFileName )
|
|
METHOD RunAtStartup( lRunAtStartup )
|
|
METHOD SaveAppScreen()
|
|
METHOD SaveAppState()
|
|
METHOD SaveSettings( cFileName )
|
|
METHOD Show()
|
|
METHOD ShowAllGlobals()
|
|
METHOD ShowAppScreen()
|
|
METHOD ShowCallStack()
|
|
METHOD ShowCodeLine( nProc )
|
|
METHOD ShowHelp( cTopic )
|
|
METHOD ShowVars()
|
|
METHOD LocatePrgPath( cPrgName )
|
|
METHOD Sort() INLINE ASort( ::aVars,,, {| x, y | x[ 1 ] < y[ 1 ] } ), ;
|
|
::lSortVars := .T., ;
|
|
iif( ::oBrwVars != NIL, ::oBrwVars:RefreshAll(), NIL ), ;
|
|
iif( ::oWndVars != NIL .AND. ::oWndVars:lVisible, iif( ! ::lGo .AND. ::oBrwVars != NIL, ::oBrwVars:ForceStable(), NIL ), NIL )
|
|
|
|
METHOD Speed() INLINE ::nSpeed := ::InputBox( "Step delay (in tenths of a second)", ::nSpeed )
|
|
|
|
METHOD Stack()
|
|
METHOD Static()
|
|
|
|
METHOD Step()
|
|
|
|
METHOD TabWidth() INLINE ;
|
|
::nTabWidth := ::InputBox( "Tab width", ::nTabWidth ), ;
|
|
::oBrwText:nTabWidth := ::nTabWidth, ::oBrwText:RefreshAll()
|
|
|
|
METHOD ToggleBreakPoint( nLine, cFileName )
|
|
METHOD DeleteBreakPoint( cPos )
|
|
METHOD ListBreakPoint()
|
|
|
|
METHOD Trace()
|
|
|
|
METHOD ToCursor()
|
|
METHOD NextRoutine()
|
|
METHOD ViewSets()
|
|
METHOD WndVarsLButtonDown( nMRow, nMCol )
|
|
METHOD LineNumbers( lLineNumbers ) // Toggles numbering of source code lines
|
|
METHOD RemoveWindow( oWnd )
|
|
METHOD SearchLine()
|
|
METHOD ToggleAnimate() INLINE ::oPullDown:GetItemByIdent( "ANIMATE" ):checked := ::lAnimate := ! ::lAnimate
|
|
METHOD ToggleCaseSensitive() INLINE ::oPullDown:GetItemByIdent( "CASE" ):checked := ::lCaseSensitive := ! ::lCaseSensitive
|
|
METHOD ShowWorkAreas() INLINE __dbgShowWorkAreas( Self )
|
|
|
|
METHOD TracepointAdd( cExpr )
|
|
METHOD WatchpointAdd( cExpr )
|
|
METHOD WatchpointDel( nPos )
|
|
METHOD WatchpointsShow()
|
|
METHOD WatchpointsHide()
|
|
METHOD WatchpointEdit( nPos )
|
|
METHOD WatchpointInspect( nPos )
|
|
METHOD WatchGetInfo( nWatch )
|
|
|
|
METHOD VarGetInfo( aVar )
|
|
METHOD VarGetValue( aVar )
|
|
METHOD VarSetValue( aVar, uValue )
|
|
|
|
METHOD ResizeWindows( oWindow )
|
|
METHOD NotSupported() INLINE __dbgAlert( "Not implemented yet!" )
|
|
|
|
METHOD OpenDebuggerWindow()
|
|
METHOD CloseDebuggerWindow()
|
|
|
|
ENDCLASS
|
|
|
|
|
|
METHOD New() CLASS HBDebugger
|
|
|
|
t_oDebugger := Self
|
|
|
|
/* default the search path for files to the current directory
|
|
that way if the source is in the same directory it will still be found even if the application
|
|
changes the current directory with the SET DEFAULT command. */
|
|
::cPathForFiles := GetEnv( "HB_DBG_PATH" )
|
|
IF Empty( ::cPathForFiles )
|
|
::cPathForFiles := GetEnv( "PATH" )
|
|
ENDIF
|
|
::aPathDirs := PathToArray( ::cPathForFiles )
|
|
|
|
::lGo := ::lRunAtStartup
|
|
|
|
/* Store the initial screen dimensions for now */
|
|
::nMaxRow := MaxRow()
|
|
::nMaxCol := MaxCol()
|
|
|
|
::oPullDown := __dbgBuildMenu( Self )
|
|
|
|
::oWndCode := HBDbWindow():New( 1, 0, ::nMaxRow - 6, ::nMaxCol )
|
|
::oWndCode:bKeyPressed := {| nKey | ::CodeWindowProcessKey( nKey ) }
|
|
|
|
AAdd( ::aWindows, ::oWndCode )
|
|
|
|
::BuildCommandWindow()
|
|
::BuildBrowseStack()
|
|
|
|
IF hb_FileExists( ::cSettingsFileName )
|
|
::LoadSettings()
|
|
::lGo := ::lRunAtStartup // Once again after settings file is loaded
|
|
ENDIF
|
|
|
|
RETURN Self
|
|
|
|
METHOD PROCEDURE OpenDebuggerWindow() CLASS HBDebugger
|
|
|
|
IF ! ::lDebuggerWindowIsOpen
|
|
::hUserWindow := hb_gtInfo( HB_GTI_GETWIN )
|
|
IF ::hDebuggerWindow == NIL
|
|
::hDebuggerWindow := hb_gtInfo( HB_GTI_GETWIN, ;
|
|
{ "Debugger", DEBUGGER_MINROW, DEBUGGER_MINCOL, ;
|
|
DEBUGGER_MAXROW, DEBUGGER_MAXCOL } )
|
|
ELSE
|
|
hb_gtInfo( HB_GTI_SETWIN, ::hDebuggerWindow )
|
|
ENDIF
|
|
::lDebuggerWindowIsOpen := .T.
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE CloseDebuggerWindow() CLASS HBDebugger
|
|
|
|
IF ::lDebuggerWindowIsOpen
|
|
::hDebuggerWindow := hb_gtInfo( HB_GTI_GETWIN )
|
|
hb_gtInfo( HB_GTI_SETWIN, ::hUserWindow )
|
|
::lDebuggerWindowIsOpen := .F.
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Activate() CLASS HBDebugger
|
|
|
|
LOCAL lFirst := .F.
|
|
|
|
::LoadCallStack()
|
|
::SaveAppState()
|
|
|
|
IF ::lActive
|
|
::SaveAppScreen()
|
|
ELSE
|
|
::lActive := .T.
|
|
::Show()
|
|
IF ::lShowCallStack
|
|
::ShowCallStack()
|
|
ENDIF
|
|
lFirst := .T.
|
|
ENDIF
|
|
|
|
::LoadVars()
|
|
::ShowVars()
|
|
|
|
IF ::oWndPnt != NIL
|
|
::WatchpointsShow()
|
|
ENDIF
|
|
|
|
// show the topmost procedure
|
|
::ShowCodeLine( 1 ) // ::aCallStack[ 1 ][ CSTACK_LINE ], ::aCallStack[ 1 ][ CSTACK_MODULE ] )
|
|
|
|
// Most commands can be executed only after activation
|
|
IF lFirst
|
|
::LoadSettings()
|
|
ENDIF
|
|
|
|
::HandleEvent()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE All() CLASS HBDebugger
|
|
|
|
::lShowPublics := ::lShowPrivates := ::lShowStatics := ;
|
|
::lShowLocals := ::lShowGlobals := ::lAll := ! ::lAll
|
|
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
METHOD PROCEDURE BarDisplay() CLASS HBDebugger
|
|
|
|
LOCAL cClrItem := __dbgColors()[ 8 ]
|
|
LOCAL cClrHotKey := __dbgColors()[ 9 ]
|
|
|
|
DispBegin()
|
|
|
|
hb_Scroll( ::nMaxRow, 0, ::nMaxRow, ::nMaxCol,,, cClrItem )
|
|
hb_DispOutAt( ::nMaxRow, 0, "F1-Help F2-Zoom F3-Repeat F4-User F5-Go F6-WA F7-Here F8-Step F9-BkPt F10-Trace", cClrItem )
|
|
hb_DispOutAt( ::nMaxRow, 0, "F1", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 8, "F2", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 16, "F3", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 26, "F4", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 34, "F5", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 40, "F6", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 46, "F7", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 54, "F8", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 62, "F9", cClrHotKey )
|
|
hb_DispOutAt( ::nMaxRow, 70, "F10", cClrHotKey )
|
|
|
|
DispEnd()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE BuildBrowseStack() CLASS HBDebugger
|
|
|
|
LOCAL aColors
|
|
|
|
IF ::oBrwStack == NIL
|
|
aColors := __dbgColors()
|
|
::oBrwStack := HBDbBrowser():New( 2, ::nMaxCol - 14, ::nMaxRow - 7, ::nMaxCol - 1 )
|
|
::oBrwStack:ColorSpec := aColors[ 3 ] + "," + aColors[ 4 ] + "," + aColors[ 5 ] + "," + aColors[ 6 ]
|
|
::oBrwStack:goTopBlock := {|| ::oBrwStack:Cargo := 1 }
|
|
::oBrwStack:goBottomBlock := {|| ::oBrwStack:Cargo := Len( ::aProcStack ) }
|
|
::oBrwStack:skipBlock := {| nSkip, nOld | nOld := ::oBrwStack:Cargo, ;
|
|
::oBrwStack:Cargo += nSkip, ;
|
|
::oBrwStack:Cargo := Min( Max( ::oBrwStack:Cargo, 1 ), ;
|
|
Len( ::aProcStack ) ), ::oBrwStack:Cargo - nOld }
|
|
|
|
::oBrwStack:Cargo := 1 // Actual highligthed row
|
|
|
|
::oBrwStack:AddColumn( HBDbColumnNew( "", {|| iif( Len( ::aProcStack ) > 0, ;
|
|
PadC( ::aProcStack[ ::oBrwStack:Cargo ][ CSTACK_FUNCTION ], 14 ), Space( 14 ) ) } ) )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE BuildCommandWindow() CLASS HBDebugger
|
|
|
|
LOCAL nSize
|
|
|
|
::oWndCommand := HBDbWindow():New( ::nMaxRow - 5, 0, ::nMaxRow - 1, ::nMaxCol, "Command" )
|
|
|
|
::oWndCommand:bKeyPressed := {| nKey | ::CommandWindowProcessKey( nKey ) }
|
|
::oWndCommand:bPainted := {|| ::CommandWindowDisplay(), ;
|
|
hb_DispOutAt( ::oWndCommand:nBottom - 1, ::oWndCommand:nLeft + 1, ;
|
|
"> ", __dbgColors()[ 2 ] ), ;
|
|
::oGetCommand:SetColor( __dbgColors()[ 2 ] ):display() }
|
|
AAdd( ::aWindows, ::oWndCommand )
|
|
|
|
::aHistCommands := { "" }
|
|
::aLastCommands := { "" }
|
|
::nCommand := 1
|
|
|
|
nSize := ::oWndCommand:nRight - ::oWndCommand:nLeft - 3
|
|
::oGetCommand := HbDbInput():new( ::oWndCommand:nBottom - 1, ::oWndCommand:nLeft + 3, ;
|
|
nSize, "", __dbgColors()[ 2 ], Max( nSize, 256 ) )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE CallStackProcessKey( nKey ) CLASS HBDebugger
|
|
|
|
LOCAL n
|
|
LOCAL nSkip
|
|
LOCAL lUpdate := .F.
|
|
|
|
SWITCH nKey
|
|
CASE K_HOME
|
|
CASE K_CTRL_PGUP
|
|
CASE K_CTRL_HOME
|
|
|
|
IF ::oBrwStack:Cargo > 1
|
|
::oBrwStack:GoTop()
|
|
::oBrwStack:ForceStable()
|
|
lUpdate := .T.
|
|
ENDIF
|
|
EXIT
|
|
|
|
CASE K_END
|
|
CASE K_CTRL_PGDN
|
|
CASE K_CTRL_END
|
|
|
|
IF ::oBrwStack:Cargo < Len( ::aProcStack )
|
|
::oBrwStack:GoBottom()
|
|
::oBrwStack:ForceStable()
|
|
lUpdate := .T.
|
|
ENDIF
|
|
EXIT
|
|
|
|
CASE K_UP
|
|
|
|
IF ::oBrwStack:Cargo > 1
|
|
::oBrwStack:Up()
|
|
::oBrwStack:ForceStable()
|
|
lUpdate := .T.
|
|
ENDIF
|
|
EXIT
|
|
|
|
CASE K_DOWN
|
|
|
|
IF ::oBrwStack:Cargo < Len( ::aProcStack )
|
|
::oBrwStack:Down()
|
|
::oBrwStack:ForceStable()
|
|
lUpdate := .T.
|
|
ENDIF
|
|
EXIT
|
|
|
|
CASE K_PGUP
|
|
|
|
::oBrwStack:PageUp()
|
|
::oBrwStack:ForceStable()
|
|
lUpdate := .T.
|
|
EXIT
|
|
|
|
CASE K_PGDN
|
|
|
|
::oBrwStack:PageDown()
|
|
::oBrwStack:ForceStable()
|
|
lUpdate := .T.
|
|
EXIT
|
|
|
|
CASE K_LBUTTONDOWN
|
|
|
|
IF ( nSkip := MRow() - ::oWndStack:nTop - ::oBrwStack:RowPos ) != 0
|
|
IF nSkip > 0
|
|
FOR n := 1 TO nSkip
|
|
::oBrwStack:Down()
|
|
::oBrwStack:Stabilize()
|
|
NEXT
|
|
ELSE
|
|
FOR n := 1 TO nSkip + 2 STEP -1
|
|
::oBrwStack:Up()
|
|
::oBrwStack:Stabilize()
|
|
NEXT
|
|
ENDIF
|
|
::oBrwStack:ForceStable()
|
|
ENDIF
|
|
lUpdate := .T.
|
|
EXIT
|
|
|
|
ENDSWITCH
|
|
|
|
IF lUpdate
|
|
IF ::oWndVars != NIL .AND. ::oWndVars:lVisible
|
|
::LoadVars()
|
|
::ShowVars()
|
|
ENDIF
|
|
|
|
// jump to source line for a function
|
|
|
|
#if 0
|
|
IF ::aCallStack[ ::oBrwStack:Cargo ][ CSTACK_LINE ] != NIL
|
|
::ShowCodeLine( ::aCallStack[ ::oBrwStack:Cargo ][ CSTACK_LINE ], ::aCallStack[ ::oBrwStack:Cargo ][ CSTACK_MODULE ] )
|
|
ELSE
|
|
::GotoLine( 1 )
|
|
ENDIF
|
|
#endif
|
|
|
|
::ShowCodeLine( ::oBrwStack:Cargo )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE CodeblockTrace() CLASS HBDebugger
|
|
|
|
::oPullDown:GetItemByIdent( "CODEBLOCK" ):checked := ::lCBTrace := ! ::lCBTrace
|
|
__dbgSetCBTrace( ::pInfo, ::lCBTrace )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE CodeWindowProcessKey( nKey ) CLASS HBDebugger
|
|
|
|
IF ::oBrwText != NIL
|
|
|
|
SWITCH nKey
|
|
CASE K_CTRL_PGUP
|
|
CASE K_CTRL_HOME
|
|
|
|
::oBrwText:GoTop()
|
|
EXIT
|
|
|
|
CASE K_CTRL_PGDN
|
|
CASE K_CTRL_END
|
|
|
|
::oBrwText:GoBottom()
|
|
::oBrwText:nCol := ::oWndCode:nLeft + 1
|
|
::oBrwText:nFirstCol := ::oWndCode:nLeft + 1
|
|
EXIT
|
|
|
|
CASE K_HOME
|
|
::oBrwText:Home()
|
|
EXIT
|
|
|
|
CASE K_END
|
|
::oBrwText:End()
|
|
EXIT
|
|
|
|
CASE K_LEFT
|
|
::oBrwText:Left()
|
|
EXIT
|
|
|
|
CASE K_RIGHT
|
|
::oBrwText:Right()
|
|
EXIT
|
|
|
|
CASE K_UP
|
|
::oBrwText:Up()
|
|
EXIT
|
|
|
|
CASE K_DOWN
|
|
::oBrwText:Down()
|
|
EXIT
|
|
|
|
CASE K_PGUP
|
|
::oBrwText:PageUp()
|
|
EXIT
|
|
|
|
CASE K_PGDN
|
|
::oBrwText:PageDown()
|
|
EXIT
|
|
|
|
ENDSWITCH
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Colors() CLASS HBDebugger
|
|
|
|
LOCAL oWndColors := HBDbWindow():New( 4, 5, 16, ::nMaxCol - 5, ;
|
|
"Debugger Colors[1..11]", ::ClrModal() )
|
|
LOCAL aColors := { ;
|
|
"Border", "Text", "Text High", "Text PPO", "Text Selected", ;
|
|
"Text High Sel.", "Text PPO Sel.", "Menu", "Menu High", ;
|
|
"Menu Selected", "Menu High Sel." }
|
|
|
|
LOCAL oBrwColors := HBDbBrowser():New( oWndColors:nTop + 1, oWndColors:nLeft + 1, ;
|
|
oWndColors:nBottom - 1, oWndColors:nRight - 1 )
|
|
LOCAL nWidth := oWndColors:nRight - oWndColors:nLeft - 1
|
|
LOCAL oCol
|
|
|
|
IF ::lMonoDisplay
|
|
__dbgAlert( "Monochrome display" )
|
|
RETURN
|
|
ENDIF
|
|
|
|
oBrwColors:Cargo := { 1, {} } // Actual highligthed row
|
|
oBrwColors:ColorSpec := ::ClrModal()
|
|
oBrwColors:goTopBlock := {|| oBrwColors:cargo[ 1 ] := 1 }
|
|
oBrwColors:goBottomBlock := {|| oBrwColors:cargo[ 1 ] := Len( oBrwColors:cargo[ 2 ][ 1 ] ) }
|
|
oBrwColors:skipBlock := {| nPos | ( nPos := ArrayBrowseSkip( nPos, oBrwColors ), oBrwColors:cargo[ 1 ] := ;
|
|
oBrwColors:cargo[ 1 ] + nPos, nPos ) }
|
|
|
|
oBrwColors:AddColumn( oCol := HBDbColumnNew( "", {|| PadR( aColors[ oBrwColors:Cargo[ 1 ] ], 14 ) } ) )
|
|
oCol:defColor := { 1, 2 }
|
|
AAdd( oBrwColors:Cargo[ 2 ], aColors )
|
|
oBrwColors:AddColumn( oCol := HBDbColumnNew( "", ;
|
|
{|| PadR( '"' + ::aColors[ oBrwColors:Cargo[ 1 ] ] + '"', nWidth - 15 ) } ) )
|
|
AAdd( oBrwColors:Cargo[ 2 ], aColors )
|
|
oCol:defColor := { 1, 3 }
|
|
ocol:width := 50
|
|
oBrwColors:autolite := .F.
|
|
|
|
oWndColors:bPainted := {|| oBrwColors:ForceStable(), RefreshVarsS( oBrwColors ) }
|
|
|
|
oWndColors:bKeyPressed := {| nKey | SetsKeyPressed( nKey, oBrwColors, ;
|
|
Len( aColors ), oWndColors, "Debugger Colors", ;
|
|
{|| ::EditColor( oBrwColors:Cargo[ 1 ], oBrwColors ) } ) }
|
|
|
|
oWndColors:ShowModal()
|
|
|
|
::LoadColors()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE CommandWindowDisplay( cLine, lCmd ) CLASS HBDebugger
|
|
|
|
LOCAL n, nRow, nSize
|
|
|
|
IF cLine != NIL
|
|
cLine := iif( lCmd, "> ", " " ) + cLine
|
|
IF Len( ::aHistCommands ) >= DEBUGGER_CMDHIST_SIZE
|
|
ADel( ::aHistCommands, 1 )
|
|
::aHistCommands[ Len( ::aHistCommands ) ] := cLine
|
|
ELSE
|
|
AAdd( ::aHistCommands, cLine )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
n := Len( ::aHistCommands )
|
|
nRow := ::oWndCommand:nBottom
|
|
nSize := ::oWndCommand:nRight - ::oWndCommand:nLeft - 1
|
|
hb_DispOutAt( --nRow, ::oWndCommand:nLeft + 1, PadR( "> ", nSize ), ;
|
|
__dbgColors()[ 2 ] )
|
|
DO WHILE --nRow > ::oWndCommand:nTop
|
|
hb_DispOutAt( nRow, ::oWndCommand:nLeft + 1, ;
|
|
PadR( iif( n > 0, ::aHistCommands[ n-- ], "" ), nSize ), ;
|
|
__dbgColors()[ 2 ] )
|
|
ENDDO
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE CommandWindowProcessKey( nKey ) CLASS HBDebugger
|
|
|
|
LOCAL cCommand
|
|
LOCAL n
|
|
|
|
SWITCH nKey
|
|
CASE K_UP
|
|
CASE K_F3
|
|
IF ::nCommand > 1
|
|
::aLastCommands[ ::nCommand ] := RTrim( ::oGetCommand:getValue() )
|
|
::oGetCommand:setValue( ::aLastCommands[ --::nCommand ] ):display()
|
|
ENDIF
|
|
EXIT
|
|
CASE K_DOWN
|
|
IF ::nCommand < Len( ::aLastCommands )
|
|
::aLastCommands[ ::nCommand ] := RTrim( ::oGetCommand:getValue() )
|
|
::oGetCommand:setValue( ::aLastCommands[ ++::nCommand ] ):display()
|
|
ENDIF
|
|
EXIT
|
|
CASE K_ENTER
|
|
cCommand := RTrim( ::oGetCommand:getValue() )
|
|
IF ! Empty( cCommand )
|
|
IF ( n := hb_AScan( ::aLastCommands, cCommand, , , .T. ) ) > 0 .AND. n < Len( ::aLastCommands )
|
|
hb_ADel( ::aLastCommands, n, .T. )
|
|
ENDIF
|
|
::nCommand := Len( ::aLastCommands )
|
|
::aLastCommands[ ::nCommand ] := cCommand
|
|
AAdd( ::aLastCommands, "" )
|
|
::nCommand := Len( ::aLastCommands )
|
|
::CommandWindowDisplay( cCommand, .T. )
|
|
::DoCommand( cCommand )
|
|
ENDIF
|
|
hb_DispOutAt( ::oWndCommand:nBottom - 1, ::oWndCommand:nLeft + 1, ;
|
|
PadR( "> ", ::oWndCommand:nRight - ::oWndCommand:nLeft - 1 ), ;
|
|
__dbgColors()[ 2 ] )
|
|
::oGetCommand:setValue( "" ):display()
|
|
EXIT
|
|
OTHERWISE
|
|
::oGetCommand:applyKey( nKey )
|
|
ENDSWITCH
|
|
|
|
RETURN
|
|
|
|
|
|
/*
|
|
* ?? <expr>
|
|
* displays inspect window with value or display nothing on error
|
|
* ? <expr>
|
|
* displays either result or error description in command window
|
|
*/
|
|
METHOD DoCommand( cCommand ) CLASS HBDebugger
|
|
|
|
LOCAL aCmnd[ 3 ]
|
|
LOCAL cParam := ""
|
|
LOCAL cParam1 := ""
|
|
LOCAL cResult
|
|
LOCAL lValid
|
|
LOCAL oWindow
|
|
LOCAL n
|
|
|
|
cCommand := AllTrim( cCommand )
|
|
|
|
DO CASE
|
|
CASE Empty( cCommand )
|
|
RETURN ""
|
|
|
|
CASE hb_LeftEq( cCommand, "??" )
|
|
cParam := AllTrim( SubStr( cCommand, 3 ) )
|
|
cCommand := "??"
|
|
|
|
CASE hb_LeftEq( cCommand, "?" )
|
|
cParam := SubStr( cCommand, 2 )
|
|
cCommand := "?"
|
|
|
|
OTHERWISE
|
|
IF ( n := At( " ", cCommand ) ) > 0
|
|
cParam := AllTrim( SubStr( cCommand, n + 1 ) )
|
|
cCommand := Left( cCommand, n - 1 )
|
|
ENDIF
|
|
cCommand := Upper( cCommand )
|
|
|
|
ENDCASE
|
|
|
|
DO CASE
|
|
CASE cCommand == "??" .OR. cCommand == "?"
|
|
aCmnd[ WP_TYPE ] := cCommand
|
|
aCmnd[ WP_EXPR ] := cParam
|
|
|
|
::RestoreAppState()
|
|
cResult := ::GetExprValue( cParam, @lValid )
|
|
::SaveAppState()
|
|
|
|
IF aCmnd[ WP_TYPE ] == "??"
|
|
IF lValid
|
|
::Inspect( aCmnd[ WP_EXPR ], cResult )
|
|
ENDIF
|
|
cResult := "" // discard result
|
|
ELSEIF lValid
|
|
cResult := __dbgValToStr( cResult )
|
|
ENDIF
|
|
::RefreshVars()
|
|
|
|
CASE hb_LeftEqN( "ANIMATE", cCommand, 4 )
|
|
IF ::lActive
|
|
::lAnimate := .T.
|
|
::Animate()
|
|
ENDIF
|
|
|
|
CASE cCommand == "BP"
|
|
/* TODO: Support BP <cFuncName> */
|
|
IF Empty( cParam )
|
|
::ToggleBreakPoint()
|
|
ELSE
|
|
IF ( n := At( " ", cParam ) ) > 0
|
|
cParam1 := AllTrim( SubStr( cParam, n + 1 ) )
|
|
cParam := Left( cParam, n - 1 )
|
|
ELSE
|
|
cParam1 := ::cPrgName
|
|
ENDIF
|
|
::ToggleBreakPoint( Val( cParam ), cParam1 )
|
|
ENDIF
|
|
|
|
CASE hb_LeftEqN( "CALLSTACK", cCommand, 4 )
|
|
::Stack( Upper( cParam ) == "ON" )
|
|
|
|
CASE hb_LeftEqN( "DELETE", cCommand, 3 )
|
|
IF ( n := At( " ", cParam ) ) > 0
|
|
cParam1 := Upper( AllTrim( SubStr( cParam, n + 1 ) ) )
|
|
cParam := Left( cParam, n - 1 )
|
|
ENDIF
|
|
cParam := Upper( cParam )
|
|
|
|
DO CASE
|
|
CASE cParam == "ALL" .AND. hb_LeftEq( cParam1, "B" )
|
|
::DeleteBreakPoint( cParam )
|
|
CASE cParam == "BP"
|
|
::DeleteBreakPoint( cParam1 )
|
|
OTHERWISE
|
|
/* TODO: Support DELETE ALL [TP|WP], DELETE WP|TP <nNumber> */
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE cCommand == "DOS"
|
|
::OsShell()
|
|
|
|
CASE hb_LeftEq( "FILE", cCommand )
|
|
cParam := Upper( cParam )
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "OPEN", cParam )
|
|
::Open()
|
|
CASE hb_LeftEq( "RESUME", cParam )
|
|
::Resume()
|
|
CASE hb_LeftEq( "OS", cParam ) .OR. hb_LeftEq( "DOS", cParam )
|
|
::OSShell()
|
|
CASE hb_LeftEq( "EXIT", cParam )
|
|
::Quit()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE cCommand == "FIND"
|
|
::Locate( 0, cParam )
|
|
|
|
CASE hb_LeftEqN( "GOTO", cCommand, 4 ) .AND. Val( cParam ) > 0
|
|
::GoToLine( Val( cParam ) )
|
|
|
|
CASE hb_LeftEq( "GO", cCommand )
|
|
::Go()
|
|
|
|
CASE cCommand == "HELP"
|
|
::ShowHelp( cParam )
|
|
|
|
CASE hb_LeftEqN( "INPUT", cCommand, 4 )
|
|
IF Empty( cParam )
|
|
cParam := AllTrim( ::InputBox( "File name" ) )
|
|
IF LastKey() == K_ESC
|
|
cParam := ""
|
|
ENDIF
|
|
ENDIF
|
|
IF ! Empty( cParam )
|
|
::DoScript( cParam )
|
|
ENDIF
|
|
|
|
CASE cCommand == "LIST"
|
|
IF ( n := At( " ", cParam ) ) > 0
|
|
cParam := Left( cParam, n - 1 )
|
|
ENDIF
|
|
cParam := Upper( cParam )
|
|
|
|
DO CASE
|
|
CASE cParam == "BP"
|
|
::ListBreakPoint()
|
|
OTHERWISE
|
|
/* TODO: Support LIST WP|TP */
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE hb_LeftEq( "LOCATE", cCommand )
|
|
cParam := Upper( cParam )
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "FIND", cParam )
|
|
::Locate()
|
|
CASE hb_LeftEq( "NEXT", cParam )
|
|
::FindNext()
|
|
CASE hb_LeftEq( "PREVIOUS", cParam )
|
|
::FindPrevious()
|
|
CASE hb_LeftEq( "GOTOLINE", cParam )
|
|
::SearchLine()
|
|
CASE hb_LeftEq( "CASESENSITIVE", cParam )
|
|
::ToggleCaseSensitive()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE hb_LeftEq( "MONITOR", cCommand )
|
|
|
|
cParam := Upper( cParam )
|
|
|
|
/* Here the order of CASEs makes sense: M P is Public, while M Pr is
|
|
* Private, etc. */
|
|
DO CASE
|
|
CASE hb_LeftEq( "PUBLIC", cParam )
|
|
::Public()
|
|
CASE hb_LeftEq( "PRIVATE", cParam )
|
|
::Private()
|
|
CASE hb_LeftEq( "STATIC", cParam )
|
|
::Static()
|
|
CASE hb_LeftEq( "LOCAL", cParam )
|
|
::Local()
|
|
CASE hb_LeftEq( "GLOBAL", cParam )
|
|
::Global()
|
|
CASE hb_LeftEq( "ALL", cParam )
|
|
::All()
|
|
CASE hb_LeftEq( "SORT", cParam )
|
|
::Sort()
|
|
CASE hb_LeftEq( "SHOWALLGLOBALS", cParam )
|
|
::ShowAllGlobals()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE cCommand == "NEXT"
|
|
::FindNext()
|
|
|
|
CASE cCommand == "NUM"
|
|
SWITCH Upper( cParam )
|
|
CASE "OFF"
|
|
::LineNumbers( .F. ) ; EXIT
|
|
CASE "ON"
|
|
::LineNumbers( .T. ) ; EXIT
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDSWITCH
|
|
|
|
CASE hb_LeftEq( "OPTIONS", cCommand )
|
|
|
|
IF ( n := At( " ", cParam ) ) > 0
|
|
cParam1 := AllTrim( SubStr( cParam, n + 1 ) )
|
|
cParam := Left( cParam, n - 1 )
|
|
ENDIF
|
|
|
|
cParam := Upper( cParam )
|
|
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "PREPROCESSEDCODE", cParam )
|
|
::OpenPPO()
|
|
CASE hb_LeftEq( "LINENUMBERS", cParam )
|
|
::LineNumbers()
|
|
CASE hb_LeftEq( "EXCHANGESCREENS", cParam ) .OR. ;
|
|
hb_LeftEq( "SWAPONINPUT", cParam ) .OR. ;
|
|
hb_LeftEq( "MENUBAR", cParam )
|
|
::NotSupported()
|
|
CASE hb_LeftEq( "CODEBLOCKTRACE", cParam )
|
|
::CodeblockTrace()
|
|
CASE hb_LeftEq( "MONODISPLAY", cParam )
|
|
::MonoDisplay()
|
|
CASE hb_LeftEq( "COLORS", cParam )
|
|
IF Empty( cParam1 )
|
|
::Colors()
|
|
ELSE
|
|
cParam1 := SubStr( cParam1, At( "{", cParam1 ) + 1 )
|
|
FOR n := 1 TO 11
|
|
IF "," $ cParam1
|
|
::aColors[ n ] := ;
|
|
StrTran( Left( cParam1, At( ",", cParam1 ) - 1 ), '"' )
|
|
cParam1 := SubStr( cParam1, At( ",", cParam1 ) + 1 )
|
|
ELSE
|
|
::aColors[ n ] := ;
|
|
StrTran( Left( cParam1, At( "}", cParam1 ) - 1 ), '"' )
|
|
ENDIF
|
|
NEXT
|
|
::LoadColors()
|
|
ENDIF
|
|
CASE hb_LeftEq( "TABWIDTH", cParam )
|
|
IF Empty( cParam1 )
|
|
::TabWidth()
|
|
ELSE
|
|
::nTabWidth := Val( Left( cParam1, 3 ) )
|
|
ENDIF
|
|
CASE hb_LeftEq( "PATHFORFILES", cParam )
|
|
::PathForFiles( AllTrim( cParam1 ) )
|
|
CASE hb_LeftEq( "RUNATSTARTUP", cParam )
|
|
::RunAtStartup( .T. )
|
|
CASE hb_LeftEq( "NORUNATSTARTUP", cParam )
|
|
::RunAtStartup( .F. )
|
|
CASE hb_LeftEq( "SAVESETTINGS", cParam )
|
|
::SaveSettings( AllTrim( cParam1 ) )
|
|
CASE hb_LeftEq( "RESTORESETTINGS", cParam )
|
|
::RestoreSettings( AllTrim( cParam1 ) )
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE hb_LeftEqN( "OUTPUT", cCommand, 4 )
|
|
::ShowAppScreen()
|
|
|
|
CASE hb_LeftEq( "POINT", cCommand )
|
|
cParam := Upper( cParam )
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "WATCHPOINT", cParam )
|
|
::WatchpointAdd()
|
|
CASE hb_LeftEq( "TRACEPOINT", cParam )
|
|
::TracepointAdd()
|
|
CASE hb_LeftEq( "BREAKPOINT", cParam )
|
|
::ToggleBreakPoint()
|
|
CASE hb_LeftEq( "DELETE", cParam )
|
|
::WatchpointDel()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE cCommand == "PREV"
|
|
::FindPrevious()
|
|
|
|
CASE hb_LeftEq( "QUIT", cCommand )
|
|
::Quit()
|
|
|
|
/* TODO: Support RESTART */
|
|
|
|
CASE hb_LeftEqN( "RESUME", cCommand, 4 )
|
|
::Resume()
|
|
|
|
CASE hb_LeftEq( "RUN", cCommand )
|
|
cParam := Upper( cParam )
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "ANIMATE", cParam )
|
|
::ToggleAnimate()
|
|
::Animate()
|
|
CASE hb_LeftEq( "STEP", cParam )
|
|
::Step()
|
|
CASE hb_LeftEq( "TRACE", cParam )
|
|
::Trace()
|
|
CASE hb_LeftEq( "GO", cParam )
|
|
::Go()
|
|
CASE hb_LeftEq( "TOCURSOR", cParam )
|
|
::ToCursor()
|
|
CASE hb_LeftEq( "NEXTROUTINE", cParam )
|
|
::NextRoutine()
|
|
CASE hb_LeftEq( "SPEED", cParam )
|
|
::Speed()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE hb_LeftEqN( "SPEED", cCommand, 4 )
|
|
IF Empty( cParam )
|
|
::nSpeed := 0
|
|
ELSE
|
|
::nSpeed := Val( cParam )
|
|
ENDIF
|
|
|
|
CASE cCommand == "STEP"
|
|
::Step()
|
|
|
|
CASE cCommand == "TP"
|
|
::TracepointAdd( cParam )
|
|
|
|
CASE hb_LeftEq( "VIEW", cCommand )
|
|
cParam := Upper( cParam )
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "SETS", cParam )
|
|
::ViewSets()
|
|
CASE hb_LeftEq( "WORKAREAS", cParam )
|
|
::ShowWorkAreas()
|
|
CASE hb_LeftEq( "APPSCREEN", cParam )
|
|
::ShowAppScreen()
|
|
CASE hb_LeftEq( "CALLSTACK", cParam )
|
|
::Stack()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE hb_LeftEq( "WINDOW", cCommand )
|
|
|
|
IF ( n := At( " ", cParam ) ) > 0
|
|
cParam1 := AllTrim( SubStr( cParam, n + 1 ) )
|
|
cParam := Left( cParam, n - 1 )
|
|
ENDIF
|
|
|
|
cParam := Upper( cParam )
|
|
DO CASE
|
|
CASE Empty( cParam )
|
|
::OpenMenu( cCommand )
|
|
CASE hb_LeftEq( "NEXT", cParam )
|
|
::NextWindow()
|
|
CASE hb_LeftEq( "PREV", cParam )
|
|
::PrevWindow()
|
|
CASE hb_LeftEq( "MOVE", cParam )
|
|
IF Empty( cParam1 )
|
|
::NotSupported()
|
|
ELSE
|
|
oWindow := ::aWindows[ ::nCurrentWindow ]
|
|
IF ( n := At( " ", cParam1 ) ) > 0
|
|
n := Val( SubStr( cParam1, n ) )
|
|
ENDIF
|
|
oWindow:Resize( Val( cParam1 ), n, ;
|
|
oWindow:nBottom + Val( cParam1 ) - oWindow:nTop, ;
|
|
oWindow:nRight + n - oWindow:nLeft )
|
|
::lWindowsAutoSized := .F.
|
|
ENDIF
|
|
CASE hb_LeftEq( "SIZE", cParam )
|
|
IF Empty( cParam1 )
|
|
::NotSupported()
|
|
ELSE
|
|
IF Val( cParam1 ) >= 2 .AND. ;
|
|
( n := At( " ", cParam1 ) ) > 0 .AND. Val( SubStr( cParam1, n ) ) > 0
|
|
oWindow := ::aWindows[ ::nCurrentWindow ]
|
|
oWindow:Resize( oWindow:nTop, oWindow:nLeft, ;
|
|
Val( cParam1 ) - 1 + oWindow:nTop, ;
|
|
Val( SubStr( cParam1, n ) ) - 1 + oWindow:nLeft )
|
|
::lWindowsAutoSized := .F.
|
|
ENDIF
|
|
ENDIF
|
|
CASE hb_LeftEq( "ZOOM", cParam ) .OR. ;
|
|
hb_LeftEq( "ICONIZE", cParam ) .OR. ;
|
|
hb_LeftEq( "TILE", cParam )
|
|
::NotSupported()
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
ENDCASE
|
|
|
|
CASE cCommand == "WP"
|
|
::WatchpointAdd( cParam )
|
|
|
|
OTHERWISE
|
|
cResult := "Command error"
|
|
|
|
ENDCASE
|
|
|
|
IF ::lActive
|
|
|
|
hb_DispOutAt( ::oWndCommand:nBottom - 1, ::oWndCommand:nLeft + 1, ;
|
|
Space( ::oWndCommand:nRight - ::oWndCommand:nLeft - 1 ), ;
|
|
__dbgColors()[ 2 ] )
|
|
IF ! Empty( cResult )
|
|
::CommandWindowDisplay( cResult, .F. )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN cResult
|
|
|
|
|
|
METHOD PROCEDURE DoScript( cFileName ) CLASS HBDebugger
|
|
|
|
LOCAL cInfo
|
|
LOCAL n, nPos
|
|
LOCAL cLine
|
|
LOCAL nLen
|
|
|
|
IF hb_FileExists( cFileName )
|
|
cInfo := MemoRead( cFileName )
|
|
nLen := MLCount( cInfo, 16384,, .F., .T. )
|
|
FOR n := 1 TO nLen
|
|
cLine := AllTrim( MemoLine( cInfo, 16384, n,, .F., .T. ) )
|
|
IF ::lActive .OR. ( ( nPos := At( " ", cLine ) ) > 0 .AND. ;
|
|
hb_LeftEqI( "OPTIONS", Left( cLine, nPos - 1 ) ) )
|
|
// In inactive debugger, only "OPTIONS" commands can be executed safely
|
|
::DoCommand( cLine )
|
|
ENDIF
|
|
NEXT
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE EditColor( nColor, oBrwColors ) CLASS HBDebugger
|
|
|
|
LOCAL cColor := PadR( '"' + ::aColors[ nColor ] + '"', ;
|
|
oBrwColors:getColumn( 2 ):Width )
|
|
|
|
oBrwColors:RefreshCurrent()
|
|
oBrwColors:ForceStable()
|
|
|
|
IF __dbgInput( Row(), Col() + 15,, @cColor, ;
|
|
{| cColor | Type( cColor ) == "C" .OR. ;
|
|
( __dbgAlert( "Must be string" ), .F. ) }, ;
|
|
SubStr( ::ClrModal(), 5 ) )
|
|
::aColors[ nColor ] := &cColor
|
|
ENDIF
|
|
|
|
oBrwColors:RefreshCurrent()
|
|
oBrwColors:ForceStable()
|
|
|
|
RETURN
|
|
|
|
METHOD PROCEDURE EditSet( nSet, oBrwSets ) CLASS HBDebugger
|
|
|
|
LOCAL cSet := __dbgValToExp( Set( nSet ) )
|
|
LOCAL cType := ValType( Set( nSet ) )
|
|
|
|
oBrwSets:RefreshCurrent()
|
|
oBrwSets:ForceStable()
|
|
|
|
IF __dbgInput( Row(), Col() + 13,, @cSet, ;
|
|
{| cSet | Type( cSet ) == cType .OR. ;
|
|
( __dbgAlert( "Must be of type '" + cType + "'" ), .F. ) }, ;
|
|
SubStr( ::ClrModal(), 5 ), 256 )
|
|
Set( nSet, &cSet )
|
|
ENDIF
|
|
|
|
oBrwSets:RefreshCurrent()
|
|
oBrwSets:ForceStable()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE EditVar( nVar ) CLASS HBDebugger
|
|
|
|
LOCAL cVarName := ::aVars[ nVar ][ 1 ]
|
|
LOCAL cVarStr
|
|
LOCAL oErr
|
|
|
|
LOCAL uVarValue := ::VarGetValue( ::aVars[ nVar ] )
|
|
|
|
IF ValType( uVarValue ) $ "AHOPB"
|
|
::InputBox( cVarName, uVarValue,, .F. )
|
|
ELSE
|
|
cVarStr := ::InputBox( cVarName, __dbgValToExp( uVarValue ), __dbgExprValidBlock() )
|
|
|
|
IF LastKey() != K_ESC
|
|
BEGIN SEQUENCE WITH {| oErr | Break( oErr ) }
|
|
::VarSetValue( ::aVars[ nVar ], &cVarStr )
|
|
RECOVER USING oErr
|
|
__dbgAlert( oErr:description )
|
|
END SEQUENCE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
::oBrwVars:RefreshCurrent()
|
|
::oBrwVars:ForceStable()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD FindNext() CLASS HBDebugger
|
|
RETURN ::Locate( 1, ::cSearchString )
|
|
|
|
|
|
METHOD FindPrevious() CLASS HBDebugger
|
|
RETURN ::Locate( 2, ::cSearchString )
|
|
|
|
|
|
METHOD GetExprValue( xExpr, lValid ) CLASS HBDebugger
|
|
|
|
LOCAL xResult
|
|
LOCAL oErr
|
|
|
|
lValid := .F.
|
|
|
|
BEGIN SEQUENCE WITH {| oErr | Break( oErr ) }
|
|
xResult := __dbgGetExprValue( ::pInfo, xExpr, @lValid )
|
|
IF ! lValid
|
|
xResult := "Syntax error"
|
|
ENDIF
|
|
RECOVER USING oErr
|
|
xResult := oErr:operation + ": " + oErr:description
|
|
IF HB_ISARRAY( oErr:args )
|
|
xResult += "; arguments:"
|
|
AEval( oErr:args, {| x, i | xResult += iif( i == 1, " ", ", " ) + ;
|
|
AllTrim( __dbgValToStr( x ) ) } )
|
|
ENDIF
|
|
lValid := .F.
|
|
END SEQUENCE
|
|
|
|
RETURN xResult
|
|
|
|
|
|
METHOD GetSourceFiles() CLASS HBDebugger
|
|
RETURN __dbgGetSourceFiles( ::pInfo )
|
|
|
|
|
|
METHOD ModuleMatch( cModuleName1, cModuleName2 ) CLASS HBDebugger
|
|
RETURN __dbgModuleMatch( ::pInfo, cModuleName1, cModuleName2 )
|
|
|
|
|
|
METHOD PROCEDURE Global() CLASS HBDebugger
|
|
|
|
::lShowGlobals := ! ::lShowGlobals
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Go() CLASS HBDebugger
|
|
|
|
// we are starting to run again so reset to the deepest call if
|
|
// displaying stack
|
|
IF ::oBrwStack != NIL
|
|
::oBrwStack:GoTop()
|
|
ENDIF
|
|
::RestoreAppScreen()
|
|
::RestoreAppState()
|
|
__dbgSetGo( ::pInfo )
|
|
::Exit()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE GotoLine( nLine ) CLASS HBDebugger
|
|
|
|
::oBrwText:GotoLine( nLine )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE HandleEvent() CLASS HBDebugger
|
|
|
|
LOCAL nPopup
|
|
LOCAL oWnd
|
|
LOCAL nKey
|
|
LOCAL nMRow
|
|
LOCAL nMCol
|
|
|
|
IF ::lAnimate
|
|
IF ::nSpeed != 0
|
|
Inkey( ::nSpeed / 10 )
|
|
ENDIF
|
|
IF __dbgInvokeDebug() // NextKey() == K_ALT_D
|
|
::lAnimate := .F.
|
|
ELSE
|
|
::Step()
|
|
RETURN
|
|
ENDIF
|
|
ENDIF
|
|
|
|
::lEnd := .F.
|
|
|
|
DO WHILE ! ::lEnd
|
|
|
|
IF ::oWndCommand:lFocused
|
|
::oGetCommand:showCursor()
|
|
ELSEIF ::oWndCode:lFocused .AND. ::oBrwText != NIL
|
|
::oBrwText:ForceStable()
|
|
SetCursor( SC_SPECIAL1 )
|
|
ELSE
|
|
SetCursor( SC_NONE )
|
|
ENDIF
|
|
nKey := __dbgInkey()
|
|
SetCursor( SC_NONE )
|
|
|
|
IF nKey == K_ALT_X
|
|
t_oDebugger:Quit()
|
|
ELSEIF ::oPullDown:IsOpen()
|
|
::oPullDown:ProcessKey( nKey )
|
|
IF ::oPullDown:nOpenPopup == 0 // Closed
|
|
::aWindows[ ::nCurrentWindow ]:Show( .T. )
|
|
ENDIF
|
|
ELSE
|
|
SWITCH nKey
|
|
CASE K_LDBLCLK
|
|
|
|
IF MRow() != 0 .AND. MRow() != ::nMaxRow
|
|
|
|
nMRow := MRow()
|
|
nMCol := MCol()
|
|
FOR EACH oWnd IN ::aWindows
|
|
IF oWnd:IsOver( nMRow, nMCol )
|
|
IF ! oWnd:lFocused
|
|
::aWindows[ ::nCurrentWindow ]:Show( .F. )
|
|
::nCurrentWindow := oWnd:__enumIndex()
|
|
oWnd:Show( .T. )
|
|
ENDIF
|
|
oWnd:LDblClick( nMRow, nMCol )
|
|
EXIT
|
|
ENDIF
|
|
NEXT
|
|
ENDIF
|
|
EXIT
|
|
|
|
CASE K_LBUTTONDOWN
|
|
|
|
IF MRow() == 0
|
|
|
|
IF ( nPopup := ::oPullDown:GetItemOrdByCoors( 0, MCol() ) ) != 0
|
|
::oPullDown:ShowPopup( nPopup )
|
|
ENDIF
|
|
|
|
ELSEIF MRow() != ::nMaxRow
|
|
|
|
nMRow := MRow()
|
|
nMCol := MCol()
|
|
FOR EACH oWnd IN ::aWindows
|
|
IF oWnd:IsOver( nMRow, nMCol )
|
|
IF ! oWnd:lFocused
|
|
::aWindows[ ::nCurrentWindow ]:Show( .F. )
|
|
::nCurrentWindow := oWnd:__enumIndex()
|
|
oWnd:Show( .T. )
|
|
ENDIF
|
|
oWnd:LButtonDown( nMRow, nMCol )
|
|
EXIT
|
|
ENDIF
|
|
NEXT
|
|
ENDIF
|
|
EXIT
|
|
|
|
CASE K_RBUTTONDOWN
|
|
EXIT
|
|
#if 0
|
|
CASE K_ESC
|
|
::RestoreAppStatus()
|
|
t_oDebugger := NIL
|
|
s_lExit := .T.
|
|
DispEnd()
|
|
::Exit()
|
|
EXIT
|
|
#endif
|
|
|
|
CASE K_ENTER
|
|
IF ! Empty( ::oGetCommand:getValue() )
|
|
::oWndCommand:KeyPressed( nKey )
|
|
EXIT
|
|
ENDIF
|
|
CASE K_UP
|
|
CASE K_DOWN
|
|
CASE K_LEFT
|
|
CASE K_RIGHT
|
|
CASE K_PGUP
|
|
CASE K_PGDN
|
|
CASE K_HOME
|
|
CASE K_END
|
|
CASE K_DEL
|
|
CASE K_CTRL_PGUP
|
|
CASE K_CTRL_PGDN
|
|
CASE K_CTRL_HOME
|
|
CASE K_CTRL_END
|
|
CASE K_CTRL_ENTER
|
|
::aWindows[ ::nCurrentWindow ]:KeyPressed( nKey )
|
|
EXIT
|
|
|
|
CASE K_ALT_G /* Grow active window */
|
|
CASE K_ALT_S /* Shrink active window */
|
|
CASE K_ALT_U /* Move the border between Command and Code windows Up */
|
|
CASE K_ALT_D /* Move the border between Command and Code windows Down */
|
|
::NotSupported()
|
|
EXIT
|
|
|
|
CASE K_F1
|
|
::ShowHelp()
|
|
EXIT
|
|
|
|
CASE K_F2
|
|
::NotSupported()
|
|
EXIT
|
|
|
|
CASE K_F4
|
|
::ShowAppScreen()
|
|
EXIT
|
|
|
|
CASE K_F5
|
|
::Go()
|
|
EXIT
|
|
|
|
CASE K_CTRL_F5
|
|
::NextRoutine()
|
|
EXIT
|
|
|
|
CASE K_F6
|
|
::ShowWorkAreas()
|
|
EXIT
|
|
|
|
CASE K_F7
|
|
::ToCursor()
|
|
EXIT
|
|
|
|
CASE K_F8
|
|
::Step()
|
|
EXIT
|
|
|
|
CASE K_F9
|
|
::ToggleBreakPoint()
|
|
EXIT
|
|
|
|
CASE K_F10
|
|
::Trace()
|
|
EXIT
|
|
|
|
CASE K_TAB
|
|
::NextWindow()
|
|
EXIT
|
|
|
|
CASE K_SH_TAB
|
|
::PrevWindow()
|
|
EXIT
|
|
|
|
OTHERWISE
|
|
IF ! ::OpenMenu( __dbgAltToKey( nKey ) )
|
|
::oWndCommand:KeyPressed( nKey )
|
|
ENDIF
|
|
ENDSWITCH
|
|
ENDIF
|
|
ENDDO
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Hide() CLASS HBDebugger
|
|
|
|
::CloseDebuggerWindow()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE HideCallStack() CLASS HBDebugger
|
|
|
|
::lShowCallStack := .F.
|
|
|
|
IF ::oWndStack != NIL
|
|
DispBegin()
|
|
::oWndStack:Hide()
|
|
IF ::aWindows[ ::nCurrentWindow ] == ::oWndStack
|
|
::NextWindow()
|
|
ENDIF
|
|
::RemoveWindow( ::oWndStack )
|
|
::oWndStack := NIL
|
|
|
|
::oWndCode:Resize( ,,, ::oWndCode:nRight + 16 )
|
|
IF ::oWndVars != NIL
|
|
::oWndVars:Resize( ,,, ::oWndVars:nRight + 16 )
|
|
ENDIF
|
|
IF ::oWndPnt != NIL
|
|
::oWndPnt:Resize( ,,, ::oWndPnt:nRight + 16 )
|
|
ENDIF
|
|
DispEnd()
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE HideVars() CLASS HBDebugger
|
|
|
|
LOCAL nTop
|
|
|
|
IF ::oWndVars == NIL
|
|
RETURN
|
|
ENDIF
|
|
|
|
::oWndVars:Hide()
|
|
IF ::oWndPnt == NIL
|
|
nTop := 1
|
|
ELSE
|
|
::oWndPnt:Resize( 1, , ::oWndPnt:nBottom - ( ::oWndPnt:nTop - 1 ) )
|
|
::oBrwPnt:Resize( 2, , ::oWndPnt:nBottom - 1 )
|
|
nTop := ::oWndPnt:nBottom + 1
|
|
ENDIF
|
|
::oWndCode:Resize( nTop )
|
|
IF ::oBrwText != NIL
|
|
::oBrwText:Resize( ::oWndCode:nTop + 1 )
|
|
ENDIF
|
|
|
|
IF ::aWindows[ ::nCurrentWindow ] == ::oWndVars
|
|
::NextWindow()
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD InputBox( cMsg, uValue, bValid, lEditable ) CLASS HBDebugger
|
|
|
|
LOCAL nTop := Int( ( ::nMaxRow / 2 ) - 5 )
|
|
LOCAL nLeft := Int( ( ::nMaxCol / 2 ) - 25 )
|
|
LOCAL nBottom := nTop + 2
|
|
LOCAL nRight := nLeft + 50
|
|
LOCAL cType := ValType( uValue )
|
|
LOCAL nWidth := nRight - nLeft - 1
|
|
LOCAL uTemp
|
|
LOCAL lExit
|
|
LOCAL oWndInput := HBDbWindow():New( nTop, nLeft, nBottom, nRight, cMsg, ;
|
|
::oPullDown:cClrPopup )
|
|
|
|
oWndInput:lShadow := .T.
|
|
oWndInput:Show()
|
|
|
|
uTemp := uValue
|
|
|
|
IF hb_defaultValue( lEditable, .T. )
|
|
|
|
IF ! cType == "C" .OR. Len( uValue ) < nWidth
|
|
uTemp := PadR( uValue, nWidth )
|
|
ENDIF
|
|
__dbgInput( nTop + 1, nLeft + 1, nWidth, @uTemp, bValid, ;
|
|
__dbgColors()[ 5 ], Max( Max( nWidth, Len( uTemp ) ), 256 ) )
|
|
SWITCH cType
|
|
CASE "C" ; uTemp := AllTrim( uTemp ) ; EXIT
|
|
CASE "D" ; uTemp := CToD( uTemp ) ; EXIT
|
|
CASE "N" ; uTemp := Val( uTemp ) ; EXIT
|
|
ENDSWITCH
|
|
|
|
ELSE
|
|
|
|
hb_DispOutAt( nTop + 1, nLeft + 1, left( __dbgValToStr( uValue ), nRight - nLeft - 1 ), ;
|
|
__dbgColors()[ 2 ] + "," + __dbgColors()[ 5 ] )
|
|
SetPos( nTop + 1, nLeft + 1 )
|
|
|
|
lExit := .F.
|
|
|
|
DO WHILE ! lExit
|
|
|
|
SWITCH __dbgInkey()
|
|
CASE K_ESC
|
|
lExit := .T.
|
|
EXIT
|
|
|
|
CASE K_ENTER
|
|
|
|
SWITCH cType
|
|
CASE "A"
|
|
IF Len( uValue ) == 0
|
|
__dbgAlert( "Array is empty" )
|
|
ELSE
|
|
__dbgArrays( uValue, cMsg )
|
|
ENDIF
|
|
LOOP
|
|
CASE "H"
|
|
IF Len( uValue ) == 0
|
|
__dbgAlert( "Hash is empty" )
|
|
ELSE
|
|
__dbgHashes( uValue, cMsg )
|
|
ENDIF
|
|
LOOP
|
|
CASE "O"
|
|
__dbgObject( uValue, cMsg )
|
|
LOOP
|
|
ENDSWITCH
|
|
|
|
OTHERWISE
|
|
__dbgAlert( "Value cannot be edited" )
|
|
|
|
ENDSWITCH
|
|
ENDDO
|
|
ENDIF
|
|
|
|
oWndInput:Hide()
|
|
|
|
RETURN uTemp
|
|
|
|
|
|
METHOD PROCEDURE Inspect( uValue, cValueName ) CLASS HBDebugger
|
|
|
|
::InputBox( uValue, cValueName,, .F. )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD IsValidStopLine( cName, nLine ) CLASS HBDebugger
|
|
RETURN __dbgIsValidStopLine( ::pInfo, cName, nLine )
|
|
|
|
|
|
METHOD RunAtStartup( lRunAtStartup ) CLASS HBDebugger
|
|
|
|
::lRunAtStartup := hb_defaultValue( lRunAtStartup, ! ::lRunAtStartup )
|
|
::oPulldown:GetItemByIdent( "ALTD" ):checked := ::lRunAtStartup
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD LineNumbers( lLineNumbers ) CLASS HBDebugger
|
|
|
|
::lLineNumbers := hb_defaultValue( lLineNumbers, ! ::lLineNumbers )
|
|
::oPulldown:GetItemByIdent( "LINE" ):checked := ::lLineNumbers
|
|
IF ::oBrwText != NIL
|
|
::oBrwText:lLineNumbers := ::lLineNumbers
|
|
::oBrwText:RefreshAll()
|
|
ENDIF
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD ListBox( cCaption, aItems ) CLASS HBDebugger
|
|
|
|
LOCAL nItems
|
|
LOCAL nMaxWid
|
|
LOCAL nLeft
|
|
LOCAL nTop
|
|
LOCAL nBottom
|
|
LOCAL nRight
|
|
LOCAL oWndList
|
|
LOCAL aColors
|
|
LOCAL n
|
|
|
|
nItems := Len( aItems )
|
|
nMaxWid := Len( cCaption ) + 2
|
|
AEval( aItems, {| x | nMaxWid := Max( Len( x ), nMaxWid ) } )
|
|
nMaxWid += 2
|
|
|
|
nTop := Int( ( ::nMaxRow / 2 ) - Min( nItems, ::nMaxRow - 5 ) / 2 )
|
|
nBottom := Int( ( ::nMaxRow / 2 ) + Min( nItems, ::nMaxRow - 5 ) / 2 + 1 )
|
|
nLeft := Int( ( ::nMaxCol / 2 ) - Min( nMaxWid, ::nMaxCol * 3 / 2 ) / 2 )
|
|
nRight := Int( ( ::nMaxCol / 2 ) + Min( nMaxWid, ::nMaxCol * 3 / 2 ) / 2 )
|
|
oWndList := HBDbWindow():new( nTop, nLeft, nBottom, nRight, cCaption, ;
|
|
::oPullDown:cClrPopup )
|
|
oWndList:lShadow := .T.
|
|
oWndList:Show()
|
|
|
|
aColors := __dbgColors()
|
|
n := __dbgAChoice( nTop + 1, nLeft + 1, nBottom - 1, nRight - 1, aItems, ;
|
|
aColors[ 8 ] + "," + aColors[ 10 ] )
|
|
oWndList:Hide()
|
|
|
|
RETURN n
|
|
|
|
|
|
METHOD PROCEDURE LoadCallStack() CLASS HBDebugger
|
|
|
|
LOCAL i
|
|
LOCAL nDebugLevel
|
|
LOCAL nCurrLevel
|
|
LOCAL nLevel
|
|
LOCAL nPos
|
|
|
|
::aProcStack := Array( ::nProcLevel )
|
|
|
|
nCurrLevel := __dbgProcLevel() - 1
|
|
nDebugLevel := nCurrLevel - ::nProcLevel + 1
|
|
|
|
FOR i := nDebugLevel TO nCurrLevel
|
|
nLevel := nCurrLevel - i + 1
|
|
IF ( nPos := AScan( ::aCallStack, {| a | a[ CSTACK_LEVEL ] == nLevel } ) ) > 0
|
|
// a procedure with debug info
|
|
::aProcStack[ i - nDebugLevel + 1 ] := ::aCallStack[ nPos ]
|
|
ELSE
|
|
::aProcStack[ i - nDebugLevel + 1 ] := iif( ProcLine( i ) != 0, ;
|
|
{ ProcFile( i ), ProcName( i ), ProcLine( i ), nLevel, {}, {} }, ;
|
|
{, ProcName( i ) + "(" + hb_ntos( ProcLine( i ) ) + ")", , nLevel, , } )
|
|
ENDIF
|
|
NEXT
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE LoadColors() CLASS HBDebugger
|
|
|
|
LOCAL oWnd
|
|
|
|
::oPullDown:LoadColors()
|
|
IF ::lActive
|
|
::oPullDown:Refresh()
|
|
::BarDisplay()
|
|
ENDIF
|
|
FOR EACH oWnd IN ::aWindows
|
|
oWnd:LoadColors()
|
|
IF ::lActive
|
|
oWnd:Refresh()
|
|
ENDIF
|
|
NEXT
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE LoadSettings() CLASS HBDebugger
|
|
|
|
::DoScript( ::cSettingsFileName )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE LoadVars() CLASS HBDebugger // updates monitored variables
|
|
|
|
LOCAL nCount
|
|
LOCAL n
|
|
LOCAL m
|
|
LOCAL xValue
|
|
LOCAL cName
|
|
LOCAL hSkip
|
|
|
|
LOCAL aBVars := {}
|
|
|
|
IF ::lShowPublics
|
|
nCount := __mvDbgInfo( HB_MV_PUBLIC )
|
|
FOR n := nCount TO 1 STEP -1
|
|
xValue := __mvDbgInfo( HB_MV_PUBLIC, n, @cName )
|
|
AAdd( aBVars, { cName, xValue, "Public" } )
|
|
NEXT
|
|
ENDIF
|
|
|
|
IF ::lShowPrivates
|
|
/* CA-Cl*pper shows only local private variables in monitor
|
|
* We are marking non local private variables with "^" character
|
|
*/
|
|
nCount := __mvDbgInfo( HB_MV_PRIVATE )
|
|
IF nCount > 0
|
|
m := __mvDbgInfo( HB_MV_PRIVATE_LOCAL, ::nProcLevel )
|
|
hSkip := { => }
|
|
hb_HAllocate( hSkip, nCount )
|
|
FOR n := nCount TO 1 STEP -1
|
|
xValue := __mvDbgInfo( HB_MV_PRIVATE, n, @cName )
|
|
IF ! cName $ hSkip
|
|
AAdd( aBVars, { cName, xValue, iif( m > 0, "Private", "Private^" ) } )
|
|
hSkip[ cName ] := NIL
|
|
ENDIF
|
|
--m
|
|
NEXT
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ::aProcStack[ ::oBrwStack:Cargo ][ CSTACK_LINE ] != NIL
|
|
IF ::lShowGlobals
|
|
cName := ::aProcStack[ ::oBrwStack:Cargo ][ CSTACK_MODULE ]
|
|
FOR EACH n IN ::aModules
|
|
IF ! ::lShowAllGlobals
|
|
IF ! ::ModuleMatch( n[ MODULE_NAME ], cName )
|
|
LOOP
|
|
ENDIF
|
|
ENDIF
|
|
FOR EACH m IN n[ MODULE_GLOBALS ]
|
|
AAdd( aBVars, m )
|
|
NEXT
|
|
IF ! ::lShowAllGlobals
|
|
FOR EACH m IN n[ MODULE_EXTERNGLOBALS ]
|
|
AAdd( aBVars, m )
|
|
NEXT
|
|
ENDIF
|
|
NEXT
|
|
ENDIF
|
|
|
|
IF ::lShowStatics
|
|
cName := ::aProcStack[ ::oBrwStack:Cargo ][ CSTACK_MODULE ]
|
|
IF ( n := AScan( ::aModules, {| a | ::ModuleMatch( a[ MODULE_NAME ], cName ) } ) ) > 0
|
|
FOR EACH m IN ::aModules[ n ][ MODULE_STATICS ]
|
|
AAdd( aBVars, m )
|
|
NEXT
|
|
ENDIF
|
|
FOR EACH n IN ::aProcStack[ ::oBrwStack:Cargo ][ CSTACK_STATICS ]
|
|
AAdd( aBVars, n )
|
|
NEXT
|
|
ENDIF
|
|
|
|
IF ::lShowLocals
|
|
FOR EACH n IN ::aProcStack[ ::oBrwStack:Cargo ][ CSTACK_LOCALS ]
|
|
cName := n[ VAR_NAME ]
|
|
// Is there another var with this name ?
|
|
IF ( m := AScan( aBVars, {| aVar | aVar[ VAR_NAME ] == cName .AND. hb_LeftEq( aVar[ VAR_TYPE ], "S" ) } ) ) > 0
|
|
aBVars[ m ] := n
|
|
ELSE
|
|
AAdd( aBVars, n )
|
|
ENDIF
|
|
NEXT
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ::oBrwVars != NIL .AND. ::oBrwVars:cargo[ 1 ] > Len( aBVars )
|
|
::oBrwVars:GoTop()
|
|
ENDIF
|
|
::aVars := aBVars
|
|
IF ::lSortVars .AND. ! Empty( ::aVars )
|
|
::Sort()
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Local() CLASS HBDebugger
|
|
|
|
::lShowLocals := ! ::lShowLocals
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD Locate( nMode, cValue ) CLASS HBDebugger
|
|
|
|
LOCAL lFound
|
|
|
|
IF Empty( cValue )
|
|
cValue := ::InputBox( "Search string", ::cSearchString )
|
|
IF Empty( cValue )
|
|
RETURN NIL
|
|
ENDIF
|
|
ENDIF
|
|
|
|
::cSearchString := cValue
|
|
|
|
lFound := ::oBrwText:Search( ::cSearchString, ::lCaseSensitive, nMode )
|
|
|
|
RETURN lFound
|
|
|
|
|
|
METHOD LocatePrgPath( cPrgName ) CLASS HBDebugger
|
|
|
|
LOCAL cRetPrgName
|
|
LOCAL cDir
|
|
|
|
FOR EACH cDir IN ::aPathDirs
|
|
cRetPrgName := cDir + hb_ps() + cPrgName
|
|
IF hb_FileExists( cRetPrgName )
|
|
RETURN cRetPrgName
|
|
ENDIF
|
|
NEXT
|
|
|
|
RETURN NIL
|
|
|
|
|
|
METHOD PROCEDURE MonoDisplay() CLASS HBDebugger
|
|
|
|
::lMonoDisplay := ! ::lMonoDisplay
|
|
::oPullDown:GetItemByIdent( "MONO" ):checked := ::lMonoDisplay
|
|
::LoadColors()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD NextRoutine() CLASS HBDebugger
|
|
|
|
::RestoreAppScreen()
|
|
::RestoreAppState()
|
|
__dbgSetNextRoutine( ::pInfo )
|
|
::Exit()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD PROCEDURE NextWindow() CLASS HBDebugger
|
|
|
|
LOCAL oWnd
|
|
|
|
IF Len( ::aWindows ) > 0
|
|
|
|
oWnd := ::aWindows[ ::nCurrentWindow++ ]
|
|
oWnd:Show( .F. )
|
|
IF ::nCurrentWindow > Len( ::aWindows )
|
|
::nCurrentWindow := 1
|
|
ENDIF
|
|
DO WHILE ! ::aWindows[ ::nCurrentWindow ]:lVisible
|
|
::nCurrentWindow++
|
|
IF ::nCurrentWindow > Len( ::aWindows )
|
|
::nCurrentWindow := 1
|
|
ENDIF
|
|
ENDDO
|
|
oWnd := ::aWindows[ ::nCurrentWindow ]
|
|
oWnd:Show( .T. )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Open() CLASS HBDebugger
|
|
|
|
LOCAL nFileName
|
|
LOCAL cFileName
|
|
LOCAL cRealName
|
|
LOCAL aFiles := ::GetSourceFiles()
|
|
|
|
ASort( aFiles )
|
|
hb_AIns( aFiles, 1, "(Another file)", .T. )
|
|
|
|
nFileName := ::ListBox( "Please choose a source file", aFiles )
|
|
SWITCH nFileName
|
|
CASE 0
|
|
RETURN
|
|
CASE 1
|
|
cFileName := AllTrim( ::InputBox( "Please enter the filename" ) )
|
|
EXIT
|
|
OTHERWISE
|
|
cFileName := aFiles[ nFileName ]
|
|
ENDSWITCH
|
|
|
|
IF ! Empty( cFileName ) .AND. ;
|
|
( ! HB_ISSTRING( ::cPrgName ) .OR. ! hb_FileMatch( cFileName, ::cPrgName ) )
|
|
|
|
IF ! hb_FileExists( cFileName ) .AND. ! Empty( ::cPathForFiles )
|
|
cRealName := ::LocatePrgPath( cFileName )
|
|
IF Empty( cRealName )
|
|
__dbgAlert( "File '" + cFileName + "' not found!" )
|
|
RETURN
|
|
ENDIF
|
|
cFileName := cRealName
|
|
ENDIF
|
|
::cPrgName := cFileName
|
|
::lPPO := ( Lower( hb_FNameExt( cFileName ) ) == ".ppo" )
|
|
::oPulldown:GetItemByIdent( "PPO" ):Checked := ::lPPO
|
|
::oBrwText := HBBrwText():New( ::oWndCode:nTop + 1, ::oWndCode:nLeft + 1, ;
|
|
::oWndCode:nBottom - 1, ::oWndCode:nRight - 1, cFileName, ;
|
|
__dbgColors()[ 2 ] + "," + __dbgColors()[ 5 ] + "," + ;
|
|
__dbgColors()[ 3 ] + "," + __dbgColors()[ 6 ], ;
|
|
::lLineNumbers, ::nTabWidth )
|
|
::oWndCode:Browser := ::oBrwText
|
|
::oWndCode:SetCaption( ::cPrgName )
|
|
::oWndCode:Refresh() // to force the window caption to update
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
METHOD OpenMenu( cName ) CLASS HBDebugger
|
|
|
|
LOCAL nPopup := ::oPullDown:GetHotKeyPos( Left( cName, 1 ) )
|
|
|
|
IF nPopup == 0
|
|
RETURN .F.
|
|
ENDIF
|
|
IF ::oPullDown:nOpenPopup != nPopup
|
|
::oPullDown:ShowPopup( nPopup )
|
|
ENDIF
|
|
|
|
RETURN .T.
|
|
|
|
METHOD OpenPPO() CLASS HBDebugger
|
|
|
|
LOCAL lSuccess
|
|
|
|
IF Empty( ::cPrgName )
|
|
RETURN .F.
|
|
ENDIF
|
|
|
|
IF Lower( hb_FNameExt( ::cPrgName ) ) == ".ppo"
|
|
::cPrgName := hb_FNameExtSet( ::cPrgName, ".prg" )
|
|
lSuccess := hb_FileExists( ::cPrgName )
|
|
::lPPO := ! lSuccess
|
|
ELSE
|
|
::cPrgName := hb_FNameExtSet( ::cPrgName, ".ppo" )
|
|
lSuccess := hb_FileExists( ::cPrgName )
|
|
::lPPO := lSuccess
|
|
ENDIF
|
|
|
|
IF lSuccess
|
|
::oBrwText := HBBrwText():New( ::oWndCode:nTop + 1, ::oWndCode:nLeft + 1, ;
|
|
::oWndCode:nBottom - 1, ::oWndCode:nRight - 1, ::cPrgName, ;
|
|
__dbgColors()[ 2 ] + "," + __dbgColors()[ 5 ] + "," + ;
|
|
__dbgColors()[ 3 ] + "," + __dbgColors()[ 6 ], ::lLineNumbers, ::nTabWidth )
|
|
::oWndCode:Browser := ::oBrwText
|
|
::oWndCode:SetCaption( ::cPrgName )
|
|
::oWndCode:Refresh() // to force the window caption to update
|
|
ENDIF
|
|
|
|
::oPullDown:GetItemByIdent( "PPO" ):checked := ::lPPO
|
|
|
|
RETURN lSuccess
|
|
|
|
|
|
METHOD PROCEDURE OSShell() CLASS HBDebugger
|
|
|
|
LOCAL cImage := SaveScreen()
|
|
LOCAL cColors := SetColor()
|
|
LOCAL oE
|
|
|
|
SetColor( "W/N" )
|
|
CLS
|
|
QOut( "Type 'exit' to RETURN to the Debugger" )
|
|
SetCursor( SC_NORMAL ) // standard cursor for OS shell
|
|
|
|
BEGIN SEQUENCE WITH {| objErr | Break( objErr ) }
|
|
|
|
#if defined( __PLATFORM__WINDOWS ) .OR. ;
|
|
defined( __PLATFORM__DOS ) .OR. ;
|
|
defined( __PLATFORM__OS2 )
|
|
hb_run( GetEnv( "COMSPEC" ) )
|
|
#elif defined( __PLATFORM__UNIX )
|
|
hb_run( GetEnv( "SHELL" ) )
|
|
#else
|
|
::NotSupported()
|
|
#endif
|
|
|
|
RECOVER USING oE
|
|
|
|
__dbgAlert( "Error: " + oE:description )
|
|
|
|
END SEQUENCE
|
|
|
|
SetCursor( SC_NONE )
|
|
RestScreen( ,,,, cImage )
|
|
SetColor( cColors )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Quit() CLASS HBDebugger
|
|
|
|
::Exit()
|
|
::Hide()
|
|
__dbgSetQuit( ::pInfo )
|
|
t_oDebugger := NIL
|
|
|
|
__Quit()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PathForFiles( cPathForFiles ) CLASS HBDebugger
|
|
|
|
IF cPathForFiles == NIL
|
|
cPathForFiles := ::InputBox( "Search path for source files:", ::cPathForFiles )
|
|
ENDIF
|
|
::cPathForFiles := cPathForFiles
|
|
::aPathDirs := PathToArray( ::cPathForFiles )
|
|
|
|
::Resume()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD PROCEDURE PrevWindow() CLASS HBDebugger
|
|
|
|
LOCAL oWnd
|
|
|
|
IF Len( ::aWindows ) > 0
|
|
|
|
oWnd := ::aWindows[ ::nCurrentWindow-- ]
|
|
oWnd:Show( .F. )
|
|
IF ::nCurrentWindow < 1
|
|
::nCurrentWindow := Len( ::aWindows )
|
|
ENDIF
|
|
DO WHILE ! ::aWindows[ ::nCurrentWindow ]:lVisible
|
|
::nCurrentWindow--
|
|
IF ::nCurrentWindow < 1
|
|
::nCurrentWindow := Len( ::aWindows )
|
|
ENDIF
|
|
ENDDO
|
|
oWnd := ::aWindows[ ::nCurrentWindow ]
|
|
oWnd:Show( .T. )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Private() CLASS HBDebugger
|
|
|
|
::lShowPrivates := ! ::lShowPrivates
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Public() CLASS HBDebugger
|
|
|
|
::lShowPublics := ! ::lShowPublics
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE RefreshVars() CLASS HBDebugger
|
|
|
|
::oPulldown:GetItemByIdent( "GLOBAL" ):checked := ::lShowGlobals
|
|
::oPulldown:GetItemByIdent( "LOCAL" ):checked := ::lShowLocals
|
|
::oPulldown:GetItemByIdent( "PRIVATE" ):checked := ::lShowPrivates
|
|
::oPulldown:GetItemByIdent( "PUBLIC" ):checked := ::lShowPublics
|
|
::oPulldown:GetItemByIdent( "STATIC" ):checked := ::lShowStatics
|
|
::oPulldown:GetItemByIdent( "ALL" ):checked := ::lAll
|
|
::oPulldown:GetItemByIdent( "SHOWALLGLOBALS" ):checked := ::lShowAllGlobals
|
|
|
|
IF ::lActive
|
|
IF ::lShowGlobals .OR. ::lShowPublics .OR. ::lShowPrivates .OR. ::lShowStatics .OR. ::lShowLocals
|
|
::LoadVars()
|
|
::ShowVars()
|
|
ELSE
|
|
::HideVars()
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE RemoveWindow( oWnd ) CLASS HBDebugger
|
|
|
|
LOCAL n
|
|
|
|
IF ( n := hb_AScan( ::aWindows, oWnd,,, .T. ) ) > 0
|
|
::aWindows := hb_ADel( ::aWindows, n, .T. )
|
|
ENDIF
|
|
|
|
::nCurrentWindow := 1
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD ResizeWindows( oWindow ) CLASS HBDebugger
|
|
|
|
LOCAL oWindow2
|
|
LOCAL nTop
|
|
LOCAL lVisible2 := .F.
|
|
|
|
DO CASE
|
|
CASE oWindow == ::oWndVars
|
|
oWindow2 := ::oWndPnt
|
|
CASE oWindow == ::oWndPnt
|
|
oWindow2 := ::oWndVars
|
|
ENDCASE
|
|
|
|
DispBegin()
|
|
IF oWindow2 == NIL
|
|
nTop := oWindow:nBottom + 1
|
|
ELSE
|
|
lVisible2 := oWindow2:lVisible
|
|
IF oWindow2:lVisible
|
|
IF oWindow:nTop < oWindow2:nTop
|
|
nTop := oWindow2:nBottom - oWindow2:nTop + 1
|
|
oWindow2:Resize( oWindow:nBottom + 1,, oWindow:nBottom + nTop )
|
|
ELSE
|
|
nTop := oWindow:nBottom - oWindow:nTop + 1
|
|
oWindow:Resize( oWindow2:nBottom + 1,, oWindow2:nBottom + nTop )
|
|
ENDIF
|
|
nTop := Max( oWindow:nBottom, oWindow2:nBottom ) + 1
|
|
ELSE
|
|
IF oWindow:nTop > 1
|
|
nTop := oWindow:nBottom - oWindow:nTop + 1
|
|
oWindow:Resize( 1,, nTop )
|
|
ENDIF
|
|
nTop := oWindow:nBottom + 1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
oWindow:hide()
|
|
IF oWindow2 != NIL
|
|
oWindow2:hide()
|
|
ENDIF
|
|
|
|
::oWndCode:Resize( nTop )
|
|
|
|
IF oWindow2 != NIL .AND. lVisible2
|
|
oWindow2:Show()
|
|
ENDIF
|
|
oWindow:Show()
|
|
DispEnd()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD PROCEDURE RestoreAppScreen() CLASS HBDebugger
|
|
|
|
LOCAL i
|
|
|
|
::CloseDebuggerWindow()
|
|
|
|
FOR i := 1 TO ::nAppDispCount
|
|
DispBegin()
|
|
NEXT
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE RestoreAppState() CLASS HBDebugger
|
|
|
|
Set( _SET_DIRCASE, ::nAppDirCase )
|
|
Set( _SET_FILECASE, ::nAppFileCase )
|
|
Set( _SET_TYPEAHEAD, ::nAppTypeAhead )
|
|
hb_keySetLast( ::nAppLastKey )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE RestoreSettings( cFileName ) CLASS HBDebugger
|
|
|
|
IF Empty( cFileName )
|
|
::cSettingsFileName := ::InputBox( "File name", ::cSettingsFileName )
|
|
IF LastKey() == K_ESC
|
|
RETURN
|
|
ENDIF
|
|
ELSE
|
|
::cSettingsFileName := cFileName
|
|
ENDIF
|
|
|
|
::LoadSettings()
|
|
::ShowVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE SaveAppScreen() CLASS HBDebugger
|
|
|
|
LOCAL nRight
|
|
LOCAL nTop
|
|
LOCAL i
|
|
|
|
::nAppDispCount := DispCount()
|
|
FOR i := 1 TO ::nAppDispCount
|
|
DispEnd()
|
|
NEXT
|
|
|
|
::OpenDebuggerWindow()
|
|
|
|
IF ::nMaxRow != MaxRow() .OR. ::nMaxCol != MaxCol()
|
|
DispBegin()
|
|
::nMaxRow := MaxRow()
|
|
::nMaxCol := MaxCol()
|
|
nTop := 1
|
|
nRight := ::nMaxCol
|
|
::oWndCommand:Resize( ::nMaxRow - 5, 0, ::nMaxRow - 1, ::nMaxCol )
|
|
::oGetCommand:newPos( ::oWndCommand:nBottom - 1, ::oWndCommand:nLeft + 3 )
|
|
::oBrwStack:nTop := 2
|
|
::oBrwStack:nLeft := ::nMaxCol - 14
|
|
::oBrwStack:nRight := ::nMaxCol - 1
|
|
::oBrwStack:nBottom := ::nMaxRow - 7
|
|
IF ::oWndStack != NIL
|
|
nRight -= 16
|
|
::oWndStack:Resize( , nRight + 1, ::nMaxRow - 6, ::nMaxCol )
|
|
ENDIF
|
|
IF ::oWndVars != NIL
|
|
::oWndVars:Resize( , , , nRight )
|
|
nTop := Max( nTop, ::oWndVars:nBottom + 1 )
|
|
ENDIF
|
|
IF ::oWndPnt != NIL
|
|
::oWndPnt:Resize( , , , nRight )
|
|
nTop := Max( nTop, ::oWndPnt:nBottom + 1 )
|
|
ENDIF
|
|
::oWndCode:Resize( nTop, 0, ::nMaxRow - 6, nRight )
|
|
::oPullDown:Refresh()
|
|
::BarDisplay()
|
|
DispEnd()
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE SaveAppState() CLASS HBDebugger
|
|
|
|
::nAppDirCase := Set( _SET_DIRCASE, 0 )
|
|
::nAppFileCase := Set( _SET_FILECASE, 0 )
|
|
::nAppTypeAhead := Set( _SET_TYPEAHEAD, 16 )
|
|
::nAppLastKey := LastKey()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE SaveSettings( cFileName ) CLASS HBDebugger
|
|
|
|
LOCAL cInfo := ""
|
|
LOCAL n
|
|
LOCAL oWnd
|
|
LOCAL aBreak, aWatch
|
|
|
|
IF Empty( cFileName )
|
|
::cSettingsFileName := ::InputBox( "File name", ::cSettingsFileName )
|
|
IF LastKey() == K_ESC
|
|
RETURN
|
|
ENDIF
|
|
ELSE
|
|
::cSettingsFileName := cFileName
|
|
ENDIF
|
|
|
|
IF ! Empty( ::cPathForFiles )
|
|
cInfo += "Options Path " + ::cPathForFiles + hb_eol()
|
|
ENDIF
|
|
|
|
cInfo += "Options Colors {"
|
|
FOR EACH n IN ::aColors
|
|
cInfo += '"' + n + '"'
|
|
IF ! n:__enumIsLast()
|
|
cInfo += ","
|
|
ENDIF
|
|
NEXT
|
|
cInfo += "}" + hb_eol()
|
|
|
|
IF ::lMonoDisplay
|
|
cInfo += "Options mono " + hb_eol()
|
|
ENDIF
|
|
|
|
IF ! ::lRunAtStartup
|
|
cInfo += "Options NoRunAtStartup " + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::nSpeed != 0
|
|
cInfo += "Run Speed " + hb_ntos( ::nSpeed ) + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::nTabWidth != 4
|
|
cInfo += "Options Tab " + hb_ntos( ::nTabWidth ) + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lShowStatics
|
|
cInfo += "Monitor Static" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lShowPublics
|
|
cInfo += "Monitor Public" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lShowLocals
|
|
cInfo += "Monitor Local" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lShowPrivates
|
|
cInfo += "Monitor Private" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lShowGlobals
|
|
cInfo += "Monitor Global" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lSortVars
|
|
cInfo += "Monitor Sort" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ::lShowCallStack
|
|
cInfo += "View CallStack" + hb_eol()
|
|
ENDIF
|
|
|
|
IF ! ::lLineNumbers
|
|
cInfo += "Num Off" + hb_eol()
|
|
ENDIF
|
|
|
|
FOR EACH aBreak IN __dbgGetBreakPoints( ::pInfo )
|
|
cInfo += "BP " + hb_ntos( aBreak[ 1 ] ) + " " + ;
|
|
AllTrim( aBreak[ 2 ] ) + hb_eol()
|
|
NEXT
|
|
|
|
FOR EACH aWatch IN ::aWatch
|
|
cInfo += Upper( aWatch[ 1 ] ) + " " + aWatch[ 2 ] + hb_eol()
|
|
NEXT
|
|
|
|
IF ! ::lWindowsAutoSized
|
|
/* This part of the script must be executed after all windows are created */
|
|
FOR EACH oWnd IN ::aWindows
|
|
cInfo += ;
|
|
"Window Size " + hb_ntos( oWnd:nBottom - oWnd:nTop + 1 ) + " " + ;
|
|
hb_ntos( oWnd:nRight - oWnd:nLeft + 1 ) + hb_eol() + ;
|
|
"Window Move " + hb_ntos( oWnd:nTop ) + " " + ;
|
|
hb_ntos( oWnd:nLeft ) + hb_eol() + ;
|
|
"Window Next" + hb_eol()
|
|
NEXT
|
|
ENDIF
|
|
|
|
hb_MemoWrit( ::cSettingsFileName, cInfo )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE SearchLine() CLASS HBDebugger
|
|
|
|
::GotoLine( Max( 1, ::InputBox( "Line number", 1 ) ) )
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Show() CLASS HBDebugger
|
|
|
|
::SaveAppScreen()
|
|
::oPullDown:Display()
|
|
::oWndCode:Show( .T. )
|
|
::oWndCommand:Show()
|
|
hb_DispOutAt( ::oWndCommand:nBottom - 1, ::oWndCommand:nLeft + 1, ">", __dbgColors()[ 2 ] )
|
|
|
|
::BarDisplay()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE ShowAllGlobals() CLASS HBDebugger
|
|
|
|
::lShowAllGlobals := ! ::lShowAllGlobals
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE ShowAppScreen() CLASS HBDebugger
|
|
|
|
::CloseDebuggerWindow()
|
|
|
|
IF LastKey() == K_LBUTTONDOWN
|
|
__dbgInkey()
|
|
ENDIF
|
|
DO WHILE __dbgInkey() == K_MOUSEMOVE
|
|
ENDDO
|
|
|
|
::OpenDebuggerWindow()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE ShowCallStack() CLASS HBDebugger
|
|
|
|
::lShowCallStack := .T.
|
|
|
|
IF ::oWndStack == NIL
|
|
|
|
DispBegin()
|
|
// Resize code window
|
|
::oWndCode:Resize( ,,, ::oWndCode:nRight - 16 )
|
|
// Resize vars window
|
|
IF ::oWndVars != NIL
|
|
::oWndVars:Resize( ,,, ::oWndVars:nRight - 16 )
|
|
ENDIF
|
|
// Resize watchpoints window
|
|
IF ::oWndPnt != NIL
|
|
::oWndPnt:Resize( ,,, ::oWndPnt:nRight - 16 )
|
|
ENDIF
|
|
DispEnd()
|
|
|
|
IF ::aWindows[ ::nCurrentWindow ]:lFocused
|
|
::aWindows[ ::nCurrentWindow ]:Show( .F. )
|
|
ENDIF
|
|
|
|
::oWndStack := HBDbWindow():New( 1, ::nMaxCol - 15, ::nMaxRow - 6, ::nMaxCol, ;
|
|
"Calls" )
|
|
::oWndStack:bKeyPressed := {| nKey | ::CallStackProcessKey( nKey ) }
|
|
::oWndStack:bLButtonDown := {|| ::CallStackProcessKey( K_LBUTTONDOWN ) }
|
|
|
|
// Maintain fixed window array order: code, monitor, watch, callstack, command
|
|
IF ::nCurrentWindow >= Len( ::aWindows )
|
|
::nCurrentWindow++
|
|
ENDIF
|
|
hb_AIns( ::aWindows, Len( ::aWindows ), ::oWndStack, .T. )
|
|
|
|
IF ::oBrwStack == NIL
|
|
::BuildBrowseStack()
|
|
ENDIF
|
|
|
|
::oWndStack:bPainted := {|| ::oBrwStack:ColorSpec := __dbgColors()[ 2 ] + "," + ;
|
|
__dbgColors()[ 5 ] + "," + __dbgColors()[ 4 ] + "," + __dbgColors()[ 6 ], ;
|
|
::oBrwStack:RefreshAll(), ::oBrwStack:ForceStable() }
|
|
|
|
::oWndStack:Show( .F. )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE ShowCodeLine( nProc ) CLASS HBDebugger
|
|
|
|
LOCAL nLine
|
|
LOCAL cPrgName
|
|
|
|
// we only update the stack window and up a new browse
|
|
// to view the code if we have just broken execution
|
|
IF ! ::lGo
|
|
IF ::oWndStack != NIL
|
|
::oBrwStack:RefreshAll()
|
|
ENDIF
|
|
|
|
nLine := ::aProcStack[ nProc ][ CSTACK_LINE ]
|
|
cPrgName := ::aProcStack[ nProc ][ CSTACK_MODULE ]
|
|
IF nLine == NIL
|
|
::oBrwText := NIL
|
|
::oWndCode:Browser := NIL
|
|
::oWndCode:SetCaption( ::aProcStack[ nProc ][ CSTACK_FUNCTION ] + ;
|
|
": Code not available" )
|
|
::oWndCode:Refresh() // to force the window caption to update
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF ::lPPO
|
|
cPrgName := hb_FNameExtSet( cPrgName, ".ppo" )
|
|
ENDIF
|
|
|
|
IF ! Empty( cPrgName )
|
|
|
|
IF ! ::ModuleMatch( cPrgName, ::cPrgName ) .OR. ;
|
|
::oBrwText == NIL
|
|
|
|
IF ! hb_FileExists( cPrgName ) .AND. ! Empty( ::cPathForFiles )
|
|
cPrgName := ::LocatePrgPath( cPrgName )
|
|
ENDIF
|
|
|
|
::cPrgName := cPrgName
|
|
|
|
IF ! hb_FileExists( cPrgName )
|
|
::oBrwText := NIL
|
|
::oWndCode:Browser := NIL
|
|
::oWndCode:SetCaption( ::aProcStack[ nProc ][ CSTACK_MODULE ] + ;
|
|
" File not found" )
|
|
::oWndCode:Refresh()
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF ::oBrwText == NIL
|
|
::oBrwText := HBBrwText():New( ::oWndCode:nTop + 1, ::oWndCode:nLeft + 1, ;
|
|
::oWndCode:nBottom - 1, ::oWndCode:nRight - 1, cPrgName, ;
|
|
__dbgColors()[ 2 ] + "," + __dbgColors()[ 5 ] + "," + ;
|
|
__dbgColors()[ 3 ] + "," + __dbgColors()[ 6 ], ;
|
|
::lLineNumbers, ::nTabWidth )
|
|
|
|
::oWndCode:Browser := ::oBrwText
|
|
ELSE
|
|
::oBrwText:LoadFile( cPrgName )
|
|
ENDIF
|
|
|
|
::oWndCode:bPainted := {|| iif( ::oBrwText != NIL, ::oBrwText:RefreshAll():ForceStable(), ::oWndCode:Clear() ) }
|
|
::oWndCode:SetCaption( ::cPrgName )
|
|
::oWndCode:Refresh() // to force the window caption to update
|
|
ENDIF
|
|
::oBrwText:SetActiveLine( nLine )
|
|
::GotoLine( nLine )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE ShowHelp( cTopic ) CLASS HBDebugger
|
|
|
|
__dbgHelp( cTopic )
|
|
|
|
RETURN
|
|
|
|
|
|
#define MAX_VARS_HEIGHT 7
|
|
|
|
METHOD PROCEDURE ShowVars() CLASS HBDebugger
|
|
|
|
LOCAL oCol
|
|
LOCAL lRepaint := .F.
|
|
LOCAL nTop
|
|
LOCAL nBottom
|
|
LOCAL lWindowCreated := .F.
|
|
LOCAL aColors
|
|
|
|
IF ::lGo
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF ! ( ::lShowLocals .OR. ::lShowStatics .OR. ::lShowPrivates .OR. ;
|
|
::lShowPublics .OR. ::lShowGlobals )
|
|
RETURN
|
|
ENDIF
|
|
|
|
DispBegin()
|
|
|
|
IF ::oWndVars == NIL
|
|
|
|
nTop := iif( ::oWndPnt != NIL .AND. ::oWndPnt:lVisible, ::oWndPnt:nBottom + 1, 1 )
|
|
nBottom := nTop + Min( MAX_VARS_HEIGHT, Len( ::aVars ) + 1 )
|
|
|
|
::oWndVars := HBDbWindow():New( nTop, 0, nBottom, ;
|
|
::nMaxCol - iif( ::oWndStack != NIL, ::oWndStack:nWidth(), 0 ), ;
|
|
"Monitor:" + ;
|
|
iif( ::lShowGlobals, " Global", "" ) + iif( ::lShowLocals, " Local", "" ) + ;
|
|
iif( ::lShowStatics, " Static", "" ) + iif( ::lShowPrivates, " Private", "" ) + ;
|
|
iif( ::lShowPublics, " Public", "" ) )
|
|
|
|
::oWndVars:bLButtonDown := {| nMRow, nMCol | ::WndVarsLButtonDown( nMRow, nMCol ) }
|
|
::oWndVars:bLDblClick := {|| ::EditVar( ::oBrwVars:Cargo[ 1 ] ) }
|
|
::oWndVars:bPainted := {|| iif( Len( ::aVars ) > 0, ( ::oBrwVars:RefreshAll():ForceStable(), RefreshVarsS( ::oBrwVars ) ), ) }
|
|
|
|
::oWndVars:bKeyPressed := {| nKey | iif( Len( ::aVars ) == 0, NIL, ( ;
|
|
iif( nKey == K_DOWN, ::oBrwVars:Down(), NIL ), ;
|
|
iif( nKey == K_UP, ::oBrwVars:Up(), NIL ), ;
|
|
iif( nKey == K_PGDN, ::oBrwVars:PageDown(), NIL ), ;
|
|
iif( nKey == K_PGUP, ::oBrwVars:PageUp(), NIL ), ;
|
|
iif( nKey == K_HOME, ::oBrwVars:GoTop(), NIL ), ;
|
|
iif( nKey == K_END, ::oBrwVars:GoBottom(), NIL ), ;
|
|
iif( nKey == K_ENTER, ::EditVar( ::oBrwVars:Cargo[ 1 ] ), NIL ), ;
|
|
iif( Len( ::aVars ) > 0, ::oBrwVars:ForceStable(), NIL ) ) ) }
|
|
|
|
// Maintain fixed window array order: code, monitor, watch, callstack, command
|
|
hb_AIns( ::aWindows, 2, ::oWndVars, .T. )
|
|
IF ::nCurrentWindow >= 2
|
|
::nCurrentWindow++
|
|
ENDIF
|
|
|
|
lWindowCreated := .T.
|
|
ELSE
|
|
|
|
nTop := ::oWndVars:nTop
|
|
::oWndVars:cCaption := "Monitor:" + ;
|
|
iif( ::lShowGlobals, " Global", "" ) + ;
|
|
iif( ::lShowLocals, " Local", "" ) + ;
|
|
iif( ::lShowStatics, " Static", "" ) + ;
|
|
iif( ::lShowPrivates, " Private", "" ) + ;
|
|
iif( ::lShowPublics, " Public", "" )
|
|
|
|
nBottom := ::oWndVars:nBottom
|
|
DO CASE
|
|
CASE Len( ::aVars ) == 0
|
|
IF ::oWndVars:nBottom - ::oWndVars:nTop > 1
|
|
nBottom := nTop + 1
|
|
ENDIF
|
|
CASE Len( ::aVars ) > ::oWndVars:nBottom - ::oWndVars:nTop - 1
|
|
nBottom := nTop + Min( Len( ::aVars ) + 1, MAX_VARS_HEIGHT )
|
|
CASE Len( ::aVars ) < ::oWndVars:nBottom - ::oWndVars:nTop - 1
|
|
nBottom := nTop + Len( ::aVars ) + 1
|
|
OTHERWISE
|
|
nBottom := ::oWndVars:nBottom
|
|
ENDCASE
|
|
ENDIF
|
|
|
|
IF Len( ::aVars ) > 0 .AND. ::oBrwVars == NIL
|
|
::oBrwVars := HBDbBrowser():New( nTop + 1, 1, nBottom - 1, ;
|
|
::nMaxCol - iif( ::oWndStack != NIL, ::oWndStack:nWidth(), 0 ) - 1 )
|
|
aColors := __dbgColors()
|
|
::oBrwVars:Cargo := { 1, {} } // Actual highlighted row
|
|
::oBrwVars:ColorSpec := aColors[ 2 ] + "," + aColors[ 5 ] + "," + aColors[ 3 ] + "," + aColors[ 6 ]
|
|
::oBrwVars:goTopBlock := {|| ::oBrwVars:cargo[ 1 ] := Min( 1, Len( ::aVars ) ) }
|
|
::oBrwVars:goBottomBlock := {|| ::oBrwVars:cargo[ 1 ] := Max( 1, Len( ::aVars ) ) }
|
|
::oBrwVars:skipBlock := {| nSkip, nOld | ;
|
|
nOld := ::oBrwVars:Cargo[ 1 ], ;
|
|
::oBrwVars:Cargo[ 1 ] += nSkip, ;
|
|
::oBrwVars:Cargo[ 1 ] := Min( Max( ::oBrwVars:Cargo[ 1 ], 1 ), Len( ::aVars ) ), ;
|
|
::oBrwVars:Cargo[ 1 ] - nOld }
|
|
|
|
oCol := HBDbColumnNew( "", ;
|
|
{|| PadR( hb_ntos( ::oBrwVars:Cargo[ 1 ] - 1 ) + ") " + ;
|
|
::VarGetInfo( ::aVars[ Max( ::oBrwVars:Cargo[ 1 ], 1 ) ] ), ;
|
|
::oWndVars:nWidth() - 2 ) } )
|
|
::oBrwVars:AddColumn( oCol )
|
|
AAdd( ::oBrwVars:Cargo[ 2 ], ::aVars )
|
|
oCol:DefColor := { 1, 2 }
|
|
::oBrwVars:ForceStable()
|
|
ELSEIF Len( ::aVars ) == 0
|
|
::oBrwVars := NIL
|
|
::oWndVars:Browser := NIL
|
|
ENDIF
|
|
|
|
::oWndVars:Browser := ::oBrwVars
|
|
|
|
IF lWindowCreated
|
|
::oWndVars:Show()
|
|
::ResizeWindows( ::oWndVars )
|
|
|
|
ELSE
|
|
|
|
IF ::oBrwVars != NIL
|
|
IF ::oBrwVars:cargo[ 1 ] <= 0
|
|
::oBrwVars:cargo[ 1 ] := 1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF Len( ::aVars ) == 0
|
|
IF nBottom == ::oWndVars:nBottom
|
|
/* We still need to redraw window caption, it could have changed */
|
|
::oWndVars:Refresh()
|
|
ENDIF
|
|
ENDIF
|
|
IF nBottom != ::oWndVars:nBottom
|
|
::oWndVars:Resize( ,, nBottom )
|
|
lRepaint := .T.
|
|
ELSE
|
|
IF ::oBrwVars != NIL
|
|
::oBrwVars:RefreshAll():ForceStable()
|
|
ENDIF
|
|
::oWndVars:Refresh()
|
|
ENDIF
|
|
IF ! ::oWndVars:lVisible .OR. lRepaint
|
|
::ResizeWindows( ::oWndVars )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
DispEnd()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Stack() CLASS HBDebugger
|
|
|
|
::lShowCallStack := ! ::lShowCallStack
|
|
::oPulldown:GetItemByIdent( "CALLSTACK" ):checked := ::lShowCallStack
|
|
|
|
IF ::lActive
|
|
IF ::lShowCallStack
|
|
::ShowCallStack()
|
|
ELSE
|
|
::HideCallStack()
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Static() CLASS HBDebugger
|
|
|
|
::lShowStatics := ! ::lShowStatics
|
|
::RefreshVars()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE Step() CLASS HBDebugger
|
|
|
|
// we are starting to run again so reset to the deepest call if displaying stack
|
|
IF ::oBrwStack != NIL
|
|
::oBrwStack:GoTop()
|
|
ENDIF
|
|
|
|
::RestoreAppScreen()
|
|
::RestoreAppState()
|
|
::Exit()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD ToCursor() CLASS HBDebugger
|
|
|
|
IF ::IsValidStopLine( ::cPrgName, ::oBrwText:RowPos )
|
|
__dbgSetToCursor( ::pInfo, ::cPrgName, ::oBrwText:RowPos )
|
|
::RestoreAppScreen()
|
|
::RestoreAppState()
|
|
::Exit()
|
|
ENDIF
|
|
|
|
RETURN Self
|
|
|
|
|
|
// Toggle a breakpoint at the cursor position in the currently viewed file
|
|
// which may be different from the file in which execution was broken
|
|
METHOD PROCEDURE ToggleBreakPoint( nLine, cFileName ) CLASS HBDebugger
|
|
|
|
// look for a breakpoint which matches both line number and module name
|
|
|
|
LOCAL nAt
|
|
|
|
IF ! ::lActive
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF nLine == NIL
|
|
cFileName := ::cPrgName
|
|
nLine := ::oBrwText:RowPos
|
|
ENDIF
|
|
|
|
IF ( nAt := __dbgIsBreak( ::pInfo, cFileName, nLine ) ) >= 0
|
|
__dbgDelBreak( ::pInfo, nAt )
|
|
ELSEIF ::IsValidStopLine( cFileName, nLine )
|
|
__dbgAddBreak( ::pInfo, cFileName, nLine )
|
|
ENDIF
|
|
|
|
::oBrwText:RefreshAll():ForceStable()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD DeleteBreakPoint( cPos ) CLASS HBDebugger
|
|
|
|
LOCAL nAt
|
|
|
|
IF Empty( cPos )
|
|
cPos := AllTrim( ::InputBox( "Item number to delete", "0" ) )
|
|
IF LastKey() == K_ESC
|
|
cPos := ""
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IsDigit( cPos )
|
|
__dbgDelBreak( ::pInfo, Val( cPos ) )
|
|
ELSEIF cPos == "ALL"
|
|
FOR nAt := Len( __dbgGetBreakPoints( ::pInfo ) ) - 1 TO 0 STEP -1
|
|
__dbgDelBreak( ::pInfo, nAt )
|
|
NEXT
|
|
ENDIF
|
|
|
|
::oBrwText:RefreshAll():ForceStable()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD ListBreakPoint() CLASS HBDebugger
|
|
|
|
LOCAL aBreak
|
|
|
|
FOR EACH aBreak IN __dbgGetBreakPoints( ::pInfo )
|
|
::CommandWindowDisplay( ;
|
|
hb_ntos( aBreak:__enumIndex() - 1 ) + ") " + ;
|
|
hb_ntos( aBreak[ 1 ] ) + " " + ;
|
|
AllTrim( aBreak[ 2 ] ), .F. )
|
|
NEXT
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD Trace() CLASS HBDebugger
|
|
|
|
__dbgSetTrace( ::pInfo )
|
|
::Step() // forces a Step()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD TracepointAdd( cExpr ) CLASS HBDebugger
|
|
|
|
LOCAL aWatch
|
|
|
|
IF cExpr == NIL
|
|
cExpr := AllTrim( ::InputBox( "Enter Tracepoint",, __dbgExprValidBlock() ) )
|
|
IF LastKey() == K_ESC
|
|
RETURN Self
|
|
ENDIF
|
|
ENDIF
|
|
cExpr := AllTrim( cExpr )
|
|
IF Empty( cExpr )
|
|
RETURN Self
|
|
ENDIF
|
|
aWatch := { "tp", cExpr, NIL }
|
|
::RestoreAppState()
|
|
__dbgAddWatch( ::pInfo, cExpr, .T. )
|
|
::SaveAppState()
|
|
AAdd( ::aWatch, aWatch )
|
|
::WatchpointsShow()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD VarGetInfo( aVar ) CLASS HBDebugger
|
|
|
|
LOCAL uValue := ::VarGetValue( aVar )
|
|
LOCAL cType
|
|
|
|
SWITCH Left( aVar[ VAR_TYPE ], 1 )
|
|
CASE "G" ; cType := "Global" ; EXIT
|
|
CASE "L" ; cType := "Local" ; EXIT
|
|
CASE "S" ; cType := "Static" ; EXIT
|
|
OTHERWISE ; cType := aVar[ VAR_TYPE ]
|
|
ENDSWITCH
|
|
|
|
RETURN aVar[ VAR_NAME ] + " <" + cType + ", " + ValType( uValue ) + ">: " + __dbgValToStr( uValue )
|
|
|
|
|
|
METHOD VarGetValue( aVar ) CLASS HBDebugger
|
|
|
|
SWITCH Left( aVar[ VAR_TYPE ], 1 )
|
|
CASE "G" ; RETURN __dbgVMVarGGet( aVar[ VAR_LEVEL ], aVar[ VAR_POS ] )
|
|
CASE "L" ; RETURN __dbgVMVarLGet( __dbgProcLevel() - aVar[ VAR_LEVEL ], aVar[ VAR_POS ] )
|
|
CASE "S" ; RETURN __dbgVMVarSGet( aVar[ VAR_LEVEL ], aVar[ VAR_POS ] )
|
|
ENDSWITCH
|
|
|
|
RETURN aVar[ VAR_POS ] // Public or Private
|
|
|
|
|
|
METHOD VarSetValue( aVar, uValue ) CLASS HBDebugger
|
|
|
|
LOCAL nProcLevel
|
|
|
|
SWITCH Left( aVar[ VAR_TYPE ], 1 )
|
|
CASE "G"
|
|
__dbgVMVarGSet( aVar[ VAR_LEVEL ], aVar[ VAR_POS ], uValue )
|
|
EXIT
|
|
CASE "L"
|
|
nProcLevel := __dbgProcLevel() - aVar[ VAR_LEVEL ] // skip debugger stack
|
|
__dbgVMVarLSet( nProcLevel, aVar[ VAR_POS ], uValue )
|
|
EXIT
|
|
CASE "S"
|
|
__dbgVMVarSSet( aVar[ VAR_LEVEL ], aVar[ VAR_POS ], uValue )
|
|
EXIT
|
|
OTHERWISE
|
|
// Public or Private
|
|
aVar[ VAR_POS ] := uValue
|
|
&( aVar[ VAR_NAME ] ) := uValue
|
|
ENDSWITCH
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD PROCEDURE ViewSets() CLASS HBDebugger
|
|
|
|
LOCAL oWndSets := HBDbWindow():New( 1, 8, ::nMaxRow - 2, ::nMaxCol - 8, ;
|
|
"System Settings[1..47]", ::ClrModal() )
|
|
LOCAL aSets := { ;
|
|
"Exact", "Fixed", "Decimals", "DateFormat", "Epoch", "Path", ;
|
|
"Default", "Exclusive", "SoftSeek", "Unique", "Deleted", ;
|
|
"Cancel", "Debug", "TypeAhead", "Color", "Cursor", "Console", ;
|
|
"Alternate", "AltFile", "Device", "Extra", "ExtraFile", ;
|
|
"Printer", "PrintFile", "Margin", "Bell", "Confirm", "Escape", ;
|
|
"Insert", "Exit", "Intensity", "ScoreBoard", "Delimeters", ;
|
|
"DelimChars", "Wrap", "Message", "MCenter", "ScrollBreak", ;
|
|
"EventMask", "VideoMode", "MBlockSize", "MFileExt", ;
|
|
"StrictRead", "Optimize", "Autopen", "Autorder", "AutoShare" }
|
|
|
|
LOCAL oBrwSets := HBDbBrowser():new( oWndSets:nTop + 1, oWndSets:nLeft + 1, ;
|
|
oWndSets:nBottom - 1, oWndSets:nRight - 1 )
|
|
LOCAL nWidth := oWndSets:nRight - oWndSets:nLeft - 1
|
|
LOCAL oCol
|
|
|
|
oBrwSets:Cargo := { 1, {} } // Actual highlighted row
|
|
oBrwSets:autolite := .F.
|
|
oBrwSets:ColorSpec := ::ClrModal()
|
|
oBrwSets:goTopBlock := {|| oBrwSets:cargo[ 1 ] := 1 }
|
|
oBrwSets:goBottomBlock := {|| oBrwSets:cargo[ 1 ] := Len( oBrwSets:cargo[ 2 ][ 1 ] ) }
|
|
oBrwSets:skipBlock := {| nPos | ( nPos := ArrayBrowseSkip( nPos, oBrwSets ), oBrwSets:cargo[ 1 ] := ;
|
|
oBrwSets:cargo[ 1 ] + nPos, nPos ) }
|
|
oBrwSets:AddColumn( oCol := HBDbColumnNew( "", {|| PadR( aSets[ oBrwSets:cargo[ 1 ] ], 12 ) } ) )
|
|
AAdd( oBrwSets:Cargo[ 2 ], aSets )
|
|
ocol:defcolor := { 1, 2 }
|
|
oBrwSets:AddColumn( oCol := HBDbColumnNew( "", ;
|
|
{|| PadR( __dbgValToExp( Set( oBrwSets:cargo[ 1 ] ) ), nWidth - 13 ) } ) )
|
|
ocol:defcolor := { 1, 3 }
|
|
ocol:width := 40
|
|
oWndSets:bPainted := {|| oBrwSets:ForceStable(), RefreshVarsS( oBrwSets ) }
|
|
oWndSets:bKeyPressed := {| nKey | SetsKeyPressed( nKey, oBrwSets, Len( aSets ), ;
|
|
oWndSets, "System Settings", ;
|
|
{|| ::EditSet( oBrwSets:Cargo[ 1 ], oBrwSets ) } ) }
|
|
|
|
oWndSets:ShowModal()
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD WatchGetInfo( nWatch ) CLASS HBDebugger
|
|
|
|
LOCAL xVal
|
|
LOCAL cType
|
|
LOCAL lValid
|
|
LOCAL aWatch := ::aWatch[ nWatch ]
|
|
|
|
::RestoreAppState()
|
|
xVal := ::GetExprValue( nWatch, @lValid )
|
|
::SaveAppState()
|
|
|
|
IF lValid
|
|
cType := ValType( xVal )
|
|
xVal := __dbgValToStr( xVal )
|
|
ELSE
|
|
cType := "U"
|
|
xVal := "Undefined"
|
|
ENDIF
|
|
|
|
RETURN aWatch[ WP_EXPR ] + " <" + aWatch[ WP_TYPE ] + ", " + cType + ">: " + xVal
|
|
|
|
|
|
METHOD WatchpointAdd( cExpr ) CLASS HBDebugger
|
|
|
|
LOCAL aWatch
|
|
|
|
IF cExpr == NIL
|
|
cExpr := ::InputBox( "Enter Watchpoint",, __dbgExprValidBlock() )
|
|
IF LastKey() == K_ESC
|
|
RETURN Self
|
|
ENDIF
|
|
ENDIF
|
|
|
|
cExpr := AllTrim( cExpr )
|
|
|
|
IF Empty( cExpr )
|
|
RETURN Self
|
|
ENDIF
|
|
|
|
aWatch := { "wp", cExpr }
|
|
__dbgAddWatch( ::pInfo, cExpr, .F. )
|
|
AAdd( ::aWatch, aWatch )
|
|
::WatchpointsShow()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD WatchpointDel( nPos ) CLASS HBDebugger
|
|
|
|
IF ::oWndPnt != NIL .AND. ::oWndPnt:lVisible
|
|
IF nPos == NIL
|
|
// called from the menu
|
|
nPos := ::InputBox( "Enter item number to delete", ::oBrwPnt:cargo[ 1 ] - 1 )
|
|
IF LastKey() == K_ESC
|
|
nPos := -1
|
|
ENDIF
|
|
ELSE
|
|
nPos--
|
|
ENDIF
|
|
IF nPos >= 0 .AND. nPos < Len( ::aWatch )
|
|
::oBrwPnt:gotop()
|
|
__dbgDelWatch( ::pInfo, nPos )
|
|
hb_ADel( ::aWatch, nPos + 1, .T. )
|
|
IF Len( ::aWatch ) == 0
|
|
::WatchpointsHide()
|
|
ELSE
|
|
::WatchpointsShow()
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD WatchpointEdit( nPos ) CLASS HBDebugger
|
|
|
|
LOCAL cExpr := ::InputBox( "Enter Watchpoint", ::aWatch[ nPos ][ WP_EXPR ], __dbgExprValidBlock() )
|
|
LOCAL aWatch
|
|
|
|
IF LastKey() == K_ESC
|
|
RETURN Self
|
|
ENDIF
|
|
|
|
cExpr := AllTrim( cExpr )
|
|
|
|
IF Empty( cExpr )
|
|
RETURN Self
|
|
ENDIF
|
|
|
|
aWatch := { "wp", cExpr }
|
|
|
|
__dbgSetWatch( ::pInfo, nPos - 1, cExpr, .F. )
|
|
::aWatch[ nPos ] := aWatch
|
|
::WatchpointsShow()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD WatchpointInspect( nPos ) CLASS HBDebugger
|
|
|
|
LOCAL xValue
|
|
LOCAL lValid
|
|
|
|
::RestoreAppState()
|
|
xValue := ::GetExprValue( ::aWatch[ nPos ][ WP_EXPR ], @lValid )
|
|
::SaveAppState()
|
|
|
|
::InputBox( ::aWatch[ nPos ][ WP_EXPR ], xValue,, .F. )
|
|
::RefreshVars()
|
|
|
|
RETURN Self
|
|
|
|
|
|
METHOD PROCEDURE WatchpointsHide() CLASS HBDebugger
|
|
|
|
::oWndPnt:Hide()
|
|
::oWndCode:nTop := iif( ::oWndVars != NIL .AND. ::oWndVars:lVisible, ::oWndVars:nBottom + 1, 1 )
|
|
::oBrwText:Resize( ::oWndCode:nTop + 1 )
|
|
IF ::aWindows[ ::nCurrentWindow ] == ::oWndPnt
|
|
::NextWindow()
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE WatchpointsShow() CLASS HBDebugger
|
|
|
|
LOCAL oCol
|
|
LOCAL lRepaint := .F.
|
|
LOCAL nTop
|
|
LOCAL aColors
|
|
LOCAL nPos
|
|
|
|
IF ::lGo
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF Len( ::aWatch ) == 0
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF ::oWndPnt == NIL
|
|
|
|
nTop := iif( ::oWndVars != NIL .AND. ::oWndVars:lVisible, ::oWndVars:nBottom, 0 ) + 1
|
|
|
|
::oWndPnt := HBDbWindow():New( nTop, ;
|
|
0, ;
|
|
nTop + Min( 4, Len( ::aWatch ) ) + 1, ;
|
|
::nMaxCol - iif( ::oWndStack != NIL, ::oWndStack:nWidth(), 0 ), ;
|
|
"Watch" )
|
|
|
|
#if 0
|
|
::oBrwText:Resize( ::oWndPnt:nBottom + 1 )
|
|
::oWndCode:nTop := ::oWndPnt:nBottom + 1
|
|
::oBrwText:Resize( ::oWndCode:nTop + 1 )
|
|
::oBrwText:RefreshAll()
|
|
::oWndCode:SetFocus( .T. )
|
|
|
|
::oWndPnt:bLButtonDown := {| nMRow, nMCol | ::WndVarsLButtonDown( nMRow, nMCol ) }
|
|
::oWndPnt:bLDblClick := {| nMRow, nMCol | ::EditVar( ::oBrwPnt:Cargo[ 1 ] ) }
|
|
#endif
|
|
|
|
::oBrwPnt := HBDbBrowser():New( nTop + 1, 1, ::oWndPnt:nBottom - 1, ::nMaxCol - iif( ::oWndStack != NIL, ;
|
|
::oWndStack:nWidth(), 0 ) - 1 )
|
|
|
|
::oWndPnt:Browser := ::oBrwPnt
|
|
|
|
::oBrwPnt:Cargo := { 1, {} } // Actual highlighted row
|
|
aColors := __dbgColors()
|
|
::oBrwPnt:ColorSpec := aColors[ 2 ] + "," + aColors[ 5 ] + "," + aColors[ 3 ] + "," + aColors[ 6 ]
|
|
::oBrwPnt:goTopBlock := {|| ::oBrwPnt:cargo[ 1 ] := Min( 1, Len( ::aWatch ) ) }
|
|
::oBrwPnt:goBottomBlock := {|| ::oBrwPnt:cargo[ 1 ] := Len( ::aWatch ) }
|
|
::oBrwPnt:skipBlock := {| nSkip, nOld | nOld := ::oBrwPnt:Cargo[ 1 ], ;
|
|
::oBrwPnt:Cargo[ 1 ] += nSkip, ;
|
|
::oBrwPnt:Cargo[ 1 ] := Min( Max( ::oBrwPnt:Cargo[ 1 ], 1 ), ;
|
|
Len( ::aWatch ) ), ;
|
|
iif( Len( ::aWatch ) > 0, ::oBrwPnt:Cargo[ 1 ] - nOld, 0 ) }
|
|
|
|
oCol := HBDbColumnNew( "", ;
|
|
{|| PadR( iif( Len( ::aWatch ) > 0, ;
|
|
hb_ntos( ::oBrwPnt:Cargo[ 1 ] - 1 ) + ") " + ;
|
|
::WatchGetInfo( Max( ::oBrwPnt:Cargo[ 1 ], 1 ) ), ;
|
|
" " ), ::oWndPnt:nWidth() - 2 ) } )
|
|
::oBrwPnt:AddColumn( oCol )
|
|
AAdd( ::oBrwPnt:Cargo[ 2 ], ::aWatch )
|
|
oCol:DefColor := { 1, 2 }
|
|
|
|
::oWndPnt:bPainted := {|| iif( Len( ::aWatch ) > 0, ( ::oBrwPnt:RefreshAll():ForceStable(), RefreshVarsS( ::oBrwPnt ) /*, ::RefreshVars()*/ ) , ) }
|
|
|
|
::oWndPnt:bKeyPressed := {| nKey | ( ;
|
|
iif( nKey == K_DOWN, ::oBrwPnt:Down(), NIL ), ;
|
|
iif( nKey == K_UP, ::oBrwPnt:Up(), NIL ), ;
|
|
iif( nKey == K_PGDN, ::oBrwPnt:PageDown(), NIL ), ;
|
|
iif( nKey == K_PGUP, ::oBrwPnt:PageUp(), NIL ), ;
|
|
iif( nKey == K_HOME, ::oBrwPnt:GoTop(), NIL ), ;
|
|
iif( nKey == K_END, ::oBrwPnt:GoBottom(), NIL ), ;
|
|
iif( nKey == K_DEL, ::WatchpointDel( ::oBrwPnt:Cargo[ 1 ] ), NIL ), ;
|
|
iif( nKey == K_ENTER, ::WatchpointEdit( ::oBrwPnt:Cargo[ 1 ] ), NIL ), ;
|
|
iif( nKey == K_CTRL_ENTER, ::WatchpointInspect( ::oBrwPnt:Cargo[ 1 ] ), NIL ), ;
|
|
::oBrwPnt:ForceStable() ) }
|
|
|
|
// Maintain fixed window array order: code, monitor, watch, callstack, command
|
|
nPos := iif( ::aWindows[ 2 ] == ::oWndVars, 3, 2 )
|
|
hb_AIns( ::aWindows, nPos, ::oWndPnt, .T. )
|
|
IF ::nCurrentWindow >= nPos
|
|
::nCurrentWindow++
|
|
ENDIF
|
|
|
|
::oWndPnt:Show()
|
|
::ResizeWindows( ::oWndPnt )
|
|
ELSE
|
|
IF ::oBrwPnt:cargo[ 1 ] <= 0
|
|
::oBrwPnt:cargo[ 1 ] := 1
|
|
ENDIF
|
|
DispBegin()
|
|
DO CASE
|
|
CASE Len( ::aWatch ) > ::oWndPnt:nBottom - ::oWndPnt:nTop - 1
|
|
// Resize( top, left, bottom, right )
|
|
::oWndPnt:Resize( ,, ::oWndPnt:nTop + Min( Len( ::aWatch ) + 1, 4 ) )
|
|
lRepaint := .T.
|
|
CASE Len( ::aWatch ) < ::oWndPnt:nBottom - ::oWndPnt:nTop - 1
|
|
::oWndPnt:Resize( ,, ::oWndPnt:nTop + Len( ::aWatch ) + 1 )
|
|
lRepaint := .T.
|
|
OTHERWISE
|
|
::oBrwPnt:RefreshAll():ForceStable()
|
|
ENDCASE
|
|
IF ! ::oWndPnt:lVisible .OR. lRepaint
|
|
::ResizeWindows( ::oWndPnt )
|
|
ENDIF
|
|
DispEnd()
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
METHOD PROCEDURE WndVarsLButtonDown( nMRow, nMCol ) CLASS HBDebugger
|
|
|
|
IF nMRow > ::oWndVars:nTop .AND. ;
|
|
nMRow < ::oWndVars:nBottom .AND. ;
|
|
nMCol > ::oWndVars:nLeft .AND. ;
|
|
nMCol < ::oWndVars:nRight
|
|
|
|
IF nMRow - ::oWndVars:nTop >= 1 .AND. ;
|
|
nMRow - ::oWndVars:nTop <= Len( ::aVars )
|
|
|
|
DO WHILE ::oBrwVars:RowPos > nMRow - ::oWndVars:nTop
|
|
::oBrwVars:Up()
|
|
::oBrwVars:ForceStable()
|
|
ENDDO
|
|
|
|
DO WHILE ::oBrwVars:RowPos < nMRow - ::oWndVars:nTop
|
|
::oBrwVars:Down()
|
|
::oBrwVars:ForceStable()
|
|
ENDDO
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
|
|
STATIC PROCEDURE SetsKeyPressed( nKey, oBrwSets, nSets, oWnd, cCaption, bEdit )
|
|
|
|
SWITCH nKey
|
|
CASE K_UP
|
|
oBrwSets:up()
|
|
EXIT
|
|
|
|
CASE K_DOWN
|
|
oBrwSets:down()
|
|
EXIT
|
|
|
|
CASE K_HOME
|
|
CASE K_CTRL_PGUP
|
|
CASE K_CTRL_HOME
|
|
oBrwSets:goTop()
|
|
EXIT
|
|
|
|
CASE K_END
|
|
CASE K_CTRL_PGDN
|
|
CASE K_CTRL_END
|
|
oBrwSets:goBottom()
|
|
EXIT
|
|
|
|
CASE K_PGDN
|
|
|
|
oBrwSets:pageDown()
|
|
EXIT
|
|
|
|
CASE K_PGUP
|
|
|
|
oBrwSets:pageUp()
|
|
EXIT
|
|
|
|
CASE K_ENTER
|
|
|
|
IF bEdit != NIL
|
|
Eval( bEdit )
|
|
ENDIF
|
|
|
|
IF LastKey() == K_ENTER
|
|
hb_keyPut( K_DOWN )
|
|
ENDIF
|
|
EXIT
|
|
|
|
ENDSWITCH
|
|
|
|
RefreshVarsS( oBrwSets )
|
|
|
|
oWnd:SetCaption( cCaption + "[" + hb_ntos( oBrwSets:Cargo[ 1 ] ) + ".." + hb_ntos( nSets ) + "]" )
|
|
|
|
RETURN
|
|
|
|
|
|
FUNCTION __dbgColors()
|
|
RETURN t_oDebugger:GetColors()
|
|
|
|
|
|
FUNCTION __dbg()
|
|
RETURN t_oDebugger
|
|
|
|
|
|
STATIC PROCEDURE RefreshVarsS( oBrowse )
|
|
|
|
LOCAL nLen := oBrowse:colCount
|
|
|
|
IF nLen == 2
|
|
oBrowse:deHilite():colPos := 2
|
|
ENDIF
|
|
oBrowse:deHilite():forceStable()
|
|
|
|
IF nLen == 2
|
|
oBrowse:hilite():colPos := 1
|
|
ENDIF
|
|
oBrowse:hilite()
|
|
|
|
RETURN
|
|
|
|
|
|
STATIC FUNCTION ArrayBrowseSkip( nPos, oBrwSets )
|
|
RETURN iif( oBrwSets:cargo[ 1 ] + nPos < 1, 0 - oBrwSets:cargo[ 1 ] + 1, ;
|
|
iif( oBrwSets:cargo[ 1 ] + nPos > Len( oBrwSets:cargo[ 2 ][ 1 ] ), ;
|
|
Len( oBrwSets:cargo[ 2 ][ 1 ] ) - oBrwSets:cargo[ 1 ], nPos ) )
|
|
|
|
|
|
STATIC FUNCTION PathToArray( cList )
|
|
|
|
LOCAL aList := {}
|
|
LOCAL cSep := hb_osPathListSeparator()
|
|
LOCAL cDirSep := hb_osPathDelimiters()
|
|
LOCAL nPos
|
|
|
|
IF cList != NIL
|
|
|
|
DO WHILE ( nPos := At( cSep, cList ) ) > 0
|
|
AAdd( aList, Left( cList, nPos - 1 ) ) // Add a new element
|
|
cList := SubStr( cList, nPos + 1 )
|
|
ENDDO
|
|
|
|
AAdd( aList, cList ) // Add final element
|
|
|
|
/* Strip ending delimiters */
|
|
AEval( aList, {| x, i | iif( Right( x, 1 ) $ cDirSep, aList[ i ] := hb_StrShrink( x ), ) } )
|
|
ENDIF
|
|
|
|
RETURN aList
|
|
|
|
|
|
/* Check if a string starts with another string with a min length */
|
|
STATIC FUNCTION hb_LeftEqN( cLine, cStart, nMin )
|
|
RETURN Len( cStart ) >= nMin .AND. hb_LeftEq( cLine, cStart )
|
|
|
|
|
|
FUNCTION __dbgExprValidBlock()
|
|
RETURN {| u | ! Type( u ) == "UE" .OR. ( __dbgAlert( "Expression error" ), .F. ) }
|
|
|
|
|
|
FUNCTION __dbgInput( nRow, nCol, nWidth, cValue, bValid, cColor, nSize )
|
|
|
|
LOCAL lOK := .F.
|
|
LOCAL nKey
|
|
LOCAL oGet
|
|
|
|
IF ! HB_ISNUMERIC( nWidth )
|
|
nWidth := Len( cValue )
|
|
ENDIF
|
|
oGet := HbDbInput():new( nRow, nCol, nWidth, cValue, cColor, nSize )
|
|
|
|
oGet:display()
|
|
|
|
DO WHILE .T.
|
|
oGet:showCursor()
|
|
nKey := __dbgInkey()
|
|
DO CASE
|
|
CASE nKey == K_ESC
|
|
EXIT
|
|
CASE nKey == K_ENTER
|
|
IF bValid == NIL .OR. Eval( bValid, oGet:getValue() )
|
|
cValue := oGet:getValue()
|
|
lOK := .T.
|
|
EXIT
|
|
ENDIF
|
|
OTHERWISE
|
|
oGet:applyKey( nKey )
|
|
ENDCASE
|
|
ENDDO
|
|
|
|
SetCursor( SC_NONE )
|
|
|
|
RETURN lOK
|
|
|
|
|
|
FUNCTION __dbgAChoice( nTop, nLeft, nBottom, nRight, aItems, cColors )
|
|
|
|
LOCAL oBrw
|
|
LOCAL oCol
|
|
LOCAL nRow
|
|
LOCAL nLen
|
|
|
|
oBrw := HBDbBrowser():New( nTop, nLeft, nBottom, nRight )
|
|
oBrw:colorSpec := cColors
|
|
nLen := nRight - nLeft + 1
|
|
nRow := 1
|
|
oCol := HBDbColumnNew( "", {|| PadR( aItems[ nRow ], nLen ) } )
|
|
oBrw:AddColumn( oCol )
|
|
oBrw:goTopBlock := {|| nRow := 1 }
|
|
oBrw:goBottomBlock := {|| nRow := Len( aItems ) }
|
|
oBrw:skipBlock := {| n | n := iif( n < 0, Max( n, 1 - nRow ), ;
|
|
Min( Len( aItems ) - nRow, n ) ), ;
|
|
nRow += n, n }
|
|
DO WHILE .T.
|
|
oBrw:forceStable()
|
|
SWITCH __dbgInkey()
|
|
CASE K_UP; oBrw:up(); EXIT
|
|
CASE K_DOWN; oBrw:down(); EXIT
|
|
CASE K_PGUP; oBrw:pageUp(); EXIT
|
|
CASE K_PGDN; oBrw:pageDown(); EXIT
|
|
CASE K_HOME; oBrw:goTop(); EXIT
|
|
CASE K_END; oBrw:goBottom(); EXIT
|
|
CASE K_ESC; nRow := 0
|
|
CASE K_ENTER; RETURN nRow
|
|
ENDSWITCH
|
|
ENDDO
|
|
|
|
RETURN 0
|
|
|
|
|
|
FUNCTION __dbgAlert( cMessage )
|
|
RETURN hb_gtAlert( cMessage, { "Ok" }, "W+/R", "W+/B" )
|
|
|
|
|
|
FUNCTION __dbgInkey()
|
|
|
|
LOCAL nKey
|
|
LOCAL lDebug, lCancel
|
|
|
|
lDebug := Set( _SET_DEBUG, .F. )
|
|
lCancel := Set( _SET_CANCEL, .F. )
|
|
nKey := Inkey( 0, INKEY_ALL )
|
|
Set( _SET_CANCEL, lCancel )
|
|
Set( _SET_DEBUG, lDebug )
|
|
|
|
RETURN nKey
|
|
|
|
|
|
FUNCTION __dbgValToStr( uVal )
|
|
|
|
SWITCH ValType( uVal )
|
|
#ifdef HB_CLP_STRICT
|
|
CASE "C"
|
|
CASE "M" ; RETURN '"' + uVal + '"'
|
|
CASE "D" ; RETURN DToC( uVal )
|
|
CASE "T" ; RETURN hb_TToC( uVal )
|
|
CASE "O" ; RETURN "{ ... }"
|
|
#else
|
|
CASE "C"
|
|
CASE "M" ; RETURN hb_StrToExp( uVal )
|
|
CASE "D" ; RETURN Left( hb_TSToStr( uVal, .F. ), 10 )
|
|
CASE "T" ; RETURN hb_TSToStr( uVal, .T. )
|
|
CASE "O" ; RETURN "Class " + uVal:ClassName() + " object"
|
|
#endif
|
|
CASE "N" ; RETURN Str( uVal )
|
|
CASE "L" ; RETURN iif( uVal, ".T.", ".F." )
|
|
CASE "S" ; RETURN "@" + uVal:name + "()"
|
|
CASE "B" ; RETURN "{|| ... }"
|
|
CASE "A" ; RETURN "{ ... }"
|
|
CASE "H" ; RETURN "{ => }"
|
|
CASE "P" ; RETURN "<pointer>"
|
|
OTHERWISE
|
|
IF uVal == NIL
|
|
RETURN "NIL"
|
|
ENDIF
|
|
ENDSWITCH
|
|
|
|
RETURN "U"
|
|
|
|
|
|
FUNCTION __dbgValToExp( uVal )
|
|
|
|
SWITCH ValType( uVal )
|
|
#ifdef HB_CLP_STRICT
|
|
CASE "C"
|
|
CASE "M" ; RETURN '"' + uVal + '"'
|
|
CASE "D" ; RETURN 'CToD("' + DToC( uVal ) + '")'
|
|
CASE "T" ; RETURN 'hb_CToT("' + hb_TToC( uVal ) + '")'
|
|
CASE "O" ; RETURN "Object"
|
|
#else
|
|
CASE "C"
|
|
CASE "M" ; RETURN hb_StrToExp( uVal )
|
|
CASE "D" ; RETURN 'd"' + Left( hb_TSToStr( uVal, .F. ), 10 ) + '"'
|
|
CASE "T" ; RETURN 't"' + hb_TSToStr( uVal, .T. ) + '"'
|
|
CASE "O" ; RETURN "{ " + uVal:className() + " Object }"
|
|
#endif
|
|
CASE "N" ; RETURN hb_ntos( uVal )
|
|
CASE "L" ; RETURN iif( uVal, ".T.", ".F." )
|
|
CASE "S" ; RETURN "@" + uVal:name + "()"
|
|
CASE "B" ; RETURN "{|| ... }"
|
|
CASE "A" ; RETURN "{ ... }"
|
|
CASE "H" ; RETURN "{ => }"
|
|
CASE "P" ; RETURN "<pointer>"
|
|
OTHERWISE
|
|
IF uVal == NIL
|
|
RETURN "NIL"
|
|
ENDIF
|
|
ENDSWITCH
|
|
|
|
RETURN "U"
|