VirtualBox

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

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

gcc-4.5 warning

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