VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strformatrt.cpp@ 8402

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

Added %Rhrc, %Rhrf and %Rhra for formatting COM/XPCOM status codes. Added RTErrCOMGet() for looking up these status codes. Note that we're not yet generating the XPCOM database, only the win32/64 one.

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

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