/* $Id$ */
/** @file
* IPRT - IPRT String Formatter Extensions.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifndef RT_NO_EXPORT_SYMBOL
slurps arch-specific headers defining symbols */
#endif
#ifdef IN_RING3
#endif
#define STRFORMAT_WITH_X86
#ifdef STRFORMAT_WITH_X86
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/**
* Helper that formats a 16-bit hex word in a IPv6 address.
*
* @returns Length in chars.
* @param pszDst The output buffer. Written from the start.
* @param uWord The word to format as hex.
*/
{
else
off = 0;
switch (cDigits)
{
break;
}
return off;
}
/**
* Helper function to format IPv6 address according to RFC 5952.
*
* @returns The number of bytes formatted.
* @param pfnOutput Pointer to output function.
* @param pvArgOutput Argument for the output function.
* @param pIpv6Addr IPv6 address
*/
static size_t rtstrFormatIPv6(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PCRTNETADDRIPV6 pIpv6Addr)
{
bool fEmbeddedIpv4;
/*
* Check for embedded IPv4 address.
*
* IPv4-compatible - ::11.22.33.44 (obsolete)
* IPv4-mapped - ::ffff:11.22.33.44
* IPv4-translated - ::ffff:0:11.22.33.44 (RFC 2765)
*/
fEmbeddedIpv4 = false;
{
fEmbeddedIpv4 = true;
cwHexPart -= 2;
}
/*
* Find the longest sequences of two or more zero words.
*/
cwLongestZeroRun = 0;
iLongestZeroStart = 0;
{
do
idx++;
{
break;
}
}
/*
* Do the formatting.
*/
cch = 0;
if (cwLongestZeroRun == 0)
{
{
if (idx > 0)
cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
}
if (fEmbeddedIpv4)
}
else
{
if (iLongestZeroStart == 0)
else
{
cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
}
if (iLongestZeroEnd == cwHexPart)
else
{
{
cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
}
if (fEmbeddedIpv4)
}
}
if (fEmbeddedIpv4)
"%u.%u.%u.%u",
return cch;
}
/**
* Callback to format iprt formatting extentions.
* See @ref pg_rt_str_format for a reference on the format types.
*
* @returns The number of bytes formatted.
* @param pfnOutput Pointer to output function.
* @param pvArgOutput Argument for the output function.
* @param ppszFormat Pointer to the format string pointer. Advance this till the char
* after the format specifier.
* @param pArgs Pointer to the argument list. Use this to fetch the arguments.
* @param cchWidth Format Width. -1 if not specified.
* @param cchPrecision Format Precision. -1 if not specified.
* @param fFlags Flags (RTSTR_NTFS_*).
* @param chArgSize The argument size specifier, 'l' or 'L'.
*/
DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
{
if (ch == 'R')
{
ch = *(*ppszFormat)++;
switch (ch)
{
/*
* Groups 1 and 2.
*/
case 'T':
case 'G':
case 'H':
case 'R':
case 'C':
case 'I':
case 'X':
case 'U':
{
/*
* Interpret the type.
*/
typedef enum
{
} RTSF;
static const struct
{
}
/** Sorted array of types, looked up using binary search! */
s_aTypes[] =
{
};
int iStart = 0;
union
{
bool fBool;
} u;
/*
* Lookup the type - binary search.
*/
for (;;)
{
if (!iDiff)
break;
{
return 0;
}
if (iDiff < 0)
iEnd = i - 1;
else
iStart = i + 1;
{
return 0;
}
}
/*
* Advance the format string and merge flags.
*/
/*
* Fetch the argument.
* It's important that a signed value gets sign-extended up to 64-bit.
*/
RT_ZERO(u);
if (fFlags & RTSTR_F_VALSIGNED)
{
{
case sizeof(int8_t):
fFlags |= RTSTR_F_8BIT;
break;
case sizeof(int16_t):
fFlags |= RTSTR_F_16BIT;
break;
case sizeof(int32_t):
fFlags |= RTSTR_F_32BIT;
break;
case sizeof(int64_t):
fFlags |= RTSTR_F_64BIT;
break;
default:
break;
}
}
else
{
{
case sizeof(uint8_t):
fFlags |= RTSTR_F_8BIT;
break;
case sizeof(uint16_t):
fFlags |= RTSTR_F_16BIT;
break;
case sizeof(uint32_t):
fFlags |= RTSTR_F_32BIT;
break;
case sizeof(uint64_t):
fFlags |= RTSTR_F_64BIT;
break;
case sizeof(RTFAR32):
break;
case sizeof(RTFAR64):
break;
default:
break;
}
}
/*
* Format the output.
*/
{
case RTSF_INT:
{
break;
}
/* hex which defaults to max width. */
case RTSF_INTW:
{
if (cchWidth < 0)
{
}
break;
}
case RTSF_BOOL:
{
if (u.u64 == 1)
if (u.u64 == 0)
/* invalid boolean value */
}
case RTSF_FP16:
{
fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
break;
}
case RTSF_FP32:
{
fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
break;
}
case RTSF_FP64:
{
fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
break;
}
case RTSF_IPV4:
"%u.%u.%u.%u",
case RTSF_IPV6:
{
}
case RTSF_MAC:
{
"%02x:%02x:%02x:%02x:%02x:%02x",
}
case RTSF_NETADDR:
{
{
{
case RTNETADDRTYPE_IPV4:
"%u.%u.%u.%u",
"%u.%u.%u.%u:%u",
case RTNETADDRTYPE_IPV6:
"[%RTnaipv6]:%u",
case RTNETADDRTYPE_MAC:
"%02x:%02x:%02x:%02x:%02x:%02x",
default:
}
}
}
case RTSF_UUID:
{
{
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
}
}
default:
return 0;
}
/*
* Finally, output the formatted string and return.
*/
}
/* Group 3 */
/*
* Base name printing.
*/
case 'b':
{
switch (*(*ppszFormat)++)
{
case 'n':
{
const char *pszLastSep;
{
if (RTPATH_IS_SEP(ch))
{
do
psz++;
if (!ch)
break;
pszLastSep = psz;
}
psz++;
}
}
default:
break;
}
break;
}
/*
* Pretty function / method name printing.
*/
case 'f':
{
switch (*(*ppszFormat)++)
{
/*
* Pretty function / method name printing.
* This isn't 100% right (see classic signal prototype) and it assumes
* standardized names, but it'll do for today.
*/
case 'n':
{
const char *pszStart;
{
if (RT_C_IS_BLANK(ch))
{
psz++;
psz++;
if (ch)
}
else if (ch == '(')
break;
else
psz++;
}
}
default:
break;
}
break;
}
/*
*/
case 'h':
{
switch (*(*ppszFormat)++)
{
/*
* Hex stuff.
*/
case 'x':
{
if (cchPrecision < 0)
cchPrecision = 16;
if (pu8)
{
switch (*(*ppszFormat)++)
{
/*
* Regular hex dump.
*/
case 'd':
{
int off = 0;
cch = 0;
if (cchWidth <= 0)
cchWidth = 16;
while (off < cchPrecision)
{
int i;
cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
while (i++ < cchWidth)
{
}
/* next */
}
return cch;
}
/*
* Hex string.
*/
case 's':
{
if (cchPrecision-- > 0)
{
return cch;
}
break;
}
default:
break;
}
}
else
break;
}
#ifdef IN_RING3
/*
* XPCOM / COM status code: %Rhrc, %Rhrf, %Rhra
* ASSUMES: If Windows Then COM else XPCOM.
*/
case 'r':
{
switch (*(*ppszFormat)++)
{
case 'c':
case 'f':
case 'a':
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, hrc, pMsg->pszMsgFull);
default:
return 0;
}
break;
}
#endif /* IN_RING3 */
default:
return 0;
}
break;
}
/*
* iprt status code: %Rrc, %Rrs, %Rrf, %Rra.
*/
case 'r':
{
#ifdef IN_RING3 /* we don't want this anywhere else yet. */
switch (*(*ppszFormat)++)
{
case 'c':
case 's':
case 'f':
case 'a':
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (%d) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
default:
return 0;
}
#else /* !IN_RING3 */
switch (*(*ppszFormat)++)
{
case 'c':
case 's':
case 'f':
case 'a':
default:
return 0;
}
#endif /* !IN_RING3 */
break;
}
#if defined(IN_RING3)
/*
* Windows status code: %Rwc, %Rwf, %Rwa
*/
case 'w':
{
# if defined(RT_OS_WINDOWS)
# endif
switch (*(*ppszFormat)++)
{
# if defined(RT_OS_WINDOWS)
case 'c':
case 'f':
case 'a':
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
# else
case 'c':
case 'f':
case 'a':
# endif
default:
return 0;
}
break;
}
#endif /* IN_RING3 */
/*
* Group 4, structure dumpers.
*/
case 'D':
{
/*
* Interpret the type.
*/
typedef enum
{
} RTST;
/** Set if it's a pointer */
static const struct
{
}
/** Sorted array of types, looked up using binary search! */
s_aTypes[] =
{
};
int iStart = 0;
union
{
const void *pv;
} u;
/*
* Lookup the type - binary search.
*/
for (;;)
{
if (!iDiff)
break;
{
return 0;
}
if (iDiff < 0)
iEnd = i - 1;
else
iStart = i + 1;
{
return 0;
}
}
/*
* Fetch the argument.
*/
u.u64 = 0;
{
case sizeof(const void *):
break;
default:
break;
}
/*
* If it's a pointer, we'll check if it's valid before going on.
*/
/*
* Format the output.
*/
{
case RTST_TIMESPEC:
default:
break;
}
break;
}
#ifdef IN_RING3
/*
* Group 5, XML / HTML escapers.
*/
case 'M':
{
AssertMsgBreak(chWhat == 'a' || chWhat == 'e', ("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
*ppszFormat += 2;
switch (chType)
{
case 's':
{
pszStr = "<NULL>";
if (fAttr)
if (!(fFlags & RTSTR_F_LEFT))
{
{
{
default:
AssertFailed();
}
}
offCur++;
}
if (fAttr)
return cchOutput;
}
default:
}
break;
}
#endif /* IN_RING3 */
/*
* Groups 6 - CPU Architecture Register Formatters.
* "%RAarch[reg]"
*/
case 'A':
{
int cPrinted = 0;
/* Parse out the */
{ /* nothing */ }
AssertMsgBreak(ch == '[', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
cchReg = 0;
cchReg++;
AssertMsgBreak(ch == ']', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
#define REG_EQUALS(a_szReg) (sizeof(a_szReg) - 1 == cchReg && !strncmp(a_szReg, pszReg, sizeof(a_szReg) - 1))
do { \
if ((a_uVal) & (a_fBitMask)) \
{ \
if (!cPrinted++) \
else \
(a_uVal) &= ~(a_fBitMask); \
} \
} while (0)
do { \
if ((a_uVal)) \
{ \
cPrinted++; \
} \
if (cPrinted) \
} while (0)
if (0)
{ /* dummy */ }
#ifdef STRFORMAT_WITH_X86
/*
* X86 & AMD64.
*/
&& pszArch[0] == 'x'
{
if (REG_EQUALS("cr0"))
{
fFlags |= RTSTR_F_64BIT;
}
else if (REG_EQUALS("cr4"))
{
fFlags |= RTSTR_F_64BIT;
}
else
}
#endif
else
return cchOutput;
}
/*
*/
default:
break;
}
}
else
return 0;
}