441 lines
13 KiB
C++
441 lines
13 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
///////////////////////////////////////////////////////////////////// VPrintf.
|
|
//
|
|
// Completely side-effect free printf replacement.
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
#if !USE_64
|
|
#ifndef _VA_LIST_DEFINED
|
|
typedef char *va_list;
|
|
#define _VA_LIST_DEFINED
|
|
|
|
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
|
|
#define va_start(ap,v) ap = (va_list)&v + _INTSIZEOF(v)
|
|
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
|
|
#define va_end(ap) ap = (va_list)0
|
|
#endif
|
|
|
|
#else // 64-bit
|
|
// the following extern "C" code is needed to ensure the
|
|
// compiler intrinsic IV_VA_START is invoked.
|
|
extern "C" {
|
|
typedef char * va_list;
|
|
extern void __cdecl __va_start(va_list *, ...);
|
|
#define _crt_va_start(ap, x) ( __va_start(&ap, x) )
|
|
#define _crt_va_arg(ap, t) \
|
|
( ( sizeof(t) > sizeof(__int64) || ( sizeof(t) & (sizeof(t) - 1) ) != 0 ) \
|
|
? **(t **)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) \
|
|
: *(t *)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) )
|
|
#define _crt_va_end(ap) ( ap = (va_list)0 )
|
|
}
|
|
|
|
#ifndef _VA_LIST_DEFINED
|
|
typedef char *va_list;
|
|
#define _VA_LIST_DEFINED
|
|
extern void __cdecl __va_start(va_list *, ...);
|
|
#define va_dcl va_list va_alist;
|
|
#define va_start(ap,x) ( __va_start(&ap, x) )
|
|
#define va_arg(ap, t) \
|
|
( ( sizeof(t) > sizeof(__int64) || ( sizeof(t) & (sizeof(t) - 1) ) != 0 ) \
|
|
? **(t **)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) \
|
|
: *(t *)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) )
|
|
#define va_end(ap) ( ap = (va_list)0 )
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* define a macro to compute the size of a type, variable or expression,
|
|
* rounded up to the nearest multiple of sizeof(int). This number is its
|
|
* size as function argument (Intel architecture). Note that the macro
|
|
* depends on sizeof(int) being a power of 2!
|
|
*/
|
|
|
|
|
|
#pragma optimize ("", off)
|
|
|
|
static char *do_base(char * pszOut, ULARGEST nValue, UINT nBase, char * pszDigits)
|
|
{
|
|
char szTmp[96];
|
|
int nDigit = sizeof(szTmp)-2;
|
|
for (; nDigit >= 0; nDigit--) {
|
|
szTmp[nDigit] = pszDigits[nValue % nBase];
|
|
nValue /= nBase;
|
|
}
|
|
for (nDigit = 0; nDigit < sizeof(szTmp) - 2 && szTmp[nDigit] == '0'; nDigit++) {
|
|
// skip leading zeros.
|
|
}
|
|
for (; nDigit < sizeof(szTmp) - 1; nDigit++) {
|
|
*pszOut++ = szTmp[nDigit];
|
|
}
|
|
*pszOut = '\0';
|
|
return pszOut;
|
|
}
|
|
|
|
#pragma optimize ("", on)
|
|
|
|
static char * do_str(char * pszOut, char * pszIn)
|
|
{
|
|
while (*pszIn) {
|
|
*pszOut++ = *pszIn++;
|
|
}
|
|
*pszOut = '\0';
|
|
return pszOut;
|
|
}
|
|
|
|
static char * do_wstr(char * pszOut, short * pszIn)
|
|
{
|
|
while (*pszIn) {
|
|
*pszOut++ = (char)*pszIn++;
|
|
}
|
|
*pszOut = '\0';
|
|
return pszOut;
|
|
}
|
|
|
|
static int do_out(void (*pfOutput)(void *pContext, char c), void *pContext, char *pszIn)
|
|
{
|
|
int nOut = 0;
|
|
|
|
while (*pszIn) {
|
|
pfOutput(pContext, *pszIn++);
|
|
nOut++;
|
|
}
|
|
return nOut;
|
|
}
|
|
|
|
int strformat(void (*pfOutput)(void *pContext, char c), void *pContext,
|
|
const char * pszFmt, va_list args)
|
|
{
|
|
int nOut = 0;
|
|
|
|
while (*pszFmt) {
|
|
if (*pszFmt == '%') {
|
|
char szTemp[128];
|
|
char szHead[4] = "";
|
|
int nLen;
|
|
int nWidth = 0;
|
|
int nPrecision = 0;
|
|
int fLeft = 0;
|
|
int fPositive = 0;
|
|
int fPound = 0;
|
|
int fBlank = 0;
|
|
int fZero = 0;
|
|
int fDigit = 0;
|
|
int fSmall = 0;
|
|
int fLarge = 0;
|
|
int fString = 0;
|
|
const char * pszArg = pszFmt;
|
|
|
|
pszFmt++;
|
|
|
|
for (; (*pszFmt == '-' ||
|
|
*pszFmt == '+' ||
|
|
*pszFmt == '#' ||
|
|
*pszFmt == ' ' ||
|
|
*pszFmt == '0'); pszFmt++) {
|
|
switch (*pszFmt) {
|
|
case '-': fLeft = 1; break;
|
|
case '+': fPositive = 1; break;
|
|
case '#': fPound = 1; break;
|
|
case ' ': fBlank = 1; break;
|
|
case '0': fZero = 1; break;
|
|
}
|
|
}
|
|
|
|
if (*pszFmt == '*') {
|
|
nWidth = va_arg(args, int);
|
|
pszFmt++;
|
|
}
|
|
else {
|
|
while (*pszFmt >= '0' && *pszFmt <= '9') {
|
|
nWidth = nWidth * 10 + (*pszFmt++ - '0');
|
|
}
|
|
}
|
|
if (*pszFmt == '.') {
|
|
pszFmt++;
|
|
fDigit = 1;
|
|
if (*pszFmt == '*') {
|
|
nPrecision = va_arg(args, int);
|
|
pszFmt++;
|
|
}
|
|
else {
|
|
while (*pszFmt >= '0' && *pszFmt <= '9') {
|
|
nPrecision = nPrecision * 10 + (*pszFmt++ - '0');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*pszFmt == 'h') {
|
|
fSmall = 1;
|
|
pszFmt++;
|
|
}
|
|
else if (*pszFmt == 'l' || *pszFmt == 'L') {
|
|
fLarge = 1;
|
|
pszFmt++;
|
|
}
|
|
|
|
if (*pszFmt == 's' || *pszFmt == 'S' ||
|
|
*pszFmt == 'c' || *pszFmt == 'C') {
|
|
if (*pszFmt == 's' || *pszFmt == 'S') {
|
|
char * pszDst = szTemp;
|
|
void * pvData = va_arg(args, void *);
|
|
|
|
if (*pszFmt == 'S') {
|
|
fLarge = 1;
|
|
}
|
|
pszFmt++;
|
|
|
|
fString = 1;
|
|
if (fSmall) {
|
|
fLarge = 0;
|
|
}
|
|
|
|
if (!pvData) {
|
|
pszDst = do_str(pszDst, "<NULL>");
|
|
}
|
|
else if (fLarge) {
|
|
pszDst = do_wstr(pszDst, (short *)pvData);
|
|
}
|
|
else {
|
|
pszDst = do_str(pszDst, (char *)pvData);
|
|
}
|
|
nLen = (int) (pszDst - szTemp);
|
|
}
|
|
else if (*pszFmt == 'c' || *pszFmt == 'C') {
|
|
if (*pszFmt == 'S') {
|
|
fLarge = 1;
|
|
}
|
|
pszFmt++;
|
|
|
|
fString = 1;
|
|
|
|
szTemp[0] = (char)va_arg(args, int);
|
|
szTemp[1] = '\0';
|
|
nLen = 1;
|
|
}
|
|
|
|
if (nPrecision && nLen > nPrecision) {
|
|
nLen = nPrecision;
|
|
szTemp[nLen] = '\0';
|
|
}
|
|
|
|
if (fLeft) {
|
|
nOut += do_out(pfOutput, pContext, szTemp);
|
|
for (; nLen < nWidth; nLen++) {
|
|
pfOutput(pContext, ' ');
|
|
nOut++;
|
|
}
|
|
}
|
|
else {
|
|
for (; nLen < nWidth; nLen++) {
|
|
pfOutput(pContext, ' ');
|
|
nOut++;
|
|
}
|
|
nOut = do_out(pfOutput, pContext, szTemp);
|
|
}
|
|
}
|
|
else if (*pszFmt == 'p' || *pszFmt == 'u' ||
|
|
*pszFmt == 'd' || *pszFmt == 'i' || *pszFmt == 'o' ||
|
|
*pszFmt == 'x' || *pszFmt == 'X' || *pszFmt == 'b') {
|
|
|
|
ULARGEST value;
|
|
if (fLarge) {
|
|
value = va_arg(args, ULARGEST);
|
|
}
|
|
else {
|
|
value = va_arg(args, unsigned int);
|
|
}
|
|
|
|
if (*pszFmt == 'p') {
|
|
if (nWidth == 0) {
|
|
nWidth = fLarge ? 2 * sizeof(ULARGEST) : 2 * sizeof(unsigned int);
|
|
fZero = 1;
|
|
}
|
|
pszFmt++;
|
|
nLen = (int) (do_base(szTemp, value, 16, "0123456789abcdef") - szTemp);
|
|
if (fPound && value) {
|
|
do_str(szHead, "0x");
|
|
}
|
|
}
|
|
else if (*pszFmt == 'x' || *pszFmt == 'p') {
|
|
pszFmt++;
|
|
nLen = (int) (do_base(szTemp, value, 16, "0123456789abcdef") - szTemp);
|
|
if (fPound && value) {
|
|
do_str(szHead, "0x");
|
|
}
|
|
}
|
|
else if (*pszFmt == 'X') {
|
|
pszFmt++;
|
|
nLen = (int) (do_base(szTemp, value, 16, "0123456789ABCDEF") - szTemp);
|
|
if (fPound && value) {
|
|
do_str(szHead, "0X");
|
|
}
|
|
}
|
|
else if (*pszFmt == 'd') {
|
|
pszFmt++;
|
|
if ((LARGEST)value < 0) {
|
|
value = -(LARGEST)value;
|
|
do_str(szHead, "-");
|
|
}
|
|
else if (fPositive) {
|
|
if (value > 0) {
|
|
do_str(szHead, "+");
|
|
}
|
|
}
|
|
else if (fBlank) {
|
|
if (value > 0) {
|
|
do_str(szHead, " ");
|
|
}
|
|
}
|
|
nLen = (int) (do_base(szTemp, value, 10, "0123456789") - szTemp);
|
|
nPrecision = 0;
|
|
}
|
|
else if (*pszFmt == 'u') {
|
|
pszFmt++;
|
|
nLen = (int) (do_base(szTemp, value, 10, "0123456789") - szTemp);
|
|
nPrecision = 0;
|
|
}
|
|
else if (*pszFmt == 'o') {
|
|
pszFmt++;
|
|
nLen = (int) (do_base(szTemp, value, 8, "01234567") - szTemp);
|
|
nPrecision = 0;
|
|
|
|
if (fPound && value) {
|
|
do_str(szHead, "0");
|
|
}
|
|
}
|
|
else if (*pszFmt == 'b') {
|
|
pszFmt++;
|
|
nLen = (int) (do_base(szTemp, value, 2, "01") - szTemp);
|
|
nPrecision = 0;
|
|
|
|
if (fPound && value) {
|
|
do_str(szHead, "0b");
|
|
}
|
|
}
|
|
|
|
int nHead = 0;
|
|
for (; szHead[nHead]; nHead++) {
|
|
// Count characters in head string.
|
|
}
|
|
|
|
if (fLeft) {
|
|
if (nHead) {
|
|
nOut += do_out(pfOutput, pContext, szHead);
|
|
nLen += nHead;
|
|
}
|
|
nOut += do_out(pfOutput, pContext, szTemp);
|
|
for (; nLen < nWidth; nLen++) {
|
|
pfOutput(pContext, ' ');
|
|
nOut++;
|
|
}
|
|
}
|
|
else if (fZero) {
|
|
if (nHead) {
|
|
nOut += do_out(pfOutput, pContext, szHead);
|
|
nLen += nHead;
|
|
}
|
|
for (; nLen < nWidth; nLen++) {
|
|
pfOutput(pContext, '0');
|
|
nOut++;
|
|
}
|
|
nOut += do_out(pfOutput, pContext, szTemp);
|
|
}
|
|
else {
|
|
if (nHead) {
|
|
nLen += nHead;
|
|
}
|
|
for (; nLen < nWidth; nLen++) {
|
|
pfOutput(pContext, ' ');
|
|
nOut++;
|
|
}
|
|
if (nHead) {
|
|
nOut += do_out(pfOutput, pContext, szHead);
|
|
}
|
|
nOut += do_out(pfOutput, pContext, szTemp);
|
|
}
|
|
}
|
|
else {
|
|
pszFmt++;
|
|
while (pszArg < pszFmt) {
|
|
pfOutput(pContext, *pszArg++);
|
|
nOut++;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
pfOutput(pContext, *pszFmt++);
|
|
nOut++;
|
|
}
|
|
}
|
|
return nOut;
|
|
}
|
|
|
|
////////////////////////////////////////////////// Publicly Visible Interface.
|
|
//
|
|
|
|
void __cdecl PutChar(char cOut);
|
|
|
|
static void printfout(void * /* pContext */, char c)
|
|
{
|
|
PutChar(c);
|
|
}
|
|
|
|
int printf(const char *pszFmt, ...)
|
|
{
|
|
int nOut;
|
|
va_list args;
|
|
|
|
va_start(args, pszFmt);
|
|
nOut = strformat(printfout, 0, pszFmt, args);
|
|
va_end(args);
|
|
|
|
return nOut;
|
|
}
|
|
|
|
int vprintf(const char *pszFmt, va_list args)
|
|
{
|
|
int nOut;
|
|
|
|
nOut = strformat(printfout, 0, pszFmt, args);
|
|
|
|
return nOut;
|
|
}
|
|
|
|
static void sprintfout(void *pContext, char c)
|
|
{
|
|
char **ppszOut = (char **)pContext;
|
|
|
|
*(*ppszOut)++ = c;
|
|
}
|
|
|
|
int sprintf(char *pszOut, const char *pszFmt, ...)
|
|
{
|
|
int nOut;
|
|
va_list args;
|
|
|
|
va_start(args, pszFmt);
|
|
nOut = strformat(sprintfout, &pszOut, pszFmt, args);
|
|
va_end(args);
|
|
|
|
*pszOut = '\0';
|
|
|
|
return nOut;
|
|
}
|
|
|
|
int svprintf(char *pszOut, const char *pszFmt, va_list args)
|
|
{
|
|
int nOut;
|
|
|
|
nOut = strformat(sprintfout, &pszOut, pszFmt, args);
|
|
*pszOut = '\0';
|
|
|
|
return nOut;
|
|
}
|