hxstrfmt.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:12k
源码类别:

Symbian

开发平台:

C/C++

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