VirtualBox

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

Last change on this file was 99422, checked in by vboxsync, 13 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
Line 
1/* $Id: strformatrt.cpp 99422 2023-04-17 15:18:33Z vboxsync $ */
2/** @file
3 * IPRT - IPRT String Formatter Extensions.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
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 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
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
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.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_STRING
42#include <iprt/string.h>
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
47#include "internal/iprt.h"
48
49#include <iprt/log.h>
50#include <iprt/assert.h>
51#include <iprt/string.h>
52#include <iprt/stdarg.h>
53#ifdef IN_RING3
54# include <iprt/errcore.h>
55# include <iprt/thread.h>
56# include <iprt/utf16.h>
57#endif
58#include <iprt/ctype.h>
59#include <iprt/time.h>
60#include <iprt/net.h>
61#include <iprt/path.h>
62#include <iprt/asm.h>
63#define STRFORMAT_WITH_X86
64#ifdef STRFORMAT_WITH_X86
65# include <iprt/x86.h>
66#endif
67#include "internal/string.h"
68
69
70/*********************************************************************************************************************************
71* Global Variables *
72*********************************************************************************************************************************/
73static char g_szHexDigits[17] = "0123456789abcdef";
74#ifdef IN_RING3
75static char g_szHexDigitsUpper[17] = "0123456789ABCDEF";
76#endif
77
78
79/**
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 {
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();
102 case 1: pszDst[off++] = g_szHexDigits[(uWord >> 0) & 0xf];
103 break;
104 }
105 pszDst[off] = '\0';
106 return off;
107}
108
109
110/**
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{
120 size_t cch; /* result */
121 bool fEmbeddedIpv4;
122 size_t cwHexPart;
123 size_t cwLongestZeroRun;
124 size_t iLongestZeroStart;
125 size_t idx;
126 char szHexWord[8];
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);
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) )
143 || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0x0000ffff)
144 || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0xffff0000) ) )
145 {
146 fEmbeddedIpv4 = true;
147 cwHexPart -= 2;
148 }
149
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)
157 {
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)
165 {
166 cwLongestZeroRun = cwZeroRun;
167 iLongestZeroStart = iZeroStart;
168 if (cwZeroRun >= cwHexPart - idx)
169 break;
170 }
171 }
172
173 /*
174 * Do the formatting.
175 */
176 cch = 0;
177 if (cwLongestZeroRun == 0)
178 {
179 for (idx = 0; idx < cwHexPart; ++idx)
180 {
181 if (idx > 0)
182 cch += pfnOutput(pvArgOutput, ":", 1);
183 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
184 }
185
186 if (fEmbeddedIpv4)
187 cch += pfnOutput(pvArgOutput, ":", 1);
188 }
189 else
190 {
191 const size_t iLongestZeroEnd = iLongestZeroStart + cwLongestZeroRun;
192
193 if (iLongestZeroStart == 0)
194 cch += pfnOutput(pvArgOutput, ":", 1);
195 else
196 for (idx = 0; idx < iLongestZeroStart; ++idx)
197 {
198 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
199 cch += pfnOutput(pvArgOutput, ":", 1);
200 }
201
202 if (iLongestZeroEnd == cwHexPart)
203 cch += pfnOutput(pvArgOutput, ":", 1);
204 else
205 {
206 for (idx = iLongestZeroEnd; idx < cwHexPart; ++idx)
207 {
208 cch += pfnOutput(pvArgOutput, ":", 1);
209 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
210 }
211
212 if (fEmbeddedIpv4)
213 cch += pfnOutput(pvArgOutput, ":", 1);
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
229/**
230 * Callback to format iprt formatting extentions.
231 * See @ref pg_rt_str_format for a reference on the format types.
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 */
244DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
245 int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
246{
247 const char *pszFormatOrg = *ppszFormat;
248 char ch = *(*ppszFormat)++;
249 size_t cch;
250 char szBuf[80];
251
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':
263 case 'R':
264 case 'C':
265 case 'I':
266 case 'X':
267 case 'U':
268 case 'K':
269 {
270 /*
271 * Interpret the type.
272 */
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,
284 RTSF_NETADDR,
285 RTSF_UUID,
286 RTSF_ERRINFO,
287 RTSF_ERRINFO_MSG_ONLY
288 } RTSF;
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
302 { STRMEM("Ci"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
303 { STRMEM("Cp"), sizeof(RTCCPHYS), 16, RTSF_INTW, 0 },
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 },
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 },
316 { STRMEM("Hr"), sizeof(RTHCUINTREG), 16, RTSF_INTW, 0 },
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 },
324 { STRMEM("Kv"), sizeof(RTHCPTR), 16, RTSF_INT, RTSTR_F_OBFUSCATE_PTR },
325 { STRMEM("Rv"), sizeof(RTRCPTR), 16, RTSF_INTW, 0 },
326 { STRMEM("Tbool"), sizeof(bool), 10, RTSF_BOOL, 0 },
327 { STRMEM("Teic"), sizeof(PCRTERRINFO), 16, RTSF_ERRINFO, 0 },
328 { STRMEM("Teim"), sizeof(PCRTERRINFO), 16, RTSF_ERRINFO_MSG_ONLY, 0 },
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 },
340 { STRMEM("Tmac"), sizeof(PCRTMAC), 16, RTSF_MAC, 0 },
341 { STRMEM("Tnaddr"), sizeof(PCRTNETADDR), 10, RTSF_NETADDR,0 },
342 { STRMEM("Tnaipv4"), sizeof(RTNETADDRIPV4), 10, RTSF_IPV4, 0 },
343 { STRMEM("Tnaipv6"), sizeof(PCRTNETADDRIPV6),16, RTSF_IPV6, 0 },
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 },
347 { STRMEM("Treg"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
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 };
368
369 const char *pszType = *ppszFormat - 1;
370 int iStart = 0;
371 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
372 int i = RT_ELEMENTS(s_aTypes) / 2;
373
374 union
375 {
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;
384 RTR0INTPTR uR0Ptr;
385 RTFAR16 fp16;
386 RTFAR32 fp32;
387 RTFAR64 fp64;
388 bool fBool;
389 PCRTMAC pMac;
390 RTNETADDRIPV4 Ipv4Addr;
391 PCRTNETADDRIPV6 pIpv6Addr;
392 PCRTNETADDR pNetAddr;
393 PCRTUUID pUuid;
394 PCRTERRINFO pErrInfo;
395 } u;
396
397 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
398 RT_NOREF_PV(chArgSize);
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 */
435 RT_ZERO(u);
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
493#ifndef DEBUG
494 /*
495 * For now don't show the address.
496 */
497 if (fFlags & RTSTR_F_OBFUSCATE_PTR)
498 {
499 cch = rtStrFormatKernelAddress(szBuf, sizeof(szBuf), u.uR0Ptr, cchWidth, cchPrecision, fFlags);
500 return pfnOutput(pvArgOutput, szBuf, cch);
501 }
502#endif
503
504 /*
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
528 case RTSF_BOOL:
529 {
530 static const char s_szTrue[] = "true ";
531 static const char s_szFalse[] = "false";
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));
534 if (u.u64 == 0)
535 return pfnOutput(pvArgOutput, s_szFalse, sizeof(s_szFalse) - 1);
536 /* invalid boolean value */
537 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "!%lld!", u.u64);
538 }
539
540 case RTSF_FP16:
541 {
542 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
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 {
553 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
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 {
564 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
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
574 case RTSF_IPV4:
575 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
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:
583 if (RT_VALID_PTR(u.pIpv6Addr))
584 return rtstrFormatIPv6(pfnOutput, pvArgOutput, u.pIpv6Addr);
585 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, u.pIpv6Addr,
586 szBuf, RT_STR_TUPLE("!BadIPv6"));
587
588 case RTSF_MAC:
589 if (RT_VALID_PTR(u.pMac))
590 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
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]);
598 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, u.pMac,
599 szBuf, RT_STR_TUPLE("!BadMac"));
600
601 case RTSF_NETADDR:
602 if (RT_VALID_PTR(u.pNetAddr))
603 {
604 switch (u.pNetAddr->enmType)
605 {
606 case RTNETADDRTYPE_IPV4:
607 if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
608 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
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]);
614 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
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)
624 return rtstrFormatIPv6(pfnOutput, pvArgOutput, &u.pNetAddr->uAddr.IPv6);
625
626 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
627 "[%RTnaipv6]:%u",
628 &u.pNetAddr->uAddr.IPv6,
629 u.pNetAddr->uPort);
630
631 case RTNETADDRTYPE_MAC:
632 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
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:
642 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
643 "unsupported-netaddr-type=%u", u.pNetAddr->enmType);
644
645 }
646 }
647 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, u.pNetAddr,
648 szBuf, RT_STR_TUPLE("!BadNetAddr"));
649
650 case RTSF_UUID:
651 if (RT_VALID_PTR(u.pUuid))
652 /* cannot call RTUuidToStr because of GC/R0. */
653 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
654 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
655 RT_H2LE_U32(u.pUuid->Gen.u32TimeLow),
656 RT_H2LE_U16(u.pUuid->Gen.u16TimeMid),
657 RT_H2LE_U16(u.pUuid->Gen.u16TimeHiAndVersion),
658 u.pUuid->Gen.u8ClockSeqHiAndReserved,
659 u.pUuid->Gen.u8ClockSeqLow,
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]);
666 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, u.pUuid,
667 szBuf, RT_STR_TUPLE("!BadUuid"));
668
669 case RTSF_ERRINFO:
670 case RTSF_ERRINFO_MSG_ONLY:
671 if (RT_VALID_PTR(u.pErrInfo) && RTErrInfoIsSet(u.pErrInfo))
672 {
673 cch = 0;
674 if (s_aTypes[i].enmFormat == RTSF_ERRINFO)
675 {
676#ifdef IN_RING3 /* we don't want this anywhere else yet. */
677 cch += RTErrFormatMsgShort(u.pErrInfo->rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
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(": "));
689 cch += pfnOutput(pvArgOutput, u.pErrInfo->pszMsg,
690 RTStrNLen(u.pErrInfo->pszMsg, u.pErrInfo->cbMsg));
691 }
692 return cch;
693 }
694 return 0;
695
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 /*
711 * Base name printing, big endian UTF-16.
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 *);
721 if (!RT_VALID_PTR(psz))
722 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, psz,
723 szBuf, RT_STR_TUPLE("!BadBaseName"));
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
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
782 szBuf[0] = (char)(*pwszStr++ >> 8);
783 cch += pfnOutput(pvArgOutput, szBuf, 1);
784#endif
785 }
786 while (--cchWidth >= 0)
787 cch += pfnOutput(pvArgOutput, " ", 1);
788 return cch;
789 }
790 RT_FALL_THRU();
791
792 default:
793 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
794 break;
795 }
796 break;
797 }
798
799
800 /*
801 * Pretty function / method name printing.
802 */
803 case 'f':
804 {
805 switch (*(*ppszFormat)++)
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 *);
816 int cAngle = 0;
817
818 if (!RT_VALID_PTR(psz))
819 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, psz,
820 szBuf, RT_STR_TUPLE("!BadFnNm"));
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++;
829 if (ch && cAngle == 0)
830 pszStart = psz;
831 }
832 else if (ch == '(')
833 break;
834 else if (ch == '<')
835 {
836 cAngle++;
837 psz++;
838 }
839 else if (ch == '>')
840 {
841 cAngle--;
842 psz++;
843 }
844 else
845 psz++;
846 }
847
848 return pfnOutput(pvArgOutput, pszStart, psz - pszStart);
849 }
850
851 default:
852 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
853 break;
854 }
855 break;
856 }
857
858
859 /*
860 * hex dumping, COM/XPCOM, human readable sizes.
861 */
862 case 'h':
863 {
864 ch = *(*ppszFormat)++;
865 switch (ch)
866 {
867 /*
868 * Hex stuff.
869 */
870 case 'x':
871 case 'X':
872 {
873 uint8_t *pu8 = va_arg(*pArgs, uint8_t *);
874 uint64_t uMemAddr;
875 int cchMemAddrWidth;
876
877 if (cchPrecision < 0)
878 cchPrecision = 16;
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
891 if (pu8)
892 {
893 switch (*(*ppszFormat)++)
894 {
895 /*
896 * Regular hex dump.
897 */
898 case 'd':
899 {
900 int off = 0;
901 cch = 0;
902
903 if (cchWidth <= 0)
904 cchWidth = 16;
905
906 while (off < cchPrecision)
907 {
908 int i;
909 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*llx/%04x:",
910 off ? "\n" : "", cchMemAddrWidth, uMemAddr + off, off);
911 for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
912 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
913 off + i < cchPrecision ? !(i & 7) && i ? "-%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 /* next */
927 pu8 += cchWidth;
928 off += cchWidth;
929 }
930 return cch;
931 }
932
933 /*
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 {
959 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "\n%.*s **** <ditto x %u>",
960 cchMemAddrWidth, "****************", cDuplicates);
961 cDuplicates = 0;
962 }
963
964 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*llx/%04x:",
965 off ? "\n" : "", cchMemAddrWidth, uMemAddr + off, off);
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 /*
993 * Hex string.
994 * The default separator is ' ', RTSTR_F_THOUSAND_SEP changes it to ':',
995 * and RTSTR_F_SPECIAL removes it.
996 */
997 case 's':
998 {
999 if (cchPrecision-- > 0)
1000 {
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++);
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);
1015 return cch;
1016 }
1017 break;
1018 }
1019
1020 default:
1021 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1022 break;
1023 }
1024 }
1025 else
1026 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
1027 break;
1028 }
1029
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);
1039# ifndef RT_OS_WINDOWS
1040 PCRTCOMERRMSG pMsg = RTErrCOMGet(hrc);
1041# endif
1042 switch (*(*ppszFormat)++)
1043 {
1044# ifdef RT_OS_WINDOWS
1045 case 'c':
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':
1053 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
1054 case 'f':
1055 return pfnOutput(pvArgOutput, pMsg->pszMsgFull, strlen(pMsg->pszMsgFull));
1056 case 'a':
1057 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, hrc, pMsg->pszMsgFull);
1058# endif /* !RT_OS_WINDOWS */
1059 default:
1060 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1061 return 0;
1062 }
1063 break;
1064 }
1065#endif /* IN_RING3 */
1066
1067 /*
1068 * Human readable sizes.
1069 */
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)++;
1079 AssertMsgReturn(ch2 == 'b' || ch2 == 'B' || ch2 == 'i', ("invalid type '%.10s'!\n", pszFormatOrg), 0);
1080 uValue = va_arg(*pArgs, uint64_t);
1081
1082 if (!(fFlags & RTSTR_F_PRECISION))
1083 cchPrecision = 1; /** @todo default to flexible decimal point. */
1084 else if (cchPrecision > 3)
1085 cchPrecision = 3;
1086 else if (cchPrecision < 0)
1087 cchPrecision = 0;
1088
1089 if (ch2 == 'b' || ch2 == 'B')
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 },
1104 { "Ki", 10, _1K, _1K*2 },
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), },
1135 { "k", UINT64_C(1000), UINT64_C(1010), },
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 }
1165 if (fFlags & RTSTR_F_BLANK)
1166 szBuf[cchBuf++] = ' ';
1167 szBuf[cchBuf++] = *pszPrefix++;
1168 if (*pszPrefix && ch2 != 'B')
1169 szBuf[cchBuf++] = *pszPrefix;
1170 }
1171 else if (fFlags & RTSTR_F_BLANK)
1172 szBuf[cchBuf++] = ' ';
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
1188 default:
1189 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1190 return 0;
1191
1192 }
1193 break;
1194 }
1195
1196 /*
1197 * iprt status code: %Rrc, %Rrs, %Rrf, %Rra.
1198 */
1199 case 'r':
1200 {
1201 int rc = va_arg(*pArgs, int);
1202#ifdef IN_RING3 /* we don't want this anywhere else yet. */
1203 switch (*(*ppszFormat)++)
1204 {
1205 case 'c':
1206 return RTErrFormatDefine(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1207 case 's':
1208 return RTErrFormatMsgShort(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1209 case 'f':
1210 return RTErrFormatMsgFull(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1211 case 'a':
1212 return RTErrFormatMsgAll(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1213 default:
1214 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1215 return 0;
1216 }
1217#else /* !IN_RING3 */
1218 switch (*(*ppszFormat)++)
1219 {
1220 case 'c':
1221 case 's':
1222 case 'f':
1223 case 'a':
1224 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%d", rc);
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);
1240 switch (*(*ppszFormat)++)
1241 {
1242# if defined(RT_OS_WINDOWS)
1243 case 'c':
1244 return RTErrWinFormatDefine(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1245 case 'f':
1246 return RTErrWinFormatMsg(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1247 case 'a':
1248 return RTErrWinFormatMsgAll(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1249# else /* !RT_OS_WINDOWS */
1250 case 'c':
1251 case 'f':
1252 case 'a':
1253 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "0x%08x", rc);
1254# endif /* !RT_OS_WINDOWS */
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 */
1276#define RTST_FLAGS_POINTER RT_BIT(0)
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
1289 { STRMEM("Dtimespec"), sizeof(PCRTTIMESPEC), RTST_FLAGS_POINTER, RTST_TIMESPEC},
1290#undef STRMEM
1291 };
1292 const char *pszType = *ppszFormat - 1;
1293 int iStart = 0;
1294 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
1295 int i = RT_ELEMENTS(s_aTypes) / 2;
1296
1297 union
1298 {
1299 const void *pv;
1300 uint64_t u64;
1301 PCRTTIMESPEC pTimeSpec;
1302 } u;
1303
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 */
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"));
1352
1353 /*
1354 * Format the output.
1355 */
1356 switch (s_aTypes[i].enmType)
1357 {
1358 case RTST_TIMESPEC:
1359 return RTStrFormat(pfnOutput, pvArgOutput, NULL, NULL, "%'lld ns", RTTimeSpecGetNano(u.pTimeSpec));
1360
1361 default:
1362 AssertMsgFailed(("Invalid/unhandled enmType=%d\n", s_aTypes[i].enmType));
1363 break;
1364 }
1365 break;
1366 }
1367
1368#ifdef IN_RING3
1369
1370 /*
1371 * Group 5, XML / HTML, JSON and URI escapers.
1372 */
1373 case 'M':
1374 {
1375 char chWhat = (*ppszFormat)[0];
1376 if (chWhat == 'a' || chWhat == 'e')
1377 {
1378 /* XML attributes and element values. */
1379 bool fAttr = chWhat == 'a';
1380 char chType = (*ppszFormat)[1];
1381 *ppszFormat += 2;
1382 switch (chType)
1383 {
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;
1395
1396 if (!RT_VALID_PTR(pszStr))
1397 pszStr = "<NULL>";
1398 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1399
1400 if (fAttr)
1401 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1402 if (!(fFlags & RTSTR_F_LEFT))
1403 while (--cchWidth >= cchStr)
1404 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1405
1406 offLast = offCur = 0;
1407 while (offCur < cchStr)
1408 {
1409 if (memchr(pszEscape, pszStr[offCur], cchEscape))
1410 {
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;
1426 }
1427 offCur++;
1428 }
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;
1437 }
1438
1439 default:
1440 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1441 }
1442 }
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
1458 if (!RT_VALID_PTR(pszStr))
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 }
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;
1537 AssertMsgBreak(chVariant == 'a' || chVariant == 'p' || chVariant == 'q' || chVariant == 'f',
1538 ("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1539
1540 if (!RT_VALID_PTR(pszStr))
1541 pszStr = "<NULL>";
1542 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1543
1544 if (!(fFlags & RTSTR_F_LEFT))
1545 while (--cchWidth >= cchStr)
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 }
1576 }
1577 if (offLast < offCur)
1578 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1579
1580 while (--cchWidth >= cchStr)
1581 cchOutput += pfnOutput(pvArgOutput, "%20", 3);
1582 }
1583 else
1584 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1585 break;
1586 }
1587
1588#endif /* IN_RING3 */
1589
1590 /*
1591 * Groups 6 - CPU Architecture Register Formatters.
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 { \
1620 if (!cPrinted++) \
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 { \
1631 cchOutput += pfnOutput(pvArgOutput, !cPrinted ? "{unkn=" : ",unkn=", 6); \
1632 cch = RTStrFormatNumber(&szBuf[0], (a_uVal), 16, 1, -1, fFlags); \
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;
1656 cch = RTStrFormatNumber(&szBuf[0], cr0, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
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;
1675 cch = RTStrFormatNumber(&szBuf[0], cr4, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
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");
1686 REG_OUT_BIT(cr4, X86_CR4_OSFXSR, "OSFXSR");
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");
1692 REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
1693 REG_OUT_BIT(cr4, X86_CR4_SMAP, "SMAP");
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 /*
1709 * Invalid/Unknown. Bitch about it.
1710 */
1711 default:
1712 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1713 break;
1714 }
1715 }
1716 else
1717 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
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