VirtualBox

source: vbox/trunk/src/VBox/ImageMounter/vboximg-mount/SelfSizingTable.h@ 75970

Last change on this file since 75970 was 75970, checked in by vboxsync, 6 years ago

Rename vboxraw to vboximg-mount and make it possible to build it by giving VBOX_WITH_VBOXIMGMOUNT=1 on the command line

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1/* $Id: SelfSizingTable.h 75970 2018-12-05 12:30:09Z vboxsync $ $Revision: 75970 $ */
2/** @file
3 * vboxraw header file
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* SELFSIZINGTABLE
19 *
20 * An ANSI text-display oriented table, whose column widths conform to width of
21 * their contents. The goal is to optimize whitespace usage, so there's neither too
22 * much nor too little whitespace (e.g. min. necessary for optimal readability).
23 *
24 * Contents can only be added to and redisplayed, not manipulated after adding.
25 *
26 * Simple API (see example below):
27 *
28 * 1. Create table instance.
29 * 2. Add column definitions.
30 * 3. Add each row and set data for each column in a row.
31 * 4. Invoke the displayTable() method.
32 *
33 * Each time the table is [re]displayed its contents are [re]evaluated to determine
34 * the column sizes and header and data padding.
35 *
36 * Example:
37 *
38 * SELFSIZINGTABLE tbl(2);
39 * void *colPlanet = tbl.addCol("Planet" "%s", 1);
40 * void *colInhabit = tbl.addCol("Inhabitability", "%-12s = %s");
41 *
42 * // This is an 'unrolled loop' example. More typical would be to iterate,
43 * // providing data content from arrays, indicies, in-place calculations,
44 * // databases, etc... rather than just hardcoded literals.
45 *
46 * void *row = tbl.addRow();
47 * tbl.setCell(row, colPlanet, "Earth");
48 * tbl.setCell(row, colInhabit, "Viability", "Decreasing");
49 * row = tbl.addRow();
50 * tbl.setCell(row, colPlanet, "Mars");
51 * tbl.setCell(row, colInhabit, "Tolerability", "Miserable");
52 * row = tbl.addRow();
53 * tbl.setCell(row, colPlanet, "Neptune");
54 * tbl.setCell(row, colInhabit, "Plausibility", "Forget it");
55 *
56 * tbl.displayTable();
57 *
58 * Planet Inhabitability
59 * Earth Viability = Decreasing
60 * Mars Tolerability = Miserable
61 * Neptune Plausibility = Forget it
62 *
63 * (note:
64 * Column headers displayed in bold red to distinguish from data)
65 *
66 */
67
68#ifndef ___SELFSIZINGTABLE_H
69#define ___SELFSIZINGTABLE_H
70
71#include <iprt/types.h>
72#include <iprt/string.h>
73#include <iprt/assert.h>
74#include <iprt/message.h>
75#include <iprt/stream.h>
76
77#define ANSI_BOLD "\x1b[1m" /** ANSI terminal esc. seq [CSI] to switch font to bold */
78#define ANSI_BLACK "\x1b[30m" /** ANSI terminal esc. seq [CSI] to switch font to black */
79#define ANSI_RED "\x1b[31m" /** ANSI terminal esc. seq [CSI] to switch font to red */
80#define ANSI_RESET "\x1b[m" /** ANSI terminal esc. seq to reset terminal attributes mode */
81
82#define HDRLABEL_MAX 30 /** Maximum column header label length (for RTStrNLen()) */
83#define COLUMN_WIDTH_MAX 256 /** Maximum width of a display column */
84
85typedef class SelfSizingTable
86{
87 public:
88 SelfSizingTable(int cbDefaultPadding = 1);
89 ~SelfSizingTable();
90 void *addCol(const char *pszHdr, const char *pszFmt, int8_t align = LEFT, int8_t padRight = 0);
91 void *addRow();
92 void setCell(void *row, void *col, ...);
93 void displayTable();
94
95 private:
96 typedef struct ColDesc {
97 struct ColDesc *next;
98 char *pszHdr;
99 uint8_t hdrLen;
100 char *pszFmt;
101 int8_t alignment;
102 uint8_t cbPadRightOpt;
103 uint8_t cbWidestDataInCol;
104 } COLDESC;
105
106 typedef struct ColData
107 {
108 struct ColData *next;
109 COLDESC *pColDesc;
110 char *pszData;
111 uint8_t cbData;
112 } COLDATA;
113
114 typedef struct Row
115 {
116 struct Row *next;
117 uint32_t id;
118 COLDATA colDataListhead;
119 } ROW;
120
121 int cbDefaultColPadding;
122 COLDESC colDescListhead;
123 ROW rowListhead;
124
125 public:
126 enum Alignment /* column/cell alignment */
127 {
128 CENTER = 0, RIGHT = 1, LEFT = -1,
129 };
130
131} SELFSIZINGTABLE;
132
133SELFSIZINGTABLE::SelfSizingTable(int cbDefaultPadding)
134{
135 this->cbDefaultColPadding = cbDefaultPadding;
136 colDescListhead.next = NULL;
137 rowListhead.next = NULL;
138}
139SELFSIZINGTABLE::~SelfSizingTable()
140{
141 COLDESC *pColDesc = colDescListhead.next;
142 while (pColDesc)
143 {
144 COLDESC *pColDescNext = pColDesc->next;
145 RTMemFree(pColDesc->pszHdr);
146 RTMemFree(pColDesc->pszFmt);
147 delete pColDesc;
148 pColDesc = pColDescNext;
149 }
150 ROW *pRow = rowListhead.next;
151 while(pRow)
152 {
153 ROW *pRowNext = pRow->next;
154 COLDATA *pColData = pRow->colDataListhead.next;
155 while (pColData)
156 {
157 COLDATA *pColDataNext = pColData->next;
158 delete pColData->pszData;
159 delete pColData;
160 pColData = pColDataNext;
161 }
162 delete pRow;
163 pRow = pRowNext;
164 }
165}
166
167void *SELFSIZINGTABLE::addCol(const char *pszHdr, const char *pszFmt, int8_t align, int8_t padRight)
168{
169 COLDESC *pColDescNew = new COLDESC();
170 if (!pColDescNew)
171 {
172 RTMsgErrorExitFailure("out of memory");
173 return NULL;
174 }
175 pColDescNew->pszHdr = RTStrDup(pszHdr);
176 pColDescNew->hdrLen = RTStrNLen(pszHdr, HDRLABEL_MAX);
177 pColDescNew->pszFmt = RTStrDup(pszFmt);
178 pColDescNew->alignment = align;
179 pColDescNew->cbPadRightOpt = padRight;
180 COLDESC *pColDesc = &colDescListhead;
181
182 while (pColDesc->next)
183 pColDesc = pColDesc->next;
184
185 pColDesc->next = pColDescNew;
186 return (void *)pColDescNew;
187}
188
189void *SELFSIZINGTABLE::addRow()
190{
191 ROW *pNewRow = new Row();
192 COLDESC *pColDesc = colDescListhead.next;
193 COLDATA *pCurColData = &pNewRow->colDataListhead;
194 while (pColDesc)
195 {
196 COLDATA *pNewColData = new COLDATA();
197 pNewColData->pColDesc = pColDesc;
198 pCurColData = pCurColData->next = pNewColData;
199 pColDesc = pColDesc->next;
200 }
201 ROW *pRow = &rowListhead;
202 while (pRow->next)
203 pRow = pRow->next;
204 pRow->next = pNewRow;
205 return (void *)pNewRow;
206}
207
208void SELFSIZINGTABLE::setCell(void *row, void *col, ...)
209{
210 ROW *pRow = (ROW *)row;
211 COLDESC *pColDesc = (COLDESC *)col;
212 va_list ap;
213 va_start(ap, col);
214
215 char *pszData = new char[COLUMN_WIDTH_MAX];
216 int cbData = RTStrPrintfV(pszData, COLUMN_WIDTH_MAX, pColDesc->pszFmt, ap);
217 COLDATA *pColData = pRow->colDataListhead.next;
218 while (pColData)
219 {
220 if (pColData->pColDesc == pColDesc)
221 {
222 pColData->pszData = pszData;
223 pColData->cbData = cbData;
224 break;
225 }
226 pColData = pColData->next;
227 }
228}
229
230void SELFSIZINGTABLE::displayTable()
231{
232 /* Determine max cell (and column header) length for each column */
233
234 COLDESC *pColDesc = colDescListhead.next;
235 while (pColDesc)
236 {
237 pColDesc->cbWidestDataInCol = pColDesc->hdrLen;
238 pColDesc = pColDesc->next;
239 }
240 ROW *pRow = rowListhead.next;
241 while(pRow)
242 {
243 COLDATA *pColData = pRow->colDataListhead.next;
244 while (pColData)
245 {
246 pColDesc = pColData->pColDesc;
247 if (pColData->cbData > pColDesc->cbWidestDataInCol)
248 pColDesc->cbWidestDataInCol = pColData->cbData;;
249 pColData = pColData->next;
250 }
251 pRow = pRow->next;
252 }
253
254 /* Display col headers based on actual column size w/alignment & padding */
255 pColDesc = colDescListhead.next;
256 while (pColDesc)
257 {
258 uint8_t colWidth = pColDesc->cbWidestDataInCol;
259 char colHdr[colWidth + 1], *pszColHdr = (char *)colHdr;
260 switch (pColDesc->alignment)
261 {
262 case RIGHT:
263 RTStrPrintf(pszColHdr, colWidth + 1, "%*s", colWidth, pColDesc->pszHdr);
264 break;
265 case LEFT:
266 RTStrPrintf(pszColHdr, colWidth + 1, "%-*s", colWidth, pColDesc->pszHdr);
267 break;
268 case CENTER:
269 int cbPad = (colWidth - pColDesc->hdrLen) / 2;
270 RTStrPrintf(pszColHdr, colWidth + 1, "%*s%s%*s", cbPad, "", pColDesc->pszHdr, cbPad, "");
271 }
272 RTPrintf(ANSI_BOLD ANSI_RED);
273 uint8_t cbPad = pColDesc->cbPadRightOpt ? pColDesc->cbPadRightOpt : cbDefaultColPadding;
274 RTPrintf("%s%*s", pszColHdr, cbPad, " ");
275 RTPrintf(ANSI_RESET);
276 pColDesc = pColDesc->next;
277 }
278 RTPrintf("\n");
279 /*
280 * Display each of the column data items for the row
281 */
282 pRow = rowListhead.next;
283 while(pRow)
284 {
285 COLDATA *pColData = pRow->colDataListhead.next;
286 while (pColData)
287 { pColDesc = pColData->pColDesc;
288 uint8_t colWidth = pColDesc->cbWidestDataInCol;
289 char aCell[colWidth + 1];
290 switch (pColDesc->alignment)
291 {
292 case RIGHT:
293 RTStrPrintf(aCell, colWidth + 1, "%*s", colWidth, pColData->pszData);
294 break;
295 case LEFT:
296 RTStrPrintf(aCell, colWidth + 1, "%-*s", colWidth, pColData->pszData);
297 break;
298 case CENTER:
299 int cbPad = (colWidth - pColData->cbData) / 2;
300 RTStrPrintf(aCell, colWidth + 1, "%*s%s%*s", cbPad, "", pColData->pszData, cbPad, "");
301 }
302 uint8_t cbPad = pColDesc->cbPadRightOpt ? pColDesc->cbPadRightOpt : this->cbDefaultColPadding;
303 RTPrintf("%s%*s", aCell, cbPad, " ");
304 pColData = pColData->next;
305 }
306 RTPrintf("\n");
307 pRow = pRow->next;
308 }
309}
310#endif
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