VirtualBox

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

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

build fix (2nd try)

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