VirtualBox

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

Last change on this file was 99422, checked in by vboxsync, 14 months ago

IPRT/strformatrt.cpp: Corrected formatting RTERRINFO (%RTeim and %RTeic), was outputting too much.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use