📄 hxstrfmt.cpp
字号:
/* ***** 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] = '\0'; 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] = '\0'; 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] = '\0'; 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 wrongstatic 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -