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