strformat.cpp revision 45fdb697e9030f33bf5fabea82ca7eeafab2f6af
/* $Id$ */
/** @file
* IPRT - String Formatter.
*/
/*
* Copyright (C) 2006-2007 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.
*/
/*******************************************************************************
* Defined Constants *
*******************************************************************************/
/*#define MAX(a, b) ((a) >= (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b)) */
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_STRING
#ifdef IN_RING3
#endif
/* Wrappers for converting to iprt facilities. */
#define KENDIAN_LITTLE 1
#define KENDIAN KENDIAN_LITTLE
typedef struct
{
} KSIZE64;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags);
/**
* Finds the length of a string up to cchMax.
* @returns Length.
* @param psz Pointer to string.
* @param cchMax Max length.
*/
{
psz++;
}
/**
* Finds the length of a string up to cchMax.
* @returns Length.
* @param pwsz Pointer to string.
* @param cchMax Max length.
*/
{
#ifdef IN_RING3
unsigned cwc = 0;
while (cchMax-- > 0)
{
break;
cwc++;
}
return cwc;
#else /* !IN_RING3 */
pwsz++;
#endif /* !IN_RING3 */
}
/**
* Finds the length of a string up to cchMax.
* @returns Length.
* @param pusz Pointer to string.
* @param cchMax Max length.
*/
{
pusz++;
}
/**
* Formats an integer number according to the parameters.
*
* @returns Length of the formatted number.
* @param psz Pointer to output string buffer of sufficient size.
* @param u64Value Value to format.
* @param uiBase Number representation base.
* @param cchWidth Width.
* @param cchPrecision Precision.
* @param fFlags Flags (NTFS_*).
*/
RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision,
unsigned int fFlags)
{
return rtStrFormatNumber(psz, *(KSIZE64 *)(void *)&u64Value, uiBase, cchWidth, cchPrecision, fFlags);
}
/**
* Formats an integer number according to the parameters.
*
* @returns Length of the number.
* @param psz Pointer to output string.
* @param ullValue Value. Using the high part is optional.
* @param uiBase Number representation base.
* @param cchWidth Width
* @param cchPrecision Precision.
* @param fFlags Flags (NTFS_*).
*/
static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision,
unsigned int fFlags)
{
const char *pachDigits = "0123456789abcdef";
int cchMax;
int cchValue;
unsigned long ul;
int i;
int j;
/*
* Validate and adjust input...
*/
if (fFlags & RTSTR_F_CAPITAL)
pachDigits = "0123456789ABCDEF";
if (fFlags & RTSTR_F_LEFT)
fFlags &= ~RTSTR_F_ZEROPAD;
if ( (fFlags & RTSTR_F_THOUSAND_SEP)
&& ( uiBase != 10
/*
* Determine value length
*/
cchValue = 0;
{
do
{
cchValue++;
} while (u64);
}
else
{
ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
do
{
cchValue++;
} while (ul);
}
if (fFlags & RTSTR_F_THOUSAND_SEP)
{
if (cchValue <= 3)
else
}
/*
* Sign (+/-).
*/
i = 0;
if (fFlags & RTSTR_F_VALSIGNED)
{
{
psz[i++] = '-';
}
}
/*
* Special (0/0x).
*/
{
psz[i++] = '0';
if (uiBase == 16)
}
/*
* width - only if ZEROPAD
*/
if (fFlags & RTSTR_F_ZEROPAD)
{
AssertBreak(i < cchMax);
psz[i++] = '0';
cchPrecision--;
}
{
for (j = i - 1; j >= 0; j--)
for (j = 0; j < cchWidth; j++)
psz[j] = ' ';
i += cchWidth;
}
/*
* precision
*/
while (--cchPrecision >= cchValue)
{
AssertBreak(i < cchMax);
psz[i++] = '0';
}
psz += i;
/*
* write number - not good enough but it works
*/
i = -1;
{
if (fFlags & RTSTR_F_THOUSAND_SEP)
{
do
{
if ((-i - 1) % 4 == 3)
psz[i--] = ' ';
} while (u64);
}
else
{
do
{
} while (u64);
}
}
else
{
ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
if (fFlags & RTSTR_F_THOUSAND_SEP)
{
do
{
if ((-i - 1) % 4 == 3)
psz[i--] = ' ';
} while (ul);
}
else
{
do
{
} while (ul);
}
}
/*
* width if RTSTR_F_LEFT
*/
if (fFlags & RTSTR_F_LEFT)
while (--cchWidth >= 0)
*psz++ = ' ';
*psz = '\0';
}
/**
* Partial implementation of a printf like formatter.
* It doesn't do everything correct, and there is no floating point support.
* However, it supports custom formats by the means of a format callback.
*
* @returns number of bytes formatted.
* @param pfnOutput Output worker.
* Called in two ways. Normally with a string an it's length.
* For termination, it's called with NULL for string, 0 for length.
* @param pvArgOutput Argument to the output worker.
* @param pfnFormat Custom format worker.
* @param pvArgFormat Argument to the format worker.
* @param pszFormat Format string.
* @param InArgs Argument list.
*/
RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat,
{
const char *pszStartOutput = pszFormat;
while (*pszFormat != '\0')
{
if (*pszFormat == '%')
{
/* output pending string. */
if (pszStartOutput != pszFormat)
/* skip '%' */
pszFormat++;
pszStartOutput = pszFormat++;
else
{
unsigned int fFlags = 0;
int cchWidth = -1;
int cchPrecision = -1;
unsigned int uBase = 10;
char chArgSize;
/* flags */
for (;;)
{
switch (*pszFormat++)
{
}
pszFormat--;
break;
}
/* width */
{
{
cchWidth *= 10;
}
fFlags |= RTSTR_F_WIDTH;
}
else if (*pszFormat == '*')
{
pszFormat++;
if (cchWidth < 0)
{
fFlags |= RTSTR_F_LEFT;
}
fFlags |= RTSTR_F_WIDTH;
}
/* precision */
if (*pszFormat == '.')
{
pszFormat++;
{
{
cchPrecision *= 10;
}
}
else if (*pszFormat == '*')
{
pszFormat++;
}
if (cchPrecision < 0)
cchPrecision = 0;
}
/* argsize */
if (chArgSize != 'l' && chArgSize != 'L' && chArgSize != 'h' && chArgSize != 'j' && chArgSize != 'z' && chArgSize != 't')
chArgSize = 0;
else
{
pszFormat++;
{
chArgSize = 'L';
pszFormat++;
}
{
chArgSize = 'H';
pszFormat++;
}
}
/*
* The type.
*/
switch (*pszFormat++)
{
/* char */
case 'c':
{
char ch;
if (!(fFlags & RTSTR_F_LEFT))
while (--cchWidth > 0)
while (--cchWidth > 0)
break;
}
case 'S': /* Legacy, conversion done by streams now. */
case 's':
{
if (chArgSize == 'l')
{
/* utf-16 -> utf-8 */
int cchStr;
{
}
if (!(fFlags & RTSTR_F_LEFT))
while (cchStr-- > 0)
{
/**@todo #ifndef IN_RC*/
#ifdef IN_RING3
#else
#endif
}
while (--cchWidth >= 0)
}
else if (chArgSize == 'L')
{
/* unicp -> utf8 */
int cchStr;
{
}
if (!(fFlags & RTSTR_F_LEFT))
while (cchStr-- > 0)
{
/**@todo #ifndef IN_RC*/
#ifdef IN_RING3
#else
#endif
}
while (--cchWidth >= 0)
}
else
{
int cchStr;
pszStr = "<NULL>";
if (!(fFlags & RTSTR_F_LEFT))
}
break;
}
/*-----------------*/
/*-----------------*/
case 'd':
case 'i':
case 'o':
case 'p':
case 'u':
case 'x':
case 'X':
{
int cchNum;
switch (pszFormat[-1])
{
case 'd': /* signed decimal integer */
case 'i':
break;
case 'o':
uBase = 8;
break;
case 'p':
uBase = 16;
if (cchWidth < 0)
cchWidth = sizeof(char *) * 2;
break;
case 'u':
uBase = 10;
break;
case 'X':
case 'x':
uBase = 16;
break;
}
else if (fFlags & RTSTR_F_VALSIGNED)
{
if (chArgSize == 'L')
{
fFlags |= RTSTR_F_64BIT;
}
else if (chArgSize == 'l')
{
fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
}
else if (chArgSize == 'h')
{
fFlags |= RTSTR_GET_BIT_FLAG(signed short);
}
else if (chArgSize == 'H')
{
}
else if (chArgSize == 'j')
{
fFlags |= RTSTR_F_64BIT;
}
else if (chArgSize == 'z')
{
}
else if (chArgSize == 't')
{
}
else
{
fFlags |= RTSTR_GET_BIT_FLAG(signed int);
}
}
else
{
if (chArgSize == 'L')
{
fFlags |= RTSTR_F_64BIT;
}
else if (chArgSize == 'l')
{
fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
}
else if (chArgSize == 'h')
{
fFlags |= RTSTR_GET_BIT_FLAG(unsigned short);
}
else if (chArgSize == 'H')
{
}
else if (chArgSize == 'j')
{
fFlags |= RTSTR_F_64BIT;
}
else if (chArgSize == 'z')
{
}
else if (chArgSize == 't')
{
}
else
{
fFlags |= RTSTR_GET_BIT_FLAG(unsigned int);
}
}
cchNum = RTStrFormatNumber((char *)SSToDS(&achNum), u64Value, uBase, cchWidth, cchPrecision, fFlags);
break;
}
/*
* Nested extensions.
*/
case 'M': /* replace the format string (not stacked yet). */
{
break;
}
case 'N': /* real nesting. */
{
break;
}
/*
* IPRT Extensions.
*/
case 'R':
{
if (*pszFormat != '[')
{
pszFormat--;
cch += rtstrFormatRt(pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
}
else
{
pszFormat--;
cch += rtstrFormatType(pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
}
break;
}
/*
* Custom format.
*/
default:
{
if (pfnFormat)
{
pszFormat--;
cch += pfnFormat(pvArgFormat, pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
}
break;
}
}
}
}
else
pszFormat++;
}
/* output pending string. */
if (pszStartOutput != pszFormat)
/* terminate the output */
return cch;
}
/**
* Partial implementation of a printf like formatter.
* It doesn't do everything correct, and there is no floating point support.
* However, it supports custom formats by the means of a format callback.
*
* @returns number of bytes formatted.
* @param pfnOutput Output worker.
* Called in two ways. Normally with a string an it's length.
* For termination, it's called with NULL for string, 0 for length.
* @param pvArgOutput Argument to the output worker.
* @param pfnFormat Custom format worker.
* @param pvArgFormat Argument to the format worker.
* @param pszFormat Format string.
* @param ... Argument list.
*/
RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, ...)
{
return cch;
}