VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCScreenAscii.cpp

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.1 KB
Line 
1/* $Id: DBGCScreenAscii.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, ASCII screen with optional coloring support.
4 */
5
6/*
7 * Copyright (C) 2016-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DBGC
33#include <VBox/err.h>
34#include <VBox/log.h>
35
36#include <iprt/mem.h>
37#include <iprt/string.h>
38
39#include "DBGCInternal.h"
40
41
42/*********************************************************************************************************************************
43* Defined Constants And Macros *
44*********************************************************************************************************************************/
45
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51
52/**
53 * Debug console ASCII screen.
54 */
55typedef struct DBGCSCREENINT
56{
57 /** Width of the screen. */
58 uint32_t cchWidth;
59 /** Height of the screen. */
60 uint32_t cchHeight;
61 /** Extra amount of characters at the end of each line (usually terminator). */
62 uint32_t cchStride;
63 /** Pointer to the char buffer. */
64 char *pszScreen;
65 /** Color information for each pixel. */
66 PDBGCSCREENCOLOR paColors;
67} DBGCSCREENINT;
68/** Pointer to an ASCII screen. */
69typedef DBGCSCREENINT *PDBGCSCREENINT;
70
71
72/*********************************************************************************************************************************
73* Internal Functions *
74*********************************************************************************************************************************/
75
76
77/**
78 * Returns the buffer starting at the given position.
79 *
80 * @returns Pointer to the ASCII buffer.
81 * @param pThis The screen.
82 * @param uX Horizontal position.
83 * @param uY Vertical position.
84 */
85DECLINLINE(char *) dbgcScreenAsciiGetBufferAtPos(PDBGCSCREENINT pThis, uint32_t uX, uint32_t uY)
86{
87 AssertReturn(uX < pThis->cchWidth && uY < pThis->cchHeight, NULL);
88 return pThis->pszScreen + (pThis->cchWidth + pThis->cchStride) * uY + uX;
89}
90
91
92/**
93 * Returns the color buffer starting at the given position.
94 *
95 * @returns Pointer to the color buffer.
96 * @param pThis The screen.
97 * @param uX Horizontal position.
98 * @param uY Vertical position.
99 */
100DECLINLINE(PDBGCSCREENCOLOR) dbgcScreenAsciiGetColorBufferAtPos(PDBGCSCREENINT pThis, uint32_t uX, uint32_t uY)
101{
102 AssertReturn(uX < pThis->cchWidth && uY < pThis->cchHeight, NULL);
103 return &pThis->paColors[pThis->cchWidth * uY + uX];
104}
105
106
107/**
108 * Converts the given color the correct escape sequence.
109 *
110 * @returns Pointer to the string containing the escape sequence for the given color.
111 * @param enmColor The color.
112 */
113static const char *dbgcScreenAsciiColorToEscapeSeq(DBGCSCREENCOLOR enmColor)
114{
115 const char *psz = NULL;
116
117 switch (enmColor)
118 {
119 case DBGCSCREENCOLOR_DEFAULT:
120 psz = "\033[0m";
121 break;
122 case DBGCSCREENCOLOR_BLACK:
123 psz = "\033[30m";
124 break;
125 case DBGCSCREENCOLOR_BLACK_BRIGHT:
126 psz = "\033[30;1m";
127 break;
128 case DBGCSCREENCOLOR_RED:
129 psz = "\033[31m";
130 break;
131 case DBGCSCREENCOLOR_RED_BRIGHT:
132 psz = "\033[31;1m";
133 break;
134 case DBGCSCREENCOLOR_GREEN:
135 psz = "\033[32m";
136 break;
137 case DBGCSCREENCOLOR_GREEN_BRIGHT:
138 psz = "\033[32;1m";
139 break;
140 case DBGCSCREENCOLOR_YELLOW:
141 psz = "\033[33m";
142 break;
143 case DBGCSCREENCOLOR_YELLOW_BRIGHT:
144 psz = "\033[33;1m";
145 break;
146 case DBGCSCREENCOLOR_BLUE:
147 psz = "\033[34m";
148 break;
149 case DBGCSCREENCOLOR_BLUE_BRIGHT:
150 psz = "\033[34;1m";
151 break;
152 case DBGCSCREENCOLOR_MAGENTA:
153 psz = "\033[35m";
154 break;
155 case DBGCSCREENCOLOR_MAGENTA_BRIGHT:
156 psz = "\033[35;1m";
157 break;
158 case DBGCSCREENCOLOR_CYAN:
159 psz = "\033[36m";
160 break;
161 case DBGCSCREENCOLOR_CYAN_BRIGHT:
162 psz = "\033[36;1m";
163 break;
164 case DBGCSCREENCOLOR_WHITE:
165 psz = "\033[37m";
166 break;
167 case DBGCSCREENCOLOR_WHITE_BRIGHT:
168 psz = "\033[37;1m";
169 break;
170 default:
171 AssertFailed();
172 }
173
174 return psz;
175}
176
177
178/**
179 * Creates a new ASCII screen for layouting.
180 *
181 * @returns VBox status code.
182 * @param phScreen Where to store the handle to the screen instance on success.
183 * @param cchWidth Width of the screen in characters.
184 * @param cchHeight Height of the screen in characters.
185 */
186DECLHIDDEN(int) dbgcScreenAsciiCreate(PDBGCSCREEN phScreen, uint32_t cchWidth, uint32_t cchHeight)
187{
188 int rc = VINF_SUCCESS;
189
190 PDBGCSCREENINT pThis = (PDBGCSCREENINT)RTMemAllocZ(sizeof(DBGCSCREENINT));
191 if (pThis)
192 {
193 pThis->cchWidth = cchWidth;
194 pThis->cchHeight = cchHeight;
195 pThis->cchStride = 1; /* Zero terminators after every line. */
196 pThis->pszScreen = RTStrAlloc((cchWidth + 1) * cchHeight * sizeof(char));
197 if (RT_LIKELY(pThis->pszScreen))
198 {
199 pThis->paColors = (PDBGCSCREENCOLOR)RTMemAllocZ(cchWidth * cchHeight * sizeof(DBGCSCREENCOLOR));
200 if (RT_LIKELY(pThis->paColors))
201 {
202 memset(pThis->pszScreen, 0, (cchWidth + 1) * cchHeight * sizeof(char));
203 /* Initialize the screen with spaces. */
204 for (uint32_t i = 0; i < cchHeight; i++)
205 dbgcScreenAsciiDrawLineHorizontal(pThis, 0, cchWidth - 1, i, ' ',
206 DBGCSCREENCOLOR_DEFAULT);
207 *phScreen = pThis;
208 }
209 else
210 rc = VERR_NO_MEMORY;
211
212 if (RT_FAILURE(rc))
213 RTStrFree(pThis->pszScreen);
214 }
215 else
216 rc = VERR_NO_STR_MEMORY;
217
218 if (RT_FAILURE(rc))
219 RTMemFree(pThis);
220 }
221 else
222 rc = VERR_NO_MEMORY;
223
224 return rc;
225}
226
227
228/**
229 * Destroys a given ASCII screen.
230 *
231 * @param hScreen The screen handle.
232 */
233DECLHIDDEN(void) dbgcScreenAsciiDestroy(DBGCSCREEN hScreen)
234{
235 PDBGCSCREENINT pThis = hScreen;
236 AssertPtrReturnVoid(pThis);
237
238 RTStrFree(pThis->pszScreen);
239 RTMemFree(pThis->paColors);
240 RTMemFree(pThis);
241}
242
243
244/**
245 * Blits the entire screen using the given callback callback.
246 *
247 * @returns VBox status code.
248 * @param hScreen The screen to blit.
249 * @param pfnBlit Blitting callback.
250 * @param pvUser Opaque user data to pass to the dumper callback.
251 * @param fAddColors Flag whether to use the color info inserting
252 * appropriate escape sequences.
253 */
254DECLHIDDEN(int) dbgcScreenAsciiBlit(DBGCSCREEN hScreen, PFNDGCSCREENBLIT pfnBlit, void *pvUser, bool fAddColors)
255{
256 int rc = VINF_SUCCESS;
257 PDBGCSCREENINT pThis = hScreen;
258 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
259
260 if (!fAddColors)
261 {
262 for (uint32_t iY = 0; iY < pThis->cchHeight && RT_SUCCESS(rc); iY++)
263 {
264 /* Play safe and restore line endings. */
265 char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, 0, iY);
266 psz[pThis->cchWidth] = '\0';
267 rc = pfnBlit(psz, pvUser);
268 if (RT_SUCCESS(rc))
269 rc = pfnBlit("\n", pvUser);
270 }
271 }
272 else
273 {
274 for (uint32_t iY = 0; iY < pThis->cchHeight && RT_SUCCESS(rc); iY++)
275 {
276 /* Play safe and restore line endings. */
277 char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, 0, iY);
278 PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, 0, iY);
279 psz[pThis->cchWidth] = '\0';
280
281 /*
282 * Blit only stuff with the same color at once so to be able to inject the
283 * correct color escape sequences.
284 */
285 uint32_t uStartX = 0;
286 while ( uStartX < pThis->cchWidth
287 && RT_SUCCESS(rc))
288 {
289 uint32_t cchWrite = 0;
290 DBGCSCREENCOLOR enmColorStart = *pColor;
291 while ( uStartX + cchWrite < pThis->cchWidth
292 && enmColorStart == *pColor)
293 {
294 pColor++;
295 cchWrite++;
296 }
297
298 const char *pszEsc = dbgcScreenAsciiColorToEscapeSeq(enmColorStart);
299 rc = pfnBlit(pszEsc, pvUser);
300 if (RT_SUCCESS(rc))
301 {
302 char chTmp = psz[cchWrite];
303 psz[cchWrite] = '\0';
304 rc = pfnBlit(psz, pvUser);
305 psz[cchWrite] = chTmp;
306 uStartX += cchWrite;
307 psz += cchWrite;
308 }
309 }
310 rc = pfnBlit("\n", pvUser);
311 }
312
313 /* Restore to default values at the end. */
314 if (RT_SUCCESS(rc))
315 {
316 const char *pszEsc = dbgcScreenAsciiColorToEscapeSeq(DBGCSCREENCOLOR_DEFAULT);
317 rc = pfnBlit(pszEsc, pvUser);
318 }
319 }
320
321 return rc;
322}
323
324
325/**
326 * Draws a single character to the screen at the given coordinates.
327 *
328 * @returns VBox status code.
329 * @param hScreen The screen handle.
330 * @param uX X coordinate.
331 * @param uY Y coordinate.
332 * @param ch Character to draw.
333 * @param enmColor The color to use.
334 */
335DECLHIDDEN(int) dbgcScreenAsciiDrawCharacter(DBGCSCREEN hScreen, uint32_t uX, uint32_t uY, char ch,
336 DBGCSCREENCOLOR enmColor)
337{
338 PDBGCSCREENINT pThis = hScreen;
339 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
340
341 char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uX, uY);
342 PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uX, uY);
343 AssertPtrReturn(psz, VERR_INVALID_STATE);
344 AssertPtrReturn(pColor, VERR_INVALID_STATE);
345 AssertReturn(*psz != '\0', VERR_INVALID_STATE);
346
347 *psz = ch;
348 *pColor = enmColor;
349 return VINF_SUCCESS;
350}
351
352
353/**
354 * Draws a vertical line at the given coordinates.
355 *
356 * @returns VBox status code.
357 * @param hScreen The screen handle.
358 * @param uX X position to draw.
359 * @param uStartY Y position to start drawing.
360 * @param uEndY Y position to draw to (inclusive).
361 * @param ch The character to use for drawing.
362 * @param enmColor The color to use.
363 */
364DECLHIDDEN(int) dbgcScreenAsciiDrawLineVertical(DBGCSCREEN hScreen, uint32_t uX, uint32_t uStartY,
365 uint32_t uEndY, char ch, DBGCSCREENCOLOR enmColor)
366{
367 PDBGCSCREENINT pThis = hScreen;
368 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
369
370 while (uStartY <= uEndY)
371 {
372 char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uX, uStartY);
373 PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uX, uStartY);
374 AssertPtrReturn(psz, VERR_INVALID_STATE);
375 AssertPtrReturn(pColor, VERR_INVALID_STATE);
376 *psz = ch;
377 *pColor = enmColor;
378 uStartY++;
379 }
380
381 return VINF_SUCCESS;
382}
383
384
385/**
386 * Draws a horizontal line at the given coordinates.
387 *
388 * @returns VBox status code..
389 * @param hScreen The screen handle.
390 * @param uStartX X position to start drawing.
391 * @param uEndX X position to draw the line to (inclusive).
392 * @param uY Y position.
393 * @param ch The character to use for drawing.
394 * @param enmColor The color to use.
395 */
396DECLHIDDEN(int) dbgcScreenAsciiDrawLineHorizontal(DBGCSCREEN hScreen, uint32_t uStartX, uint32_t uEndX,
397 uint32_t uY, char ch, DBGCSCREENCOLOR enmColor)
398{
399 PDBGCSCREENINT pThis = hScreen;
400 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
401
402 char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uStartX, uY);
403 PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uStartX, uY);
404 AssertPtrReturn(psz, VERR_INVALID_STATE);
405 AssertPtrReturn(pColor, VERR_INVALID_STATE);
406
407 memset(psz, ch, uEndX - uStartX + 1);
408 for (unsigned i = 0; i < uEndX - uStartX + 1; i++)
409 pColor[i] = enmColor;
410
411 return VINF_SUCCESS;
412}
413
414
415/**
416 * Draws a given string to the screen.
417 *
418 * @returns VBox status code..
419 * @param hScreen The screen handle.
420 * @param uX X position to start drawing.
421 * @param uY Y position.
422 * @param pszText The string to draw.
423 * @param enmColor The color to use.
424 */
425DECLHIDDEN(int) dbgcScreenAsciiDrawString(DBGCSCREEN hScreen, uint32_t uX, uint32_t uY, const char *pszText,
426 DBGCSCREENCOLOR enmColor)
427{
428 PDBGCSCREENINT pThis = hScreen;
429 size_t cchText = strlen(pszText);
430 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
431 AssertReturn(uX + cchText <= pThis->cchWidth, VERR_OUT_OF_RANGE);
432 AssertReturn(uY < pThis->cchHeight, VERR_OUT_OF_RANGE);
433
434 char *psz = dbgcScreenAsciiGetBufferAtPos(pThis, uX, uY);
435 PDBGCSCREENCOLOR pColor = dbgcScreenAsciiGetColorBufferAtPos(pThis, uX, uY);
436 AssertPtrReturn(psz, VERR_INVALID_STATE);
437 AssertPtrReturn(pColor, VERR_INVALID_STATE);
438
439 memcpy(psz, pszText, cchText);
440
441 for (unsigned i = 0; i < cchText; i++)
442 pColor[i] = enmColor;
443
444 return VINF_SUCCESS;
445}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette