diff --git a/internal/support/vwatch/vwatch.bm b/internal/support/vwatch/vwatch.bm index e6c6990fb..65dbb3a86 100644 --- a/internal/support/vwatch/vwatch.bm +++ b/internal/support/vwatch/vwatch.bm @@ -5,16 +5,16 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) STATIC AS LONG vw_runToLine, vw_originalVarLineNumber STATIC AS _BYTE vw_pauseMode, vw_stepOver, vw_bypass, vw_setNextLine, vw_hwndSent STATIC AS _OFFSET vw_ideHwnd - STATIC vw_buffer$ - DIM AS LONG vw_i, vw_tempIndex, vw_localIndex, vw_varSize, vw_cmdSize + STATIC vw_buffer$, vw_globalWatchpoints$, vw_localWatchpoints$, vw_lastWatchpoint$ + DIM AS LONG vw_i, vw_j, vw_tempIndex, vw_localIndex, vw_varSize, vw_cmdSize DIM AS LONG vw_arrayElementSize, vw_element, vw_elementOffset, vw_storage, vw_blockSize DIM AS LONG vw_arrayDimension, vw_arrayTotalDimensions, vw_arrayIndex, vw_realArrayIndex DIM AS _OFFSET vw_address, vw_lBound, vw_uBound DIM AS _MEM vw_m, vw_m2 - DIM AS _BYTE vw_isArray, vw_isUDT + DIM AS _BYTE vw_isArray, vw_isUDT, vw_checkingWatchpoints DIM vw_start!, vw_temp$, vw_cmd$, vw_value$, vw_k&, vw_buf$, vw_scope$, vw_varType$ - DIM vw_prevValue$, vw_getBytes&, vw_getBytesPosition&, vw_valueBytes$, vw_dummy%& - DIM vw_arrayIndexes$ + DIM vw_getBytes&, vw_getBytesPosition&, vw_valueBytes$, vw_dummy%& + DIM vw_arrayIndexes$, vw_wpExpression$ DECLARE LIBRARY SUB vwatch_stoptimers ALIAS stop_timers @@ -27,8 +27,8 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) END DECLARE $IF WIN THEN - DECLARE DYNAMIC LIBRARY "user32" - FUNCTION SetForegroundWindow& (BYVAL hWnd AS _OFFSET) + DECLARE CUSTOMTYPE LIBRARY + FUNCTION vwSetForegroundWindow& ALIAS "SetForegroundWindow" (BYVAL hWnd AS _OFFSET) END DECLARE $END IF @@ -177,6 +177,20 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) REDIM vwatch_skiplines(UBOUND(vwatch_skiplines)) AS _BYTE END SELECT + IF LEN(vw_globalWatchpoints$) > 0 OR LEN(vw_localWatchpoints$) > 0 THEN + vw_checkingWatchpoints = -1 + GOSUB CheckWatchpoints + IF vw_checkingWatchpoints = 2 THEN + vw_checkingWatchpoints = 0 + vw_pauseMode = -1 + vw_stepOver = 0 + vw_runToLine = 0 + vw_cmd$ = "watchpoint:" + MKL$(vw_tempIndex) + MKL$(LEN(vw_arrayIndexes$)) + vw_arrayIndexes$ + MKL$(vw_elementOffset) + MKI$(LEN(vw_wpExpression$)) + vw_wpExpression$ + GOTO breakReached + END IF + END IF + vw_checkingWatchpoints = 0 + IF vwatch_skiplines(vwatch_linenumber) THEN vwatch_goto = -vwatch_linenumber: EXIT SUB IF vw_stepOver = -1 AND vwatch_sublevel > vw_startLevel AND vwatch_breakpoints(vwatch_linenumber) = 0 THEN @@ -197,16 +211,17 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) EXIT SUB END IF - vwatch_stoptimers vw_cmd$ = "line number:" IF vwatch_breakpoints(vwatch_linenumber) THEN vw_cmd$ = "breakpoint:" + breakReached: + vwatch_stoptimers vw_cmd$ = vw_cmd$ + MKL$(vwatch_linenumber) GOSUB SendCommand vw_cmd$ = "current sub:" + LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) GOSUB SendCommand $IF WIN THEN - vw_i = SetForegroundWindow&(vw_ideHwnd) + vw_i = vwSetForegroundWindow&(vw_ideHwnd) $END IF DO 'main loop @@ -258,6 +273,7 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) 'send call stack history GOSUB SendCallStack CASE "get global var", "get local var" + getGlobalLocal: vw_getBytes& = 4: GOSUB GetBytes: vw_tempIndex = CVL(vw_valueBytes$) vw_getBytes& = 1: GOSUB GetBytes: vw_isArray = _CV(_BYTE, vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_originalVarLineNumber = CVL(vw_valueBytes$) @@ -266,10 +282,14 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) vw_getBytes& = vw_arrayTotalDimensions: GOSUB GetBytes: vw_arrayIndexes$ = vw_valueBytes$ vw_arrayTotalDimensions = vw_arrayTotalDimensions \ 4 vw_getBytes& = 4: GOSUB GetBytes: vw_arrayElementSize = CVL(vw_valueBytes$) + IF vw_checkingWatchpoints THEN vw_getBytes& = 4: GOSUB GetBytes 'discard 4 bytes (isUDT) vw_getBytes& = 4: GOSUB GetBytes: vw_element = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_varSize = CVL(vw_valueBytes$) - IF vw_varSize = 0 THEN GOTO cmdProcessingDone + IF vw_varSize = 0 THEN + IF vw_checkingWatchpoints THEN RETURN + GOTO cmdProcessingDone + END IF vw_getBytes& = 4: GOSUB GetBytes: vw_storage = CVL(vw_valueBytes$) vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) IF vw_i THEN @@ -284,6 +304,7 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) IF vw_scope$ = LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) THEN vw_address = _OFFSET(localVariables) + LEN(vw_address) * vw_localIndex ELSE + IF vw_checkingWatchpoints THEN vw_varType$ = "": RETURN GOTO cmdProcessingDone END IF END IF @@ -294,7 +315,10 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) IF vw_isArray THEN IF vw_originalVarLineNumber > 0 THEN 'prevent fetching array data before DIM line - IF vwatch_linenumber <= vw_originalVarLineNumber THEN GOTO cmdProcessingDone + IF vwatch_linenumber <= vw_originalVarLineNumber THEN + IF vw_checkingWatchpoints THEN vw_varType$ = "": RETURN + GOTO cmdProcessingDone + END IF END IF vw_realArrayIndex = 0 @@ -305,6 +329,7 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) vw_uBound = check_ubound%&(vw_address, vw_arrayDimension, vw_arrayTotalDimensions) vw_arrayIndex = CVL(MID$(vw_arrayIndexes$, vw_arrayDimension * 4 - 3, 4)) IF vw_arrayIndex < vw_lBound OR vw_arrayIndex > vw_uBound THEN + IF vw_checkingWatchpoints THEN vw_varType$ = "": RETURN GOTO cmdProcessingDone END IF @@ -381,24 +406,36 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) vw_address = _CV(LONG, LEFT$(vw_buf$, 4)) 'Pointer to data vw_varSize = CVL(MID$(vw_buf$, 5)) END IF + vw_buf$ = SPACE$(vw_varSize) vw_m = _MEM(vw_address, vw_varSize) vw_m2 = _MEM(_OFFSET(vw_buf$), vw_varSize) _MEMCOPY vw_m, vw_m.OFFSET, vw_m.SIZE TO vw_m2, vw_m2.OFFSET END IF + IF vw_checkingWatchpoints THEN RETURN + vw_cmd$ = "address read:" + MKL$(vw_tempIndex) + MKL$(vw_arrayIndex) + MKL$(vw_element) + MKL$(vw_storage) + vw_buf$ GOSUB SendCommand CASE "set global address", "set local address" + vw_getBytes& = 4: GOSUB GetBytes: vw_tempIndex = CVL(vw_valueBytes$) + vw_getBytes& = 1: GOSUB GetBytes: vw_isArray = _CV(_BYTE, vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_originalVarLineNumber = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_localIndex = CVL(vw_valueBytes$) - vw_getBytes& = 4: GOSUB GetBytes: vw_isArray = (CVL(vw_valueBytes$) <> 0) vw_getBytes& = 4: GOSUB GetBytes: vw_arrayTotalDimensions = CVL(vw_valueBytes$) vw_getBytes& = vw_arrayTotalDimensions: GOSUB GetBytes: vw_arrayIndexes$ = vw_valueBytes$ vw_arrayTotalDimensions = vw_arrayTotalDimensions \ 4 - vw_getBytes& = 4: GOSUB GetBytes: vw_isUDT = (CVL(vw_valueBytes$) <> 0) - vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_arrayElementSize = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_isUDT = (CVL(vw_valueBytes$) <> 0) + vw_getBytes& = 4: GOSUB GetBytes: vw_element = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) vw_getBytes& = 4: GOSUB GetBytes: vw_varSize = CVL(vw_valueBytes$) + IF vw_varSize = 0 THEN GOTO cmdProcessingDone + vw_getBytes& = 4: GOSUB GetBytes: vw_storage = CVL(vw_valueBytes$) + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + IF vw_i THEN + vw_getBytes& = vw_i: GOSUB GetBytes: vw_scope$ = vw_valueBytes$ + END IF vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) vw_getBytes& = vw_i: GOSUB GetBytes: vw_varType$ = vw_valueBytes$ vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) @@ -509,6 +546,72 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) 'vw_address now points to the actual data vw_m = _MEM(vw_address, vw_varSize) _MEMPUT vw_m, vw_m.OFFSET, vw_value$ + CASE "clear last watchpoint" + IF LEFT$(vw_lastWatchpoint$, 1) = "g" THEN + vw_cmd$ = "clear global watchpoint" + ELSE + vw_cmd$ = "clear local watchpoint" + END IF + vw_value$ = MID$(vw_lastWatchpoint$, 2) + vw_getBytesPosition& = 1 + GOTO WatchpointCommands + CASE "set global watchpoint", "set local watchpoint", "clear global watchpoint", "clear local watchpoint" + WatchpointCommands: + vw_getBytes& = 4: GOSUB GetBytes: vw_tempIndex = CVL(vw_valueBytes$) + vw_getBytes& = 1: GOSUB GetBytes: vw_isArray = _CV(_BYTE, vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_originalVarLineNumber = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_localIndex = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_arrayTotalDimensions = CVL(vw_valueBytes$) + vw_getBytes& = vw_arrayTotalDimensions: GOSUB GetBytes: vw_arrayIndexes$ = vw_valueBytes$ + + vw_temp$ = LEFT$(vw_value$, vw_arrayTotalDimensions + 33) + + vw_arrayTotalDimensions = vw_arrayTotalDimensions \ 4 + vw_getBytes& = 4: GOSUB GetBytes: vw_arrayElementSize = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_isUDT = (CVL(vw_valueBytes$) <> 0) + vw_getBytes& = 4: GOSUB GetBytes: vw_element = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_elementOffset = CVL(vw_valueBytes$) + vw_getBytes& = 4: GOSUB GetBytes: vw_varSize = CVL(vw_valueBytes$) + IF vw_varSize = 0 THEN GOTO cmdProcessingDone + vw_getBytes& = 4: GOSUB GetBytes: vw_storage = CVL(vw_valueBytes$) + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + IF vw_i THEN + vw_getBytes& = vw_i: GOSUB GetBytes: vw_scope$ = vw_valueBytes$ + END IF + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + vw_getBytes& = vw_i: GOSUB GetBytes: vw_varType$ = vw_valueBytes$ + vw_getBytes& = 2: GOSUB GetBytes: vw_i = CVI(vw_valueBytes$) + vw_getBytes& = vw_i: GOSUB GetBytes: vw_wpExpression$ = vw_valueBytes$ + + IF INSTR(vw_cmd$, " global ") THEN + vw_buf$ = vw_globalWatchpoints$ + ELSE + vw_buf$ = vw_localWatchpoints$ + END IF + + vw_i = 0 + vw_i = INSTR(vw_i + 1, vw_buf$, MKL$(-1)) + DO WHILE vw_i + IF MID$(vw_buf$, vw_i + 8, LEN(vw_temp$)) = vw_temp$ THEN EXIT DO + vw_i = INSTR(vw_i + 1, vw_buf$, MKL$(-1)) + LOOP + + IF vw_i > 0 THEN + 'remove existing watchpoint for the same variable/index/element + vw_j = CVL(MID$(vw_buf$, vw_i + 4, 4)) + vw_buf$ = LEFT$(vw_buf$, vw_i - 1) + MID$(vw_buf$, vw_i + vw_j + 8) + END IF + + IF LEFT$(vw_cmd$, 4) = "set " THEN + vw_value$ = vw_value$ + MKL$(LEN(vw_wpExpression$)) + vw_buf$ = vw_buf$ + MKL$(-1) + MKL$(LEN(vw_value$)) + vw_value$ + END IF + + IF INSTR(vw_cmd$, " global ") THEN + vw_globalWatchpoints$ = vw_buf$ + ELSE + vw_localWatchpoints$ = vw_buf$ + END IF CASE "current sub" vw_cmd$ = "current sub:" + LEFT$(vwatch_stack(vwatch_sublevel), INSTR(vwatch_stack(vwatch_sublevel), ",") - 1) GOSUB SendCommand @@ -595,4 +698,123 @@ SUB vwatch (globalVariables AS _OFFSET, localVariables AS _OFFSET) vw_valueBytes$ = MID$(vw_value$, vw_getBytesPosition&, vw_getBytes&) vw_getBytesPosition& = vw_getBytesPosition& + vw_getBytes& RETURN + + CheckWatchpoints: + DIM AS LONG vw_wpi, vw_wpj + DIM vw_wpTemp$, vw_v1$, vw_v2$ + FOR vw_wpi = 1 TO 2 + IF vw_wpi = 1 AND LEN(vw_globalWatchpoints$) > 0 THEN + vw_wpTemp$ = MID$(vw_globalWatchpoints$, 5) + ELSEIF vw_wpi = 2 AND LEN(vw_localWatchpoints$) > 0 THEN + vw_wpTemp$ = MID$(vw_localWatchpoints$, 5) + ELSE + _CONTINUE + END IF + + DO WHILE LEN(vw_wpTemp$) + vw_wpj = CVL(LEFT$(vw_wpTemp$, 4)) + vw_value$ = MID$(vw_wpTemp$, 5, vw_wpj) + vw_wpTemp$ = MID$(vw_wpTemp$, 9 + vw_wpj) + IF vw_wpi = 1 THEN vw_cmd$ = "get global var" ELSE vw_cmd$ = "get local var" + + vw_i = CVL(RIGHT$(vw_value$, 4)) + vw_wpExpression$ = MID$(vw_value$, LEN(vw_value$) - (4 + vw_i) + 1, vw_i) + + vw_getBytesPosition& = 1 + GOSUB getGlobalLocal + IF vw_varType$ = "" THEN _CONTINUE + + IF INSTR(vw_varType$, "STRING") THEN + IF LEFT$(vw_wpExpression$, 1) = "=" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) = _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<=" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) <= _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = ">=" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) >= _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<>" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) <> _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = "<" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) < _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = ">" THEN + IF _TRIM$(MID$(vw_wpExpression$, 2)) > _TRIM$(vw_buf$) THEN GOTO WatchPointBreak + END IF + ELSE + IF LEFT$(vw_wpExpression$, 1) = "=" THEN + vw_v1$ = _TRIM$(MID$(vw_wpExpression$, 2)) + ELSEIF LEFT$(vw_wpExpression$, 2) = "<=" OR LEFT$(vw_wpExpression$, 2) = ">=" OR LEFT$(vw_wpExpression$, 2) = "<>" THEN + vw_v1$ = _TRIM$(MID$(vw_wpExpression$, 3)) + ELSEIF LEFT$(vw_wpExpression$, 1) = "<" OR LEFT$(vw_wpExpression$, 1) = ">" THEN + vw_v1$ = _TRIM$(MID$(vw_wpExpression$, 2)) + END IF + + GOSUB GetV2 + + IF LEFT$(vw_wpExpression$, 1) = "=" THEN + IF VAL(vw_v2$) = VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<=" THEN + IF VAL(vw_v2$) <= VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = ">=" THEN + IF VAL(vw_v2$) >= VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 2) = "<>" THEN + IF VAL(vw_v2$) <> VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = "<" THEN + IF VAL(vw_v2$) < VAL(vw_v1$) THEN GOTO WatchPointBreak + ELSEIF LEFT$(vw_wpExpression$, 1) = ">" THEN + IF VAL(vw_v2$) > VAL(vw_v1$) THEN GOTO WatchPointBreak + END IF + END IF + LOOP + NEXT + RETURN + + WatchPointBreak: + 'send watchpoint info and pause + IF INSTR(vw_cmd$, "global") THEN + vw_lastWatchpoint$ = "g" + vw_value$ + ELSE + vw_lastWatchpoint$ = "l" + vw_value$ + END IF + vw_checkingWatchpoints = 2 + RETURN + + GetV2: + IF INSTR(vw_varType$, "BIT *") THEN + IF VAL(MID$(vw_varType$, _INSTRREV(vw_varType$, " ") + 1)) > 32 THEN + IF INSTR(vw_varType$, "UNSIGNED") THEN + vw_v2$ = STR$(_CV(_UNSIGNED _INTEGER64, vw_buf$)) + ELSE + vw_v2$ = STR$(_CV(_INTEGER64, vw_buf$)) + END IF + ELSE + IF INSTR(vw_varType$, "UNSIGNED") THEN + vw_v2$ = STR$(_CV(_UNSIGNED LONG, vw_buf$)) + ELSE + vw_v2$ = STR$(_CV(LONG, vw_buf$)) + END IF + END IF + RETURN + ELSEIF INSTR("@_BIT@BIT@_UNSIGNED _BIT@UNSIGNED BIT@", "@" + vw_varType$ + "@") THEN + IF INSTR(vw_varType$, "UNSIGNED") THEN + vw_v2$ = STR$(_CV(_UNSIGNED LONG, vw_buf$)) + ELSE + vw_v2$ = STR$(_CV(LONG, vw_buf$)) + END IF + RETURN + END IF + SELECT CASE vw_varType$ + CASE "_BYTE", "BYTE": vw_v2$ = STR$(_CV(_BYTE, vw_buf$)) + CASE "_UNSIGNED _BYTE", "UNSIGNED BYTE": vw_v2$ = STR$(_CV(_UNSIGNED _BYTE, vw_buf$)) + CASE "INTEGER": vw_v2$ = STR$(_CV(INTEGER, vw_buf$)) + CASE "_UNSIGNED INTEGER", "UNSIGNED INTEGER": vw_v2$ = STR$(_CV(_UNSIGNED INTEGER, vw_buf$)) + CASE "LONG": vw_v2$ = STR$(_CV(LONG, vw_buf$)) + CASE "_UNSIGNED LONG", "UNSIGNED LONG": vw_v2$ = STR$(_CV(_UNSIGNED LONG, vw_buf$)) + CASE "_INTEGER64", "INTEGER64": vw_v2$ = STR$(_CV(_INTEGER64, vw_buf$)) + CASE "_UNSIGNED _INTEGER64", "UNSIGNED INTEGER64": vw_v2$ = STR$(_CV(_UNSIGNED _INTEGER64, vw_buf$)) + CASE "SINGLE": vw_v2$ = STR$(CVS(vw_buf$)) + CASE "DOUBLE": vw_v2$ = STR$(CVD(vw_buf$)) + CASE "_FLOAT", "FLOAT": vw_v2$ = STR$(_CV(_FLOAT, vw_buf$)) + CASE "_OFFSET", "OFFSET": vw_v2$ = STR$(_CV(_OFFSET, vw_buf$)) + CASE "_UNSIGNED _OFFSET", "UNSIGNED OFFSET": vw_v2$ = STR$(_CV(_UNSIGNED _OFFSET, vw_buf$)) + END SELECT + RETURN END SUB diff --git a/source/global/IDEsettings.bas b/source/global/IDEsettings.bas index 7781d6bcb..e4b14a6f3 100644 --- a/source/global/IDEsettings.bas +++ b/source/global/IDEsettings.bas @@ -18,7 +18,7 @@ DIM SHARED WatchListToConsole AS _BYTE DIM SHARED windowSettingsSection$, colorSettingsSection$, customDictionarySection$ DIM SHARED mouseSettingsSection$, generalSettingsSection$, displaySettingsSection$ DIM SHARED colorSchemesSection$, debugSettingsSection$, iniFolderIndex$, DebugInfoIniWarning$, ConfigFile$ -DIM SHARED idebaseTcpPort AS LONG +DIM SHARED idebaseTcpPort AS LONG, AutoAddDebugCommand AS _BYTE ConfigFile$ = "internal/config.ini" iniFolderIndex$ = STR$(tempfolderindex) @@ -241,6 +241,18 @@ ELSE WriteConfigSetting debugSettingsSection$, "WatchListToConsole", "False" END IF +IF ReadConfigSetting(debugSettingsSection$, "AutoAddDebugCommand", value$) THEN + IF UCASE$(value$) = "TRUE" OR VAL(value$) = -1 THEN + AutoAddDebugCommand = -1 + ELSE + AutoAddDebugCommand = 0 + WriteConfigSetting debugSettingsSection$, "AutoAddDebugCommand", "False" + END IF +ELSE + AutoAddDebugCommand = -1 + WriteConfigSetting debugSettingsSection$, "AutoAddDebugCommand", "True" +END IF + 'Display settings ------------------------------------------------------------- IF ReadConfigSetting(displaySettingsSection$, "IDE_SortSUBs", value$) THEN IF UCASE$(value$) = "TRUE" OR VAL(value$) = -1 THEN diff --git a/source/ide/ide_global.bas b/source/ide/ide_global.bas index cde1730e4..f0cd63c55 100644 --- a/source/ide/ide_global.bas +++ b/source/ide/ide_global.bas @@ -11,8 +11,8 @@ DIM SHARED IDEBuildModeChanged DIM SHARED IdeInfo AS STRING DIM SHARED IdeContextHelpSF AS _BYTE -DIM SHARED host&, debugClient&, hostport$, variableWatchList$ -DIM SHARED vWatchReceivedData$(1 TO 1000), nextvWatchDataSlot +DIM SHARED host&, debugClient&, hostport$, variableWatchList$, watchpointList$ +DIM SHARED vWatchReceivedData$(1 TO 1000), nextvWatchDataSlot, latestWatchpointMet& DIM SHARED startPausedPending AS _BYTE DIM SHARED IdeSystem AS LONG @@ -222,6 +222,7 @@ DIM SHARED ViewMenuShowSeparatorID AS INTEGER, ViewMenuShowBGID AS INTEGER DIM SHARED ViewMenuCompilerWarnings AS INTEGER DIM SHARED RunMenuID AS INTEGER, RunMenuSaveExeWithSource AS INTEGER, brackethighlight AS INTEGER DIM SHARED DebugMenuID AS INTEGER, DebugMenuCallStack AS INTEGER, DebugMenuWatchListToConsole AS INTEGER +DIM SHARED DebugMenuAutoAddCommand AS INTEGER DIM SHARED multihighlight AS INTEGER, keywordHighlight AS INTEGER DIM SHARED PresetColorSchemes AS INTEGER, TotalColorSchemes AS INTEGER, ColorSchemes$(0) DIM SHARED LastValidColorScheme AS INTEGER diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index b3f3d8435..55d8c889c 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -357,6 +357,12 @@ FUNCTION ide2 (ignore) menu$(DebugMenuID, DebugMenuCallStack) = "Call #Stack... F12": i = i + 1 menuDesc$(m, i - 1) = "Displays the call stack of the current program's last execution" menu$(m, i) = "-": i = i + 1 + DebugMenuAutoAddCommand = i + menu$(m, i) = "Auto-add $#Debug Metacommand": i = i + 1 + menuDesc$(m, i - 1) = "Toggles whether the IDE will auto-add the $Debug metacommand as required" + IF AutoAddDebugCommand THEN + menu$(DebugMenuID, DebugMenuAutoAddCommand) = CHR$(7) + menu$(DebugMenuID, DebugMenuAutoAddCommand) + END IF DebugMenuWatchListToConsole = i menu$(m, i) = "#Output Watch List to Console": i = i + 1 menuDesc$(m, i - 1) = "Toggles directing the output of the watch list to the console window" @@ -500,6 +506,7 @@ FUNCTION ide2 (ignore) REDIM IdeBreakpoints(iden) AS _BYTE REDIM IdeSkipLines(iden) AS _BYTE variableWatchList$ = "" + watchpointList$ = "" callstacklist$ = "": callStackLength = 0 ideunsaved = -1 idechangemade = 1 @@ -596,6 +603,7 @@ FUNCTION ide2 (ignore) REDIM IdeBreakpoints(iden) AS _BYTE REDIM IdeSkipLines(iden) AS _BYTE variableWatchList$ = "" + watchpointList$ = "" callstacklist$ = "": callStackLength = 0 IF ideStartAtLine > 0 AND ideStartAtLine <= iden THEN idecy = ideStartAtLine @@ -1147,6 +1155,7 @@ FUNCTION ide2 (ignore) IF idelayoutallow THEN idelayoutallow = idelayoutallow - 1 variableWatchList$ = "" + watchpointList$ = "" idecurrentlinelayouti = 0 'invalidate idefocusline = 0 idechangemade = 0 @@ -4988,6 +4997,19 @@ FUNCTION ide2 (ignore) GOTO ideloop END IF + IF RIGHT$(menu$(m, s), 28) = "Auto-add $#Debug Metacommand" THEN + PCOPY 2, 0 + AutoAddDebugCommand = NOT AutoAddDebugCommand + IF AutoAddDebugCommand THEN + WriteConfigSetting debugSettingsSection$, "AutoAddDebugCommand", "True" + menu$(DebugMenuID, DebugMenuAutoAddCommand) = CHR$(7) + "Auto-add $#Debug Metacommand" + ELSE + WriteConfigSetting debugSettingsSection$, "AutoAddDebugCommand", "False" + menu$(DebugMenuID, DebugMenuAutoAddCommand) = "Auto-add $#Debug Metacommand" + END IF + PCOPY 3, 0: SCREEN , , 3, 0 + GOTO ideloop + END IF IF MID$(menu$(m, s), 1, 17) = "#Quick Navigation" OR MID$(menu$(m, s), 2, 17) = "#Quick Navigation" THEN PCOPY 2, 0 @@ -5703,6 +5725,16 @@ FUNCTION ide2 (ignore) PCOPY 3, 0: SCREEN , , 3, 0 startPausedMenuHandler: IF vWatchOn = 0 THEN + IF AutoAddDebugCommand = 0 THEN + SCREEN , , 3, 0 + clearStatusWindow 2 + COLOR 14, 1 + x = 2 + y = idewy - 2 + printWrapStatus x, y, x, "$DEBUG metacommand is required to start paused." + PCOPY 3, 0 + GOTO ideloop + END IF result = idemessagebox("Start Paused", "Insert $DEBUG metacommand?", "#Yes;#No") IF result = 1 THEN ideselect = 0 @@ -5726,6 +5758,16 @@ FUNCTION ide2 (ignore) PCOPY 2, 0 showWatchList: IF vWatchOn = 0 THEN + IF AutoAddDebugCommand = 0 THEN + SCREEN , , 3, 0 + clearStatusWindow 2 + COLOR 14, 1 + x = 2 + y = idewy - 2 + printWrapStatus x, y, x, "$DEBUG metacommand is required for Watch List functionality." + PCOPY 3, 0 + GOTO ideloop + END IF result = idemessagebox("Watch List", "Insert $DEBUG metacommand?", "#Yes;#No") IF result = 1 THEN ideselect = 0 @@ -5807,6 +5849,16 @@ FUNCTION ide2 (ignore) PCOPY 3, 0: SCREEN , , 3, 0 toggleBreakpoint: IF vWatchOn = 0 THEN + IF AutoAddDebugCommand = 0 THEN + SCREEN , , 3, 0 + clearStatusWindow 2 + COLOR 14, 1 + x = 2 + y = idewy - 2 + printWrapStatus x, y, x, "$DEBUG metacommand is required to enable breakpoints." + PCOPY 3, 0 + GOTO ideloop + END IF result = idemessagebox("Toggle Breakpoint", "Insert $DEBUG metacommand?", "#Yes;#No") IF result = 1 THEN ideselect = 0 @@ -5843,6 +5895,16 @@ FUNCTION ide2 (ignore) PCOPY 3, 0: SCREEN , , 3, 0 toggleSkipLine: IF vWatchOn = 0 THEN + IF AutoAddDebugCommand = 0 THEN + SCREEN , , 3, 0 + clearStatusWindow 2 + COLOR 14, 1 + x = 2 + y = idewy - 2 + printWrapStatus x, y, x, "$DEBUG metacommand is required to enable line skipping." + PCOPY 3, 0 + GOTO ideloop + END IF result = idemessagebox("Toggle Skip Line", "Insert $DEBUG metacommand?", "#Yes;#No") IF result = 1 THEN ideselect = 0 @@ -5946,6 +6008,7 @@ FUNCTION ide2 (ignore) REDIM IdeBreakpoints(1) AS _BYTE REDIM IdeSkipLines(1) AS _BYTE variableWatchList$ = "" + watchpointList$ = "" callstacklist$ = "": callStackLength = 0 idet$ = MKL$(0) + MKL$(0): idel = 1: ideli = 1: iden = 1: IdeBmkN = 0 idesx = 1 @@ -6413,6 +6476,7 @@ SUB DebugMode vWatchPanel.h = 5 END IF + watchpointList$ = "" vWatchPanel.w = 40 vWatchPanel.x = idewx - vWatchPanel.w - 6 vWatchPanel.y = 4 @@ -7069,19 +7133,24 @@ SUB DebugMode filter$ = "" DO result$ = idevariablewatchbox$(currentSub$, filter$, selectVar, returnAction) + temp$ = GetBytes$("", 0) 'reset buffer IF returnAction = 1 THEN - temp$ = GetBytes$("", 0) 'reset buffer 'set address tempIndex& = CVL(GetBytes$(result$, 4)) + tempIsArray& = _CV(_BYTE, GetBytes$(result$, 1)) + temp$ = GetBytes$(result$, 4) 'skip original line number tempLocalIndex& = CVL(GetBytes$(result$, 4)) - tempIsArray& = CVL(GetBytes$(result$, 4)) tempArrayIndex& = CVL(GetBytes$(result$, 4)) tempArrayIndexes$ = MKL$(tempArrayIndex&) + GetBytes$(result$, tempArrayIndex&) - tempIsUDT& = CVL(GetBytes$(result$, 4)) - tempElementOffset& = CVL(GetBytes$(result$, 4)) tempArrayElementSize& = CVL(GetBytes$(result$, 4)) + tempIsUDT& = CVL(GetBytes$(result$, 4)) + temp$ = GetBytes$(result$, 4) 'skip element number + tempElementOffset& = CVL(GetBytes$(result$, 4)) + temp$ = GetBytes$(result$, 4) 'skip var size tempStorage& = CVL(GetBytes$(result$, 4)) i = CVI(GetBytes$(result$, 2)) + tempScope$ = GetBytes$(result$, i) + i = CVI(GetBytes$(result$, 2)) varType$ = GetBytes$(result$, i) i = CVI(GetBytes$(result$, 2)) value$ = GetBytes$(result$, i) @@ -7092,6 +7161,7 @@ SUB DebugMode cmd$ = "set local address:" END IF + findVarSize: tempVarType$ = varType$ fixedVarSize& = 0 IF INSTR(varType$, "STRING *") THEN @@ -7168,13 +7238,20 @@ SUB DebugMode END IF END SELECT + IF returnAction = 2 OR returnAction = 3 THEN RETURN + + cmd$ = cmd$ + MKL$(tempIndex&) + cmd$ = cmd$ + _MK$(_BYTE, tempIsArray& <> 0) + cmd$ = cmd$ + MKL$(0) cmd$ = cmd$ + MKL$(tempLocalIndex&) - cmd$ = cmd$ + MKL$(tempIsArray&) cmd$ = cmd$ + tempArrayIndexes$ - cmd$ = cmd$ + MKL$(tempIsUDT&) - cmd$ = cmd$ + MKL$(tempElementOffset&) cmd$ = cmd$ + MKL$(tempArrayElementSize&) + cmd$ = cmd$ + MKL$(tempIsUDT&) + cmd$ = cmd$ + MKL$(0) + cmd$ = cmd$ + MKL$(tempElementOffset&) cmd$ = cmd$ + MKL$(varSize&) + cmd$ = cmd$ + MKL$(tempStorage&) + cmd$ = cmd$ + MKI$(LEN(tempScope$)) + tempScope$ cmd$ = cmd$ + MKI$(LEN(varType$)) + varType$ cmd$ = cmd$ + MKI$(LEN(value$)) + value$ GOSUB SendCommand @@ -7187,7 +7264,68 @@ SUB DebugMode WHILE _MOUSEINPUT: WEND hidePanel = -1 GOSUB UpdateDisplay - ELSEIF returnAction = 2 THEN + ELSEIF returnAction = 2 OR returnAction = 3 THEN + 'send watchpoint data + tempIndex& = CVL(GetBytes$(result$, 4)) + tempIsArray& = _CV(_BYTE, GetBytes$(result$, 1)) <> 0 + temp$ = GetBytes$(result$, 4) 'skip original line number + tempLocalIndex& = CVL(GetBytes$(result$, 4)) + tempArrayIndex& = CVL(GetBytes$(result$, 4)) + tempArrayIndexes$ = MKL$(tempArrayIndex&) + GetBytes$(result$, tempArrayIndex&) + tempArrayElementSize& = CVL(GetBytes$(result$, 4)) + tempIsUDT& = CVL(GetBytes$(result$, 4)) + tempElement& = CVL(GetBytes$(result$, 4)) + tempElementOffset& = CVL(GetBytes$(result$, 4)) + temp$ = GetBytes$(result$, 4) 'skip var size + tempStorage& = CVL(GetBytes$(result$, 4)) + i = CVI(GetBytes$(result$, 2)) + tempScope$ = GetBytes$(result$, i) + i = CVI(GetBytes$(result$, 2)) + varType$ = GetBytes$(result$, i) + i = CVI(GetBytes$(result$, 2)) + value$ = GetBytes$(result$, i) + + IF returnAction = 2 THEN + temp$ = "set " + ELSE + 'clear watchpoint data + temp$ = "clear " + END IF + + IF LEN(usedVariableList(tempIndex&).subfunc) = 0 THEN + cmd$ = temp$ + "global watchpoint:" + ELSE + cmd$ = temp$ + "local watchpoint:" + END IF + + temp$ = value$ + IF INSTR(varType$, "STRING") = 0 THEN + GOSUB findVarSize + ELSE + varSize& = LEN(dummy%&) + LEN(dummy&) + END IF + + cmd$ = cmd$ + MKL$(tempIndex&) + cmd$ = cmd$ + _MK$(_BYTE, tempIsArray& <> 0) + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).linenumber) + cmd$ = cmd$ + MKL$(tempLocalIndex&) + cmd$ = cmd$ + tempArrayIndexes$ + cmd$ = cmd$ + MKL$(tempArrayElementSize&) + cmd$ = cmd$ + MKL$(tempIsUDT&) + cmd$ = cmd$ + MKL$(tempElement&) + cmd$ = cmd$ + MKL$(tempElementOffset&) + cmd$ = cmd$ + MKL$(varSize&) + cmd$ = cmd$ + MKL$(tempStorage&) + cmd$ = cmd$ + MKI$(LEN(tempScope$)) + tempScope$ + cmd$ = cmd$ + MKI$(LEN(varType$)) + varType$ + cmd$ = cmd$ + MKI$(LEN(temp$)) + temp$ + GOSUB SendCommand + + PCOPY 3, 0: SCREEN , , 3, 0 + WHILE _MOUSEINPUT: WEND + hidePanel = -1 + GOSUB UpdateDisplay + ELSEIF returnAction = -1 THEN PCOPY 3, 0: SCREEN , , 3, 0 WHILE _MOUSEINPUT: WEND hidePanel = -1 @@ -7394,8 +7532,43 @@ SUB DebugMode GOSUB GetCommand SELECT CASE cmd$ - CASE "breakpoint", "line number" + CASE "breakpoint", "line number", "watchpoint" BypassRequestCallStack = 0 + IF cmd$ = "watchpoint" THEN + temp$ = GetBytes$("", 0) 'reset buffer + tempIndex& = CVL(GetBytes$(value$, 4)) + latestWatchpointMet& = tempIndex& + tempArrayIndexes$ = GetBytes$(value$, 4) + tempArrayIndexes$ = tempArrayIndexes$ + GetBytes$(value$, CVL(tempArrayIndexes$)) + tempElementOffset$ = GetBytes$(value$, 4) + i = CVI(GetBytes$(value$, 2)) + temp$ = usedVariableList(tempIndex&).name + GetBytes$(value$, i) + result = idemessagebox("Watchpoint condition met", temp$, "#OK;#Clear Watchpoint") + IF result = 2 THEN + 'find existing watchpoint for the same variable/index/element + temp$ = MKL$(tempIndex&) + tempArrayIndexes$ + tempElementOffset$ + i = 0 + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + DO WHILE i + IF MID$(watchpointList$, i + 8, LEN(temp$)) = temp$ THEN EXIT DO + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + LOOP + + IF i > 0 THEN + 'remove it + j = CVL(MID$(watchpointList$, i + 4, 4)) + watchpointList$ = LEFT$(watchpointList$, i - 1) + MID$(watchpointList$, i + j + 8) + END IF + + cmd$ = "clear last watchpoint" + GOSUB SendCommand + END IF + value$ = RIGHT$(value$, 4) + ELSE + latestWatchpointMet& = 0 + END IF + PCOPY 3, 0: SCREEN , , 3, 0 + WHILE _MOUSEINPUT: WEND l = CVL(value$) idecy = l ideselect = 0 @@ -7405,6 +7578,8 @@ SUB DebugMode clearStatusWindow 1 IF cmd$ = "breakpoint" THEN setStatusMessage 1, "Breakpoint reached on line" + STR$(l), 2 + ELSEIF cmd$ = "watchpoint" THEN + setStatusMessage 1, "Watchpoint condition met (" + temp$ + ")", 2 ELSE setStatusMessage 1, "Paused.", 2 END IF @@ -7774,6 +7949,20 @@ SUB showvWatchPanel (this AS vWatchPanelType, currentScope$, action as _BYTE) END IF IF LEN(item$) > this.contentWidth THEN this.contentWidth = LEN(item$) IF WatchListToConsole = 0 THEN + 'find existing watchpoint for this variable/index/element + temp2$ = MKL$(tempIndex&) + MKL$(tempTotalArrayIndexes& * 4) + tempArrayIndexes$ + MKL$(tempElementOffset&) + j = 0 + j = INSTR(j + 1, watchpointList$, MKL$(-1)) + DO WHILE j + IF MID$(watchpointList$, j + 8, LEN(temp2$)) = temp2$ THEN EXIT DO + j = INSTR(j + 1, watchpointList$, MKL$(-1)) + LOOP + + IF j > 0 THEN + IF latestWatchpointMet& = tempIndex& THEN COLOR 15 ELSE COLOR 4 + _PRINTSTRING (this.x + 1, this.y + y), CHR$(7) 'watchpoint bullet indicator + COLOR fg + END IF _PRINTSTRING (this.x + 2, this.y + y), MID$(item$, this.hPos, this.w - 4) ELSE _ECHO item$ @@ -7853,7 +8042,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) selectedBG = 2 TYPE varDlgList - AS LONG index, bgColorFlag, colorFlag, colorFlag2, indicator + AS LONG index, bgColorFlag, colorFlag, colorFlag2, indicator, indicator2 AS _BYTE selected AS STRING varType END TYPE @@ -7883,7 +8072,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) dialogWidth = 6 + maxModuleNameLen + maxVarLen + maxTypeLen IF IdeDebugMode > 0 THEN dialogWidth = dialogWidth + 40 'make room for "= values" - IF dialogWidth < 60 THEN dialogWidth = 60 + IF dialogWidth < 70 THEN dialogWidth = 70 IF dialogWidth > idewx - 8 THEN dialogWidth = idewx - 8 idepar p, dialogWidth, dialogHeight, "Add Watch - Variable List" @@ -7910,7 +8099,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) o(buttonSet).typ = 3 o(buttonSet).y = dialogHeight IF IdeDebugMode > 0 AND o(buttonSet).txt = 0 THEN - o(buttonSet).txt = idenewtxt("#Add All" + sep + "#Remove All" + sep + "#Send Value" + sep + "#Close") + o(buttonSet).txt = idenewtxt("#Add All" + sep + "#Remove All" + sep + "#Send Value" + sep + "Add #Watchpoint" + sep + "#Close") ELSE o(buttonSet).txt = idenewtxt("#Add All" + sep + "#Remove All" + sep + "#Close") END IF @@ -8036,15 +8225,29 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) _CONTINUE END IF - IF (IdeDebugMode > 0 AND focus = 5 AND info <> 0) THEN - 'set address + IF (IdeDebugMode > 0 AND focus = 5 AND info <> 0) OR _ + (IdeDebugMode > 0 AND focus = 6 AND info <> 0) THEN + 'set address/add watchpoint sendValue: + SELECT CASE focus + CASE 5 + dlgTitle$ = "Change Value" + dlgPrompt$ = "#Index to change" + dlgPrompt2$ = "#New value" + thisReturnAction = 1 + CASE 6 + dlgTitle$ = "Add Watchpoint" + dlgPrompt$ = "#Index to monitor" + dlgPrompt2$ = "#Condition" + thisReturnAction = 2 + END SELECT + y = ABS(o(varListBox).sel) IF y >= 1 AND y <= totalVisibleVariables THEN tempIndex& = varDlgList(y).index - IF usedVariableList(tempIndex&).subfunc = currentScope$ OR usedVariableList(tempIndex&).subfunc = "" THEN - 'scope is valid + IF (focus = 5 AND (usedVariableList(tempIndex&).subfunc = currentScope$ OR usedVariableList(tempIndex&).subfunc = "")) OR focus = 6 THEN + 'scope is valid (or we're setting a watchpoint) tempArrayIndex& = 0 tempArrayIndexes$ = MKL$(0) tempStorage& = 0 @@ -8052,7 +8255,8 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) tempElementOffset$ = MKL$(0) IF usedVariableList(tempIndex&).isarray THEN setArrayRange3: - v$ = ideinputbox$("Change Value", "#Index to change", temp$, "01234567890,", 45, 0, ok) + v$ = ideinputbox$(dlgTitle$, dlgPrompt$, temp$, "01234567890,", 45, 0, ok) + _KEYCLEAR IF ok THEN IF LEN(v$) > 0 THEN WHILE RIGHT$(v$, 1) = ",": v$ = LEFT$(v$, LEN(v$) - 1): WEND @@ -8060,6 +8264,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) i = countelements(temp$) IF i <> ABS(ids(usedVariableList(tempIndex&).id).arrayelements) THEN result = idemessagebox("Error", "Array has" + STR$(ABS(ids(usedVariableList(tempIndex&).id).arrayelements)) + " dimension(s).", "#OK") + _KEYCLEAR temp$ = _TRIM$(v$) GOTO setArrayRange3 END IF @@ -8106,6 +8311,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) LOOP PCOPY 0, 4 v$ = ideelementwatchbox$(usedVariableList(tempIndex&).name + ".", elementIndexes$, 0, -1, ok) + _KEYCLEAR PCOPY 2, 0 PCOPY 2, 1 SCREEN , , 1, 0 @@ -8129,7 +8335,8 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) temp$ = v$ IF numelements(temp$) <> 1 THEN 'shouldn't ever happen - result = idemessagebox("Error", "Only one UDT element can be changed at a time", "#OK") + result = idemessagebox("Error", "Only one UDT element can be selected at a time", "#OK") + _KEYCLEAR _CONTINUE END IF @@ -8143,6 +8350,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) 'shouldn't ever happen Error_Happened = 0 result = idemessagebox("Error", Error_Message, "#OK") + _KEYCLEAR _CONTINUE ELSE typ = typ - ISUDT @@ -8185,7 +8393,8 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) END IF ELSE 'shouldn't ever happen - result = idemessagebox("Error", "Cannot send value to full UDT", "#OK") + result = idemessagebox("Error", "Cannot select full UDT", "#OK") + _KEYCLEAR GOTO dlgLoop END IF END SELECT @@ -8212,46 +8421,153 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) LOOP END IF a2$ = "" - IF storageSlot& > 0 THEN + IF storageSlot& > 0 AND focus = 5 THEN a2$ = vWatchReceivedData$(storageSlot&) + ELSEIF focus = 6 THEN + 'find existing watchpoint for this variable/index/element + temp$ = MKL$(tempIndex&) + tempArrayIndexes$ + tempElementOffset$ + i = 0 + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + DO WHILE i + IF MID$(watchpointList$, i + 8, LEN(temp$)) = temp$ THEN EXIT DO + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + LOOP + + IF i > 0 THEN + j = CVL(MID$(watchpointList$, i + 4, 4)) + temp$ = MID$(watchpointList$, i + 8, j) + j = CVI(RIGHT$(temp$, 2)) + a2$ = MID$(temp$, LEN(temp$) - (2 + j) + 1, j) + END IF END IF IF INSTR(varType$, "STRING") THEN thisWidth = idewx - 20 ELSE thisWidth = 45 END IF - v$ = ideinputbox$("Change Value", "#New value", a2$, "", thisWidth, 0, ok) + getNewValueInput: + v$ = ideinputbox$(dlgTitle$, dlgPrompt2$, a2$, "", thisWidth, 0, ok) + _KEYCLEAR IF ok THEN - temp$ = "" - temp$ = temp$ + MKL$(tempIndex&) - temp$ = temp$ + MKL$(usedVariableList(tempIndex&).localindex) - temp$ = temp$ + MKL$(usedVariableList(tempIndex&).isarray <> 0) - temp$ = temp$ + tempArrayIndexes$ - temp$ = temp$ + MKL$(tempIsUDT&) - temp$ = temp$ + tempElementOffset$ - temp$ = temp$ + MKL$(usedVariableList(tempIndex&).arrayElementSize) - temp$ = temp$ + MKL$(storageSlot&) - temp$ = temp$ + MKI$(LEN(varType$)) + varType$ - temp$ = temp$ + MKI$(LEN(v$)) + v$ - idevariablewatchbox$ = temp$ - returnAction = 1 'actually send value + IF focus = 6 THEN + 'validate condition string first + v$ = LTRIM$(v$) + IF LEN(v$) < 2 THEN + result = idemessagebox(dlgTitle$, "Watchpoint cleared.", "#OK") + _KEYCLEAR + v$ = "" + thisReturnAction = 3 'remove watchpoint for this variable + ELSE + StartWatchPointEval: + op1$ = LEFT$(v$, 1) + op2$ = MID$(v$, 2, 1) + SELECT CASE op1$ + CASE "=" + IF op2$ = "<" OR op2$ = ">" THEN + MID$(v$, 1, 2) = op2$ + "=" + GOTO StartWatchPointEval + END IF + op$ = "=" + actualValue$ = _TRIM$(MID$(v$, 2)) + CASE ">" + IF op2$ = "<" OR op2$ = ">" THEN + result = idemessagebox(dlgTitle$, "Invalid expression.\nYou can use =, <>, >, >=, <, <=, and a literal value", "#OK") + _KEYCLEAR + GOTO getNewValueInput + END IF + IF op2$ = "=" THEN + op$ = ">=" + actualValue$ = _TRIM$(MID$(v$, 3)) + ELSE + op$ = ">" + actualValue$ = _TRIM$(MID$(v$, 2)) + END IF + CASE "<" + IF op2$ = ">" OR op2$ = "=" THEN + op$ = "<" + op2$ + actualValue$ = _TRIM$(MID$(v$, 3)) + ELSE + op$ = "<" + actualValue$ = _TRIM$(MID$(v$, 2)) + END IF + CASE ELSE + result = idemessagebox(dlgTitle$, "Invalid expression.\nYou can use =, <>, >, >=, <, <=, and a literal value", "#OK") + _KEYCLEAR + GOTO getNewValueInput + END SELECT + END IF + END IF + + IF INSTR(varType$, "STRING") = 0 AND thisReturnAction <> 3 THEN + v$ = op$ + actualValue$ + IF v$ <> op$ + LTRIM$(STR$(VAL(actualValue$))) THEN + result = idemessagebox(dlgTitle$, "Invalid expression.\nYou can use =, <>, >, >=, <, <=, and a literal value\n(scientific notation not allowed).", "#OK") + _KEYCLEAR + GOTO getNewValueInput + END IF + END IF + + cmd$ = "" + cmd$ = cmd$ + MKL$(tempIndex&) + cmd$ = cmd$ + _MK$(_BYTE, usedVariableList(tempIndex&).isarray) + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).linenumber) + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).localIndex) + cmd$ = cmd$ + tempArrayIndexes$ + cmd$ = cmd$ + MKL$(usedVariableList(tempIndex&).arrayElementSize) + cmd$ = cmd$ + MKL$(tempIsUDT&) + cmd$ = cmd$ + MKL$(tempElement&) + cmd$ = cmd$ + tempElementOffset$ + cmd$ = cmd$ + MKL$(0) + cmd$ = cmd$ + MKL$(tempStorage&) + cmd$ = cmd$ + MKI$(LEN(usedVariableList(tempIndex&).subfunc)) + cmd$ = cmd$ + usedVariableList(tempIndex&).subfunc + cmd$ = cmd$ + MKI$(LEN(varType$)) + varType$ + cmd$ = cmd$ + MKI$(LEN(v$)) + v$ + idevariablewatchbox$ = cmd$ + + IF thisReturnAction = 2 OR thisReturnAction = 3 THEN + 'find existing watchpoint for the same variable/index/element + temp$ = MKL$(tempIndex&) + tempArrayIndexes$ + tempElementOffset$ + i = 0 + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + DO WHILE i + IF MID$(watchpointList$, i + 8, LEN(temp$)) = temp$ THEN EXIT DO + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + LOOP + + IF i > 0 THEN + 'remove it + j = CVL(MID$(watchpointList$, i + 4, 4)) + watchpointList$ = LEFT$(watchpointList$, i - 1) + MID$(watchpointList$, i + j + 8) + END IF + END IF + + IF thisReturnAction = 2 THEN + 'add watchpoint + temp$ = temp$ + v$ + MKI$(LEN(v$)) + watchpointList$ = watchpointList$ + MKL$(-1) + MKL$(LEN(temp$)) + temp$ + END IF + + returnAction = thisReturnAction 'actually send command ELSE - returnAction = 2 'redraw and carry on + returnAction = -1 'redraw and carry on END IF selectVar = y EXIT FUNCTION ELSE - result = idemessagebox("Change Value", "Variable is out of scope.", "#OK") + result = idemessagebox(dlgTitle$, "Variable is out of scope.", "#OK") + _KEYCLEAR END IF ELSE - result = idemessagebox("Change Value", "Select a variable first.", "#OK") + result = idemessagebox(dlgTitle$, "Select a variable first.", "#OK") + _KEYCLEAR END IF focus = filterBox _CONTINUE END IF IF K$ = CHR$(27) OR (IdeDebugMode = 0 AND focus = 5 AND info <> 0) OR _ - (IdeDebugMode > 0 AND focus = 6 AND info <> 0) THEN + (IdeDebugMode > 0 AND focus = 7 AND info <> 0) THEN variableWatchList$ = "" longestVarName = 0 nextvWatchDataSlot = 0 @@ -8366,6 +8682,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) IF mCLICK AND focus = 2 THEN 'list click IF timeElapsedSince(lastClick!) < .3 AND clickedItem = o(varListBox).sel THEN IF doubleClickThreshold > 0 AND mX >= p.x + doubleClickThreshold AND IdeDebugMode > 0 THEN + focus = 5 GOTO sendValue ELSE GOTO toggleWatch @@ -8668,7 +8985,7 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) maxVarLen = LEN("Variable") FOR x = 1 TO totalVariablesCreated IF usedVariableList(x).includedLine THEN _CONTINUE 'don't deal with variables in $INCLUDEs - thisLen = LEN(usedVariableList(x).name) + thisLen = LEN(usedVariableList(x).name) + 3 'extra room for the eventual bullet IF LEN(usedVariableList(x).watchRange) > 0 THEN thisLen = thisLen + LEN(usedVariableList(x).watchRange) END IF @@ -8721,6 +9038,22 @@ FUNCTION idevariablewatchbox$(currentScope$, filter$, selectVar, returnAction) IF LEN(usedVariableList(x).watchRange) THEN thisName$ = LEFT$(thisName$, LEN(thisName$) - 1) + usedVariableList(x).watchRange + ")" END IF + + 'find existing watchpoint for this variable/index/element + temp$ = MKL$(x) + i = 0 + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + DO WHILE i + IF MID$(watchpointList$, i + 8, LEN(temp$)) = temp$ THEN EXIT DO + i = INSTR(i + 1, watchpointList$, MKL$(-1)) + LOOP + + IF i > 0 THEN + thisName$ = thisName$ + CHR$(16) + CHR$(4) + CHR$(7) 'red bullet to indicate watchpoint + ELSE + thisName$ = thisName$ + CHR$(16) + CHR$(16) + " " + END IF + text$ = thisName$ + CHR$(16) varDlgList(totalVisibleVariables).colorFlag2 = LEN(l$) + LEN(text$) + 1 IF usedVariableList(x).watch THEN @@ -14655,7 +14988,14 @@ FUNCTION idemessagebox (titlestr$, messagestr$, buttons$) 'specific post controls IF K$ = CHR$(27) THEN EXIT FUNCTION - IF K$ = CHR$(13) OR (info <> 0) THEN idemessagebox = focus: EXIT FUNCTION + IF K$ = CHR$(13) OR (info <> 0) THEN + idemessagebox = focus + DO UNTIL mCLICK = 0 + GetInput + _LIMIT 100 + LOOP + EXIT FUNCTION + END IF 'end of custom controls mousedown = 0