VirtualBox

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

Last change on this file since 30080 was 29963, checked in by vboxsync, 15 years ago

Runtime: Swapped width and precision for Rhxd/Rhsx format specifiers to match the callers.

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

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