VirtualBox

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

Last change on this file since 4672 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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