VirtualBox

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

Last change on this file since 37242 was 36555, checked in by vboxsync, 14 years ago

Use DECLHIDDEN, especially in IPRT.

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