📄 variant.c
字号:
{
static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' };
LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE;
WCHAR buff[4];
memcpy(lpChars, &defaultChars, sizeof(defaultChars));
GET_NUMBER_TEXT(LOCALE_SNEGATIVESIGN, cNegativeSymbol);
GET_NUMBER_TEXT(LOCALE_SPOSITIVESIGN, cPositiveSymbol);
GET_NUMBER_TEXT(LOCALE_SDECIMAL, cDecimalPoint);
GET_NUMBER_TEXT(LOCALE_STHOUSAND, cDigitSeparator);
GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint);
GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeparator);
/* Local currency symbols are often 2 characters */
lpChars->cCurrencyLocal2 = '\0';
switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, sizeof(buff)/sizeof(WCHAR)))
{
case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */
case 2: lpChars->cCurrencyLocal = buff[0];
break;
default: WARN("buffer too small for LOCALE_SCURRENCY\n");
}
TRACE("lcid 0x%x, cCurrencyLocal =%d,%d '%c','%c'\n", lcid, lpChars->cCurrencyLocal,
lpChars->cCurrencyLocal2, lpChars->cCurrencyLocal, lpChars->cCurrencyLocal2);
}
/* Number Parsing States */
#define B_PROCESSING_EXPONENT 0x1
#define B_NEGATIVE_EXPONENT 0x2
#define B_EXPONENT_START 0x4
#define B_INEXACT_ZEROS 0x8
#define B_LEADING_ZERO 0x10
#define B_PROCESSING_HEX 0x20
#define B_PROCESSING_OCT 0x40
/**********************************************************************
* VarParseNumFromStr [OLEAUT32.46]
*
* Parse a string containing a number into a NUMPARSE structure.
*
* PARAMS
* lpszStr [I] String to parse number from
* lcid [I] Locale Id for the conversion
* dwFlags [I] 0, or LOCALE_NOUSEROVERRIDE to use system default number chars
* pNumprs [I/O] Destination for parsed number
* rgbDig [O] Destination for digits read in
*
* RETURNS
* Success: S_OK. pNumprs and rgbDig contain the parsed representation of
* the number.
* Failure: E_INVALIDARG, if any parameter is invalid.
* DISP_E_TYPEMISMATCH, if the string is not a number or is formatted
* incorrectly.
* DISP_E_OVERFLOW, if rgbDig is too small to hold the number.
*
* NOTES
* pNumprs must have the following fields set:
* cDig: Set to the size of rgbDig.
* dwInFlags: Set to the allowable syntax of the number using NUMPRS_ flags
* from "oleauto.h".
*
* FIXME
* - I am unsure if this function should parse non-arabic (e.g. Thai)
* numerals, so this has not been implemented.
*/
HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags,
NUMPARSE *pNumprs, BYTE *rgbDig)
{
VARIANT_NUMBER_CHARS chars;
BYTE rgbTmp[1024];
DWORD dwState = B_EXPONENT_START|B_INEXACT_ZEROS;
int iMaxDigits = sizeof(rgbTmp) / sizeof(BYTE);
int cchUsed = 0;
TRACE("(%s,%d,0x%08x,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig);
if (!pNumprs || !rgbDig)
return E_INVALIDARG;
if (pNumprs->cDig < iMaxDigits)
iMaxDigits = pNumprs->cDig;
pNumprs->cDig = 0;
pNumprs->dwOutFlags = 0;
pNumprs->cchUsed = 0;
pNumprs->nBaseShift = 0;
pNumprs->nPwr10 = 0;
if (!lpszStr)
return DISP_E_TYPEMISMATCH;
VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags);
/* First consume all the leading symbols and space from the string */
while (1)
{
if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && isspaceW(*lpszStr))
{
pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE;
do
{
cchUsed++;
lpszStr++;
} while (isspaceW(*lpszStr));
}
else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS &&
*lpszStr == chars.cPositiveSymbol &&
!(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS))
{
pNumprs->dwOutFlags |= NUMPRS_LEADING_PLUS;
cchUsed++;
lpszStr++;
}
else if (pNumprs->dwInFlags & NUMPRS_LEADING_MINUS &&
*lpszStr == chars.cNegativeSymbol &&
!(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS))
{
pNumprs->dwOutFlags |= (NUMPRS_LEADING_MINUS|NUMPRS_NEG);
cchUsed++;
lpszStr++;
}
else if (pNumprs->dwInFlags & NUMPRS_CURRENCY &&
!(pNumprs->dwOutFlags & NUMPRS_CURRENCY) &&
*lpszStr == chars.cCurrencyLocal &&
(!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2))
{
pNumprs->dwOutFlags |= NUMPRS_CURRENCY;
cchUsed++;
lpszStr++;
/* Only accept currency characters */
chars.cDecimalPoint = chars.cCurrencyDecimalPoint;
chars.cDigitSeparator = chars.cCurrencyDigitSeparator;
}
else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' &&
!(pNumprs->dwOutFlags & NUMPRS_PARENS))
{
pNumprs->dwOutFlags |= NUMPRS_PARENS;
cchUsed++;
lpszStr++;
}
else
break;
}
if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY))
{
/* Only accept non-currency characters */
chars.cCurrencyDecimalPoint = chars.cDecimalPoint;
chars.cCurrencyDigitSeparator = chars.cDigitSeparator;
}
if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) &&
pNumprs->dwInFlags & NUMPRS_HEX_OCT)
{
dwState |= B_PROCESSING_HEX;
pNumprs->dwOutFlags |= NUMPRS_HEX_OCT;
cchUsed=cchUsed+2;
lpszStr=lpszStr+2;
}
else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) &&
pNumprs->dwInFlags & NUMPRS_HEX_OCT)
{
dwState |= B_PROCESSING_OCT;
pNumprs->dwOutFlags |= NUMPRS_HEX_OCT;
cchUsed=cchUsed+2;
lpszStr=lpszStr+2;
}
/* Strip Leading zeros */
while (*lpszStr == '0')
{
dwState |= B_LEADING_ZERO;
cchUsed++;
lpszStr++;
}
while (*lpszStr)
{
if (isdigitW(*lpszStr))
{
if (dwState & B_PROCESSING_EXPONENT)
{
int exponentSize = 0;
if (dwState & B_EXPONENT_START)
{
if (!isdigitW(*lpszStr))
break; /* No exponent digits - invalid */
while (*lpszStr == '0')
{
/* Skip leading zero's in the exponent */
cchUsed++;
lpszStr++;
}
}
while (isdigitW(*lpszStr))
{
exponentSize *= 10;
exponentSize += *lpszStr - '0';
cchUsed++;
lpszStr++;
}
if (dwState & B_NEGATIVE_EXPONENT)
exponentSize = -exponentSize;
/* Add the exponent into the powers of 10 */
pNumprs->nPwr10 += exponentSize;
dwState &= ~(B_PROCESSING_EXPONENT|B_EXPONENT_START);
lpszStr--; /* back up to allow processing of next char */
}
else
{
if ((pNumprs->cDig >= iMaxDigits) && !(dwState & B_PROCESSING_HEX)
&& !(dwState & B_PROCESSING_OCT))
{
pNumprs->dwOutFlags |= NUMPRS_INEXACT;
if (*lpszStr != '0')
dwState &= ~B_INEXACT_ZEROS; /* Inexact number with non-trailing zeros */
/* This digit can't be represented, but count it in nPwr10 */
if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
pNumprs->nPwr10--;
else
pNumprs->nPwr10++;
}
else
{
if ((dwState & B_PROCESSING_OCT) && ((*lpszStr == '8') || (*lpszStr == '9'))) {
return DISP_E_TYPEMISMATCH;
}
if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
pNumprs->nPwr10--; /* Count decimal points in nPwr10 */
rgbTmp[pNumprs->cDig] = *lpszStr - '0';
}
pNumprs->cDig++;
cchUsed++;
}
}
else if (*lpszStr == chars.cDigitSeparator && pNumprs->dwInFlags & NUMPRS_THOUSANDS)
{
pNumprs->dwOutFlags |= NUMPRS_THOUSANDS;
cchUsed++;
}
else if (*lpszStr == chars.cDecimalPoint &&
pNumprs->dwInFlags & NUMPRS_DECIMAL &&
!(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT)))
{
pNumprs->dwOutFlags |= NUMPRS_DECIMAL;
cchUsed++;
/* If we have no digits so far, skip leading zeros */
if (!pNumprs->cDig)
{
while (lpszStr[1] == '0')
{
dwState |= B_LEADING_ZERO;
cchUsed++;
lpszStr++;
pNumprs->nPwr10--;
}
}
}
else if (((*lpszStr >= 'a' && *lpszStr <= 'f') ||
(*lpszStr >= 'A' && *lpszStr <= 'F')) &&
dwState & B_PROCESSING_HEX)
{
if (pNumprs->cDig >= iMaxDigits)
{
return DISP_E_OVERFLOW;
}
else
{
if (*lpszStr >= 'a')
rgbTmp[pNumprs->cDig] = *lpszStr - 'a' + 10;
else
rgbTmp[pNumprs->cDig] = *lpszStr - 'A' + 10;
}
pNumprs->cDig++;
cchUsed++;
}
else if ((*lpszStr == 'e' || *lpszStr == 'E') &&
pNumprs->dwInFlags & NUMPRS_EXPONENT &&
!(pNumprs->dwOutFlags & NUMPRS_EXPONENT))
{
dwState |= B_PROCESSING_EXPONENT;
pNumprs->dwOutFlags |= NUMPRS_EXPONENT;
cchUsed++;
}
else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cPositiveSymbol)
{
cchUsed++; /* Ignore positive exponent */
}
else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cNegativeSymbol)
{
dwState |= B_NEGATIVE_EXPONENT;
cchUsed++;
}
else
break; /* Stop at an unrecognised character */
lpszStr++;
}
if (!pNumprs->cDig && dwState & B_LEADING_ZERO)
{
/* Ensure a 0 on its own gets stored */
pNumprs->cDig = 1;
rgbTmp[0] = 0;
}
if (pNumprs->dwOutFlags & NUMPRS_EXPONENT && dwState & B_PROCESSING_EXPONENT)
{
pNumprs->cchUsed = cchUsed;
WARN("didn't completely parse exponent\n");
return DISP_E_TYPEMISMATCH; /* Failed to completely parse the exponent */
}
if (pNumprs->dwOutFlags & NUMPRS_INEXACT)
{
if (dwState & B_INEXACT_ZEROS)
pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */
} else if(pNumprs->dwInFlags & NUMPRS_HEX_OCT)
{
/* copy all of the digits into the output digit buffer */
/* this is exactly what windows does although it also returns */
/* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */
memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
if (dwState & B_PROCESSING_HEX) {
/* hex numbers have always the same format */
pNumprs->nPwr10=0;
pNumprs->nBaseShift=4;
} else {
if (dwState & B_PROCESSING_OCT) {
/* oct numbers have always the same format */
pNumprs->nPwr10=0;
pNumprs->nBaseShift=3;
} else {
while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
{
pNumprs->nPwr10++;
pNumprs->cDig--;
}
}
}
} else
{
/* Remove trailing zeros from the last (whole number or decimal) part */
while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
{
pNumprs->nPwr10++;
pNumprs->cDig--;
}
}
if (pNumprs->cDig <= iMaxDigits)
pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* Ignore stripped zeros for NUMPRS_INEXACT */
else
pNumprs->cDig = iMaxDigits; /* Only return iMaxDigits worth of digits */
/* Copy the digits we processed into rgbDig */
memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
/* Consume
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -