static void OutputUInt (char* szOutputBuffer, unsigned int uiBufferSize, unsigned int& uiWritePos, unsigned long long int value, int iWidth, int iPrecision, unsigned int Flags, int iBase, bool bUpperCase) { #ifndef USE_STRICT_SPECIFICATION // In the non-strict implementation unsigned values will never be preceeded by signs (+ or space) Flags &= ~ (sprintfFlags::BlankSign | sprintfFlags::ForceSign); #endif // for a 32 Bit Integer one needs at most 10 digits // for a 64 Bit Integer one needs at most 20 digits // However, FormatUInt allows to add extra padding, so make the buffer a bit larger char s[128]; int iNumDigits = 0; FormatUInt (s, iNumDigits, value, iBase, bUpperCase, iPrecision); // since the uint is casted to an int, we must make sure very large values are not mapped to negative ints // therefore do the ' > 0 ? 1 : 0 ' test to just pass on the proper sign, instead of casting it to an int int iNumberWidth = GetSignSize (value > 0 ? 1 : 0, Flags, iBase, iPrecision) + iNumDigits; if (Flags & sprintfFlags::LeftJustify) { OutputIntSign (szOutputBuffer, uiBufferSize, uiWritePos, value > 0 ? 1 : 0, Flags, iBase, bUpperCase, iPrecision); OutputReverseString (szOutputBuffer, uiBufferSize, uiWritePos, s, iNumDigits); OutputPadding (szOutputBuffer, uiBufferSize, uiWritePos, iWidth - iNumberWidth, ' '); } else { OutputIntSignAndPadding (szOutputBuffer, uiBufferSize, uiWritePos, value > 0 ? 1 : 0, Flags, iWidth - iNumberWidth, iBase, bUpperCase, iPrecision); OutputReverseString (szOutputBuffer, uiBufferSize, uiWritePos, s, iNumDigits); } }
static void OutputInt (char* szOutputBuffer, unsigned int uiBufferSize, unsigned int& uiWritePos, long long int value, int iWidth, int iPrecision, unsigned int Flags, int iBase) { // for a 32 Bit Integer one needs at most 10 digits // for a 64 Bit Integer one needs at most 20 digits // However, FormatUInt allows to add extra padding, so make the buffer a bit larger char s[128]; int iNumDigits = 0; unsigned long long int absval = value < 0 ? -value : value; FormatUInt (s, iNumDigits, absval, iBase, false, iPrecision); int iNumberWidth = GetSignSize (value, Flags, iBase, iPrecision) + iNumDigits; if (Flags & sprintfFlags::LeftJustify) { OutputIntSign (szOutputBuffer, uiBufferSize, uiWritePos, value, Flags, iBase, false, iPrecision); OutputReverseString (szOutputBuffer, uiBufferSize, uiWritePos, s, iNumDigits); OutputPadding (szOutputBuffer, uiBufferSize, uiWritePos, iWidth - iNumberWidth, ' '); } else { OutputIntSignAndPadding (szOutputBuffer, uiBufferSize, uiWritePos, value, Flags, iWidth - iNumberWidth, iBase, false, iPrecision); OutputReverseString (szOutputBuffer, uiBufferSize, uiWritePos, s, iNumDigits); } }
StringExt *StringExt::AppendFormatV(char *sFormat, va_list sArgList) { StringExtFormatArg uArg; int nIndex, nWidth, nPrecision; bool bReverseAlign, bZeroFill; StringExtFormatType eFormatType; char sBuffer[65]; int nLen; char *pCur, *pTemp, *sTemp; int nArgsLen = 0; int nArgsSize = 8; StringExtFormatArg *arrArgs = (StringExtFormatArg *)MemUtilsMallocArray( nArgsSize, sizeof(StringExtFormatArg)); pCur = sFormat; while ( *pCur ) { if ( *pCur == '{' ) { ++pCur; if ( *pCur == '{' ) { ++pCur; Append('{'); } else { // Разбираем форматированную строку if ( !(*pCur >= '0' && *pCur <= '9') ) break; nIndex = *pCur - '0'; for (++pCur; *pCur >= '0' && *pCur <= '9'; ++pCur ) nIndex = 10 * nIndex + (*pCur - '0'); if ( *pCur != ':' ) break; ++pCur; if ( *pCur == '-' ) { bReverseAlign = true; ++pCur; } else bReverseAlign = false; nWidth = 0; bZeroFill = *pCur == '0'; for (; *pCur >= '0' && *pCur <= '9'; ++pCur ) nWidth = 10 * nWidth + (*pCur - '0'); if ( *pCur == '.' ) { ++pCur; nPrecision = 0; for (; *pCur >= '0' && *pCur <= '9'; ++pCur ) { nPrecision = 10 * nPrecision + (*pCur - '0'); } } else { nPrecision = 0; } for ( eFormatType = (StringExtFormatType)0; c_arrsFormatStrings[ eFormatType ]; eFormatType = (StringExtFormatType)( eFormatType + 1 ) ) { if (!strncmp( pCur, c_arrsFormatStrings[ eFormatType ], strlen(c_arrsFormatStrings[ eFormatType ]))) { break; } } if ( !c_arrsFormatStrings[ eFormatType ] ) { break; } pCur += strlen( c_arrsFormatStrings[ eFormatType ] ); if (*pCur != '}') { break; } ++pCur; // fetch the argument if ( nIndex > nArgsLen ) { break; } if ( nIndex == nArgsLen ) { if ( nArgsLen == nArgsSize ) { nArgsSize *= 2; arrArgs = (StringExtFormatArg *)MemUtilsReallocArray( arrArgs, nArgsSize, sizeof(StringExtFormatArg)); } switch ( eFormatType ) { case fmtIntDecimal: case fmtIntHex: case fmtIntOctal: case fmtIntBinary: case fmtSpace: arrArgs[nArgsLen].iValue = va_arg( sArgList, int ); break; case fmtUIntDecimal: case fmtUIntHex: case fmtUIntOctal: case fmtUIntBinary: arrArgs[nArgsLen].uiValue = va_arg( sArgList, unsigned int ); break; case fmtLongDecimal: case fmtLongHex: case fmtLongOctal: case fmtLongBinary: arrArgs[nArgsLen].lValue = va_arg( sArgList, long ); break; case fmtULongDecimal: case fmtULongHex: case fmtULongOctal: case fmtULongBinary: arrArgs[nArgsLen].ulValue = va_arg( sArgList, unsigned long ); break; case fmtDouble: case fmtDoubleTrim: arrArgs[nArgsLen].fValue = va_arg( sArgList, double ); break; case fmtChar: arrArgs[nArgsLen].cValue = (char)va_arg( sArgList, int ); break; case fmtString: arrArgs[nArgsLen].sValue = va_arg( sArgList, char * ); break; case fmtStringExt: arrArgs[nArgsLen].seValue = va_arg(sArgList, StringExt *); break; } ++nArgsLen; } uArg = arrArgs[ nIndex ]; switch ( eFormatType ) { case fmtIntDecimal: FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen ); break; case fmtIntHex: FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen ); break; case fmtIntOctal: FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen ); break; case fmtIntBinary: FormatInt( uArg.iValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen ); break; case fmtUIntDecimal: FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen ); break; case fmtUIntHex: FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen ); break; case fmtUIntOctal: FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen ); break; case fmtUIntBinary: FormatUInt( uArg.uiValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen ); break; case fmtLongDecimal: FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen ); break; case fmtLongHex: FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen ); break; case fmtLongOctal: FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen ); break; case fmtLongBinary: FormatInt( uArg.lValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen ); break; case fmtULongDecimal: FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 10, &sTemp, &nLen ); break; case fmtULongHex: FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 16, &sTemp, &nLen ); break; case fmtULongOctal: FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 8, &sTemp, &nLen ); break; case fmtULongBinary: FormatUInt( uArg.ulValue, sBuffer, sizeof(sBuffer), bZeroFill, nWidth, 2, &sTemp, &nLen ); break; case fmtDouble: FormatDouble( uArg.fValue, sBuffer, sizeof(sBuffer), nPrecision, false, &sTemp, &nLen ); break; case fmtDoubleTrim: FormatDouble( uArg.fValue, sBuffer, sizeof(sBuffer), nPrecision, true, &sTemp, &nLen ); break; case fmtChar: sBuffer[0] = uArg.cValue; sTemp = sBuffer; nLen = 1; bReverseAlign = !bReverseAlign; break; case fmtString: sTemp = uArg.sValue; nLen = strlen( sTemp ); bReverseAlign = !bReverseAlign; break; case fmtStringExt: sTemp = uArg.seValue->GetBuffer(); nLen = uArg.seValue->GetLength(); bReverseAlign = !bReverseAlign; break; case fmtSpace: sTemp = sBuffer; nLen = 0; nWidth = uArg.iValue; break; } // Добавляем аргумент в нужном формате, с нужным прилеганием if ( !bReverseAlign && nLen < nWidth ) { for (int nCounter = nLen; nCounter < nWidth; ++nCounter ) Append(' '); } Append( sTemp, nLen); if ( bReverseAlign && nLen < nWidth ) { for (int nCounter = nLen; nCounter < nWidth; ++nCounter ) Append(' '); } } } else if ( *pCur == '}' )
static bool FormatUFloat (char* szOutputBuffer, unsigned int uiBufferSize, unsigned int& uiWritePos, double value, int iPrecision, unsigned int Flags, bool bRemoveZeroes) { if (value < 0) value = - value; bool bRoundedUp = false; long long int uiIntPart = (long long int) value; char szFraction[128]; int iFractionDigits = 0; double dRemainder = value - (double) uiIntPart; // make sure we don't write outside our buffer if (iPrecision > 64) iPrecision = 64; // When no precision is given a maximum of 6 fractional digits is written // However, all trailing zeros will be removed again, to shorten the number as much as possible const bool bRemoveTrailingZeros = bRemoveZeroes || (iPrecision < 0); if (iPrecision < 0) iPrecision = 6; for (int i = 0; i < iPrecision; ++i) { dRemainder *= 10.0f; long long int digit = (long long int) dRemainder; char cDigit = '0' + (char) (digit); szFraction[iFractionDigits++] = cDigit; dRemainder -= (double) digit; } // zero terminate the string szFraction[iFractionDigits] = '\0'; // if the NEXT (not written digit) is 5 or larger, round the whole number up if (dRemainder >= 0.5) { if (RoundUpDigits (szFraction, iFractionDigits)) { bRoundedUp = true; ++uiIntPart; } } if (bRemoveTrailingZeros) RemoveTrailingZeros (szFraction, iFractionDigits); { char szBuffer[128]; int iNumDigits = 0; // for a 32 Bit Integer one needs at most 10 digits // for a 64 Bit Integer one needs at most 20 digits // However, FormatUInt allows to add extra padding, so make the buffer a bit larger FormatUInt (szBuffer, iNumDigits, uiIntPart, 10, false, 1); OutputReverseString (szOutputBuffer, uiBufferSize, uiWritePos, szBuffer, iNumDigits); } // if there is any fractional digit, or the user specifically requested it, // add the '.' if ((iFractionDigits > 0) || (Flags & sprintfFlags::Hash)) OutputChar (szOutputBuffer, uiBufferSize, uiWritePos, '.'); OutputString (szOutputBuffer, uiBufferSize, uiWritePos, szFraction, 0, 0, -1); return bRoundedUp; }