From dfb6288137bb653475b7e03fb69dff9a550c6564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Tue, 9 Sep 2014 20:49:09 +0200 Subject: [PATCH] 2014-09-09 20:49 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * include/hbvm.h * src/vm/hvm.c + added new HVM function: hb_vmTryEval() This function tries to execute given block or function inside BEGIN SEQUENCE / RECOVER oErr / END SEQUENCE statement. It return HB_TRUE if it was executed without any problem and HB_FALSE otherwise. Result or RTE object is stored in 1-st parameter and should be freed by the caller using hb_itemRelese() * src/debug/dbgentry.c ! use hb_vmTryEval() instead of hb_itemDo() to evaluate trace point expressions. Now debugger does not crash when user sets tracepoint expression which cannot be evaluated in executed context. ! allow to use expressions with more then 99 variables ! added missing protections against GPF when wrong parameters are passed to __dbg*() functions * keep original trace and watch point expression for farther processing * replaced IS_IDENT_*() macros with HB_IS*IDCHAR() + added new debuger function: __dbgGetWatchPoints() -> contains subarrays describing trace and watch points: { , , , } It was the last function necessary to extract all information about debugged context from core internals. Now it's possible to create fully functional standalone debugger without storing and updating locally any information about debugger state. All such information can be accessed at any time using __dbg*() functions. It should greatly simplify creating 3-rd party debuggers like HWDebug or HBQTDebug. * src/debug/debugger.prg ! fixed callstack window updating during tracing and stepping. Tanks to Rolf for reporting the problem. --- ChangeLog.txt | 38 ++++++ include/hbvm.h | 1 + src/debug/dbgentry.c | 266 ++++++++++++++++++++++++++--------------- src/debug/debugger.prg | 3 + src/vm/hvm.c | 126 ++++++++++++++++++- 5 files changed, 333 insertions(+), 101 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0f2d41dc6d..c7739f10d3 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,44 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2014-09-09 20:49 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * include/hbvm.h + * src/vm/hvm.c + + added new HVM function: hb_vmTryEval() + This function tries to execute given block or function + inside BEGIN SEQUENCE / RECOVER oErr / END SEQUENCE statement. + It return HB_TRUE if it was executed without any problem and + HB_FALSE otherwise. Result or RTE object is stored in 1-st + parameter and should be freed by the caller using hb_itemRelese() + + * src/debug/dbgentry.c + ! use hb_vmTryEval() instead of hb_itemDo() to evaluate trace point + expressions. Now debugger does not crash when user sets tracepoint + expression which cannot be evaluated in executed context. + ! allow to use expressions with more then 99 variables + ! added missing protections against GPF when wrong parameters are + passed to __dbg*() functions + * keep original trace and watch point expression for farther + processing + * replaced IS_IDENT_*() macros with HB_IS*IDCHAR() + + added new debuger function: + __dbgGetWatchPoints() -> + contains subarrays describing trace and watch + points: + { , , , } + It was the last function necessary to extract all information + about debugged context from core internals. Now it's possible + to create fully functional standalone debugger without storing + and updating locally any information about debugger state. + All such information can be accessed at any time using __dbg*() + functions. + It should greatly simplify creating 3-rd party debuggers like + HWDebug or HBQTDebug. + + * src/debug/debugger.prg + ! fixed callstack window updating during tracing and stepping. + Tanks to Rolf for reporting the problem. + 2014-09-08 23:40 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/hbct/ctwin.c ! fixed typo in window area checking when current window is 0 diff --git a/include/hbvm.h b/include/hbvm.h index b31049b3e6..0b7e201ee3 100644 --- a/include/hbvm.h +++ b/include/hbvm.h @@ -127,6 +127,7 @@ extern HB_EXPORT HB_USHORT hb_vmRequestQuery( void ); extern HB_EXPORT HB_BOOL hb_vmRequestReenter( void ); extern HB_EXPORT void hb_vmRequestRestore( void ); extern HB_EXPORT HB_BOOL hb_vmRequestReenterExt( void ); +extern HB_EXPORT HB_BOOL hb_vmTryEval( PHB_ITEM * pResult, PHB_ITEM pItem, HB_ULONG ulPCount, ... ); extern HB_EXPORT HB_BOOL hb_vmIsActive( void ); extern HB_EXPORT HB_BOOL hb_vmIsReady( void ); diff --git a/src/debug/dbgentry.c b/src/debug/dbgentry.c index cd1fe91826..d1f98608cb 100644 --- a/src/debug/dbgentry.c +++ b/src/debug/dbgentry.c @@ -286,6 +286,35 @@ static PHB_ITEM hb_dbgActivateBreakArray( HB_DEBUGINFO * info ) } +static PHB_ITEM hb_dbgActivateWatchArray( HB_DEBUGINFO * info ) +{ + int i, j; + PHB_ITEM pArray = hb_itemArrayNew( info->nWatchPoints ); + + for( i = 0; i < info->nWatchPoints; i++ ) + { + PHB_ITEM pWatch = hb_arrayGetItemPtr( pArray, i + 1 ), xValue; + + for( j = 0; j < info->nTracePoints; j++ ) + { + if( info->aTrace[ j ].nIndex == i ) + break; + } + xValue = hb_dbgEval( info, &info->aWatch[ i ] ); + hb_arrayNew( pWatch, 4 ); + hb_arraySetC( pWatch, 1, info->aWatch[ i ].szExpr ); + hb_arraySetL( pWatch, 2, j < info->nTracePoints ); + hb_arraySetL( pWatch, 3, xValue != NULL ); + if( xValue ) + { + hb_arraySetForward( pWatch, 4, xValue ); + hb_itemRelease( xValue ); + } + } + return pArray; +} + + static PHB_ITEM hb_dbgActivateModuleArray( void ) { PHB_ITEM pArray; @@ -568,20 +597,23 @@ static const char * hb_dbgStripModuleName( const char * szName ) void hb_dbgAddBreak( void * handle, const char * szModule, int nLine, const char * szFunction ) { - HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; - HB_BREAKPOINT * pBreak; + if( szModule || szFunction ) + { + HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; + HB_BREAKPOINT * pBreak; - pBreak = ARRAY_ADD( HB_BREAKPOINT, info->aBreak, info->nBreakPoints ); - if( szModule ) - pBreak->szModule = hb_strdup( hb_dbgStripModuleName( szModule ) ); - else - pBreak->szModule = NULL; - pBreak->nLine = nLine; + pBreak = ARRAY_ADD( HB_BREAKPOINT, info->aBreak, info->nBreakPoints ); + if( szModule ) + pBreak->szModule = hb_strdup( hb_dbgStripModuleName( szModule ) ); + else + pBreak->szModule = NULL; + pBreak->nLine = nLine; - if( szFunction ) - pBreak->szFunction = hb_strdup( szFunction ); - else - pBreak->szFunction = NULL; + if( szFunction ) + pBreak->szFunction = hb_strdup( szFunction ); + else + pBreak->szFunction = NULL; + } } @@ -815,20 +847,23 @@ static void hb_dbgAddVar( int * nVars, HB_VARINFO ** aVars, const char * szName, void hb_dbgAddWatch( void * handle, const char * szExpr, HB_BOOL bTrace ) { - HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; - HB_WATCHPOINT * pWatch; - - pWatch = ARRAY_ADD( HB_WATCHPOINT, info->aWatch, info->nWatchPoints ); - pWatch->szExpr = hb_strdup( szExpr ); - pWatch->pBlock = NULL; - pWatch->nVars = 0; - - if( bTrace ) + if( szExpr ) { - HB_TRACEPOINT * pTrace = ARRAY_ADD( HB_TRACEPOINT, info->aTrace, info->nTracePoints ); + HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; + HB_WATCHPOINT * pWatch; - pTrace->nIndex = info->nWatchPoints - 1; - pTrace->xValue = hb_dbgEval( info, pWatch ); + pWatch = ARRAY_ADD( HB_WATCHPOINT, info->aWatch, info->nWatchPoints ); + pWatch->szExpr = hb_strdup( szExpr ); + pWatch->pBlock = NULL; + pWatch->nVars = 0; + + if( bTrace ) + { + HB_TRACEPOINT * pTrace = ARRAY_ADD( HB_TRACEPOINT, info->aTrace, info->nTracePoints ); + + pTrace->nIndex = info->nWatchPoints - 1; + pTrace->xValue = hb_dbgEval( info, pWatch ); + } } } @@ -981,7 +1016,11 @@ static PHB_ITEM hb_dbgEval( HB_DEBUGINFO * info, HB_WATCHPOINT * watch ) int i; info->bInside = HB_TRUE; - xResult = hb_itemDo( watch->pBlock, 1, aNewVars ); + if( ! hb_vmTryEval( &xResult, watch->pBlock, 1, aNewVars ) ) + { + hb_itemRelease( xResult ); + xResult = NULL; + } info->bInside = bInside; for( i = 0; i < watch->nVars; i++ ) @@ -1022,13 +1061,14 @@ static PHB_ITEM hb_dbgEvalMacro( const char * szExpr, PHB_ITEM pItem ) } -#define IS_IDENT_START( c ) HB_ISFIRSTIDCHAR( ( HB_UCHAR ) ( c ) ) -#define IS_IDENT_CHAR( c ) HB_ISNEXTIDCHAR( ( HB_UCHAR ) ( c ) ) - -static int hb_dbgEvalSubstituteVar( HB_WATCHPOINT * watch, char * szWord, int nStart, int nLen ) +static int hb_dbgEvalSubstituteVar( HB_WATCHPOINT * watch, + char * szWord, int nStart, int nLen, + char ** pszOrig ) { + char buf[ 16 ]; + char * szExpr; + HB_SIZE n; int j; - char * t; for( j = 0; j < watch->nVars; j++ ) { @@ -1041,16 +1081,20 @@ static int hb_dbgEvalSubstituteVar( HB_WATCHPOINT * watch, char * szWord, int nS else hb_xfree( szWord ); - t = ( char * ) hb_xgrab( strlen( watch->szExpr ) - nLen + 9 + 1 ); - memmove( t, watch->szExpr, nStart ); - memmove( t + nStart, "__dbg[", 6 ); - t[ nStart + 6 ] = '0' + ( char ) ( ( j + 1 ) / 10 ); - t[ nStart + 7 ] = '0' + ( char ) ( ( j + 1 ) % 10 ); - t[ nStart + 8 ] = ']'; - hb_strncpy( t + nStart + 9, watch->szExpr + nStart + nLen, strlen( watch->szExpr ) - nLen - nStart ); - hb_xfree( watch->szExpr ); - watch->szExpr = t; - return nStart + 9; + n = strlen( watch->szExpr ); + j = hb_snprintf( buf, sizeof( buf ), "__dbg[%d]", j + 1 ); + szExpr = ( char * ) hb_xgrab( n - nLen + j + 1 ); + memcpy( szExpr, watch->szExpr, nStart ); + memcpy( szExpr + nStart, buf, j ); + memcpy( szExpr + nStart + j, watch->szExpr + nStart + nLen, n - nLen - nStart ); + szExpr[ n + j - nLen ] = '\0'; + if( * pszOrig == NULL ) + * pszOrig = watch->szExpr; + else + hb_xfree( watch->szExpr ); + watch->szExpr = szExpr; + + return nStart + j; } @@ -1059,7 +1103,7 @@ static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch ) int i = 0; PHB_ITEM pBlock; HB_BOOL bAfterId = HB_FALSE; - char * s; + char * szBlock, * szOrig = NULL; HB_ISIZ buffsize; watch->nVars = 0; @@ -1067,13 +1111,13 @@ static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch ) { char c = watch->szExpr[ i ]; - if( IS_IDENT_START( c ) ) + if( HB_ISFIRSTIDCHAR( c ) ) { int nStart = i, nLen; int j = i; char * szWord; - while( c && IS_IDENT_CHAR( c ) ) + while( c && HB_ISNEXTIDCHAR( c ) ) c = watch->szExpr[ ++j ]; nLen = j - i; @@ -1091,14 +1135,14 @@ static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch ) { i += 2; - while( ( c = watch->szExpr[ i ] ) != '\0' && IS_IDENT_CHAR( c ) ) + while( ( c = watch->szExpr[ i ] ) != '\0' && HB_ISNEXTIDCHAR( c ) ) i++; continue; } } szWord = hb_strupr( hb_strndup( watch->szExpr + nStart, nLen ) ); - i = hb_dbgEvalSubstituteVar( watch, szWord, nStart, nLen ); + i = hb_dbgEvalSubstituteVar( watch, szWord, nStart, nLen, &szOrig ); bAfterId = HB_TRUE; continue; } @@ -1128,11 +1172,11 @@ static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch ) } if( c == ':' || ( c == '-' && watch->szExpr[ i + 1 ] == '>' && - IS_IDENT_START( watch->szExpr[ i + 2 ] ) ) ) + HB_ISFIRSTIDCHAR( watch->szExpr[ i + 2 ] ) ) ) { if( c == ':' && watch->szExpr[ i + 1 ] == ':' ) { - i = hb_dbgEvalSubstituteVar( watch, hb_strdup( "SELF" ), i, 1 ); + i = hb_dbgEvalSubstituteVar( watch, hb_strdup( "SELF" ), i, 1, &szOrig ); bAfterId = HB_TRUE; continue; } @@ -1142,7 +1186,7 @@ static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch ) i++; - while( watch->szExpr[ i ] && IS_IDENT_CHAR( watch->szExpr[ i ] ) ) + while( watch->szExpr[ i ] && HB_ISNEXTIDCHAR( watch->szExpr[ i ] ) ) i++; bAfterId = HB_TRUE; @@ -1189,18 +1233,24 @@ static PHB_ITEM hb_dbgEvalMakeBlock( HB_WATCHPOINT * watch ) buffsize = 8 + strlen( watch->szExpr ) + 1; - s = ( char * ) hb_xgrab( buffsize + 1 ); - hb_strncpy( s, "{|__dbg|", buffsize ); - hb_strncat( s, watch->szExpr, buffsize ); - hb_strncat( s, "}", buffsize ); + szBlock = ( char * ) hb_xgrab( buffsize + 1 ); + hb_strncpy( szBlock, "{|__dbg|", buffsize ); + hb_strncat( szBlock, watch->szExpr, buffsize ); + hb_strncat( szBlock, "}", buffsize ); pBlock = hb_itemNew( NULL ); - if( ! hb_dbgEvalMacro( s, pBlock ) ) + if( ! hb_dbgEvalMacro( szBlock, pBlock ) ) { hb_itemRelease( pBlock ); pBlock = NULL; } - hb_xfree( s ); + hb_xfree( szBlock ); + + if( szOrig != NULL ) + { + hb_xfree( watch->szExpr ); + watch->szExpr = szOrig; + } return pBlock; } @@ -1417,34 +1467,38 @@ static int hb_dbgIsBreakPoint( HB_DEBUGINFO * info, const char * szModule, int n HB_BOOL hb_dbgIsValidStopLine( void * handle, const char * szModule, int nLine ) { HB_BOOL fResult = HB_FALSE; - HB_ISIZ nModules; - HB_ISIZ i; + + if( szModule ) + { + HB_ISIZ nModules; + HB_ISIZ i; #if 0 - HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; + HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; #endif - HB_SYMBOL_UNUSED( handle ); + HB_SYMBOL_UNUSED( handle ); - szModule = hb_dbgStripModuleName( szModule ); + szModule = hb_dbgStripModuleName( szModule ); - HB_DBGCOMMON_LOCK(); - nModules = hb_itemSize( s_common.pStopLines ); - for( i = 1; i <= nModules; i++ ) - { - PHB_ITEM pEntry = hb_arrayGetItemPtr( s_common.pStopLines, i ); - - if( FILENAME_EQUAL( hb_arrayGetCPtr( pEntry, 1 ), szModule ) ) + HB_DBGCOMMON_LOCK(); + nModules = hb_itemSize( s_common.pStopLines ); + for( i = 1; i <= nModules; i++ ) { - int nMin = hb_arrayGetNL( pEntry, 2 ); - int nOfs = nLine - nMin; + PHB_ITEM pEntry = hb_arrayGetItemPtr( s_common.pStopLines, i ); - if( nOfs >= 0 && ( HB_SIZE ) ( nOfs >> 3 ) < hb_arrayGetCLen( pEntry, 3 ) ) - fResult = ( hb_arrayGetCPtr( pEntry, 3 )[ nOfs >> 3 ] & ( 1 << ( nOfs & 0x07 ) ) ) != 0; + if( FILENAME_EQUAL( hb_arrayGetCPtr( pEntry, 1 ), szModule ) ) + { + int nMin = hb_arrayGetNL( pEntry, 2 ); + int nOfs = nLine - nMin; - break; + if( nOfs >= 0 && ( HB_SIZE ) ( nOfs >> 3 ) < hb_arrayGetCLen( pEntry, 3 ) ) + fResult = ( hb_arrayGetCPtr( pEntry, 3 )[ nOfs >> 3 ] & ( 1 << ( nOfs & 0x07 ) ) ) != 0; + + break; + } } + HB_DBGCOMMON_UNLOCK(); } - HB_DBGCOMMON_UNLOCK(); return fResult; } @@ -1559,11 +1613,14 @@ void hb_dbgSetToCursor( void * handle, const char * szModule, int nLine ) { HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; - szModule = hb_dbgStripModuleName( szModule ); + if( szModule ) + { + szModule = hb_dbgStripModuleName( szModule ); - info->bToCursor = HB_TRUE; - info->szToCursorModule = hb_strdup( szModule ); - info->nToCursorLine = nLine; + info->bToCursor = HB_TRUE; + info->szToCursorModule = hb_strdup( szModule ); + info->nToCursorLine = nLine; + } } @@ -1579,31 +1636,35 @@ void hb_dbgSetTrace( void * handle ) void hb_dbgSetWatch( void * handle, int nWatch, const char * szExpr, HB_BOOL bTrace ) { HB_DEBUGINFO * info = ( HB_DEBUGINFO * ) handle; - HB_WATCHPOINT * pWatch = &info->aWatch[ nWatch ]; - int i; - hb_dbgClearWatch( pWatch ); - pWatch->szExpr = hb_strdup( szExpr ); - pWatch->pBlock = NULL; - for( i = 0; i < info->nTracePoints; i++ ) + if( nWatch >= 0 && nWatch < info->nWatchPoints && szExpr ) { - HB_TRACEPOINT * pTrace = &info->aTrace[ i ]; + HB_WATCHPOINT * pWatch = &info->aWatch[ nWatch ]; + int i; - if( pTrace->nIndex == nWatch ) + hb_dbgClearWatch( pWatch ); + pWatch->szExpr = hb_strdup( szExpr ); + pWatch->pBlock = NULL; + for( i = 0; i < info->nTracePoints; i++ ) { - if( pTrace->xValue ) - hb_itemRelease( pTrace->xValue ); + HB_TRACEPOINT * pTrace = &info->aTrace[ i ]; - ARRAY_DEL( HB_TRACEPOINT, info->aTrace, info->nTracePoints, i ); - break; + if( pTrace->nIndex == nWatch ) + { + if( pTrace->xValue ) + hb_itemRelease( pTrace->xValue ); + + ARRAY_DEL( HB_TRACEPOINT, info->aTrace, info->nTracePoints, i ); + break; + } } - } - if( bTrace ) - { - HB_TRACEPOINT * pTrace = ARRAY_ADD( HB_TRACEPOINT, info->aTrace, info->nTracePoints ); + if( bTrace ) + { + HB_TRACEPOINT * pTrace = ARRAY_ADD( HB_TRACEPOINT, info->aTrace, info->nTracePoints ); - pTrace->nIndex = nWatch; - pTrace->xValue = hb_dbgEval( info, pWatch ); + pTrace->nIndex = nWatch; + pTrace->xValue = hb_dbgEval( info, pWatch ); + } } } @@ -1738,9 +1799,9 @@ HB_FUNC( __DBGGETEXPRVALUE ) PHB_ITEM pItem; if( HB_ISCHAR( 2 ) ) - pItem = hb_dbgGetExpressionValue( hb_parptr( 1 ), hb_parc( 2 ) ); + pItem = hb_dbgGetExpressionValue( ptr, hb_parc( 2 ) ); else - pItem = hb_dbgGetWatchValue( hb_parptr( 1 ), hb_parni( 2 ) - 1 ); + pItem = hb_dbgGetWatchValue( ptr, hb_parni( 2 ) - 1 ); if( pItem ) { @@ -1787,10 +1848,11 @@ HB_FUNC( __DBGDELBREAK ) HB_FUNC( __DBGISBREAK ) { void * ptr = hb_parptr( 1 ); + const char * szModule = hb_parc( 2 ); - if( ptr ) + if( ptr && szModule ) hb_retni( hb_dbgIsBreakPoint( ( HB_DEBUGINFO * ) ptr, - hb_dbgStripModuleName( hb_parc( 2 ) ), + hb_dbgStripModuleName( szModule ), hb_parni( 3 ) ) ); } @@ -1834,6 +1896,14 @@ HB_FUNC( __DBGCNTWATCH ) hb_retni( hb_dbgCountWatch( ptr ) ); } +HB_FUNC( __DBGGETWATCHPOINTS ) +{ + void * ptr = hb_parptr( 1 ); + + if( ptr ) + hb_itemReturnRelease( hb_dbgActivateWatchArray( ( HB_DEBUGINFO * ) ptr ) ); +} + HB_FUNC( __DBGGETMODULENAME ) { void * ptr = hb_parptr( 1 ); diff --git a/src/debug/debugger.prg b/src/debug/debugger.prg index bc7cdc5f34..0ba4143193 100644 --- a/src/debug/debugger.prg +++ b/src/debug/debugger.prg @@ -444,6 +444,9 @@ METHOD PROCEDURE Activate() CLASS HBDebugger ENDIF lFirst := .T. ENDIF + IF ::lShowCallStack + ::oWndStack:Show() + ENDIF ::LoadVars() ::ShowVars() diff --git a/src/vm/hvm.c b/src/vm/hvm.c index fdcd4d32a2..5008c444d2 100644 --- a/src/vm/hvm.c +++ b/src/vm/hvm.c @@ -93,6 +93,7 @@ HB_FUNC_EXTERN( SYSINIT ); +HB_FUNC_EXTERN( BREAK ); /* PCode functions */ @@ -255,7 +256,9 @@ static const char * s_vm_pszLinkedMain = NULL; /* name of startup function set b /* virtual machine state */ -HB_SYMB hb_symEval = { "EVAL", { HB_FS_PUBLIC }, { hb_vmDoBlock }, NULL }; /* symbol to evaluate codeblocks */ +HB_SYMB hb_symEval = { "EVAL", { HB_FS_PUBLIC }, { hb_vmDoBlock }, NULL }; /* symbol to evaluate codeblocks */ +static HB_SYMB s_symBreak = { "BREAK", { HB_FS_PUBLIC }, { HB_FUNCNAME( BREAK ) }, NULL }; /* symbol to generate break */ +static PHB_ITEM s_breakBlock = NULL; static HB_BOOL s_fHVMActive = HB_FALSE; /* is HVM ready for PCODE executing */ static HB_BOOL s_fDoExitProc = HB_TRUE; /* execute EXIT procedures */ @@ -282,6 +285,41 @@ static PHB_FUNC_LIST s_InitFunctions = NULL; static PHB_FUNC_LIST s_ExitFunctions = NULL; static PHB_FUNC_LIST s_QuitFunctions = NULL; +static PHB_ITEM hb_breakBlock( void ) +{ + if( s_breakBlock == NULL ) + { + static const HB_BYTE s_pCode[ 8 ] = { + HB_P_PUSHFUNCSYM, 0, 0, /* BREAK */ + HB_P_PUSHLOCALNEAR, 1, /* oErr */ + HB_P_FUNCTIONSHORT, 1, + HB_P_ENDBLOCK }; + + s_breakBlock = hb_itemNew( NULL ); + s_breakBlock->item.asBlock.value = + hb_codeblockNew( s_pCode, /* pcode buffer */ + 0, /* number of referenced local variables */ + NULL, /* table with referenced local variables */ + &s_symBreak, + sizeof( s_pCode ) ); + s_breakBlock->type = HB_IT_BLOCK; + s_breakBlock->item.asBlock.paramcnt = 1; + s_breakBlock->item.asBlock.lineno = 0; + s_breakBlock->item.asBlock.hclass = 0; + s_breakBlock->item.asBlock.method = 0; + } + return s_breakBlock; +} + +static void hb_breakBlockRelease( void ) +{ + if( s_breakBlock != NULL ) + { + hb_itemRelease( s_breakBlock ); + s_breakBlock = NULL; + } +} + static void hb_vmAddModuleFunction( PHB_FUNC_LIST * pLstPtr, HB_INIT_FUNC pFunc, void * cargo ) { PHB_FUNC_LIST pLst = ( PHB_FUNC_LIST ) hb_xgrab( sizeof( HB_FUNC_LIST ) ); @@ -1010,10 +1048,13 @@ void hb_vmInit( HB_BOOL bStartMainProc ) hb_cmdargUpdate(); hb_clsInit(); /* initialize Classy/OO system */ - hb_errInit(); - /* initialize dynamic symbol for evaluating codeblocks */ + hb_errInit(); + hb_breakBlock(); + + /* initialize dynamic symbol for evaluating codeblocks and break function */ hb_symEval.pDynSym = hb_dynsymGetCase( hb_symEval.szName ); + s_symBreak.pDynSym = hb_dynsymGetCase( s_symBreak.szName ); hb_conInit(); @@ -1188,6 +1229,7 @@ int hb_vmQuit( void ) /* release thread specific data */ hb_stackDestroyTSD(); + hb_breakBlockRelease(); hb_errExit(); hb_clsReleaseAll(); @@ -8947,6 +8989,84 @@ HB_BOOL hb_vmRequestReenterExt( void ) return HB_TRUE; } +HB_BOOL hb_vmTryEval( PHB_ITEM * pResult, PHB_ITEM pItem, HB_ULONG ulPCount, ... ) +{ + HB_BOOL fResult; + + HB_TRACE( HB_TR_DEBUG, ( "hb_vmTryEval(%p, %lu)", pItem, ulPCount ) ); + + fResult = HB_FALSE; + *pResult = NULL; + if( s_fHVMActive ) + { + PHB_SYMB pSymbol = NULL; + + if( HB_IS_STRING( pItem ) ) + { + PHB_DYNS pDynSym = hb_dynsymFindName( pItem->item.asString.value ); + + if( pDynSym ) + { + pSymbol = pDynSym->pSymbol; + pItem = NULL; + } + } + else if( HB_IS_SYMBOL( pItem ) ) + { + pSymbol = pItem->item.asSymbol.value; + pItem = NULL; + } + else if( HB_IS_BLOCK( pItem ) ) + { + pSymbol = &hb_symEval; + } + + if( pSymbol && hb_vmRequestReenter() ) + { + hb_xvmSeqBegin(); + hb_vmPush( hb_breakBlock() ); + hb_vmSeqBlock(); + + hb_vmPushSymbol( pSymbol ); + if( pItem ) + hb_vmPush( pItem ); + else + hb_vmPushNil(); + + if( ulPCount ) + { + HB_ULONG ulParam; + va_list va; + va_start( va, ulPCount ); + for( ulParam = 1; ulParam <= ulPCount; ulParam++ ) + hb_vmPush( va_arg( va, PHB_ITEM ) ); + va_end( va ); + } + if( pItem ) + hb_vmSend( ( HB_USHORT ) ulPCount ); + else + hb_vmProc( ( HB_USHORT ) ulPCount ); + + hb_stackPop(); + if( hb_xvmSeqEndTest() ) + { + hb_xvmSeqRecover(); + *pResult = hb_itemNew( NULL ); + hb_itemMove( *pResult, hb_stackItemFromTop( -1 ) ); + hb_stackDec(); + hb_stackSetActionRequest( 0 ); + } + else + { + *pResult = hb_itemNew( hb_stackReturnItem() ); + fResult = HB_TRUE; + } + hb_vmRequestRestore(); + } + } + return fResult; +} + HB_BOOL hb_vmIsActive( void ) { HB_TRACE( HB_TR_DEBUG, ( "hb_vmIsActive()" ) );