hxstrfmt.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:13k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: hxstrfmt.cpp,v 1.7.28.3 2004/07/09 01:45:59 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxstring.h"
  50. #include "hxassert.h"
  51. #include "hlxclib/string.h"
  52. #include "safestring.h"
  53. #include "hlxclib/stdarg.h"
  54. #include "hxassert.h"
  55. static const int AlternateFlag   = 0x01;
  56. static const int ZeroPadFlag     = 0x02;
  57. static const int LeftJustifyFlag = 0x04;
  58. static const int AddSpaceFlag    = 0x08;
  59. static const int AddSignFlag     = 0x10;
  60. static const int MaxWidthSize = 12;
  61. static const int WidthParam = -2;
  62. static const int WidthError = -3;
  63. static const int MaxPrecisionSize = 12;
  64. static const int NoPrecision    = -1;
  65. static const int PrecisionParam = -2;
  66. static const int PrecisionError = -3;
  67. static const int NoLength = 0;
  68. static const int ShortLength = 1;
  69. static const int LongLength = 2;
  70. static const int MaxConversionSize = 32;
  71. static const int MaxFormatSize = 11;
  72. static int GetFlags(const char*& pCur)
  73. {
  74.     int ret = 0;
  75.     for (; *pCur && strchr("#0- +", *pCur); pCur++)
  76.     {
  77. switch(*pCur) {
  78. case '#':
  79.     ret |= AlternateFlag;
  80.     break;
  81. case '0':
  82.     ret |= ZeroPadFlag;
  83.     break;
  84. case '-':
  85.     ret |= LeftJustifyFlag;
  86.     break;
  87. case ' ':
  88.     ret |= AddSpaceFlag;
  89.     break;
  90.     
  91. case '+':
  92.     ret |= AddSignFlag;
  93.     break;
  94. };
  95.     }
  96.     return ret;
  97. }
  98. static int GetWidth(const char*& pCur)
  99. {
  100.     int ret = 1;
  101.     if (*pCur)
  102.     {
  103. if (*pCur == '*')
  104. {
  105.     // The width is specified as a parameter
  106.     pCur++;
  107.     ret = WidthParam;
  108. }
  109. else
  110. {
  111.     if (strchr("123456789", *pCur))
  112.     {
  113. int i = 0;
  114. char widthBuf[MaxWidthSize]; /* Flawfinder: ignore */
  115. widthBuf[i++] = *pCur++;
  116. for(; (i < MaxWidthSize) && 
  117. *pCur && (strchr("0123456789", *pCur)); i++)
  118.     widthBuf[i] = *pCur++;
  119. if (i != MaxWidthSize)
  120. {
  121.     widthBuf[i] = '';
  122.     char* pEnd = 0;
  123.     long int tmp = strtol(widthBuf, &pEnd, 10);
  124.     
  125.     if (widthBuf[0] && !*pEnd)
  126. ret = (int)tmp;
  127. }
  128. else
  129.     ret = WidthError;
  130.     }
  131. }
  132.     }
  133.     return ret;
  134. }
  135. static int GetPrecision(const char*& pCur)
  136. {
  137.     int ret = NoPrecision;
  138.     if (*pCur == '.')
  139.     {
  140. pCur++;
  141. if (*pCur == '*')
  142. {
  143.     // The width is specified as a parameter
  144.     pCur++;
  145.     ret = PrecisionParam;
  146. }
  147. else
  148. {
  149.     int i = 0;
  150.     char precisionBuf[MaxPrecisionSize]; /* Flawfinder: ignore */
  151.     
  152.     for(; (i < MaxPrecisionSize) && 
  153.     *pCur && (strchr("0123456789", *pCur)); i++)
  154. precisionBuf[i] = *pCur++;
  155.     
  156.     if (i != MaxPrecisionSize)
  157.     {
  158. precisionBuf[i] = '';
  159.     
  160. if (strlen(precisionBuf))
  161. {
  162.     char* pEnd = 0;
  163.     long int tmp = strtol(precisionBuf, &pEnd, 10);
  164.     
  165.     if (precisionBuf[0] && !*pEnd)
  166. ret = (int)tmp;
  167. }
  168. else
  169.     ret = 0;
  170.     }
  171.     else
  172. ret = PrecisionError;
  173. }
  174.     }
  175.     return ret;
  176. }
  177. static int GetLength(const char*& pCur)
  178. {
  179.     int ret = NoLength;
  180.     switch(*pCur) {
  181.     case 'l':
  182. ret = LongLength;
  183. pCur++;
  184. break;
  185.     case 'h':
  186. ret = ShortLength;
  187. pCur++;
  188. break;
  189.     };
  190.     return ret;
  191. }
  192. static void ConstructFormat(char* fmt, char type, int flags, int length,
  193.     int precision)
  194. {
  195.     int i = 0;
  196.     fmt[i++] = '%';
  197.     if (flags & AlternateFlag)
  198. fmt[i++] = '#';
  199.     if (flags & LeftJustifyFlag)
  200. fmt[i++] = '-';
  201.     if (flags & AddSpaceFlag)
  202. fmt[i++] = ' ';
  203.     if (flags & AddSignFlag)
  204. fmt[i++] = '+';
  205.     if (flags & ZeroPadFlag)
  206. fmt[i++] = '0';
  207.     fmt[i++] = '*';
  208.     if (precision != NoPrecision)
  209.     {
  210. fmt[i++] = '.';
  211. fmt[i++] = '*';
  212.     }
  213.     if (length == ShortLength)
  214. fmt[i++] = 'h';
  215.     
  216.     if (length == LongLength)
  217. fmt[i++] = 'l';
  218.     fmt[i++] = type;
  219.     fmt[i] = '';
  220.     HX_ASSERT(i < MaxFormatSize);
  221. }
  222. // This could be handled with a single template function, but for now
  223. // we can't use templates. :( 
  224. // I'll use a macro instead.
  225. #define CONVERT_FUNC_DEF(funcName, convertType)                    
  226. static int funcName(const char* fmt,                               
  227.                     int width, int precision,                      
  228.                     convertType value)                             
  229. {                                                                  
  230.     int ret = 0;                                                   
  231.     int bufSize = width + MaxConversionSize;                       
  232.                                                                    
  233.     if (precision != NoPrecision)                                  
  234.         bufSize += precision;                                      
  235.     char* pBuf = new char[bufSize];                                
  236.     if (precision == NoPrecision)                                  
  237. ret = SafeSprintf(pBuf, bufSize, fmt, width, value);       
  238.     else                                                           
  239. ret = SafeSprintf(pBuf, bufSize, fmt, width, precision, value); 
  240.     HX_ASSERT(ret < bufSize);                                      
  241.     delete [] pBuf;                                                
  242.     return ret;                                                    
  243. }
  244. CONVERT_FUNC_DEF(ConvertInt, int)
  245. CONVERT_FUNC_DEF(ConvertShort, short int)
  246. CONVERT_FUNC_DEF(ConvertLong, long int)
  247. CONVERT_FUNC_DEF(ConvertUInt, unsigned int)
  248. CONVERT_FUNC_DEF(ConvertUShort, unsigned short int)
  249. CONVERT_FUNC_DEF(ConvertULong, unsigned long int)
  250. CONVERT_FUNC_DEF(ConvertDouble, double)
  251. CONVERT_FUNC_DEF(ConvertChar, char)
  252. CONVERT_FUNC_DEF(ConvertWChar, wchar_t)
  253. CONVERT_FUNC_DEF(ConvertPtr, void*)
  254. static bool ParseFormat(const char*& pCur, int& charCount, va_list& args)
  255. {
  256.     bool ret = true;
  257.     const char* pTmp = pCur;
  258.     int flags = GetFlags(pTmp);
  259.     int width = 1;
  260.     int precision = NoPrecision;
  261.     int convertSize = 0;
  262.     if ((width = GetWidth(pTmp)) == WidthError)
  263.     {
  264. HX_ASSERT(!fprintf(stderr, "Width field too long '%s'n", pCur));
  265. ret = false;
  266.     }
  267.     else if ((precision = GetPrecision(pTmp)) == PrecisionError)
  268.     {
  269. HX_ASSERT(!fprintf(stderr, "Precision field too long '%s'n", pCur));
  270. ret = false;
  271.     }
  272.     else
  273.     {
  274. int length = GetLength(pTmp);
  275. char type = *pTmp++;
  276. if (width == WidthParam)
  277. {
  278.     width = va_arg(args, int);
  279.     if (width < 0)
  280.     {
  281. width = -width;
  282. flags |= LeftJustifyFlag;
  283.     }
  284. }
  285. if (precision == PrecisionParam)
  286. {
  287.     precision = va_arg(args, int);
  288.     if (precision < 0)
  289. precision = 0;
  290. }
  291. switch (type) {
  292. case 's':
  293. {
  294.     const char* pVal = va_arg(args, const char*);
  295.     if (length == LongLength)
  296.     {
  297. HX_ASSERT(!"Wide characters not supported");
  298. // Make up something large and hope that it's big enough
  299. convertSize = 512;
  300.     }
  301.     else
  302.     {
  303. if (precision >= 0)
  304. {
  305.     for(; (convertSize < precision) && 
  306.     pVal[convertSize]; convertSize++);
  307. }
  308. else
  309.     convertSize = strlen(pVal);
  310.     }
  311. }break;
  312. case 'd':
  313. case 'i':
  314. {
  315.     char fmt[MaxFormatSize]; /* Flawfinder: ignore */
  316.     ConstructFormat(fmt, type, flags, length, precision);
  317.     if (length == LongLength)
  318.     {
  319. long int val = va_arg(args, long int);
  320. convertSize = ConvertLong(fmt, width, precision, val);
  321.     }
  322.     else if (length == ShortLength)
  323.     {
  324. short int val = va_arg(args, int);
  325. convertSize = ConvertShort(fmt, width, precision, val);
  326.     }
  327.     else
  328.     {
  329. int val = va_arg(args, int);
  330. convertSize = ConvertInt(fmt, width, precision, val);;
  331.     }
  332. }break;
  333. case 'u':
  334. case 'o':
  335. case 'x':
  336. case 'X':
  337. {
  338.     char fmt[MaxFormatSize]; /* Flawfinder: ignore */
  339.     ConstructFormat(fmt, type, flags, length, precision);
  340.     if (length == LongLength)
  341.     {
  342. unsigned long int val = va_arg(args, unsigned long int);
  343. convertSize = ConvertULong(fmt, width, precision, val);
  344.     }
  345.     else if (length == ShortLength)
  346.     {
  347. unsigned short int val = va_arg(args, unsigned int);
  348. convertSize = ConvertUShort(fmt, width, precision, val);
  349.     }
  350.     else
  351.     {
  352. unsigned int val = va_arg(args, unsigned int);
  353. convertSize = ConvertUInt(fmt, width, precision, val);
  354.     }
  355. }break;
  356. case 'e':
  357. case 'E':
  358. case 'f':
  359. case 'g':
  360. case 'G':
  361. {
  362.     char fmt[MaxFormatSize]; /* Flawfinder: ignore */
  363.     ConstructFormat(fmt, type, flags, length, precision);
  364.     double val = va_arg(args, double);
  365.     convertSize = ConvertDouble(fmt, width, precision, val);
  366. }break;
  367. case 'c':
  368. {
  369.     char fmt[MaxFormatSize]; /* Flawfinder: ignore */
  370.     ConstructFormat(fmt, type, flags, length, precision);
  371.     if (length == LongLength)
  372.     {
  373. wchar_t val = va_arg(args, int);
  374. convertSize = ConvertWChar(fmt, width, precision, val);
  375.     }
  376.     else
  377.     {
  378. char val = va_arg(args, int);
  379. convertSize = ConvertChar(fmt, width, precision, val);
  380.     }
  381. }break;
  382. case 'p':
  383. {
  384.     char fmt[MaxFormatSize]; /* Flawfinder: ignore */
  385.     ConstructFormat(fmt, type, flags, length, precision);
  386.     void* val = va_arg(args, void*);
  387.     convertSize = ConvertPtr(fmt, width, precision, val);
  388. }break;
  389. case '%':
  390.     convertSize = 1;
  391.     break;
  392. default:
  393. {
  394.     HX_ASSERT(!"Unknown format type");
  395.     // Make up something large and hope that it's big enough
  396.     convertSize = 512;
  397. }break;
  398. };
  399.     }
  400.     if (ret)
  401.     {
  402. charCount += (convertSize > width) ? convertSize : width;
  403. pCur = pTmp;
  404.     }
  405.     return ret;
  406. }
  407. static int GuessSize(const char* pFormat, va_list& args)
  408. {
  409.     int ret = 1;
  410.     const char* pCur = pFormat;
  411.     while(*pCur && ret != -1)
  412.     {
  413. switch(*pCur) {
  414. case '%':
  415.     pCur++;
  416.     // Handle format characters
  417.     if (!ParseFormat(pCur, ret, args))
  418. ret = -1;
  419.     break;
  420. default:
  421.     ret++;
  422.     pCur++;
  423.     break;
  424. };
  425.     }
  426.     return ret;
  427. }
  428. // This fudge factor is added to the guess to protect us
  429. // from guessing wrong
  430. static const int FormatFudgeFactor = 128;
  431. void CHXString::Format(const char* pFmt, ...)
  432. {
  433.     va_list args;
  434.     va_start(args, pFmt);
  435.     // Guess the size
  436.     int estimatedSize = GuessSize(pFmt, args);
  437.     va_end(args);
  438.     va_start(args, pFmt);
  439.     if (m_pRep)
  440. m_pRep->Resize(estimatedSize + FormatFudgeFactor);
  441.     else
  442. m_pRep = new CHXStringRep(estimatedSize + FormatFudgeFactor);
  443.     int actualSize = vsnprintf(m_pRep->GetBuffer(), m_pRep->GetBufferSize(),
  444.                                pFmt, args);
  445.     HX_ASSERT(actualSize < estimatedSize);
  446.     m_pRep->SetStringSize(actualSize);
  447.     FreeExtra();
  448.     va_end(args);
  449. }