VirtualBox

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

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

iprt: New type RTNETADDR for storing any address + type + port. Added %RTnaddr for printing it.

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