VirtualBox

source: vbox/trunk/src/VBox/Runtime/strformatrt.cpp@ 911

Last change on this file since 911 was 129, checked in by vboxsync, 18 years ago

Generic Uuid. Corrected Gen.u16TimeMin to Gen.u16TimeMid.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.1 KB
Line 
1/* $Id: strformatrt.cpp 129 2007-01-18 00:07:02Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - IPRT String Formatter Extensions.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22/** @page pg_rt_str_format_rt The IPRT String Format Extensions
23 *
24 * The string formatter supports most of the non-float format types and flags.
25 * See RTStrFormatV() for the full tail there. In addition we've added a number
26 * of iprt specific format types for the iprt typedefs and other useful stuff.
27 * Note that several of these are similar to \%p and doesn't care much if you try
28 * add formating flags/width/precision.
29 *
30 *
31 * Group 1, the basic runtime typedefs (excluding those which obviously are pointer).
32 * - \%RTbool - Takes a bool value and prints 'true', 'false', or '!%d!'.
33 * - \%RTfile - Takes a #RTFILE value.
34 * - \%RTfmode - Takes a #RTFMODE value.
35 * - \%RTfoff - Takes a #RTFOFF value.
36 * - \%RTfp16 - Takes a #RTFAR16 value.
37 * - \%RTfp32 - Takes a #RTFAR32 value.
38 * - \%RTfp64 - Takes a #RTFAR64 value.
39 * - \%RTgid - Takes a #RTGID value.
40 * - \%RTino - Takes a #RTINODE value.
41 * - \%RTint - Takes a #RTINT value.
42 * - \%RTiop - Takes a #RTIOPORT value.
43 * - \%RTldrm - Takes a #RTLDRMOD value.
44 * - \%RTnthrd - Takes a #RTNATIVETHREAD value.
45 * - \%RTproc - Takes a #RTPROCESS value.
46 * - \%RTptr - Takes a #RTINTPTR or #RTUINTPTR value (but not void *).
47 * - \%RTreg - Takes a #RTUINTREG value.
48 * - \%RTsel - Takes a #RTSEL value.
49 * - \%RTsem - Takes a #RTSEMEVENT, #RTSEMEVENTMULTI, #RTSEMMUTEX, #RTSEMFASTMUTEX, or #RTSEMRW value.
50 * - \%RTsock - Takes a #RTSOCKET value.
51 * - \%RTthrd - Takes a #RTTHREAD value.
52 * - \%RTuid - Takes a #RTUID value.
53 * - \%RTuint - Takes a #RTUINT value.
54 * - \%RTunicp - Takes a #RTUNICP value.
55 * - \%RTutf16 - Takes a #RTUTF16 value.
56 * - \%RTuuid - Takes a #PCRTUUID and will print the UUID as a string.
57 * - \%RTxuint - Takes a #RTUINT or #RTINT value, formatting it as hex.
58 * - \%RGi - Takes a #RTGCINT value.
59 * - \%RGp - Takes a #RTGCPHYS value.
60 * - \%RGr - Takes a #RTGCUINTREG value.
61 * - \%RGu - Takes a #RTGCUINT value.
62 * - \%RGv - Takes a #RTGCPTR, #RTGCINTPTR or #RTGCUINTPTR value.
63 * - \%RGx - Takes a #RTGCUINT or #RTGCINT value, formatting it as hex.
64 * - \%RHi - Takes a #RTHCINT value.
65 * - \%RHp - Takes a #RTHCPHYS value.
66 * - \%RHr - Takes a #RTHCUINTREG value.
67 * - \%RHu - Takes a #RTHCUINT value.
68 * - \%RHv - Takes a #RTHCPTR, #RTHCINTPTR or #RTHCUINTPTR value.
69 * - \%RHx - Takes a #RTHCUINT or #RTHCINT value, formatting it as hex.
70 *
71 *
72 * Group 2, the generic integer types which are prefered over relying on what
73 * bit-count a 'long', 'short', or 'long long' has on a platform. This are
74 * highly prefered for the [u]intXX_t kind of types.
75 * - \%RI[8|16|32|64] - Signed integer value of the specifed bit count.
76 * - \%RU[8|16|32|64] - Unsigned integer value of the specifed bit count.
77 * - \%RX[8|16|32|64] - Hexadecimal integer value of the specifed bit count.
78 *
79 *
80 * Group 3, hex dumpers and other complex stuff which requires more than simple formatting.
81 * - \%Rhxd - Takes a pointer to the memory which is to be dumped in typical
82 * hex format. Use the width to specify the length, and the precision to
83 * set the number of bytes per line. Default width and precision is 16.
84 * - \%Rhxs - Takes a pointer to the memory to be displayed as a hex string,
85 * i.e. a series of space separated bytes formatted as two digit hex value.
86 * Use the width to specify the length. Default length is 16 bytes.
87 * - \%Rrc - Takes an integer iprt status code as argument. Will insert the
88 * status code define corresponding to the iprt status code.
89 * - \%Rrs - Takes an integer iprt status code as argument. Will insert the
90 * short description of the specified status code.
91 * - \%Rrf - Takes an integer iprt status code as argument. Will insert the
92 * full description of the specified status code.
93 * - \%Rra - Takes an integer iprt status code as argument. Will insert the
94 * status code define + full description.
95 * - \%Rt - Current thread (RTThreadSelf()), no arguments.
96 *
97 * - \%Rwc - Takes a long Windows error code as argument. Will insert the status
98 * code define corresponding to the Windows error code.
99 * - \%Rwf - Takes a long Windows error code as argument. Will insert the
100 * full description of the specified status code.
101 * - \%Rwa - Takes a long Windows error code as argument. Will insert the
102 * error code define + full description.
103 *
104 * On other platforms, \%Rw? simply prints the argument in a form of 0xXXXXXXXX.
105 *
106 * @todo (r=dmik) Add a cross-platform \%Rcomr? that will fall back to \%Rw? on
107 * Win32 platforms and will interpret XPCOM result codes on all other.
108 *
109 *
110 * Group 4, structure dumpers.
111 *
112 * - \%RDtimespec - Takes a PCRTTIMESPEC.
113 *
114 *
115 */
116
117/*******************************************************************************
118* Header Files *
119*******************************************************************************/
120#define LOG_GROUP RTLOGGROUP_STRING
121#include <iprt/log.h>
122#include <iprt/string.h>
123#include <iprt/assert.h>
124#include <iprt/string.h>
125#include <iprt/stdarg.h>
126#ifdef IN_RING3
127# include <iprt/thread.h>
128# include <iprt/err.h>
129#endif
130#include <iprt/time.h>
131#include "internal/string.h"
132
133
134
135/**
136 * Callback to format iprt formatting extentions.
137 * See @ref pg_rt_str_format_rt for a reference on the format types.
138 *
139 * @returns The number of bytes formatted.
140 * @param pfnOutput Pointer to output function.
141 * @param pvArgOutput Argument for the output function.
142 * @param ppszFormat Pointer to the format string pointer. Advance this till the char
143 * after the format specifier.
144 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.
145 * @param cchWidth Format Width. -1 if not specified.
146 * @param cchPrecision Format Precision. -1 if not specified.
147 * @param fFlags Flags (RTSTR_NTFS_*).
148 * @param chArgSize The argument size specifier, 'l' or 'L'.
149 */
150size_t rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs, int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
151{
152 const char *pszFormatOrg = *ppszFormat;
153 char ch = *(*ppszFormat)++;
154 if (ch == 'R')
155 {
156 ch = *(*ppszFormat)++;
157 switch (ch)
158 {
159 /*
160 * Groups 1 and 2.
161 */
162 case 'T':
163 case 'G':
164 case 'H':
165 case 'I':
166 case 'X':
167 case 'U':
168 {
169 /*
170 * Interpret the type.
171 */
172 typedef enum { RTSF_INT, RTSF_INTW, RTSF_FP16, RTSF_FP32, RTSF_FP64, RTSF_UUID, RTSF_BOOL } RTSF;
173 static const struct
174 {
175 uint8_t cch; /**< the length of the string. */
176 char sz[10]; /**< the part following 'R'. */
177 uint8_t cb; /**< the size of the type. */
178 uint8_t u8Base; /**< the size of the type. */
179 RTSF enmFormat; /**< The way to format it. */
180 uint16_t fFlags; /**< additional RTSTR_F_* flags. */
181 }
182 /** Sorted array of types, looked up using binary search! */
183 s_aTypes[] =
184 {
185#define STRMEM(str) sizeof(str) - 1, str
186 { STRMEM("Gi"), sizeof(RTGCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
187 { STRMEM("Gp"), sizeof(RTGCPHYS), 16, RTSF_INTW, 0 },
188 { STRMEM("Gr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
189 { STRMEM("Gu"), sizeof(RTGCUINT), 10, RTSF_INT, 0 },
190 { STRMEM("Gv"), sizeof(RTGCPTR), 16, RTSF_INTW, 0 },
191 { STRMEM("Gx"), sizeof(RTGCUINT), 16, RTSF_INT, 0 },
192 { STRMEM("Hi"), sizeof(RTHCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
193 { STRMEM("Hp"), sizeof(RTHCPHYS), 16, RTSF_INTW, 0 },
194 { STRMEM("Hr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
195 { STRMEM("Hu"), sizeof(RTHCUINT), 10, RTSF_INT, 0 },
196 { STRMEM("Hv"), sizeof(RTHCPTR), 16, RTSF_INTW, 0 },
197 { STRMEM("Hx"), sizeof(RTHCUINT), 16, RTSF_INT, 0 },
198 { STRMEM("I16"), sizeof(int16_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
199 { STRMEM("I32"), sizeof(int32_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
200 { STRMEM("I64"), sizeof(int64_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
201 { STRMEM("I8"), sizeof(int8_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
202 { STRMEM("Tbool"), sizeof(bool), 10, RTSF_BOOL, 0 },
203 { STRMEM("Tfile"), sizeof(RTFILE), 10, RTSF_INT, 0 },
204 { STRMEM("Tfmode"), sizeof(RTFMODE), 16, RTSF_INTW, 0 },
205 { STRMEM("Tfoff"), sizeof(RTFOFF), 10, RTSF_INT, RTSTR_F_VALSIGNED },
206 { STRMEM("Tfp16"), sizeof(RTFAR16), 16, RTSF_FP16, RTSTR_F_ZEROPAD },
207 { STRMEM("Tfp32"), sizeof(RTFAR32), 16, RTSF_FP32, RTSTR_F_ZEROPAD },
208 { STRMEM("Tfp64"), sizeof(RTFAR64), 16, RTSF_FP64, RTSTR_F_ZEROPAD },
209 { STRMEM("Tgid"), sizeof(RTGID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
210 { STRMEM("Tino"), sizeof(RTINODE), 16, RTSF_INTW, 0 },
211 { STRMEM("Tint"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
212 { STRMEM("Tiop"), sizeof(RTIOPORT), 16, RTSF_INTW, 0 },
213 { STRMEM("Tldrm"), sizeof(RTLDRMOD), 16, RTSF_INTW, 0 },
214 { STRMEM("Tnthrd"), sizeof(RTNATIVETHREAD), 16, RTSF_INTW, 0 },
215 { STRMEM("Tproc"), sizeof(RTPROCESS), 16, RTSF_INTW, 0 },
216 { STRMEM("Tptr"), sizeof(RTUINTPTR), 16, RTSF_INTW, 0 },
217 { STRMEM("Treg"), sizeof(RTUINTREG), 16, RTSF_INTW, 0 },
218 { STRMEM("Tsel"), sizeof(RTSEL), 16, RTSF_INTW, 0 },
219 { STRMEM("Tsem"), sizeof(RTSEMEVENT), 16, RTSF_INTW, 0 },
220 { STRMEM("Tsock"), sizeof(RTSOCKET), 10, RTSF_INT, 0 },
221 { STRMEM("Tthrd"), sizeof(RTTHREAD), 16, RTSF_INTW, 0 },
222 { STRMEM("Tuid"), sizeof(RTUID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
223 { STRMEM("Tuint"), sizeof(RTUINT), 10, RTSF_INT, 0 },
224 { STRMEM("Tunicp"), sizeof(RTUNICP), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
225 { STRMEM("Tutf16"), sizeof(RTUTF16), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
226 { STRMEM("Tuuid"), sizeof(PCRTUUID), 16, RTSF_UUID, 0 },
227 { STRMEM("Txint"), sizeof(RTUINT), 16, RTSF_INT, 0 },
228 { STRMEM("U16"), sizeof(uint16_t), 10, RTSF_INT, 0 },
229 { STRMEM("U32"), sizeof(uint32_t), 10, RTSF_INT, 0 },
230 { STRMEM("U64"), sizeof(uint64_t), 10, RTSF_INT, 0 },
231 { STRMEM("U8"), sizeof(uint8_t), 10, RTSF_INT, 0 },
232 { STRMEM("X16"), sizeof(uint16_t), 16, RTSF_INT, 0 },
233 { STRMEM("X32"), sizeof(uint32_t), 16, RTSF_INT, 0 },
234 { STRMEM("X64"), sizeof(uint64_t), 16, RTSF_INT, 0 },
235 { STRMEM("X8"), sizeof(uint8_t), 16, RTSF_INT, 0 },
236#undef STRMEM
237 };
238 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
239
240 /*
241 * Lookup the type - binary search.
242 */
243 const char *pszType = *ppszFormat - 1;
244 int iStart = 0;
245 int iEnd = ELEMENTS(s_aTypes) - 1;
246 int i = ELEMENTS(s_aTypes) / 2;
247 for (;;)
248 {
249 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
250 if (!iDiff)
251 break;
252 if (iEnd == iStart)
253 {
254 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
255 return 0;
256 }
257 if (iDiff < 0)
258 iEnd = i - 1;
259 else
260 iStart = i + 1;
261 if (iEnd < iStart)
262 {
263 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
264 return 0;
265 }
266 i = iStart + (iEnd - iStart) / 2;
267 }
268
269 /*
270 * Advance the format string and merge flags.
271 */
272 *ppszFormat += s_aTypes[i].cch - 1;
273 fFlags |= s_aTypes[i].fFlags;
274
275 /*
276 * Fetch the argument.
277 * It's important that a signed value gets sign-extended up to 64-bit.
278 */
279 union
280 {
281 uint8_t u8;
282 uint16_t u16;
283 uint32_t u32;
284 uint64_t u64;
285 int8_t i8;
286 int16_t i16;
287 int32_t i32;
288 int64_t i64;
289 RTFAR16 fp16;
290 RTFAR32 fp32;
291 RTFAR64 fp64;
292 bool fBool;
293 PCRTUUID pUuid;
294 } u;
295 u.u64 = 0;
296 if (fFlags & RTSTR_F_VALSIGNED)
297 {
298 switch (s_aTypes[i].cb)
299 {
300 case sizeof(int8_t):
301 u.i64 = va_arg(*pArgs, /*int8_t*/int);
302 fFlags |= RTSTR_F_8BIT;
303 break;
304 case sizeof(int16_t):
305 u.i64 = va_arg(*pArgs, /*int16_t*/int);
306 fFlags |= RTSTR_F_16BIT;
307 break;
308 case sizeof(int32_t):
309 u.i64 = va_arg(*pArgs, int32_t);
310 fFlags |= RTSTR_F_32BIT;
311 break;
312 case sizeof(int64_t):
313 u.i64 = va_arg(*pArgs, int64_t);
314 fFlags |= RTSTR_F_64BIT;
315 break;
316 default:
317 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
318 break;
319 }
320 }
321 else
322 {
323 switch (s_aTypes[i].cb)
324 {
325 case sizeof(uint8_t):
326 u.u8 = va_arg(*pArgs, /*uint8_t*/unsigned);
327 fFlags |= RTSTR_F_8BIT;
328 break;
329 case sizeof(uint16_t):
330 u.u16 = va_arg(*pArgs, /*uint16_t*/unsigned);
331 fFlags |= RTSTR_F_16BIT;
332 break;
333 case sizeof(uint32_t):
334 u.u32 = va_arg(*pArgs, uint32_t);
335 fFlags |= RTSTR_F_32BIT;
336 break;
337 case sizeof(uint64_t):
338 u.u64 = va_arg(*pArgs, uint64_t);
339 fFlags |= RTSTR_F_64BIT;
340 break;
341 case sizeof(RTFAR32):
342 u.fp32 = va_arg(*pArgs, RTFAR32);
343 break;
344 case sizeof(RTFAR64):
345 u.fp64 = va_arg(*pArgs, RTFAR64);
346 break;
347 default:
348 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
349 break;
350 }
351 }
352
353 /*
354 * Format the output.
355 */
356 char szBuf[80];
357 unsigned cch;
358 switch (s_aTypes[i].enmFormat)
359 {
360 case RTSF_INT:
361 {
362 cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
363 break;
364 }
365
366 /* hex which defaults to max width. */
367 case RTSF_INTW:
368 {
369 Assert(s_aTypes[i].u8Base == 16);
370 if (cchWidth < 0)
371 {
372 cchWidth = s_aTypes[i].cb * 2 + (fFlags & RTSTR_F_SPECIAL ? 2 : 0);
373 fFlags |= RTSTR_F_ZEROPAD;
374 }
375 cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
376 break;
377 }
378
379 case RTSF_FP16:
380 {
381 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION);
382 cch = RTStrFormatNumber(&szBuf[0], u.fp16.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
383 Assert(cch == 4);
384 szBuf[4] = ':';
385 cch = RTStrFormatNumber(&szBuf[5], u.fp16.off, 16, 4, -1, fFlags | RTSTR_F_16BIT);
386 Assert(cch == 4);
387 cch = 4 + 1 + 4;
388 break;
389 }
390 case RTSF_FP32:
391 {
392 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION);
393 cch = RTStrFormatNumber(&szBuf[0], u.fp32.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
394 Assert(cch == 4);
395 szBuf[4] = ':';
396 cch = RTStrFormatNumber(&szBuf[5], u.fp32.off, 16, 8, -1, fFlags | RTSTR_F_32BIT);
397 Assert(cch == 8);
398 cch = 4 + 1 + 8;
399 break;
400 }
401 case RTSF_FP64:
402 {
403 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION);
404 cch = RTStrFormatNumber(&szBuf[0], u.fp64.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
405 Assert(cch == 4);
406 szBuf[4] = ':';
407 cch = RTStrFormatNumber(&szBuf[5], u.fp64.off, 16, 16, -1, fFlags | RTSTR_F_64BIT);
408 Assert(cch == 16);
409 cch = 4 + 1 + 16;
410 break;
411 }
412
413 case RTSF_UUID:
414 {
415 if (VALID_PTR(u.pUuid))
416 {
417 /* cannot call RTUuidToStr because of GC/R0. */
418 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
419 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
420 u.pUuid->Gen.u32TimeLow,
421 u.pUuid->Gen.u16TimeMid,
422 u.pUuid->Gen.u16TimeHiAndVersion,
423 u.pUuid->Gen.u16ClockSeq & 0xff,
424 u.pUuid->Gen.u16ClockSeq >> 8,
425 u.pUuid->Gen.au8Node[0],
426 u.pUuid->Gen.au8Node[1],
427 u.pUuid->Gen.au8Node[2],
428 u.pUuid->Gen.au8Node[3],
429 u.pUuid->Gen.au8Node[4],
430 u.pUuid->Gen.au8Node[5]);
431 }
432
433 static const char szNull[] = "<NULL>";
434 return pfnOutput(pvArgOutput, szNull, sizeof(szNull) - 1);
435 }
436
437 case RTSF_BOOL:
438 {
439 static const char szTrue[] = "true ";
440 static const char szFalse[] = "false";
441 if (u.u64 == 1)
442 return pfnOutput(pvArgOutput, szTrue, sizeof(szTrue) - 1);
443 if (u.u64 == 0)
444 return pfnOutput(pvArgOutput, szFalse, sizeof(szFalse) - 1);
445 /* invalid boolean value */
446 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "!%lld!", u.u64);
447 }
448
449 default:
450 AssertMsgFailed(("Internal error %d\n", s_aTypes[i].enmFormat));
451 return 0;
452 }
453
454 /*
455 * Finally, output the formatted string and return.
456 */
457 return pfnOutput(pvArgOutput, szBuf, cch);
458 }
459
460
461 /* Group 3 */
462
463 /*
464 * hex dumping.
465 */
466 case 'h':
467 {
468 char ch = *(*ppszFormat)++;
469 switch (ch)
470 {
471 /*
472 * Hex stuff.
473 */
474 case 'x':
475 {
476 uint8_t *pu8 = va_arg(*pArgs, uint8_t *);
477 if (cchWidth <= 0)
478 cchWidth = 16;
479 if (pu8)
480 {
481 ch = *(*ppszFormat)++;
482 switch (ch)
483 {
484 /*
485 * Regular hex dump.
486 */
487 case 'd':
488 {
489 if (cchPrecision <= 0)
490 cchPrecision = 16;
491
492 size_t cch = 0;
493 int off = 0;
494 while (off < cchWidth)
495 {
496 int i;
497 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*x %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
498 for (i = 0; i < cchPrecision && off + i < cchWidth ; i++)
499 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
500 off + i < cchWidth ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pu8[i]);
501 while (i++ < cchPrecision)
502 cch += pfnOutput(pvArgOutput, " ", 3);
503
504 cch += pfnOutput(pvArgOutput, " ", 1);
505
506 for (int i = 0; i < cchPrecision && off + i < cchWidth; i++)
507 {
508 uint8_t u8 = pu8[i];
509 cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
510 }
511
512 /* next */
513 pu8 += cchPrecision;
514 off += cchPrecision;
515 }
516 return cch;
517 }
518
519 /*
520 * Hex string.
521 */
522 case 's':
523 {
524 if (cchWidth-- > 0)
525 {
526 size_t cch = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%02x", *pu8++);
527 for (; cchWidth > 0; cchWidth--, pu8++)
528 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " %02x", *pu8);
529 return cch;
530 }
531 break;
532 }
533
534 default:
535 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", ch, pszFormatOrg));
536 break;
537 }
538 }
539 else
540 return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
541 break;
542 }
543
544 default:
545 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", ch, pszFormatOrg));
546 return 0;
547
548 }
549 break;
550 }
551
552 /*
553 * iprt status code: %Vrc, %Vrs, %Vrf, %Vra.
554 */
555 case 'r':
556 {
557 int rc = va_arg(*pArgs, int);
558 char ch = *(*ppszFormat)++;
559#ifdef IN_RING3 /* we don't want this anywhere else yet. */
560 PCRTSTATUSMSG pMsg = RTErrGet(rc);
561 switch (ch)
562 {
563 case 'c':
564 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
565 case 's':
566 return pfnOutput(pvArgOutput, pMsg->pszMsgShort, strlen(pMsg->pszMsgShort));
567 case 'f':
568 return pfnOutput(pvArgOutput, pMsg->pszMsgFull, strlen(pMsg->pszMsgFull));
569 case 'a':
570 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (%d) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
571 default:
572 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
573 return 0;
574 }
575#else /* !IN_RING3 */
576 switch (ch)
577 {
578 case 'c':
579 case 's':
580 case 'f':
581 case 'a':
582 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%d", rc);
583 default:
584 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
585 return 0;
586 }
587#endif /* !IN_RING3 */
588 break;
589 }
590
591#if defined(IN_RING3)
592 /*
593 * Windows status code: %Rwc, %Rwf, %Rwa
594 */
595 case 'w':
596 {
597 long rc = va_arg(*pArgs, long);
598 char ch = *(*ppszFormat)++;
599#if defined(__WIN__)
600 PCRTWINERRMSG pMsg = RTErrWinGet(rc);
601#endif
602 switch (ch)
603 {
604#if defined(__WIN__)
605 case 'c':
606 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
607 case 'f':
608 return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
609 case 'a':
610 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
611#else
612 case 'c':
613 case 'f':
614 case 'a':
615 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "0x%08X", rc);
616#endif
617 default:
618 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
619 return 0;
620 }
621 break;
622 }
623#endif /* IN_RING3 */
624
625 /*
626 * Group 4, structure dumpers.
627 */
628 case 'D':
629 {
630 /*
631 * Interpret the type.
632 */
633 typedef enum
634 {
635 RTST_TIMESPEC
636 } RTST;
637/** Set if it's a pointer */
638#define RTST_FLAGS_POINTER BIT(0)
639 static const struct
640 {
641 uint8_t cch; /**< the length of the string. */
642 char sz[16-2]; /**< the part following 'R'. */
643 uint8_t cb; /**< the size of the argument. */
644 uint8_t fFlags; /**< RTST_FLAGS_* */
645 RTST enmType; /**< The structure type. */
646 }
647 /** Sorted array of types, looked up using binary search! */
648 s_aTypes[] =
649 {
650#define STRMEM(str) sizeof(str) - 1, str
651 { STRMEM("timespec"), sizeof(PCRTTIMESPEC), RTST_FLAGS_POINTER, RTST_TIMESPEC},
652#undef STRMEM
653 };
654
655 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
656
657 /*
658 * Lookup the type - binary search.
659 */
660 const char *pszType = *ppszFormat - 1;
661 int iStart = 0;
662 int iEnd = ELEMENTS(s_aTypes) - 1;
663 int i = ELEMENTS(s_aTypes) / 2;
664 for (;;)
665 {
666 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
667 if (!iDiff)
668 break;
669 if (iEnd == iStart)
670 {
671 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
672 return 0;
673 }
674 if (iDiff < 0)
675 iEnd = i - 1;
676 else
677 iStart = i + 1;
678 if (iEnd < iStart)
679 {
680 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
681 return 0;
682 }
683 i = iStart + (iEnd - iStart) / 2;
684 }
685 *ppszFormat += s_aTypes[i].cch - 1;
686
687 /*
688 * Fetch the argument.
689 */
690 union
691 {
692 const void *pv;
693 uint64_t u64;
694 PCRTTIMESPEC pTimeSpec;
695 } u;
696 u.u64 = 0;
697 switch (s_aTypes[i].cb)
698 {
699 case sizeof(const void *):
700 u.pv = va_arg(*pArgs, const void *);
701 break;
702 default:
703 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
704 break;
705 }
706
707 /*
708 * If it's a pointer, we'll check if it's valid before going on.
709 */
710 if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !VALID_PTR(u.pv))
711 return pfnOutput(pvArgOutput, "<null>", sizeof("<null>") - 1);
712
713 /*
714 * Format the output.
715 */
716 switch (s_aTypes[i].enmType)
717 {
718 case RTST_TIMESPEC:
719 return RTStrFormat(pfnOutput, pvArgOutput, NULL, NULL, "%llu ns", RTTimeSpecGetNano(u.pTimeSpec));
720
721 default:
722 AssertMsgFailed(("Invalid/unhandled enmType=%d\n", s_aTypes[i].enmType));
723 break;
724 }
725 break;
726 }
727
728 /*
729 * Invalid/Unknown. Bitch about it.
730 */
731 default:
732 AssertMsgFailed(("Invalid VBox format type '%.10s'!\n", pszFormatOrg));
733 break;
734 }
735 }
736 else
737 AssertMsgFailed(("Invalid VBox format type '%.10s'!\n", pszFormatOrg));
738
739 NOREF(pszFormatOrg);
740 return 0;
741}
742
743
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