hxstrfmt.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:13k
- /* ***** BEGIN LICENSE BLOCK *****
- * Source last modified: $Id: hxstrfmt.cpp,v 1.7.28.3 2004/07/09 01:45:59 hubbe Exp $
- *
- * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the current version of the RealNetworks Community
- * Source License (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.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL") in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your version of
- * this file only under the terms of the GPL, and not to allow others
- * to use your version of this file under the terms of either the RPSL
- * or RCSL, indicate your decision by deleting the provisions above
- * and replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient may
- * use your version of this file under the terms of any one of the
- * RPSL, the RCSL or the GPL.
- *
- * 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);
- }