hxstrfmt.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:12k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hxstring.h"
- #include "hxassert.h"
- #include "hlxclib/string.h"
- #include "safestring.h"
- #include "hlxclib/stdarg.h"
- #include "hxassert.h"
- static const int AlternateFlag = 0x01;
- static const int ZeroPadFlag = 0x02;
- static const int LeftJustifyFlag = 0x04;
- static const int AddSpaceFlag = 0x08;
- static const int AddSignFlag = 0x10;
- static const int MaxWidthSize = 12;
- static const int WidthParam = -2;
- static const int WidthError = -3;
- static const int MaxPrecisionSize = 12;
- static const int NoPrecision = -1;
- static const int PrecisionParam = -2;
- static const int PrecisionError = -3;
- static const int NoLength = 0;
- static const int ShortLength = 1;
- static const int LongLength = 2;
- static const int MaxConversionSize = 32;
- static const int MaxFormatSize = 11;
- static int GetFlags(const char*& pCur)
- {
- int ret = 0;
- for (; *pCur && strchr("#0- +", *pCur); pCur++)
- {
- switch(*pCur) {
- case '#':
- ret |= AlternateFlag;
- break;
- case '0':
- ret |= ZeroPadFlag;
- break;
- case '-':
- ret |= LeftJustifyFlag;
- break;
- case ' ':
- ret |= AddSpaceFlag;
- break;
-
- case '+':
- ret |= AddSignFlag;
- break;
- };
- }
- return ret;
- }
- static int GetWidth(const char*& pCur)
- {
- int ret = 1;
- if (*pCur)
- {
- if (*pCur == '*')
- {
- // The width is specified as a parameter
- pCur++;
- ret = WidthParam;
- }
- else
- {
- if (strchr("123456789", *pCur))
- {
- int i = 0;
- char widthBuf[MaxWidthSize]; /* Flawfinder: ignore */
-
- widthBuf[i++] = *pCur++;
- for(; (i < MaxWidthSize) &&
- *pCur && (strchr("0123456789", *pCur)); i++)
- widthBuf[i] = *pCur++;
- if (i != MaxWidthSize)
- {
- widthBuf[i] = ' ';
- char* pEnd = 0;
- long int tmp = strtol(widthBuf, &pEnd, 10);
-
- if (widthBuf[0] && !*pEnd)
- ret = (int)tmp;
- }
- else
- ret = WidthError;
- }
- }
- }
- return ret;
- }
- static int GetPrecision(const char*& pCur)
- {
- int ret = NoPrecision;
- if (*pCur == '.')
- {
- pCur++;
- if (*pCur == '*')
- {
- // The width is specified as a parameter
- pCur++;
- ret = PrecisionParam;
- }
- else
- {
- int i = 0;
- char precisionBuf[MaxPrecisionSize]; /* Flawfinder: ignore */
-
- for(; (i < MaxPrecisionSize) &&
- *pCur && (strchr("0123456789", *pCur)); i++)
- precisionBuf[i] = *pCur++;
-
- if (i != MaxPrecisionSize)
- {
- precisionBuf[i] = ' ';
-
- if (strlen(precisionBuf))
- {
- char* pEnd = 0;
- long int tmp = strtol(precisionBuf, &pEnd, 10);
-
- if (precisionBuf[0] && !*pEnd)
- ret = (int)tmp;
- }
- else
- ret = 0;
- }
- else
- ret = PrecisionError;
- }
- }
- return ret;
- }
- static int GetLength(const char*& pCur)
- {
- int ret = NoLength;
- switch(*pCur) {
- case 'l':
- ret = LongLength;
- pCur++;
- break;
- case 'h':
- ret = ShortLength;
- pCur++;
- break;
- };
- return ret;
- }
- static void ConstructFormat(char* fmt, char type, int flags, int length,
- int precision)
- {
- int i = 0;
- fmt[i++] = '%';
- if (flags & AlternateFlag)
- fmt[i++] = '#';
- if (flags & LeftJustifyFlag)
- fmt[i++] = '-';
- if (flags & AddSpaceFlag)
- fmt[i++] = ' ';
- if (flags & AddSignFlag)
- fmt[i++] = '+';
- if (flags & ZeroPadFlag)
- fmt[i++] = '0';
- fmt[i++] = '*';
- if (precision != NoPrecision)
- {
- fmt[i++] = '.';
- fmt[i++] = '*';
- }
- if (length == ShortLength)
- fmt[i++] = 'h';
-
- if (length == LongLength)
- fmt[i++] = 'l';
- fmt[i++] = type;
- fmt[i] = ' ';
- HX_ASSERT(i < MaxFormatSize);
- }
- // This could be handled with a single template function, but for now
- // we can't use templates. :(
- // I'll use a macro instead.
- #define CONVERT_FUNC_DEF(funcName, convertType)
- static int funcName(const char* fmt,
- int width, int precision,
- convertType value)
- {
- int ret = 0;
- int bufSize = width + MaxConversionSize;
-
- if (precision != NoPrecision)
- bufSize += precision;
- char* pBuf = new char[bufSize];
- if (precision == NoPrecision)
- ret = SafeSprintf(pBuf, bufSize, fmt, width, value);
- else
- ret = SafeSprintf(pBuf, bufSize, fmt, width, precision, value);
- HX_ASSERT(ret < bufSize);
- delete [] pBuf;
- return ret;
- }
- CONVERT_FUNC_DEF(ConvertInt, int)
- CONVERT_FUNC_DEF(ConvertShort, short int)
- CONVERT_FUNC_DEF(ConvertLong, long int)
- CONVERT_FUNC_DEF(ConvertUInt, unsigned int)
- CONVERT_FUNC_DEF(ConvertUShort, unsigned short int)
- CONVERT_FUNC_DEF(ConvertULong, unsigned long int)
- CONVERT_FUNC_DEF(ConvertDouble, double)
- CONVERT_FUNC_DEF(ConvertChar, char)
- CONVERT_FUNC_DEF(ConvertWChar, wchar_t)
- CONVERT_FUNC_DEF(ConvertPtr, void*)
- static bool ParseFormat(const char*& pCur, int& charCount, va_list& args)
- {
- bool ret = true;
- const char* pTmp = pCur;
- int flags = GetFlags(pTmp);
- int width = 1;
- int precision = NoPrecision;
- int convertSize = 0;
- if ((width = GetWidth(pTmp)) == WidthError)
- {
- HX_ASSERT(!fprintf(stderr, "Width field too long '%s'n", pCur));
- ret = false;
- }
- else if ((precision = GetPrecision(pTmp)) == PrecisionError)
- {
- HX_ASSERT(!fprintf(stderr, "Precision field too long '%s'n", pCur));
- ret = false;
- }
- else
- {
- int length = GetLength(pTmp);
- char type = *pTmp++;
- if (width == WidthParam)
- {
- width = va_arg(args, int);
- if (width < 0)
- {
- width = -width;
- flags |= LeftJustifyFlag;
- }
- }
- if (precision == PrecisionParam)
- {
- precision = va_arg(args, int);
- if (precision < 0)
- precision = 0;
- }
- switch (type) {
- case 's':
- {
- const char* pVal = va_arg(args, const char*);
- if (length == LongLength)
- {
- HX_ASSERT(!"Wide characters not supported");
- // Make up something large and hope that it's big enough
- convertSize = 512;
- }
- else
- {
- if (precision >= 0)
- {
- for(; (convertSize < precision) &&
- pVal[convertSize]; convertSize++);
- }
- else
- convertSize = strlen(pVal);
- }
- }break;
- case 'd':
- case 'i':
- {
- char fmt[MaxFormatSize]; /* Flawfinder: ignore */
- ConstructFormat(fmt, type, flags, length, precision);
- if (length == LongLength)
- {
- long int val = va_arg(args, long int);
- convertSize = ConvertLong(fmt, width, precision, val);
- }
- else if (length == ShortLength)
- {
- short int val = va_arg(args, int);
- convertSize = ConvertShort(fmt, width, precision, val);
- }
- else
- {
- int val = va_arg(args, int);
- convertSize = ConvertInt(fmt, width, precision, val);;
- }
- }break;
- case 'u':
- case 'o':
- case 'x':
- case 'X':
- {
- char fmt[MaxFormatSize]; /* Flawfinder: ignore */
- ConstructFormat(fmt, type, flags, length, precision);
- if (length == LongLength)
- {
- unsigned long int val = va_arg(args, unsigned long int);
- convertSize = ConvertULong(fmt, width, precision, val);
- }
- else if (length == ShortLength)
- {
- unsigned short int val = va_arg(args, unsigned int);
- convertSize = ConvertUShort(fmt, width, precision, val);
- }
- else
- {
- unsigned int val = va_arg(args, unsigned int);
- convertSize = ConvertUInt(fmt, width, precision, val);
- }
- }break;
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- {
- char fmt[MaxFormatSize]; /* Flawfinder: ignore */
- ConstructFormat(fmt, type, flags, length, precision);
- double val = va_arg(args, double);
- convertSize = ConvertDouble(fmt, width, precision, val);
- }break;
- case 'c':
- {
- char fmt[MaxFormatSize]; /* Flawfinder: ignore */
- ConstructFormat(fmt, type, flags, length, precision);
- if (length == LongLength)
- {
- wchar_t val = va_arg(args, int);
- convertSize = ConvertWChar(fmt, width, precision, val);
- }
- else
- {
- char val = va_arg(args, int);
- convertSize = ConvertChar(fmt, width, precision, val);
- }
- }break;
- case 'p':
- {
- char fmt[MaxFormatSize]; /* Flawfinder: ignore */
- ConstructFormat(fmt, type, flags, length, precision);
- void* val = va_arg(args, void*);
- convertSize = ConvertPtr(fmt, width, precision, val);
- }break;
- case '%':
- convertSize = 1;
- break;
- default:
- {
- HX_ASSERT(!"Unknown format type");
- // Make up something large and hope that it's big enough
- convertSize = 512;
- }break;
- };
-
- }
- if (ret)
- {
- charCount += (convertSize > width) ? convertSize : width;
- pCur = pTmp;
- }
- return ret;
- }
- static int GuessSize(const char* pFormat, va_list& args)
- {
- int ret = 1;
- const char* pCur = pFormat;
- while(*pCur && ret != -1)
- {
- switch(*pCur) {
- case '%':
- pCur++;
- // Handle format characters
- if (!ParseFormat(pCur, ret, args))
- ret = -1;
- break;
- default:
- ret++;
- pCur++;
- break;
- };
- }
- return ret;
- }
- // This fudge factor is added to the guess to protect us
- // from guessing wrong
- static const int FormatFudgeFactor = 128;
- void CHXString::Format(const char* pFmt, ...)
- {
- va_list args;
- va_start(args, pFmt);
- // Guess the size
- int estimatedSize = GuessSize(pFmt, args);
- va_end(args);
- va_start(args, pFmt);
- if (m_pRep)
- m_pRep->Resize(estimatedSize + FormatFudgeFactor);
- else
- m_pRep = new CHXStringRep(estimatedSize + FormatFudgeFactor);
- int actualSize = vsnprintf(m_pRep->GetBuffer(), m_pRep->GetBufferSize(),
- pFmt, args);
- HX_ASSERT(actualSize < estimatedSize);
- m_pRep->SetStringSize(actualSize);
- FreeExtra();
- va_end(args);
- }