/////////////////////////////////////////////////////////////////////////////// // // 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, ""); } 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; }