diff options
Diffstat (limited to 'src/VBox/Debugger/DBGCScreenAscii.cpp')
-rw-r--r-- | src/VBox/Debugger/DBGCScreenAscii.cpp | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/src/VBox/Debugger/DBGCScreenAscii.cpp b/src/VBox/Debugger/DBGCScreenAscii.cpp new file mode 100644 index 00000000..417e898c --- /dev/null +++ b/src/VBox/Debugger/DBGCScreenAscii.cpp @@ -0,0 +1,446 @@ +/* $Id: DBGCScreenAscii.cpp $ */ +/** @file + * DBGC - Debugger Console, ASCII screen with optional coloring support. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * 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 program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DBGC +#include <VBox/err.h> +#include <VBox/log.h> + +#include <iprt/mem.h> +#include <iprt/string.h> + +#include "DBGCInternal.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ + +/** + * Debug console ASCII screen. + */ +typedef struct DBGCSCREENINT +{ + /** Width of the screen. */ + uint32_t cchWidth; + /** Height of the screen. */ + uint32_t cchHeight; + /** Extra amount of characters at the end of each line (usually terminator). */ + uint32_t cchStride; + /** Pointer to the char buffer. */ + char *pszScreen; + /** Color information for each pixel. */ + PDBGCSCREENCOLOR paColors; +} DBGCSCREENINT; +/** Pointer to an ASCII screen. */ +typedef DBGCSCREENINT *PDBGCSCREENINT; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ + + +/** + * Returns the buffer starting at the given position. + * + * @returns Pointer to the ASCII buffer. + * @param pThis The screen. + * @param uX Horizontal position. + * @param uY Vertical position. + */ +DECLINLINE(char *) dbgcScreenAsciiGetBufferAtPos(PDBGCSCREENINT pThis, uint32_t uX, uint32_t uY) +{ + AssertReturn(uX < pThis->cchWidth && uY < pThis->cchHeight, NULL); + return pThis->pszScreen + (pThis->cchWidth + pThis->cchStride) * uY + uX; +} + + +/** + * Returns the color buffer starting at the given position. + * + * @returns Pointer to the color buffer. + * @param pThis The screen. + * @param uX Horizontal position. + * @param uY Vertical position. + */ +DECLINLINE(PDBGCSCREENCOLOR) dbgcScreenAsciiGetColorBufferAtPos(PDBGCSCREENINT pThis, uint32_t uX, uint32_t uY) +{ + AssertReturn(uX < pThis->cchWidth && uY < pThis->cchHeight, NULL); + return &pThis->paColors[pThis->cchWidth * uY + uX]; +} + + +/** + * Converts the given color the correct escape sequence. + * + * @returns Pointer to the string containing the escape sequence for the given color. + * @param enmColor The color. + */ +static const char *dbgcScreenAsciiColorToEscapeSeq(DBGCSCREENCOLOR enmColor) +{ + const char *psz = NULL; + + switch (enmColor) + { + case DBGCSCREENCOLOR_DEFAULT: + psz = "\033[0m"; + break; + case DBGCSCREENCOLOR_BLACK: + psz = "\033[30m"; + break; + case DBGCSCREENCOLOR_BLACK_BRIGHT: + psz = "\033[30;1m"; + break; + case DBGCSCREENCOLOR_RED: + psz = "\033[31m"; + break; + case DBGCSCREENCOLOR_RED_BRIGHT: + psz = "\033[31;1m"; + break; + case DBGCSCREENCOLOR_GREEN: + psz = "\033[32m"; + break; + case DBGCSCREENCOLOR_GREEN_BRIGHT: + psz = "\033[32;1m"; + break; + case DBGCSCREENCOLOR_YELLOW: + psz = "\033[33m"; + break; + case DBGCSCREENCOLOR_YELLOW_BRIGHT: + psz = "\033[33;1m"; + break; + case DBGCSCREENCOLOR_BLUE: + psz = "\033[34m"; + break; + case DBGCSCREENCOLOR_BLUE_BRIGHT: + psz = "\033[34;1m"; + break; + case DBGCSCREENCOLOR_MAGENTA: + psz = "\033[35m"; + break; + case DBGCSCREENCOLOR_MAGENTA_BRIGHT: + psz = "\033[35;1m"; + break; + case DBGCSCREENCOLOR_CYAN: + psz = "\033[36m"; + break; + case DBGCSCREENCOLOR_CYAN_BRIGHT: + psz = "\033[36;1m"; + break; + case DBGCSCREENCOLOR_WHITE: + psz = "\033[37m"; + break; + case DBGCSCREENCOLOR_WHITE_BRIGHT: + psz = "\033[37;1m"; + break; + default: + AssertFailed(); + } + + return psz; +} + + +/** + * Creates a new ASCII screen for layouting. + * + * @returns VBox status code. + * @param phScreen Where to store the handle to the screen instance on success. + * @param cchWidth Width of the screen in characters. + * @param cchHeight Height of the screen in characters. + */ +DECLHIDDEN(int) dbgcScreenAsciiCreate(PDBGCSCREEN phScreen, uint32_t cchWidth, uint32_t cchHeight) +{ + int rc = VINF_SUCCESS; + + PDBGCSCREENINT pThis = (PDBGCSCREENINT)RTMemAllocZ(sizeof(DBGCSCREENINT)); + if (pThis) + { + pThis->cchWidth = cchWidth; + pThis->cchHeight = cchHeight; + pThis->cchStride = 1; /* Zero terminators after every line. */ + pThis->pszScreen = RTStrAlloc((cchWidth + 1) * cchHeight * sizeof(char)); + if (RT_LIKELY(pThis->pszScreen)) + { + pThis->paColors = (PDBGCSCREENCOLOR)RTMemAllocZ(cchWidth * cchHeight * sizeof(DBGCSCREENCOLOR)); + if (RT_LIKELY(pThis->paColors)) + { + memset(pThis->pszScreen, 0, (cchWidth + 1) * cchHeight * sizeof(char)); + /* Initialize the screen with spaces. */ + for (uint32_t i = 0; i < cchHeight; i++) + dbgcScreenAsciiDrawLineHorizontal(pThis, 0, cchWidth - 1, i, ' ', + DBGCSCREENCOLOR_DEFAULT); + *phScreen = pThis; + } + else + rc = VERR_NO_MEMORY; + + if (RT_FAILURE(rc)) + RTStrFree(pThis->pszScreen); + } + else + rc = VERR_NO_STR_MEMORY; + + if (RT_FAILURE(rc)) + RTMemFree(pThis); + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + + +/** + * Destroys a given ASCII screen. + * + * @returns nothing. + * @param hScreen The screen handle. + */ +DECLHIDDEN(void) dbgcScreenAsciiDestroy(DBGCSCREEN hScreen) +{ + PDBGCSCREENINT pThis = hScreen; + AssertPtrReturnVoid(pThis); + + RTStrFree(pThis->pszScreen); + RTMemFree(pThis->paColors); + RTMemFree(pThis); +} + + +/** + * Blits the entire screen using the given callback callback. + * + * @returns VBox status code. + * @param hScreen The screen to blit. + * @param pfnBlit Blitting callback. + * @param pvUser Opaque user data to pass to the dumper callback. + * @param fAddColors Flag whether to use the color info inserting + * appropriate escape sequences. + */ +DECLHIDDEN(int) dbgcScreenAsciiBlit(DBGCSCREEN hScreen, PFNDGCSCREENBLIT pfnBlit, void *pvUser, bool fAddColors) +{ + int rc = VINF_SUCCESS; + PDBGCSCREENINT pThis = hScreen; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + if (!fAddColors) + { + for (uint32_t iY = 0; iY < pThis->cchHeight && RT_SUCCESS(rc); iY++) + { + /* Play safe and restore line endings. */ + char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, 0, iY); + psz[pThis->cchWidth] = '\0'; + rc = pfnBlit(psz, pvUser); + if (RT_SUCCESS(rc)) + rc = pfnBlit("\n", pvUser); + } + } + else + { + for (uint32_t iY = 0; iY < pThis->cchHeight && RT_SUCCESS(rc); iY++) + { + /* Play safe and restore line endings. */ + char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, 0, iY); + PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, 0, iY); + psz[pThis->cchWidth] = '\0'; + + /* + * Blit only stuff with the same color at once so to be able to inject the + * correct color escape sequences. + */ + uint32_t uStartX = 0; + while ( uStartX < pThis->cchWidth + && RT_SUCCESS(rc)) + { + uint32_t cchWrite = 0; + DBGCSCREENCOLOR enmColorStart = *pColor; + while ( uStartX + cchWrite < pThis->cchWidth + && enmColorStart == *pColor) + { + pColor++; + cchWrite++; + } + + const char *pszEsc = dbgcScreenAsciiColorToEscapeSeq(enmColorStart); + rc = pfnBlit(pszEsc, pvUser); + if (RT_SUCCESS(rc)) + { + char chTmp = psz[cchWrite]; + psz[cchWrite] = '\0'; + rc = pfnBlit(psz, pvUser); + psz[cchWrite] = chTmp; + uStartX += cchWrite; + psz += cchWrite; + } + } + rc = pfnBlit("\n", pvUser); + } + + /* Restore to default values at the end. */ + if (RT_SUCCESS(rc)) + { + const char *pszEsc = dbgcScreenAsciiColorToEscapeSeq(DBGCSCREENCOLOR_DEFAULT); + rc = pfnBlit(pszEsc, pvUser); + } + } + + return rc; +} + + +/** + * Draws a single character to the screen at the given coordinates. + * + * @returns VBox status code. + * @param hScreen The screen handle. + * @param uX X coordinate. + * @param uY Y coordinate. + * @param ch Character to draw. + * @param enmColor The color to use. + */ +DECLHIDDEN(int) dbgcScreenAsciiDrawCharacter(DBGCSCREEN hScreen, uint32_t uX, uint32_t uY, char ch, + DBGCSCREENCOLOR enmColor) +{ + PDBGCSCREENINT pThis = hScreen; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uX, uY); + PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uX, uY); + AssertPtrReturn(psz, VERR_INVALID_STATE); + AssertPtrReturn(pColor, VERR_INVALID_STATE); + AssertReturn(*psz != '\0', VERR_INVALID_STATE); + + *psz = ch; + *pColor = enmColor; + return VINF_SUCCESS; +} + + +/** + * Draws a vertical line at the given coordinates. + * + * @returns nothing. + * @param hScreen The screen handle. + * @param uX X position to draw. + * @param uStartY Y position to start drawing. + * @param uEndY Y position to draw to (inclusive). + * @param ch The character to use for drawing. + * @param enmColor The color to use. + */ +DECLHIDDEN(int) dbgcScreenAsciiDrawLineVertical(DBGCSCREEN hScreen, uint32_t uX, uint32_t uStartY, + uint32_t uEndY, char ch, DBGCSCREENCOLOR enmColor) +{ + PDBGCSCREENINT pThis = hScreen; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + while (uStartY <= uEndY) + { + char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uX, uStartY); + PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uX, uStartY); + AssertPtrReturn(psz, VERR_INVALID_STATE); + AssertPtrReturn(pColor, VERR_INVALID_STATE); + *psz = ch; + *pColor = enmColor; + uStartY++; + } + + return VINF_SUCCESS; +} + + +/** + * Draws a horizontal line at the given coordinates. + * + * @returns VBox status code.. + * @param hScreen The screen handle. + * @param uStartX X position to start drawing. + * @param uEndX X position to draw the line to (inclusive). + * @param uY Y position. + * @param ch The character to use for drawing. + * @param enmColor The color to use. + */ +DECLHIDDEN(int) dbgcScreenAsciiDrawLineHorizontal(DBGCSCREEN hScreen, uint32_t uStartX, uint32_t uEndX, + uint32_t uY, char ch, DBGCSCREENCOLOR enmColor) +{ + PDBGCSCREENINT pThis = hScreen; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uStartX, uY); + PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uStartX, uY); + AssertPtrReturn(psz, VERR_INVALID_STATE); + AssertPtrReturn(pColor, VERR_INVALID_STATE); + + memset(psz, ch, uEndX - uStartX + 1); + for (unsigned i = 0; i < uEndX - uStartX + 1; i++) + pColor[i] = enmColor; + + return VINF_SUCCESS; +} + + +/** + * Draws a given string to the screen. + * + * @returns VBox status code.. + * @param hScreen The screen handle. + * @param uX X position to start drawing. + * @param uY Y position. + * @param pszText The string to draw. + * @param enmColor The color to use. + */ +DECLHIDDEN(int) dbgcScreenAsciiDrawString(DBGCSCREEN hScreen, uint32_t uX, uint32_t uY, const char *pszText, + DBGCSCREENCOLOR enmColor) +{ + PDBGCSCREENINT pThis = hScreen; + size_t cchText = strlen(pszText); + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(uX + cchText <= pThis->cchWidth, VERR_OUT_OF_RANGE); + AssertReturn(uY < pThis->cchHeight, VERR_OUT_OF_RANGE); + + char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uX, uY); + PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uX, uY); + AssertPtrReturn(psz, VERR_INVALID_STATE); + AssertPtrReturn(pColor, VERR_INVALID_STATE); + + memcpy(psz, pszText, cchText); + + for (unsigned i = 0; i < cchText; i++) + pColor[i] = enmColor; + + return VINF_SUCCESS; +} |