VirtualBox

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

Last change on this file since 11836 was 11413, checked in by vboxsync, 16 years ago

Runtime: small fix to the UUID code, splitting the ClockSeq field and put the UUID variant in the right place. Rest is cleanup and documenting that the IPRT UUIDs are little endian.

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