VirtualBox

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

最後變更 在這個檔案從28800是 28800,由 vboxsync 提交於 15 年 前

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette