VirtualBox

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

Last change on this file since 72778 was 69834, checked in by vboxsync, 7 years ago

typo

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 66.8 KB
Line 
1/* $Id: strformatrt.cpp 69834 2017-11-26 04:40:40Z vboxsync $ */
2/** @file
3 * IPRT - IPRT String Formatter Extensions.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
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
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_STRING
32#include <iprt/string.h>
33#ifndef RT_NO_EXPORT_SYMBOL
34# define RT_NO_EXPORT_SYMBOL /* don't slurp <linux/module.h> which then again
35 slurps arch-specific headers defining symbols */
36#endif
37#include "internal/iprt.h"
38
39#include <iprt/log.h>
40#include <iprt/assert.h>
41#include <iprt/string.h>
42#include <iprt/stdarg.h>
43#ifdef IN_RING3
44# include <iprt/thread.h>
45# include <iprt/err.h>
46#endif
47#include <iprt/ctype.h>
48#include <iprt/time.h>
49#include <iprt/net.h>
50#include <iprt/path.h>
51#include <iprt/asm.h>
52#define STRFORMAT_WITH_X86
53#ifdef STRFORMAT_WITH_X86
54# include <iprt/x86.h>
55#endif
56#include "internal/string.h"
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62static char g_szHexDigits[17] = "0123456789abcdef";
63
64
65/**
66 * Helper that formats a 16-bit hex word in a IPv6 address.
67 *
68 * @returns Length in chars.
69 * @param pszDst The output buffer. Written from the start.
70 * @param uWord The word to format as hex.
71 */
72static size_t rtstrFormatIPv6HexWord(char *pszDst, uint16_t uWord)
73{
74 size_t off;
75 uint16_t cDigits;
76
77 if (uWord & UINT16_C(0xff00))
78 cDigits = uWord & UINT16_C(0xf000) ? 4 : 3;
79 else
80 cDigits = uWord & UINT16_C(0x00f0) ? 2 : 1;
81
82 off = 0;
83 switch (cDigits)
84 {
85 case 4: pszDst[off++] = g_szHexDigits[(uWord >> 12) & 0xf]; RT_FALL_THRU();
86 case 3: pszDst[off++] = g_szHexDigits[(uWord >> 8) & 0xf]; RT_FALL_THRU();
87 case 2: pszDst[off++] = g_szHexDigits[(uWord >> 4) & 0xf]; RT_FALL_THRU();
88 case 1: pszDst[off++] = g_szHexDigits[(uWord >> 0) & 0xf];
89 break;
90 }
91 pszDst[off] = '\0';
92 return off;
93}
94
95
96/**
97 * Helper function to format IPv6 address according to RFC 5952.
98 *
99 * @returns The number of bytes formatted.
100 * @param pfnOutput Pointer to output function.
101 * @param pvArgOutput Argument for the output function.
102 * @param pIpv6Addr IPv6 address
103 */
104static size_t rtstrFormatIPv6(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PCRTNETADDRIPV6 pIpv6Addr)
105{
106 size_t cch; /* result */
107 bool fEmbeddedIpv4;
108 size_t cwHexPart;
109 size_t cwLongestZeroRun;
110 size_t iLongestZeroStart;
111 size_t idx;
112 char szHexWord[8];
113
114 Assert(pIpv6Addr != NULL);
115
116 /*
117 * Check for embedded IPv4 address.
118 *
119 * IPv4-compatible - ::11.22.33.44 (obsolete)
120 * IPv4-mapped - ::ffff:11.22.33.44
121 * IPv4-translated - ::ffff:0:11.22.33.44 (RFC 2765)
122 */
123 fEmbeddedIpv4 = false;
124 cwHexPart = RT_ELEMENTS(pIpv6Addr->au16);
125 if ( pIpv6Addr->au64[0] == 0
126 && ( ( pIpv6Addr->au32[2] == 0
127 && pIpv6Addr->au32[3] != 0
128 && pIpv6Addr->au32[3] != RT_H2BE_U32_C(1) )
129 || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0x0000ffff)
130 || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0xffff0000) ) )
131 {
132 fEmbeddedIpv4 = true;
133 cwHexPart -= 2;
134 }
135
136 /*
137 * Find the longest sequences of two or more zero words.
138 */
139 cwLongestZeroRun = 0;
140 iLongestZeroStart = 0;
141 for (idx = 0; idx < cwHexPart; idx++)
142 if (pIpv6Addr->au16[idx] == 0)
143 {
144 size_t iZeroStart = idx;
145 size_t cwZeroRun;
146 do
147 idx++;
148 while (idx < cwHexPart && pIpv6Addr->au16[idx] == 0);
149 cwZeroRun = idx - iZeroStart;
150 if (cwZeroRun > 1 && cwZeroRun > cwLongestZeroRun)
151 {
152 cwLongestZeroRun = cwZeroRun;
153 iLongestZeroStart = iZeroStart;
154 if (cwZeroRun >= cwHexPart - idx)
155 break;
156 }
157 }
158
159 /*
160 * Do the formatting.
161 */
162 cch = 0;
163 if (cwLongestZeroRun == 0)
164 {
165 for (idx = 0; idx < cwHexPart; ++idx)
166 {
167 if (idx > 0)
168 cch += pfnOutput(pvArgOutput, ":", 1);
169 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
170 }
171
172 if (fEmbeddedIpv4)
173 cch += pfnOutput(pvArgOutput, ":", 1);
174 }
175 else
176 {
177 const size_t iLongestZeroEnd = iLongestZeroStart + cwLongestZeroRun;
178
179 if (iLongestZeroStart == 0)
180 cch += pfnOutput(pvArgOutput, ":", 1);
181 else
182 for (idx = 0; idx < iLongestZeroStart; ++idx)
183 {
184 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
185 cch += pfnOutput(pvArgOutput, ":", 1);
186 }
187
188 if (iLongestZeroEnd == cwHexPart)
189 cch += pfnOutput(pvArgOutput, ":", 1);
190 else
191 {
192 for (idx = iLongestZeroEnd; idx < cwHexPart; ++idx)
193 {
194 cch += pfnOutput(pvArgOutput, ":", 1);
195 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
196 }
197
198 if (fEmbeddedIpv4)
199 cch += pfnOutput(pvArgOutput, ":", 1);
200 }
201 }
202
203 if (fEmbeddedIpv4)
204 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
205 "%u.%u.%u.%u",
206 pIpv6Addr->au8[12],
207 pIpv6Addr->au8[13],
208 pIpv6Addr->au8[14],
209 pIpv6Addr->au8[15]);
210
211 return cch;
212}
213
214
215/**
216 * Callback to format iprt formatting extentions.
217 * See @ref pg_rt_str_format for a reference on the format types.
218 *
219 * @returns The number of bytes formatted.
220 * @param pfnOutput Pointer to output function.
221 * @param pvArgOutput Argument for the output function.
222 * @param ppszFormat Pointer to the format string pointer. Advance this till the char
223 * after the format specifier.
224 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.
225 * @param cchWidth Format Width. -1 if not specified.
226 * @param cchPrecision Format Precision. -1 if not specified.
227 * @param fFlags Flags (RTSTR_NTFS_*).
228 * @param chArgSize The argument size specifier, 'l' or 'L'.
229 */
230DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
231 int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
232{
233 const char *pszFormatOrg = *ppszFormat;
234 char ch = *(*ppszFormat)++;
235 size_t cch;
236 char szBuf[80];
237
238 if (ch == 'R')
239 {
240 ch = *(*ppszFormat)++;
241 switch (ch)
242 {
243 /*
244 * Groups 1 and 2.
245 */
246 case 'T':
247 case 'G':
248 case 'H':
249 case 'R':
250 case 'C':
251 case 'I':
252 case 'X':
253 case 'U':
254 case 'K':
255 {
256 /*
257 * Interpret the type.
258 */
259 typedef enum
260 {
261 RTSF_INT,
262 RTSF_INTW,
263 RTSF_BOOL,
264 RTSF_FP16,
265 RTSF_FP32,
266 RTSF_FP64,
267 RTSF_IPV4,
268 RTSF_IPV6,
269 RTSF_MAC,
270 RTSF_NETADDR,
271 RTSF_UUID
272 } RTSF;
273 static const struct
274 {
275 uint8_t cch; /**< the length of the string. */
276 char sz[10]; /**< the part following 'R'. */
277 uint8_t cb; /**< the size of the type. */
278 uint8_t u8Base; /**< the size of the type. */
279 RTSF enmFormat; /**< The way to format it. */
280 uint16_t fFlags; /**< additional RTSTR_F_* flags. */
281 }
282 /** Sorted array of types, looked up using binary search! */
283 s_aTypes[] =
284 {
285#define STRMEM(str) sizeof(str) - 1, str
286 { STRMEM("Ci"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
287 { STRMEM("Cp"), sizeof(RTCCPHYS), 16, RTSF_INTW, 0 },
288 { STRMEM("Cr"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
289 { STRMEM("Cu"), sizeof(RTUINT), 10, RTSF_INT, 0 },
290 { STRMEM("Cv"), sizeof(void *), 16, RTSF_INTW, 0 },
291 { STRMEM("Cx"), sizeof(RTUINT), 16, RTSF_INT, 0 },
292 { STRMEM("Gi"), sizeof(RTGCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
293 { STRMEM("Gp"), sizeof(RTGCPHYS), 16, RTSF_INTW, 0 },
294 { STRMEM("Gr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
295 { STRMEM("Gu"), sizeof(RTGCUINT), 10, RTSF_INT, 0 },
296 { STRMEM("Gv"), sizeof(RTGCPTR), 16, RTSF_INTW, 0 },
297 { STRMEM("Gx"), sizeof(RTGCUINT), 16, RTSF_INT, 0 },
298 { STRMEM("Hi"), sizeof(RTHCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
299 { STRMEM("Hp"), sizeof(RTHCPHYS), 16, RTSF_INTW, 0 },
300 { STRMEM("Hr"), sizeof(RTHCUINTREG), 16, RTSF_INTW, 0 },
301 { STRMEM("Hu"), sizeof(RTHCUINT), 10, RTSF_INT, 0 },
302 { STRMEM("Hv"), sizeof(RTHCPTR), 16, RTSF_INTW, 0 },
303 { STRMEM("Hx"), sizeof(RTHCUINT), 16, RTSF_INT, 0 },
304 { STRMEM("I16"), sizeof(int16_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
305 { STRMEM("I32"), sizeof(int32_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
306 { STRMEM("I64"), sizeof(int64_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
307 { STRMEM("I8"), sizeof(int8_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
308 { STRMEM("Kv"), sizeof(RTHCPTR), 16, RTSF_INT, RTSTR_F_OBFUSCATE_PTR },
309 { STRMEM("Rv"), sizeof(RTRCPTR), 16, RTSF_INTW, 0 },
310 { STRMEM("Tbool"), sizeof(bool), 10, RTSF_BOOL, 0 },
311 { STRMEM("Tfile"), sizeof(RTFILE), 10, RTSF_INT, 0 },
312 { STRMEM("Tfmode"), sizeof(RTFMODE), 16, RTSF_INTW, 0 },
313 { STRMEM("Tfoff"), sizeof(RTFOFF), 10, RTSF_INT, RTSTR_F_VALSIGNED },
314 { STRMEM("Tfp16"), sizeof(RTFAR16), 16, RTSF_FP16, RTSTR_F_ZEROPAD },
315 { STRMEM("Tfp32"), sizeof(RTFAR32), 16, RTSF_FP32, RTSTR_F_ZEROPAD },
316 { STRMEM("Tfp64"), sizeof(RTFAR64), 16, RTSF_FP64, RTSTR_F_ZEROPAD },
317 { STRMEM("Tgid"), sizeof(RTGID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
318 { STRMEM("Tino"), sizeof(RTINODE), 16, RTSF_INTW, 0 },
319 { STRMEM("Tint"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
320 { STRMEM("Tiop"), sizeof(RTIOPORT), 16, RTSF_INTW, 0 },
321 { STRMEM("Tldrm"), sizeof(RTLDRMOD), 16, RTSF_INTW, 0 },
322 { STRMEM("Tmac"), sizeof(PCRTMAC), 16, RTSF_MAC, 0 },
323 { STRMEM("Tnaddr"), sizeof(PCRTNETADDR), 10, RTSF_NETADDR,0 },
324 { STRMEM("Tnaipv4"), sizeof(RTNETADDRIPV4), 10, RTSF_IPV4, 0 },
325 { STRMEM("Tnaipv6"), sizeof(PCRTNETADDRIPV6),16, RTSF_IPV6, 0 },
326 { STRMEM("Tnthrd"), sizeof(RTNATIVETHREAD), 16, RTSF_INTW, 0 },
327 { STRMEM("Tproc"), sizeof(RTPROCESS), 16, RTSF_INTW, 0 },
328 { STRMEM("Tptr"), sizeof(RTUINTPTR), 16, RTSF_INTW, 0 },
329 { STRMEM("Treg"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
330 { STRMEM("Tsel"), sizeof(RTSEL), 16, RTSF_INTW, 0 },
331 { STRMEM("Tsem"), sizeof(RTSEMEVENT), 16, RTSF_INTW, 0 },
332 { STRMEM("Tsock"), sizeof(RTSOCKET), 10, RTSF_INT, 0 },
333 { STRMEM("Tthrd"), sizeof(RTTHREAD), 16, RTSF_INTW, 0 },
334 { STRMEM("Tuid"), sizeof(RTUID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
335 { STRMEM("Tuint"), sizeof(RTUINT), 10, RTSF_INT, 0 },
336 { STRMEM("Tunicp"), sizeof(RTUNICP), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
337 { STRMEM("Tutf16"), sizeof(RTUTF16), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
338 { STRMEM("Tuuid"), sizeof(PCRTUUID), 16, RTSF_UUID, 0 },
339 { STRMEM("Txint"), sizeof(RTUINT), 16, RTSF_INT, 0 },
340 { STRMEM("U16"), sizeof(uint16_t), 10, RTSF_INT, 0 },
341 { STRMEM("U32"), sizeof(uint32_t), 10, RTSF_INT, 0 },
342 { STRMEM("U64"), sizeof(uint64_t), 10, RTSF_INT, 0 },
343 { STRMEM("U8"), sizeof(uint8_t), 10, RTSF_INT, 0 },
344 { STRMEM("X16"), sizeof(uint16_t), 16, RTSF_INT, 0 },
345 { STRMEM("X32"), sizeof(uint32_t), 16, RTSF_INT, 0 },
346 { STRMEM("X64"), sizeof(uint64_t), 16, RTSF_INT, 0 },
347 { STRMEM("X8"), sizeof(uint8_t), 16, RTSF_INT, 0 },
348#undef STRMEM
349 };
350 static const char s_szNull[] = "<NULL>";
351
352 const char *pszType = *ppszFormat - 1;
353 int iStart = 0;
354 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
355 int i = RT_ELEMENTS(s_aTypes) / 2;
356
357 union
358 {
359 uint8_t u8;
360 uint16_t u16;
361 uint32_t u32;
362 uint64_t u64;
363 int8_t i8;
364 int16_t i16;
365 int32_t i32;
366 int64_t i64;
367 RTR0INTPTR uR0Ptr;
368 RTFAR16 fp16;
369 RTFAR32 fp32;
370 RTFAR64 fp64;
371 bool fBool;
372 PCRTMAC pMac;
373 RTNETADDRIPV4 Ipv4Addr;
374 PCRTNETADDRIPV6 pIpv6Addr;
375 PCRTNETADDR pNetAddr;
376 PCRTUUID pUuid;
377 } u;
378
379 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
380 RT_NOREF_PV(chArgSize);
381
382 /*
383 * Lookup the type - binary search.
384 */
385 for (;;)
386 {
387 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
388 if (!iDiff)
389 break;
390 if (iEnd == iStart)
391 {
392 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
393 return 0;
394 }
395 if (iDiff < 0)
396 iEnd = i - 1;
397 else
398 iStart = i + 1;
399 if (iEnd < iStart)
400 {
401 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
402 return 0;
403 }
404 i = iStart + (iEnd - iStart) / 2;
405 }
406
407 /*
408 * Advance the format string and merge flags.
409 */
410 *ppszFormat += s_aTypes[i].cch - 1;
411 fFlags |= s_aTypes[i].fFlags;
412
413 /*
414 * Fetch the argument.
415 * It's important that a signed value gets sign-extended up to 64-bit.
416 */
417 RT_ZERO(u);
418 if (fFlags & RTSTR_F_VALSIGNED)
419 {
420 switch (s_aTypes[i].cb)
421 {
422 case sizeof(int8_t):
423 u.i64 = va_arg(*pArgs, /*int8_t*/int);
424 fFlags |= RTSTR_F_8BIT;
425 break;
426 case sizeof(int16_t):
427 u.i64 = va_arg(*pArgs, /*int16_t*/int);
428 fFlags |= RTSTR_F_16BIT;
429 break;
430 case sizeof(int32_t):
431 u.i64 = va_arg(*pArgs, int32_t);
432 fFlags |= RTSTR_F_32BIT;
433 break;
434 case sizeof(int64_t):
435 u.i64 = va_arg(*pArgs, int64_t);
436 fFlags |= RTSTR_F_64BIT;
437 break;
438 default:
439 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
440 break;
441 }
442 }
443 else
444 {
445 switch (s_aTypes[i].cb)
446 {
447 case sizeof(uint8_t):
448 u.u8 = va_arg(*pArgs, /*uint8_t*/unsigned);
449 fFlags |= RTSTR_F_8BIT;
450 break;
451 case sizeof(uint16_t):
452 u.u16 = va_arg(*pArgs, /*uint16_t*/unsigned);
453 fFlags |= RTSTR_F_16BIT;
454 break;
455 case sizeof(uint32_t):
456 u.u32 = va_arg(*pArgs, uint32_t);
457 fFlags |= RTSTR_F_32BIT;
458 break;
459 case sizeof(uint64_t):
460 u.u64 = va_arg(*pArgs, uint64_t);
461 fFlags |= RTSTR_F_64BIT;
462 break;
463 case sizeof(RTFAR32):
464 u.fp32 = va_arg(*pArgs, RTFAR32);
465 break;
466 case sizeof(RTFAR64):
467 u.fp64 = va_arg(*pArgs, RTFAR64);
468 break;
469 default:
470 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
471 break;
472 }
473 }
474
475#ifndef DEBUG
476 /*
477 * For now don't show the address.
478 */
479 if (fFlags & RTSTR_F_OBFUSCATE_PTR)
480 {
481 cch = rtStrFormatKernelAddress(szBuf, sizeof(szBuf), u.uR0Ptr, cchWidth, cchPrecision, fFlags);
482 return pfnOutput(pvArgOutput, szBuf, cch);
483 }
484#endif
485
486 /*
487 * Format the output.
488 */
489 switch (s_aTypes[i].enmFormat)
490 {
491 case RTSF_INT:
492 {
493 cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
494 break;
495 }
496
497 /* hex which defaults to max width. */
498 case RTSF_INTW:
499 {
500 Assert(s_aTypes[i].u8Base == 16);
501 if (cchWidth < 0)
502 {
503 cchWidth = s_aTypes[i].cb * 2 + (fFlags & RTSTR_F_SPECIAL ? 2 : 0);
504 fFlags |= RTSTR_F_ZEROPAD;
505 }
506 cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
507 break;
508 }
509
510 case RTSF_BOOL:
511 {
512 static const char s_szTrue[] = "true ";
513 static const char s_szFalse[] = "false";
514 if (u.u64 == 1)
515 return pfnOutput(pvArgOutput, s_szTrue, sizeof(s_szTrue) - 1);
516 if (u.u64 == 0)
517 return pfnOutput(pvArgOutput, s_szFalse, sizeof(s_szFalse) - 1);
518 /* invalid boolean value */
519 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "!%lld!", u.u64);
520 }
521
522 case RTSF_FP16:
523 {
524 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
525 cch = RTStrFormatNumber(&szBuf[0], u.fp16.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
526 Assert(cch == 4);
527 szBuf[4] = ':';
528 cch = RTStrFormatNumber(&szBuf[5], u.fp16.off, 16, 4, -1, fFlags | RTSTR_F_16BIT);
529 Assert(cch == 4);
530 cch = 4 + 1 + 4;
531 break;
532 }
533 case RTSF_FP32:
534 {
535 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
536 cch = RTStrFormatNumber(&szBuf[0], u.fp32.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
537 Assert(cch == 4);
538 szBuf[4] = ':';
539 cch = RTStrFormatNumber(&szBuf[5], u.fp32.off, 16, 8, -1, fFlags | RTSTR_F_32BIT);
540 Assert(cch == 8);
541 cch = 4 + 1 + 8;
542 break;
543 }
544 case RTSF_FP64:
545 {
546 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
547 cch = RTStrFormatNumber(&szBuf[0], u.fp64.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
548 Assert(cch == 4);
549 szBuf[4] = ':';
550 cch = RTStrFormatNumber(&szBuf[5], u.fp64.off, 16, 16, -1, fFlags | RTSTR_F_64BIT);
551 Assert(cch == 16);
552 cch = 4 + 1 + 16;
553 break;
554 }
555
556 case RTSF_IPV4:
557 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
558 "%u.%u.%u.%u",
559 u.Ipv4Addr.au8[0],
560 u.Ipv4Addr.au8[1],
561 u.Ipv4Addr.au8[2],
562 u.Ipv4Addr.au8[3]);
563
564 case RTSF_IPV6:
565 {
566 if (VALID_PTR(u.pIpv6Addr))
567 return rtstrFormatIPv6(pfnOutput, pvArgOutput, u.pIpv6Addr);
568 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
569 }
570
571 case RTSF_MAC:
572 {
573 if (VALID_PTR(u.pMac))
574 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
575 "%02x:%02x:%02x:%02x:%02x:%02x",
576 u.pMac->au8[0],
577 u.pMac->au8[1],
578 u.pMac->au8[2],
579 u.pMac->au8[3],
580 u.pMac->au8[4],
581 u.pMac->au8[5]);
582 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
583 }
584
585 case RTSF_NETADDR:
586 {
587 if (VALID_PTR(u.pNetAddr))
588 {
589 switch (u.pNetAddr->enmType)
590 {
591 case RTNETADDRTYPE_IPV4:
592 if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
593 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
594 "%u.%u.%u.%u",
595 u.pNetAddr->uAddr.IPv4.au8[0],
596 u.pNetAddr->uAddr.IPv4.au8[1],
597 u.pNetAddr->uAddr.IPv4.au8[2],
598 u.pNetAddr->uAddr.IPv4.au8[3]);
599 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
600 "%u.%u.%u.%u:%u",
601 u.pNetAddr->uAddr.IPv4.au8[0],
602 u.pNetAddr->uAddr.IPv4.au8[1],
603 u.pNetAddr->uAddr.IPv4.au8[2],
604 u.pNetAddr->uAddr.IPv4.au8[3],
605 u.pNetAddr->uPort);
606
607 case RTNETADDRTYPE_IPV6:
608 if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
609 return rtstrFormatIPv6(pfnOutput, pvArgOutput, &u.pNetAddr->uAddr.IPv6);
610
611 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
612 "[%RTnaipv6]:%u",
613 &u.pNetAddr->uAddr.IPv6,
614 u.pNetAddr->uPort);
615
616 case RTNETADDRTYPE_MAC:
617 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
618 "%02x:%02x:%02x:%02x:%02x:%02x",
619 u.pNetAddr->uAddr.Mac.au8[0],
620 u.pNetAddr->uAddr.Mac.au8[1],
621 u.pNetAddr->uAddr.Mac.au8[2],
622 u.pNetAddr->uAddr.Mac.au8[3],
623 u.pNetAddr->uAddr.Mac.au8[4],
624 u.pNetAddr->uAddr.Mac.au8[5]);
625
626 default:
627 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
628 "unsupported-netaddr-type=%u", u.pNetAddr->enmType);
629
630 }
631 }
632 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
633 }
634
635 case RTSF_UUID:
636 {
637 if (VALID_PTR(u.pUuid))
638 {
639 /* cannot call RTUuidToStr because of GC/R0. */
640 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
641 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
642 RT_H2LE_U32(u.pUuid->Gen.u32TimeLow),
643 RT_H2LE_U16(u.pUuid->Gen.u16TimeMid),
644 RT_H2LE_U16(u.pUuid->Gen.u16TimeHiAndVersion),
645 u.pUuid->Gen.u8ClockSeqHiAndReserved,
646 u.pUuid->Gen.u8ClockSeqLow,
647 u.pUuid->Gen.au8Node[0],
648 u.pUuid->Gen.au8Node[1],
649 u.pUuid->Gen.au8Node[2],
650 u.pUuid->Gen.au8Node[3],
651 u.pUuid->Gen.au8Node[4],
652 u.pUuid->Gen.au8Node[5]);
653 }
654 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
655 }
656
657 default:
658 AssertMsgFailed(("Internal error %d\n", s_aTypes[i].enmFormat));
659 return 0;
660 }
661
662 /*
663 * Finally, output the formatted string and return.
664 */
665 return pfnOutput(pvArgOutput, szBuf, cch);
666 }
667
668
669 /* Group 3 */
670
671 /*
672 * Base name printing, big endian UTF-16.
673 */
674 case 'b':
675 {
676 switch (*(*ppszFormat)++)
677 {
678 case 'n':
679 {
680 const char *pszLastSep;
681 const char *psz = pszLastSep = va_arg(*pArgs, const char *);
682 if (!VALID_PTR(psz))
683 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
684
685 while ((ch = *psz) != '\0')
686 {
687 if (RTPATH_IS_SEP(ch))
688 {
689 do
690 psz++;
691 while ((ch = *psz) != '\0' && RTPATH_IS_SEP(ch));
692 if (!ch)
693 break;
694 pszLastSep = psz;
695 }
696 psz++;
697 }
698
699 return pfnOutput(pvArgOutput, pszLastSep, psz - pszLastSep);
700 }
701
702 /* %lRbs */
703 case 's':
704 if (chArgSize == 'l')
705 {
706 /* utf-16BE -> utf-8 */
707 int cchStr;
708 PCRTUTF16 pwszStr = va_arg(*pArgs, PRTUTF16);
709
710 if (RT_VALID_PTR(pwszStr))
711 {
712 cchStr = 0;
713 while (cchStr < cchPrecision && pwszStr[cchStr] != '\0')
714 cchStr++;
715 }
716 else
717 {
718 static RTUTF16 s_wszBigNull[] =
719 {
720 RT_H2BE_U16_C((uint16_t)'<'), RT_H2BE_U16_C((uint16_t)'N'), RT_H2BE_U16_C((uint16_t)'U'),
721 RT_H2BE_U16_C((uint16_t)'L'), RT_H2BE_U16_C((uint16_t)'L'), RT_H2BE_U16_C((uint16_t)'>'), '\0'
722 };
723 pwszStr = s_wszBigNull;
724 cchStr = RT_ELEMENTS(s_wszBigNull) - 1;
725 }
726
727 cch = 0;
728 if (!(fFlags & RTSTR_F_LEFT))
729 while (--cchWidth >= cchStr)
730 cch += pfnOutput(pvArgOutput, " ", 1);
731 cchWidth -= cchStr;
732 while (cchStr-- > 0)
733 {
734/** @todo \#ifndef IN_RC*/
735#ifdef IN_RING3
736 RTUNICP Cp = 0;
737 RTUtf16BigGetCpEx(&pwszStr, &Cp);
738 char *pszEnd = RTStrPutCp(szBuf, Cp);
739 *pszEnd = '\0';
740 cch += pfnOutput(pvArgOutput, szBuf, pszEnd - szBuf);
741#else
742 szBuf[0] = (char)(*pwszStr++ >> 8);
743 cch += pfnOutput(pvArgOutput, szBuf, 1);
744#endif
745 }
746 while (--cchWidth >= 0)
747 cch += pfnOutput(pvArgOutput, " ", 1);
748 return cch;
749 }
750 RT_FALL_THRU();
751
752 default:
753 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
754 break;
755 }
756 break;
757 }
758
759
760 /*
761 * Pretty function / method name printing.
762 */
763 case 'f':
764 {
765 switch (*(*ppszFormat)++)
766 {
767 /*
768 * Pretty function / method name printing.
769 * This isn't 100% right (see classic signal prototype) and it assumes
770 * standardized names, but it'll do for today.
771 */
772 case 'n':
773 {
774 const char *pszStart;
775 const char *psz = pszStart = va_arg(*pArgs, const char *);
776 int cAngle = 0;
777
778 if (!VALID_PTR(psz))
779 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
780
781 while ((ch = *psz) != '\0' && ch != '(')
782 {
783 if (RT_C_IS_BLANK(ch))
784 {
785 psz++;
786 while ((ch = *psz) != '\0' && (RT_C_IS_BLANK(ch) || ch == '('))
787 psz++;
788 if (ch && cAngle == 0)
789 pszStart = psz;
790 }
791 else if (ch == '(')
792 break;
793 else if (ch == '<')
794 {
795 cAngle++;
796 psz++;
797 }
798 else if (ch == '>')
799 {
800 cAngle--;
801 psz++;
802 }
803 else
804 psz++;
805 }
806
807 return pfnOutput(pvArgOutput, pszStart, psz - pszStart);
808 }
809
810 default:
811 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
812 break;
813 }
814 break;
815 }
816
817
818 /*
819 * hex dumping, COM/XPCOM, human readable sizes.
820 */
821 case 'h':
822 {
823 ch = *(*ppszFormat)++;
824 switch (ch)
825 {
826 /*
827 * Hex stuff.
828 */
829 case 'x':
830 {
831 uint8_t *pu8 = va_arg(*pArgs, uint8_t *);
832 if (cchPrecision < 0)
833 cchPrecision = 16;
834 if (pu8)
835 {
836 switch (*(*ppszFormat)++)
837 {
838 /*
839 * Regular hex dump.
840 */
841 case 'd':
842 {
843 int off = 0;
844 cch = 0;
845
846 if (cchWidth <= 0)
847 cchWidth = 16;
848
849 while (off < cchPrecision)
850 {
851 int i;
852 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
853 "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
854 for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
855 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
856 off + i < cchPrecision ? !(i & 7) && i ? "-%02x" : " %02x" : " ",
857 pu8[i]);
858 while (i++ < cchWidth)
859 cch += pfnOutput(pvArgOutput, " ", 3);
860
861 cch += pfnOutput(pvArgOutput, " ", 1);
862
863 for (i = 0; i < cchWidth && off + i < cchPrecision; i++)
864 {
865 uint8_t u8 = pu8[i];
866 cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
867 }
868
869 /* next */
870 pu8 += cchWidth;
871 off += cchWidth;
872 }
873 return cch;
874 }
875
876 /*
877 * Regular hex dump with dittoing.
878 */
879 case 'D':
880 {
881 int offEndDupCheck;
882 int cDuplicates = 0;
883 int off = 0;
884 cch = 0;
885
886 if (cchWidth <= 0)
887 cchWidth = 16;
888 offEndDupCheck = cchPrecision - cchWidth;
889
890 while (off < cchPrecision)
891 {
892 int i;
893 if ( off >= offEndDupCheck
894 || off <= 0
895 || memcmp(pu8, pu8 - cchWidth, cchWidth) != 0
896 || ( cDuplicates == 0
897 && ( off + cchWidth >= offEndDupCheck
898 || memcmp(pu8 + cchWidth, pu8, cchWidth) != 0)) )
899 {
900 if (cDuplicates > 0)
901 {
902 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
903 "\n%.*s **** <ditto x %u>",
904 sizeof(pu8) * 2, "****************", cDuplicates);
905 cDuplicates = 0;
906 }
907
908 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
909 "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
910 for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
911 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
912 off + i < cchPrecision ? !(i & 7) && i
913 ? "-%02x" : " %02x" : " ",
914 pu8[i]);
915 while (i++ < cchWidth)
916 cch += pfnOutput(pvArgOutput, " ", 3);
917
918 cch += pfnOutput(pvArgOutput, " ", 1);
919
920 for (i = 0; i < cchWidth && off + i < cchPrecision; i++)
921 {
922 uint8_t u8 = pu8[i];
923 cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
924 }
925 }
926 else
927 cDuplicates++;
928
929 /* next */
930 pu8 += cchWidth;
931 off += cchWidth;
932 }
933 return cch;
934 }
935
936 /*
937 * Hex string.
938 */
939 case 's':
940 {
941 if (cchPrecision-- > 0)
942 {
943 cch = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%02x", *pu8++);
944 for (; cchPrecision > 0; cchPrecision--, pu8++)
945 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " %02x", *pu8);
946 return cch;
947 }
948 break;
949 }
950
951 default:
952 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
953 break;
954 }
955 }
956 else
957 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
958 break;
959 }
960
961
962#ifdef IN_RING3
963 /*
964 * XPCOM / COM status code: %Rhrc, %Rhrf, %Rhra
965 * ASSUMES: If Windows Then COM else XPCOM.
966 */
967 case 'r':
968 {
969 uint32_t hrc = va_arg(*pArgs, uint32_t);
970 PCRTCOMERRMSG pMsg = RTErrCOMGet(hrc);
971 switch (*(*ppszFormat)++)
972 {
973 case 'c':
974 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
975 case 'f':
976 return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
977 case 'a':
978 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, hrc, pMsg->pszMsgFull);
979 default:
980 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
981 return 0;
982 }
983 break;
984 }
985#endif /* IN_RING3 */
986
987 case 'c':
988 case 'u':
989 {
990 unsigned i;
991 ssize_t cchBuf;
992 uint64_t uValue;
993 uint64_t uFraction = 0;
994 const char *pszPrefix = NULL;
995 unsigned cchFixedPart;
996 char ch2 = *(*ppszFormat)++;
997 AssertMsgReturn(ch2 == 'b' || ch2 == 'i', ("invalid type '%.10s'!\n", pszFormatOrg), 0);
998 uValue = va_arg(*pArgs, uint64_t);
999
1000 if (!(fFlags & RTSTR_F_PRECISION))
1001 cchPrecision = 1;
1002 else if (cchPrecision > 3)
1003 cchPrecision = 3;
1004 else if (cchPrecision < 0)
1005 cchPrecision = 0;
1006
1007 cchFixedPart = cchPrecision + (cchPrecision != 0) + (ch == 'c');
1008
1009 if (ch2 == 'b')
1010 {
1011 static const struct
1012 {
1013 const char *pszPrefix;
1014 uint8_t cShift;
1015 uint64_t cbMin;
1016 uint64_t cbMinZeroPrecision;
1017 } s_aUnits[] =
1018 {
1019 { "Ei", 60, _1E, _1E*2 },
1020 { "Pi", 50, _1P, _1P*2 },
1021 { "Ti", 40, _1T, _1T*2 },
1022 { "Gi", 30, _1G, _1G64*2 },
1023 { "Mi", 20, _1M, _1M*2 },
1024 { "Ki", 10, _1K, _1K*2 },
1025 };
1026 for (i = 0; i < RT_ELEMENTS(s_aUnits); i++)
1027 if ( uValue >= s_aUnits[i].cbMin
1028 && (cchPrecision > 0 || uValue >= s_aUnits[i].cbMinZeroPrecision))
1029 {
1030 if (cchPrecision != 0)
1031 {
1032 uFraction = uValue & (RT_BIT_64(s_aUnits[i].cShift) - 1);
1033 uFraction *= cchPrecision == 1 ? 10 : cchPrecision == 2 ? 100 : 1000;
1034 uFraction >>= s_aUnits[i].cShift;
1035 }
1036 uValue >>= s_aUnits[i].cShift;
1037 pszPrefix = s_aUnits[i].pszPrefix;
1038 cchFixedPart += 2;
1039 break;
1040 }
1041 }
1042 else
1043 {
1044 static const struct
1045 {
1046 const char *pszPrefix;
1047 uint64_t cbFactor;
1048 uint64_t cbMinZeroPrecision;
1049 } s_aUnits[] =
1050 {
1051 { "E", UINT64_C(1000000000000000000), UINT64_C(1010000000000000000), },
1052 { "P", UINT64_C(1000000000000000), UINT64_C(1010000000000000), },
1053 { "T", UINT64_C(1000000000000), UINT64_C(1010000000000), },
1054 { "G", UINT64_C(1000000000), UINT64_C(1010000000), },
1055 { "M", UINT64_C(1000000), UINT64_C(1010000), },
1056 { "k", UINT64_C(1000), UINT64_C(1010), },
1057 };
1058 for (i = 0; i < RT_ELEMENTS(s_aUnits); i++)
1059 if ( uValue >= s_aUnits[i].cbFactor
1060 && (cchPrecision > 0 || uValue >= s_aUnits[i].cbMinZeroPrecision))
1061 {
1062 if (cchPrecision == 0)
1063 uValue /= s_aUnits[i].cbFactor;
1064 else
1065 {
1066 uFraction = uValue % s_aUnits[i].cbFactor;
1067 uValue = uValue / s_aUnits[i].cbFactor;
1068 uFraction *= cchPrecision == 1 ? 10 : cchPrecision == 2 ? 100 : 1000;
1069 uFraction += s_aUnits[i].cbFactor >> 1;
1070 uFraction /= s_aUnits[i].cbFactor;
1071 }
1072 pszPrefix = s_aUnits[i].pszPrefix;
1073 cchFixedPart += 1;
1074 break;
1075 }
1076 }
1077
1078 cchBuf = RTStrFormatU64(szBuf, sizeof(szBuf), uValue, 10, 0, 0, 0);
1079 if (pszPrefix)
1080 {
1081 if (cchPrecision)
1082 {
1083 szBuf[cchBuf++] = '.';
1084 cchBuf += RTStrFormatU64(&szBuf[cchBuf], sizeof(szBuf) - cchBuf, uFraction, 10, cchPrecision, 0,
1085 RTSTR_F_ZEROPAD | RTSTR_F_WIDTH);
1086 }
1087 szBuf[cchBuf++] = *pszPrefix++;
1088 if (*pszPrefix)
1089 szBuf[cchBuf++] = *pszPrefix;
1090 }
1091 if (ch == 'c')
1092 szBuf[cchBuf++] = 'B';
1093 szBuf[cchBuf] = '\0';
1094
1095 cch = 0;
1096 if ((fFlags & RTSTR_F_WIDTH) && !(fFlags & RTSTR_F_LEFT))
1097 while (cchBuf < cchWidth)
1098 {
1099 cch += pfnOutput(pvArgOutput, fFlags & RTSTR_F_ZEROPAD ? "0" : " ", 1);
1100 cchWidth--;
1101 }
1102 cch += pfnOutput(pvArgOutput, szBuf, cchBuf);
1103 return cch;
1104 }
1105
1106 default:
1107 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1108 return 0;
1109
1110 }
1111 break;
1112 }
1113
1114 /*
1115 * iprt status code: %Rrc, %Rrs, %Rrf, %Rra.
1116 */
1117 case 'r':
1118 {
1119 int rc = va_arg(*pArgs, int);
1120#ifdef IN_RING3 /* we don't want this anywhere else yet. */
1121 PCRTSTATUSMSG pMsg = RTErrGet(rc);
1122 switch (*(*ppszFormat)++)
1123 {
1124 case 'c':
1125 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
1126 case 's':
1127 return pfnOutput(pvArgOutput, pMsg->pszMsgShort, strlen(pMsg->pszMsgShort));
1128 case 'f':
1129 return pfnOutput(pvArgOutput, pMsg->pszMsgFull, strlen(pMsg->pszMsgFull));
1130 case 'a':
1131 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (%d) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
1132 default:
1133 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1134 return 0;
1135 }
1136#else /* !IN_RING3 */
1137 switch (*(*ppszFormat)++)
1138 {
1139 case 'c':
1140 case 's':
1141 case 'f':
1142 case 'a':
1143 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%d", rc);
1144 default:
1145 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1146 return 0;
1147 }
1148#endif /* !IN_RING3 */
1149 break;
1150 }
1151
1152#if defined(IN_RING3)
1153 /*
1154 * Windows status code: %Rwc, %Rwf, %Rwa
1155 */
1156 case 'w':
1157 {
1158 long rc = va_arg(*pArgs, long);
1159# if defined(RT_OS_WINDOWS)
1160 PCRTWINERRMSG pMsg = RTErrWinGet(rc);
1161# endif
1162 switch (*(*ppszFormat)++)
1163 {
1164# if defined(RT_OS_WINDOWS)
1165 case 'c':
1166 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
1167 case 'f':
1168 return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
1169 case 'a':
1170 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
1171# else
1172 case 'c':
1173 case 'f':
1174 case 'a':
1175 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "0x%08X", rc);
1176# endif
1177 default:
1178 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1179 return 0;
1180 }
1181 break;
1182 }
1183#endif /* IN_RING3 */
1184
1185 /*
1186 * Group 4, structure dumpers.
1187 */
1188 case 'D':
1189 {
1190 /*
1191 * Interpret the type.
1192 */
1193 typedef enum
1194 {
1195 RTST_TIMESPEC
1196 } RTST;
1197/** Set if it's a pointer */
1198#define RTST_FLAGS_POINTER RT_BIT(0)
1199 static const struct
1200 {
1201 uint8_t cch; /**< the length of the string. */
1202 char sz[16-2]; /**< the part following 'R'. */
1203 uint8_t cb; /**< the size of the argument. */
1204 uint8_t fFlags; /**< RTST_FLAGS_* */
1205 RTST enmType; /**< The structure type. */
1206 }
1207 /** Sorted array of types, looked up using binary search! */
1208 s_aTypes[] =
1209 {
1210#define STRMEM(str) sizeof(str) - 1, str
1211 { STRMEM("Dtimespec"), sizeof(PCRTTIMESPEC), RTST_FLAGS_POINTER, RTST_TIMESPEC},
1212#undef STRMEM
1213 };
1214 const char *pszType = *ppszFormat - 1;
1215 int iStart = 0;
1216 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
1217 int i = RT_ELEMENTS(s_aTypes) / 2;
1218
1219 union
1220 {
1221 const void *pv;
1222 uint64_t u64;
1223 PCRTTIMESPEC pTimeSpec;
1224 } u;
1225
1226 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
1227
1228 /*
1229 * Lookup the type - binary search.
1230 */
1231 for (;;)
1232 {
1233 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
1234 if (!iDiff)
1235 break;
1236 if (iEnd == iStart)
1237 {
1238 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
1239 return 0;
1240 }
1241 if (iDiff < 0)
1242 iEnd = i - 1;
1243 else
1244 iStart = i + 1;
1245 if (iEnd < iStart)
1246 {
1247 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
1248 return 0;
1249 }
1250 i = iStart + (iEnd - iStart) / 2;
1251 }
1252 *ppszFormat += s_aTypes[i].cch - 1;
1253
1254 /*
1255 * Fetch the argument.
1256 */
1257 u.u64 = 0;
1258 switch (s_aTypes[i].cb)
1259 {
1260 case sizeof(const void *):
1261 u.pv = va_arg(*pArgs, const void *);
1262 break;
1263 default:
1264 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
1265 break;
1266 }
1267
1268 /*
1269 * If it's a pointer, we'll check if it's valid before going on.
1270 */
1271 if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !VALID_PTR(u.pv))
1272 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
1273
1274 /*
1275 * Format the output.
1276 */
1277 switch (s_aTypes[i].enmType)
1278 {
1279 case RTST_TIMESPEC:
1280 return RTStrFormat(pfnOutput, pvArgOutput, NULL, NULL, "%'lld ns", RTTimeSpecGetNano(u.pTimeSpec));
1281
1282 default:
1283 AssertMsgFailed(("Invalid/unhandled enmType=%d\n", s_aTypes[i].enmType));
1284 break;
1285 }
1286 break;
1287 }
1288
1289#ifdef IN_RING3
1290 /*
1291 * Group 5, XML / HTML escapers.
1292 */
1293 case 'M':
1294 {
1295 char chWhat = (*ppszFormat)[0];
1296 bool fAttr = chWhat == 'a';
1297 char chType = (*ppszFormat)[1];
1298 AssertMsgBreak(chWhat == 'a' || chWhat == 'e', ("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1299 *ppszFormat += 2;
1300 switch (chType)
1301 {
1302 case 's':
1303 {
1304 static const char s_szElemEscape[] = "<>&\"'";
1305 static const char s_szAttrEscape[] = "<>&\"\n\r"; /* more? */
1306 const char * const pszEscape = fAttr ? s_szAttrEscape : s_szElemEscape;
1307 size_t const cchEscape = (fAttr ? RT_ELEMENTS(s_szAttrEscape) : RT_ELEMENTS(s_szElemEscape)) - 1;
1308 size_t cchOutput = 0;
1309 const char *pszStr = va_arg(*pArgs, char *);
1310 ssize_t cchStr;
1311 ssize_t offCur;
1312 ssize_t offLast;
1313
1314 if (!VALID_PTR(pszStr))
1315 pszStr = "<NULL>";
1316 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1317
1318 if (fAttr)
1319 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1320 if (!(fFlags & RTSTR_F_LEFT))
1321 while (--cchWidth >= cchStr)
1322 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1323
1324 offLast = offCur = 0;
1325 while (offCur < cchStr)
1326 {
1327 if (memchr(pszEscape, pszStr[offCur], cchEscape))
1328 {
1329 if (offLast < offCur)
1330 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1331 switch (pszStr[offCur])
1332 {
1333 case '<': cchOutput += pfnOutput(pvArgOutput, "&lt;", 4); break;
1334 case '>': cchOutput += pfnOutput(pvArgOutput, "&gt;", 4); break;
1335 case '&': cchOutput += pfnOutput(pvArgOutput, "&amp;", 5); break;
1336 case '\'': cchOutput += pfnOutput(pvArgOutput, "&apos;", 6); break;
1337 case '"': cchOutput += pfnOutput(pvArgOutput, "&quot;", 6); break;
1338 case '\n': cchOutput += pfnOutput(pvArgOutput, "&#xA;", 5); break;
1339 case '\r': cchOutput += pfnOutput(pvArgOutput, "&#xD;", 5); break;
1340 default:
1341 AssertFailed();
1342 }
1343 offLast = offCur + 1;
1344 }
1345 offCur++;
1346 }
1347 if (offLast < offCur)
1348 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1349
1350 while (--cchWidth >= cchStr)
1351 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1352 if (fAttr)
1353 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1354 return cchOutput;
1355 }
1356
1357 default:
1358 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1359 }
1360 break;
1361 }
1362#endif /* IN_RING3 */
1363
1364
1365 /*
1366 * Groups 6 - CPU Architecture Register Formatters.
1367 * "%RAarch[reg]"
1368 */
1369 case 'A':
1370 {
1371 char const * const pszArch = *ppszFormat;
1372 const char *pszReg = pszArch;
1373 size_t cchOutput = 0;
1374 int cPrinted = 0;
1375 size_t cchReg;
1376
1377 /* Parse out the */
1378 while ((ch = *pszReg++) && ch != '[')
1379 { /* nothing */ }
1380 AssertMsgBreak(ch == '[', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
1381
1382 cchReg = 0;
1383 while ((ch = pszReg[cchReg]) && ch != ']')
1384 cchReg++;
1385 AssertMsgBreak(ch == ']', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
1386
1387 *ppszFormat = &pszReg[cchReg + 1];
1388
1389
1390#define REG_EQUALS(a_szReg) (sizeof(a_szReg) - 1 == cchReg && !strncmp(a_szReg, pszReg, sizeof(a_szReg) - 1))
1391#define REG_OUT_BIT(a_uVal, a_fBitMask, a_szName) \
1392 do { \
1393 if ((a_uVal) & (a_fBitMask)) \
1394 { \
1395 if (!cPrinted++) \
1396 cchOutput += pfnOutput(pvArgOutput, "{" a_szName, sizeof(a_szName)); \
1397 else \
1398 cchOutput += pfnOutput(pvArgOutput, "," a_szName, sizeof(a_szName)); \
1399 (a_uVal) &= ~(a_fBitMask); \
1400 } \
1401 } while (0)
1402#define REG_OUT_CLOSE(a_uVal) \
1403 do { \
1404 if ((a_uVal)) \
1405 { \
1406 cchOutput += pfnOutput(pvArgOutput, !cPrinted ? "{unkn=" : ",unkn=", 6); \
1407 cch = RTStrFormatNumber(&szBuf[0], (a_uVal), 16, 1, -1, fFlags); \
1408 cchOutput += pfnOutput(pvArgOutput, szBuf, cch); \
1409 cPrinted++; \
1410 } \
1411 if (cPrinted) \
1412 cchOutput += pfnOutput(pvArgOutput, "}", 1); \
1413 } while (0)
1414
1415
1416 if (0)
1417 { /* dummy */ }
1418#ifdef STRFORMAT_WITH_X86
1419 /*
1420 * X86 & AMD64.
1421 */
1422 else if ( pszReg - pszArch == 3 + 1
1423 && pszArch[0] == 'x'
1424 && pszArch[1] == '8'
1425 && pszArch[2] == '6')
1426 {
1427 if (REG_EQUALS("cr0"))
1428 {
1429 uint64_t cr0 = va_arg(*pArgs, uint64_t);
1430 fFlags |= RTSTR_F_64BIT;
1431 cch = RTStrFormatNumber(&szBuf[0], cr0, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
1432 cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
1433 REG_OUT_BIT(cr0, X86_CR0_PE, "PE");
1434 REG_OUT_BIT(cr0, X86_CR0_MP, "MP");
1435 REG_OUT_BIT(cr0, X86_CR0_EM, "EM");
1436 REG_OUT_BIT(cr0, X86_CR0_TS, "DE");
1437 REG_OUT_BIT(cr0, X86_CR0_ET, "ET");
1438 REG_OUT_BIT(cr0, X86_CR0_NE, "NE");
1439 REG_OUT_BIT(cr0, X86_CR0_WP, "WP");
1440 REG_OUT_BIT(cr0, X86_CR0_AM, "AM");
1441 REG_OUT_BIT(cr0, X86_CR0_NW, "NW");
1442 REG_OUT_BIT(cr0, X86_CR0_CD, "CD");
1443 REG_OUT_BIT(cr0, X86_CR0_PG, "PG");
1444 REG_OUT_CLOSE(cr0);
1445 }
1446 else if (REG_EQUALS("cr4"))
1447 {
1448 uint64_t cr4 = va_arg(*pArgs, uint64_t);
1449 fFlags |= RTSTR_F_64BIT;
1450 cch = RTStrFormatNumber(&szBuf[0], cr4, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
1451 cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
1452 REG_OUT_BIT(cr4, X86_CR4_VME, "VME");
1453 REG_OUT_BIT(cr4, X86_CR4_PVI, "PVI");
1454 REG_OUT_BIT(cr4, X86_CR4_TSD, "TSD");
1455 REG_OUT_BIT(cr4, X86_CR4_DE, "DE");
1456 REG_OUT_BIT(cr4, X86_CR4_PSE, "PSE");
1457 REG_OUT_BIT(cr4, X86_CR4_PAE, "PAE");
1458 REG_OUT_BIT(cr4, X86_CR4_MCE, "MCE");
1459 REG_OUT_BIT(cr4, X86_CR4_PGE, "PGE");
1460 REG_OUT_BIT(cr4, X86_CR4_PCE, "PCE");
1461 REG_OUT_BIT(cr4, X86_CR4_OSFXSR, "OSFXSR");
1462 REG_OUT_BIT(cr4, X86_CR4_OSXMMEEXCPT, "OSXMMEEXCPT");
1463 REG_OUT_BIT(cr4, X86_CR4_VMXE, "VMXE");
1464 REG_OUT_BIT(cr4, X86_CR4_SMXE, "SMXE");
1465 REG_OUT_BIT(cr4, X86_CR4_PCIDE, "PCIDE");
1466 REG_OUT_BIT(cr4, X86_CR4_OSXSAVE, "OSXSAVE");
1467 REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
1468 REG_OUT_BIT(cr4, X86_CR4_SMAP, "SMAP");
1469 REG_OUT_CLOSE(cr4);
1470 }
1471 else
1472 AssertMsgFailed(("Unknown x86 register specified in '%.10s'!\n", pszFormatOrg));
1473 }
1474#endif
1475 else
1476 AssertMsgFailed(("Unknown architecture specified in '%.10s'!\n", pszFormatOrg));
1477#undef REG_OUT_BIT
1478#undef REG_OUT_CLOSE
1479#undef REG_EQUALS
1480 return cchOutput;
1481 }
1482
1483 /*
1484 * Invalid/Unknown. Bitch about it.
1485 */
1486 default:
1487 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1488 break;
1489 }
1490 }
1491 else
1492 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1493
1494 NOREF(pszFormatOrg);
1495 return 0;
1496}
1497
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