VirtualBox

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

Last change on this file since 23507 was 21337, checked in by vboxsync, 15 years ago

IPRT,HostDrv,AddDrv: Export public IPRT symbols for the linux kernel (pain).

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