VirtualBox

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

Last change on this file since 34079 was 33496, checked in by vboxsync, 14 years ago

iprt/string.h: Moved the string format docs to the header so it is easier to find.

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