VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 79.3 KB
Line 
1/* $Id: strformatrt.cpp 98103 2023-01-17 14:15:46Z 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, u.pErrInfo->cbMsg);
690 }
691 return cch;
692 }
693 return 0;
694
695 default:
696 AssertMsgFailed(("Internal error %d\n", s_aTypes[i].enmFormat));
697 return 0;
698 }
699
700 /*
701 * Finally, output the formatted string and return.
702 */
703 return pfnOutput(pvArgOutput, szBuf, cch);
704 }
705
706
707 /* Group 3 */
708
709 /*
710 * Base name printing, big endian UTF-16.
711 */
712 case 'b':
713 {
714 switch (*(*ppszFormat)++)
715 {
716 case 'n':
717 {
718 const char *pszLastSep;
719 const char *psz = pszLastSep = va_arg(*pArgs, const char *);
720 if (!RT_VALID_PTR(psz))
721 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, psz,
722 szBuf, RT_STR_TUPLE("!BadBaseName"));
723
724 while ((ch = *psz) != '\0')
725 {
726 if (RTPATH_IS_SEP(ch))
727 {
728 do
729 psz++;
730 while ((ch = *psz) != '\0' && RTPATH_IS_SEP(ch));
731 if (!ch)
732 break;
733 pszLastSep = psz;
734 }
735 psz++;
736 }
737
738 return pfnOutput(pvArgOutput, pszLastSep, psz - pszLastSep);
739 }
740
741 /* %lRbs */
742 case 's':
743 if (chArgSize == 'l')
744 {
745 /* utf-16BE -> utf-8 */
746 int cchStr;
747 PCRTUTF16 pwszStr = va_arg(*pArgs, PRTUTF16);
748
749 if (RT_VALID_PTR(pwszStr))
750 {
751 cchStr = 0;
752 while (cchStr < cchPrecision && pwszStr[cchStr] != '\0')
753 cchStr++;
754 }
755 else
756 {
757 static RTUTF16 s_wszBigNull[] =
758 {
759 RT_H2BE_U16_C((uint16_t)'<'), RT_H2BE_U16_C((uint16_t)'N'), RT_H2BE_U16_C((uint16_t)'U'),
760 RT_H2BE_U16_C((uint16_t)'L'), RT_H2BE_U16_C((uint16_t)'L'), RT_H2BE_U16_C((uint16_t)'>'), '\0'
761 };
762 pwszStr = s_wszBigNull;
763 cchStr = RT_ELEMENTS(s_wszBigNull) - 1;
764 }
765
766 cch = 0;
767 if (!(fFlags & RTSTR_F_LEFT))
768 while (--cchWidth >= cchStr)
769 cch += pfnOutput(pvArgOutput, " ", 1);
770 cchWidth -= cchStr;
771 while (cchStr-- > 0)
772 {
773/** @todo \#ifndef IN_RC*/
774#ifdef IN_RING3
775 RTUNICP Cp = 0;
776 RTUtf16BigGetCpEx(&pwszStr, &Cp);
777 char *pszEnd = RTStrPutCp(szBuf, Cp);
778 *pszEnd = '\0';
779 cch += pfnOutput(pvArgOutput, szBuf, pszEnd - szBuf);
780#else
781 szBuf[0] = (char)(*pwszStr++ >> 8);
782 cch += pfnOutput(pvArgOutput, szBuf, 1);
783#endif
784 }
785 while (--cchWidth >= 0)
786 cch += pfnOutput(pvArgOutput, " ", 1);
787 return cch;
788 }
789 RT_FALL_THRU();
790
791 default:
792 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
793 break;
794 }
795 break;
796 }
797
798
799 /*
800 * Pretty function / method name printing.
801 */
802 case 'f':
803 {
804 switch (*(*ppszFormat)++)
805 {
806 /*
807 * Pretty function / method name printing.
808 * This isn't 100% right (see classic signal prototype) and it assumes
809 * standardized names, but it'll do for today.
810 */
811 case 'n':
812 {
813 const char *pszStart;
814 const char *psz = pszStart = va_arg(*pArgs, const char *);
815 int cAngle = 0;
816
817 if (!RT_VALID_PTR(psz))
818 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, psz,
819 szBuf, RT_STR_TUPLE("!BadFnNm"));
820
821 while ((ch = *psz) != '\0' && ch != '(')
822 {
823 if (RT_C_IS_BLANK(ch))
824 {
825 psz++;
826 while ((ch = *psz) != '\0' && (RT_C_IS_BLANK(ch) || ch == '('))
827 psz++;
828 if (ch && cAngle == 0)
829 pszStart = psz;
830 }
831 else if (ch == '(')
832 break;
833 else if (ch == '<')
834 {
835 cAngle++;
836 psz++;
837 }
838 else if (ch == '>')
839 {
840 cAngle--;
841 psz++;
842 }
843 else
844 psz++;
845 }
846
847 return pfnOutput(pvArgOutput, pszStart, psz - pszStart);
848 }
849
850 default:
851 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
852 break;
853 }
854 break;
855 }
856
857
858 /*
859 * hex dumping, COM/XPCOM, human readable sizes.
860 */
861 case 'h':
862 {
863 ch = *(*ppszFormat)++;
864 switch (ch)
865 {
866 /*
867 * Hex stuff.
868 */
869 case 'x':
870 case 'X':
871 {
872 uint8_t *pu8 = va_arg(*pArgs, uint8_t *);
873 uint64_t uMemAddr;
874 int cchMemAddrWidth;
875
876 if (cchPrecision < 0)
877 cchPrecision = 16;
878
879 if (ch == 'x')
880 {
881 uMemAddr = (uintptr_t)pu8;
882 cchMemAddrWidth = sizeof(pu8) * 2;
883 }
884 else
885 {
886 uMemAddr = va_arg(*pArgs, uint64_t);
887 cchMemAddrWidth = uMemAddr > UINT32_MAX || uMemAddr + cchPrecision > UINT32_MAX ? 16 : 8;
888 }
889
890 if (pu8)
891 {
892 switch (*(*ppszFormat)++)
893 {
894 /*
895 * Regular hex dump.
896 */
897 case 'd':
898 {
899 int off = 0;
900 cch = 0;
901
902 if (cchWidth <= 0)
903 cchWidth = 16;
904
905 while (off < cchPrecision)
906 {
907 int i;
908 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*llx/%04x:",
909 off ? "\n" : "", cchMemAddrWidth, uMemAddr + off, off);
910 for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
911 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
912 off + i < cchPrecision ? !(i & 7) && i ? "-%02x" : " %02x" : " ",
913 pu8[i]);
914 while (i++ < cchWidth)
915 cch += pfnOutput(pvArgOutput, " ", 3);
916
917 cch += pfnOutput(pvArgOutput, " ", 1);
918
919 for (i = 0; i < cchWidth && off + i < cchPrecision; i++)
920 {
921 uint8_t u8 = pu8[i];
922 cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
923 }
924
925 /* next */
926 pu8 += cchWidth;
927 off += cchWidth;
928 }
929 return cch;
930 }
931
932 /*
933 * Regular hex dump with dittoing.
934 */
935 case 'D':
936 {
937 int offEndDupCheck;
938 int cDuplicates = 0;
939 int off = 0;
940 cch = 0;
941
942 if (cchWidth <= 0)
943 cchWidth = 16;
944 offEndDupCheck = cchPrecision - cchWidth;
945
946 while (off < cchPrecision)
947 {
948 int i;
949 if ( off >= offEndDupCheck
950 || off <= 0
951 || memcmp(pu8, pu8 - cchWidth, cchWidth) != 0
952 || ( cDuplicates == 0
953 && ( off + cchWidth >= offEndDupCheck
954 || memcmp(pu8 + cchWidth, pu8, cchWidth) != 0)) )
955 {
956 if (cDuplicates > 0)
957 {
958 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "\n%.*s **** <ditto x %u>",
959 cchMemAddrWidth, "****************", cDuplicates);
960 cDuplicates = 0;
961 }
962
963 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*llx/%04x:",
964 off ? "\n" : "", cchMemAddrWidth, uMemAddr + off, off);
965 for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
966 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
967 off + i < cchPrecision ? !(i & 7) && i
968 ? "-%02x" : " %02x" : " ",
969 pu8[i]);
970 while (i++ < cchWidth)
971 cch += pfnOutput(pvArgOutput, " ", 3);
972
973 cch += pfnOutput(pvArgOutput, " ", 1);
974
975 for (i = 0; i < cchWidth && off + i < cchPrecision; i++)
976 {
977 uint8_t u8 = pu8[i];
978 cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
979 }
980 }
981 else
982 cDuplicates++;
983
984 /* next */
985 pu8 += cchWidth;
986 off += cchWidth;
987 }
988 return cch;
989 }
990
991 /*
992 * Hex string.
993 * The default separator is ' ', RTSTR_F_THOUSAND_SEP changes it to ':',
994 * and RTSTR_F_SPECIAL removes it.
995 */
996 case 's':
997 {
998 if (cchPrecision-- > 0)
999 {
1000 if (ch == 'x')
1001 cch = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%02x", *pu8++);
1002 else
1003 cch = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%0*llx: %02x",
1004 cchMemAddrWidth, uMemAddr, *pu8++);
1005 if (!(fFlags & (RTSTR_F_SPECIAL | RTSTR_F_THOUSAND_SEP)))
1006 for (; cchPrecision > 0; cchPrecision--, pu8++)
1007 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " %02x", *pu8);
1008 else if (fFlags & RTSTR_F_SPECIAL)
1009 for (; cchPrecision > 0; cchPrecision--, pu8++)
1010 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%02x", *pu8);
1011 else
1012 for (; cchPrecision > 0; cchPrecision--, pu8++)
1013 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, ":%02x", *pu8);
1014 return cch;
1015 }
1016 break;
1017 }
1018
1019 default:
1020 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1021 break;
1022 }
1023 }
1024 else
1025 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
1026 break;
1027 }
1028
1029
1030#ifdef IN_RING3
1031 /*
1032 * XPCOM / COM status code: %Rhrc, %Rhrf, %Rhra
1033 * ASSUMES: If Windows Then COM else XPCOM.
1034 */
1035 case 'r':
1036 {
1037 uint32_t hrc = va_arg(*pArgs, uint32_t);
1038# ifndef RT_OS_WINDOWS
1039 PCRTCOMERRMSG pMsg = RTErrCOMGet(hrc);
1040# endif
1041 switch (*(*ppszFormat)++)
1042 {
1043# ifdef RT_OS_WINDOWS
1044 case 'c':
1045 return RTErrWinFormatDefine(hrc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1046 case 'f':
1047 return RTErrWinFormatMsg(hrc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1048 case 'a':
1049 return RTErrWinFormatMsgAll(hrc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1050# else /* !RT_OS_WINDOWS */
1051 case 'c':
1052 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
1053 case 'f':
1054 return pfnOutput(pvArgOutput, pMsg->pszMsgFull, strlen(pMsg->pszMsgFull));
1055 case 'a':
1056 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, hrc, pMsg->pszMsgFull);
1057# endif /* !RT_OS_WINDOWS */
1058 default:
1059 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1060 return 0;
1061 }
1062 break;
1063 }
1064#endif /* IN_RING3 */
1065
1066 /*
1067 * Human readable sizes.
1068 */
1069 case 'c':
1070 case 'u':
1071 {
1072 unsigned i;
1073 ssize_t cchBuf;
1074 uint64_t uValue;
1075 uint64_t uFraction = 0;
1076 const char *pszPrefix = NULL;
1077 char ch2 = *(*ppszFormat)++;
1078 AssertMsgReturn(ch2 == 'b' || ch2 == 'B' || ch2 == 'i', ("invalid type '%.10s'!\n", pszFormatOrg), 0);
1079 uValue = va_arg(*pArgs, uint64_t);
1080
1081 if (!(fFlags & RTSTR_F_PRECISION))
1082 cchPrecision = 1; /** @todo default to flexible decimal point. */
1083 else if (cchPrecision > 3)
1084 cchPrecision = 3;
1085 else if (cchPrecision < 0)
1086 cchPrecision = 0;
1087
1088 if (ch2 == 'b' || ch2 == 'B')
1089 {
1090 static const struct
1091 {
1092 const char *pszPrefix;
1093 uint8_t cShift;
1094 uint64_t cbMin;
1095 uint64_t cbMinZeroPrecision;
1096 } s_aUnits[] =
1097 {
1098 { "Ei", 60, _1E, _1E*2 },
1099 { "Pi", 50, _1P, _1P*2 },
1100 { "Ti", 40, _1T, _1T*2 },
1101 { "Gi", 30, _1G, _1G64*2 },
1102 { "Mi", 20, _1M, _1M*2 },
1103 { "Ki", 10, _1K, _1K*2 },
1104 };
1105 for (i = 0; i < RT_ELEMENTS(s_aUnits); i++)
1106 if ( uValue >= s_aUnits[i].cbMin
1107 && (cchPrecision > 0 || uValue >= s_aUnits[i].cbMinZeroPrecision))
1108 {
1109 if (cchPrecision != 0)
1110 {
1111 uFraction = uValue & (RT_BIT_64(s_aUnits[i].cShift) - 1);
1112 uFraction *= cchPrecision == 1 ? 10 : cchPrecision == 2 ? 100 : 1000;
1113 uFraction >>= s_aUnits[i].cShift;
1114 }
1115 uValue >>= s_aUnits[i].cShift;
1116 pszPrefix = s_aUnits[i].pszPrefix;
1117 break;
1118 }
1119 }
1120 else
1121 {
1122 static const struct
1123 {
1124 const char *pszPrefix;
1125 uint64_t cbFactor;
1126 uint64_t cbMinZeroPrecision;
1127 } s_aUnits[] =
1128 {
1129 { "E", UINT64_C(1000000000000000000), UINT64_C(1010000000000000000), },
1130 { "P", UINT64_C(1000000000000000), UINT64_C(1010000000000000), },
1131 { "T", UINT64_C(1000000000000), UINT64_C(1010000000000), },
1132 { "G", UINT64_C(1000000000), UINT64_C(1010000000), },
1133 { "M", UINT64_C(1000000), UINT64_C(1010000), },
1134 { "k", UINT64_C(1000), UINT64_C(1010), },
1135 };
1136 for (i = 0; i < RT_ELEMENTS(s_aUnits); i++)
1137 if ( uValue >= s_aUnits[i].cbFactor
1138 && (cchPrecision > 0 || uValue >= s_aUnits[i].cbMinZeroPrecision))
1139 {
1140 if (cchPrecision == 0)
1141 uValue /= s_aUnits[i].cbFactor;
1142 else
1143 {
1144 uFraction = uValue % s_aUnits[i].cbFactor;
1145 uValue = uValue / s_aUnits[i].cbFactor;
1146 uFraction *= cchPrecision == 1 ? 10 : cchPrecision == 2 ? 100 : 1000;
1147 uFraction += s_aUnits[i].cbFactor >> 1;
1148 uFraction /= s_aUnits[i].cbFactor;
1149 }
1150 pszPrefix = s_aUnits[i].pszPrefix;
1151 break;
1152 }
1153 }
1154
1155 cchBuf = RTStrFormatU64(szBuf, sizeof(szBuf), uValue, 10, 0, 0, 0);
1156 if (pszPrefix)
1157 {
1158 if (cchPrecision)
1159 {
1160 szBuf[cchBuf++] = '.';
1161 cchBuf += RTStrFormatU64(&szBuf[cchBuf], sizeof(szBuf) - cchBuf, uFraction, 10, cchPrecision, 0,
1162 RTSTR_F_ZEROPAD | RTSTR_F_WIDTH);
1163 }
1164 if (fFlags & RTSTR_F_BLANK)
1165 szBuf[cchBuf++] = ' ';
1166 szBuf[cchBuf++] = *pszPrefix++;
1167 if (*pszPrefix && ch2 != 'B')
1168 szBuf[cchBuf++] = *pszPrefix;
1169 }
1170 else if (fFlags & RTSTR_F_BLANK)
1171 szBuf[cchBuf++] = ' ';
1172 if (ch == 'c')
1173 szBuf[cchBuf++] = 'B';
1174 szBuf[cchBuf] = '\0';
1175
1176 cch = 0;
1177 if ((fFlags & RTSTR_F_WIDTH) && !(fFlags & RTSTR_F_LEFT))
1178 while (cchBuf < cchWidth)
1179 {
1180 cch += pfnOutput(pvArgOutput, fFlags & RTSTR_F_ZEROPAD ? "0" : " ", 1);
1181 cchWidth--;
1182 }
1183 cch += pfnOutput(pvArgOutput, szBuf, cchBuf);
1184 return cch;
1185 }
1186
1187 default:
1188 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1189 return 0;
1190
1191 }
1192 break;
1193 }
1194
1195 /*
1196 * iprt status code: %Rrc, %Rrs, %Rrf, %Rra.
1197 */
1198 case 'r':
1199 {
1200 int rc = va_arg(*pArgs, int);
1201#ifdef IN_RING3 /* we don't want this anywhere else yet. */
1202 switch (*(*ppszFormat)++)
1203 {
1204 case 'c':
1205 return RTErrFormatDefine(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1206 case 's':
1207 return RTErrFormatMsgShort(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1208 case 'f':
1209 return RTErrFormatMsgFull(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1210 case 'a':
1211 return RTErrFormatMsgAll(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1212 default:
1213 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1214 return 0;
1215 }
1216#else /* !IN_RING3 */
1217 switch (*(*ppszFormat)++)
1218 {
1219 case 'c':
1220 case 's':
1221 case 'f':
1222 case 'a':
1223 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%d", rc);
1224 default:
1225 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1226 return 0;
1227 }
1228#endif /* !IN_RING3 */
1229 break;
1230 }
1231
1232#if defined(IN_RING3)
1233 /*
1234 * Windows status code: %Rwc, %Rwf, %Rwa
1235 */
1236 case 'w':
1237 {
1238 long rc = va_arg(*pArgs, long);
1239 switch (*(*ppszFormat)++)
1240 {
1241# if defined(RT_OS_WINDOWS)
1242 case 'c':
1243 return RTErrWinFormatDefine(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1244 case 'f':
1245 return RTErrWinFormatMsg(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1246 case 'a':
1247 return RTErrWinFormatMsgAll(rc, pfnOutput, pvArgOutput, szBuf, sizeof(szBuf));
1248# else /* !RT_OS_WINDOWS */
1249 case 'c':
1250 case 'f':
1251 case 'a':
1252 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "0x%08x", rc);
1253# endif /* !RT_OS_WINDOWS */
1254 default:
1255 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
1256 return 0;
1257 }
1258 break;
1259 }
1260#endif /* IN_RING3 */
1261
1262 /*
1263 * Group 4, structure dumpers.
1264 */
1265 case 'D':
1266 {
1267 /*
1268 * Interpret the type.
1269 */
1270 typedef enum
1271 {
1272 RTST_TIMESPEC
1273 } RTST;
1274/** Set if it's a pointer */
1275#define RTST_FLAGS_POINTER RT_BIT(0)
1276 static const struct
1277 {
1278 uint8_t cch; /**< the length of the string. */
1279 char sz[16-2]; /**< the part following 'R'. */
1280 uint8_t cb; /**< the size of the argument. */
1281 uint8_t fFlags; /**< RTST_FLAGS_* */
1282 RTST enmType; /**< The structure type. */
1283 }
1284 /** Sorted array of types, looked up using binary search! */
1285 s_aTypes[] =
1286 {
1287#define STRMEM(str) sizeof(str) - 1, str
1288 { STRMEM("Dtimespec"), sizeof(PCRTTIMESPEC), RTST_FLAGS_POINTER, RTST_TIMESPEC},
1289#undef STRMEM
1290 };
1291 const char *pszType = *ppszFormat - 1;
1292 int iStart = 0;
1293 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
1294 int i = RT_ELEMENTS(s_aTypes) / 2;
1295
1296 union
1297 {
1298 const void *pv;
1299 uint64_t u64;
1300 PCRTTIMESPEC pTimeSpec;
1301 } u;
1302
1303 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
1304
1305 /*
1306 * Lookup the type - binary search.
1307 */
1308 for (;;)
1309 {
1310 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
1311 if (!iDiff)
1312 break;
1313 if (iEnd == iStart)
1314 {
1315 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
1316 return 0;
1317 }
1318 if (iDiff < 0)
1319 iEnd = i - 1;
1320 else
1321 iStart = i + 1;
1322 if (iEnd < iStart)
1323 {
1324 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
1325 return 0;
1326 }
1327 i = iStart + (iEnd - iStart) / 2;
1328 }
1329 *ppszFormat += s_aTypes[i].cch - 1;
1330
1331 /*
1332 * Fetch the argument.
1333 */
1334 u.u64 = 0;
1335 switch (s_aTypes[i].cb)
1336 {
1337 case sizeof(const void *):
1338 u.pv = va_arg(*pArgs, const void *);
1339 break;
1340 default:
1341 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
1342 break;
1343 }
1344
1345 /*
1346 * If it's a pointer, we'll check if it's valid before going on.
1347 */
1348 if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !RT_VALID_PTR(u.pv))
1349 return rtStrFormatBadPointer(0, pfnOutput, pvArgOutput, cchWidth, fFlags, u.pv,
1350 szBuf, RT_STR_TUPLE("!BadRD"));
1351
1352 /*
1353 * Format the output.
1354 */
1355 switch (s_aTypes[i].enmType)
1356 {
1357 case RTST_TIMESPEC:
1358 return RTStrFormat(pfnOutput, pvArgOutput, NULL, NULL, "%'lld ns", RTTimeSpecGetNano(u.pTimeSpec));
1359
1360 default:
1361 AssertMsgFailed(("Invalid/unhandled enmType=%d\n", s_aTypes[i].enmType));
1362 break;
1363 }
1364 break;
1365 }
1366
1367#ifdef IN_RING3
1368
1369 /*
1370 * Group 5, XML / HTML, JSON and URI escapers.
1371 */
1372 case 'M':
1373 {
1374 char chWhat = (*ppszFormat)[0];
1375 if (chWhat == 'a' || chWhat == 'e')
1376 {
1377 /* XML attributes and element values. */
1378 bool fAttr = chWhat == 'a';
1379 char chType = (*ppszFormat)[1];
1380 *ppszFormat += 2;
1381 switch (chType)
1382 {
1383 case 's':
1384 {
1385 static const char s_szElemEscape[] = "<>&\"'";
1386 static const char s_szAttrEscape[] = "<>&\"\n\r"; /* more? */
1387 const char * const pszEscape = fAttr ? s_szAttrEscape : s_szElemEscape;
1388 size_t const cchEscape = (fAttr ? RT_ELEMENTS(s_szAttrEscape) : RT_ELEMENTS(s_szElemEscape)) - 1;
1389 size_t cchOutput = 0;
1390 const char *pszStr = va_arg(*pArgs, char *);
1391 ssize_t cchStr;
1392 ssize_t offCur;
1393 ssize_t offLast;
1394
1395 if (!RT_VALID_PTR(pszStr))
1396 pszStr = "<NULL>";
1397 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1398
1399 if (fAttr)
1400 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1401 if (!(fFlags & RTSTR_F_LEFT))
1402 while (--cchWidth >= cchStr)
1403 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1404
1405 offLast = offCur = 0;
1406 while (offCur < cchStr)
1407 {
1408 if (memchr(pszEscape, pszStr[offCur], cchEscape))
1409 {
1410 if (offLast < offCur)
1411 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1412 switch (pszStr[offCur])
1413 {
1414 case '<': cchOutput += pfnOutput(pvArgOutput, "&lt;", 4); break;
1415 case '>': cchOutput += pfnOutput(pvArgOutput, "&gt;", 4); break;
1416 case '&': cchOutput += pfnOutput(pvArgOutput, "&amp;", 5); break;
1417 case '\'': cchOutput += pfnOutput(pvArgOutput, "&apos;", 6); break;
1418 case '"': cchOutput += pfnOutput(pvArgOutput, "&quot;", 6); break;
1419 case '\n': cchOutput += pfnOutput(pvArgOutput, "&#xA;", 5); break;
1420 case '\r': cchOutput += pfnOutput(pvArgOutput, "&#xD;", 5); break;
1421 default:
1422 AssertFailed();
1423 }
1424 offLast = offCur + 1;
1425 }
1426 offCur++;
1427 }
1428 if (offLast < offCur)
1429 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1430
1431 while (--cchWidth >= cchStr)
1432 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1433 if (fAttr)
1434 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1435 return cchOutput;
1436 }
1437
1438 default:
1439 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1440 }
1441 }
1442 else if (chWhat == 'j')
1443 {
1444 /* JSON string escaping. */
1445 char const chType = (*ppszFormat)[1];
1446 *ppszFormat += 2;
1447 switch (chType)
1448 {
1449 case 's':
1450 {
1451 const char *pszStr = va_arg(*pArgs, char *);
1452 size_t cchOutput;
1453 ssize_t cchStr;
1454 ssize_t offCur;
1455 ssize_t offLast;
1456
1457 if (!RT_VALID_PTR(pszStr))
1458 pszStr = "<NULL>";
1459 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1460
1461 cchOutput = pfnOutput(pvArgOutput, "\"", 1);
1462 if (!(fFlags & RTSTR_F_LEFT))
1463 while (--cchWidth >= cchStr)
1464 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1465
1466 offLast = offCur = 0;
1467 while (offCur < cchStr)
1468 {
1469 unsigned int const uch = pszStr[offCur];
1470 if ( uch >= 0x5d
1471 || (uch >= 0x20 && uch != 0x22 && uch != 0x5c))
1472 offCur++;
1473 else
1474 {
1475 if (offLast < offCur)
1476 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1477 switch ((char)uch)
1478 {
1479 case '"': cchOutput += pfnOutput(pvArgOutput, "\\\"", 2); break;
1480 case '\\': cchOutput += pfnOutput(pvArgOutput, "\\\\", 2); break;
1481 case '/': cchOutput += pfnOutput(pvArgOutput, "\\/", 2); break;
1482 case '\b': cchOutput += pfnOutput(pvArgOutput, "\\b", 2); break;
1483 case '\f': cchOutput += pfnOutput(pvArgOutput, "\\f", 2); break;
1484 case '\n': cchOutput += pfnOutput(pvArgOutput, "\\n", 2); break;
1485 case '\t': cchOutput += pfnOutput(pvArgOutput, "\\t", 2); break;
1486 default:
1487 {
1488 RTUNICP uc = 0xfffd; /* replacement character */
1489 const char *pszCur = &pszStr[offCur];
1490 int rc = RTStrGetCpEx(&pszCur, &uc);
1491 if (RT_SUCCESS(rc))
1492 offCur += pszCur - &pszStr[offCur] - 1;
1493 if (uc >= 0xfffe)
1494 uc = 0xfffd; /* replacement character */
1495 szBuf[0] = '\\';
1496 szBuf[1] = 'u';
1497 szBuf[2] = g_szHexDigits[(uc >> 12) & 0xf];
1498 szBuf[3] = g_szHexDigits[(uc >> 8) & 0xf];
1499 szBuf[4] = g_szHexDigits[(uc >> 4) & 0xf];
1500 szBuf[5] = g_szHexDigits[ uc & 0xf];
1501 szBuf[6] = '\0';
1502 cchOutput += pfnOutput(pvArgOutput, szBuf, 6);
1503 break;
1504 }
1505 }
1506 offLast = ++offCur;
1507 }
1508 }
1509 if (offLast < offCur)
1510 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1511
1512 while (--cchWidth >= cchStr)
1513 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1514 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1515 return cchOutput;
1516 }
1517
1518 default:
1519 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1520 }
1521 }
1522 else if (chWhat == 'p')
1523 {
1524 /* Percent encoded string (RTC-3986). */
1525 char const chVariant = (*ppszFormat)[1];
1526 char const chAddSafe = chVariant == 'p' ? '/'
1527 : chVariant == 'q' ? '+' /* '+' in queries is problematic, so no escape. */
1528 : '~' /* whatever */;
1529 size_t cchOutput = 0;
1530 const char *pszStr = va_arg(*pArgs, char *);
1531 ssize_t cchStr;
1532 ssize_t offCur;
1533 ssize_t offLast;
1534
1535 *ppszFormat += 2;
1536 AssertMsgBreak(chVariant == 'a' || chVariant == 'p' || chVariant == 'q' || chVariant == 'f',
1537 ("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1538
1539 if (!RT_VALID_PTR(pszStr))
1540 pszStr = "<NULL>";
1541 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1542
1543 if (!(fFlags & RTSTR_F_LEFT))
1544 while (--cchWidth >= cchStr)
1545 cchOutput += pfnOutput(pvArgOutput, "%20", 3);
1546
1547 offLast = offCur = 0;
1548 while (offCur < cchStr)
1549 {
1550 ch = pszStr[offCur];
1551 if ( RT_C_IS_ALPHA(ch)
1552 || RT_C_IS_DIGIT(ch)
1553 || ch == '-'
1554 || ch == '.'
1555 || ch == '_'
1556 || ch == '~'
1557 || ch == chAddSafe)
1558 offCur++;
1559 else
1560 {
1561 if (offLast < offCur)
1562 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1563 if (ch != ' ' || chVariant != 'f')
1564 {
1565 szBuf[0] = '%';
1566 szBuf[1] = g_szHexDigitsUpper[((uint8_t)ch >> 4) & 0xf];
1567 szBuf[2] = g_szHexDigitsUpper[(uint8_t)ch & 0xf];
1568 szBuf[3] = '\0';
1569 cchOutput += pfnOutput(pvArgOutput, szBuf, 3);
1570 }
1571 else
1572 cchOutput += pfnOutput(pvArgOutput, "+", 1);
1573 offLast = ++offCur;
1574 }
1575 }
1576 if (offLast < offCur)
1577 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1578
1579 while (--cchWidth >= cchStr)
1580 cchOutput += pfnOutput(pvArgOutput, "%20", 3);
1581 }
1582 else
1583 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1584 break;
1585 }
1586
1587#endif /* IN_RING3 */
1588
1589 /*
1590 * Groups 6 - CPU Architecture Register Formatters.
1591 * "%RAarch[reg]"
1592 */
1593 case 'A':
1594 {
1595 char const * const pszArch = *ppszFormat;
1596 const char *pszReg = pszArch;
1597 size_t cchOutput = 0;
1598 int cPrinted = 0;
1599 size_t cchReg;
1600
1601 /* Parse out the */
1602 while ((ch = *pszReg++) && ch != '[')
1603 { /* nothing */ }
1604 AssertMsgBreak(ch == '[', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
1605
1606 cchReg = 0;
1607 while ((ch = pszReg[cchReg]) && ch != ']')
1608 cchReg++;
1609 AssertMsgBreak(ch == ']', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
1610
1611 *ppszFormat = &pszReg[cchReg + 1];
1612
1613
1614#define REG_EQUALS(a_szReg) (sizeof(a_szReg) - 1 == cchReg && !strncmp(a_szReg, pszReg, sizeof(a_szReg) - 1))
1615#define REG_OUT_BIT(a_uVal, a_fBitMask, a_szName) \
1616 do { \
1617 if ((a_uVal) & (a_fBitMask)) \
1618 { \
1619 if (!cPrinted++) \
1620 cchOutput += pfnOutput(pvArgOutput, "{" a_szName, sizeof(a_szName)); \
1621 else \
1622 cchOutput += pfnOutput(pvArgOutput, "," a_szName, sizeof(a_szName)); \
1623 (a_uVal) &= ~(a_fBitMask); \
1624 } \
1625 } while (0)
1626#define REG_OUT_CLOSE(a_uVal) \
1627 do { \
1628 if ((a_uVal)) \
1629 { \
1630 cchOutput += pfnOutput(pvArgOutput, !cPrinted ? "{unkn=" : ",unkn=", 6); \
1631 cch = RTStrFormatNumber(&szBuf[0], (a_uVal), 16, 1, -1, fFlags); \
1632 cchOutput += pfnOutput(pvArgOutput, szBuf, cch); \
1633 cPrinted++; \
1634 } \
1635 if (cPrinted) \
1636 cchOutput += pfnOutput(pvArgOutput, "}", 1); \
1637 } while (0)
1638
1639
1640 if (0)
1641 { /* dummy */ }
1642#ifdef STRFORMAT_WITH_X86
1643 /*
1644 * X86 & AMD64.
1645 */
1646 else if ( pszReg - pszArch == 3 + 1
1647 && pszArch[0] == 'x'
1648 && pszArch[1] == '8'
1649 && pszArch[2] == '6')
1650 {
1651 if (REG_EQUALS("cr0"))
1652 {
1653 uint64_t cr0 = va_arg(*pArgs, uint64_t);
1654 fFlags |= RTSTR_F_64BIT;
1655 cch = RTStrFormatNumber(&szBuf[0], cr0, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
1656 cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
1657 REG_OUT_BIT(cr0, X86_CR0_PE, "PE");
1658 REG_OUT_BIT(cr0, X86_CR0_MP, "MP");
1659 REG_OUT_BIT(cr0, X86_CR0_EM, "EM");
1660 REG_OUT_BIT(cr0, X86_CR0_TS, "DE");
1661 REG_OUT_BIT(cr0, X86_CR0_ET, "ET");
1662 REG_OUT_BIT(cr0, X86_CR0_NE, "NE");
1663 REG_OUT_BIT(cr0, X86_CR0_WP, "WP");
1664 REG_OUT_BIT(cr0, X86_CR0_AM, "AM");
1665 REG_OUT_BIT(cr0, X86_CR0_NW, "NW");
1666 REG_OUT_BIT(cr0, X86_CR0_CD, "CD");
1667 REG_OUT_BIT(cr0, X86_CR0_PG, "PG");
1668 REG_OUT_CLOSE(cr0);
1669 }
1670 else if (REG_EQUALS("cr4"))
1671 {
1672 uint64_t cr4 = va_arg(*pArgs, uint64_t);
1673 fFlags |= RTSTR_F_64BIT;
1674 cch = RTStrFormatNumber(&szBuf[0], cr4, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
1675 cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
1676 REG_OUT_BIT(cr4, X86_CR4_VME, "VME");
1677 REG_OUT_BIT(cr4, X86_CR4_PVI, "PVI");
1678 REG_OUT_BIT(cr4, X86_CR4_TSD, "TSD");
1679 REG_OUT_BIT(cr4, X86_CR4_DE, "DE");
1680 REG_OUT_BIT(cr4, X86_CR4_PSE, "PSE");
1681 REG_OUT_BIT(cr4, X86_CR4_PAE, "PAE");
1682 REG_OUT_BIT(cr4, X86_CR4_MCE, "MCE");
1683 REG_OUT_BIT(cr4, X86_CR4_PGE, "PGE");
1684 REG_OUT_BIT(cr4, X86_CR4_PCE, "PCE");
1685 REG_OUT_BIT(cr4, X86_CR4_OSFXSR, "OSFXSR");
1686 REG_OUT_BIT(cr4, X86_CR4_OSXMMEEXCPT, "OSXMMEEXCPT");
1687 REG_OUT_BIT(cr4, X86_CR4_VMXE, "VMXE");
1688 REG_OUT_BIT(cr4, X86_CR4_SMXE, "SMXE");
1689 REG_OUT_BIT(cr4, X86_CR4_PCIDE, "PCIDE");
1690 REG_OUT_BIT(cr4, X86_CR4_OSXSAVE, "OSXSAVE");
1691 REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
1692 REG_OUT_BIT(cr4, X86_CR4_SMAP, "SMAP");
1693 REG_OUT_CLOSE(cr4);
1694 }
1695 else
1696 AssertMsgFailed(("Unknown x86 register specified in '%.10s'!\n", pszFormatOrg));
1697 }
1698#endif
1699 else
1700 AssertMsgFailed(("Unknown architecture specified in '%.10s'!\n", pszFormatOrg));
1701#undef REG_OUT_BIT
1702#undef REG_OUT_CLOSE
1703#undef REG_EQUALS
1704 return cchOutput;
1705 }
1706
1707 /*
1708 * Invalid/Unknown. Bitch about it.
1709 */
1710 default:
1711 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1712 break;
1713 }
1714 }
1715 else
1716 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1717
1718 NOREF(pszFormatOrg);
1719 return 0;
1720}
1721
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use