📄 varformat.c
字号:
V_BOOL(&vBool) = VARIANT_TRUE;
}
else if (have_int == 1 && !exponent && rgbDig[0] == 0)
{
numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetZero(header));
V_BOOL(&vBool) = VARIANT_FALSE;
}
else
{
numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetPositive(header));
V_BOOL(&vBool) = VARIANT_TRUE;
}
TRACE("num header: flags = 0x%x, mult=%d, div=%d, whole=%d, fract=%d\n",
numHeader->flags, numHeader->multiplier, numHeader->divisor,
numHeader->whole, numHeader->fractional);
need_int = numHeader->whole;
need_frac = numHeader->fractional;
if (numHeader->flags & FMT_FLAG_PERCENT &&
!(have_int == 1 && !exponent && rgbDig[0] == 0))
exponent += 2;
if (numHeader->flags & FMT_FLAG_EXPONENT)
{
/* Exponent format: length of the integral number part is fixed and
specified by the format. */
pad = need_int - have_int;
if (pad >= 0)
exponent -= pad;
else
{
have_int = need_int;
have_frac -= pad;
exponent -= pad;
pad = 0;
}
}
else
{
/* Convert the exponent */
pad = max(exponent, -have_int);
exponent -= pad;
if (pad < 0)
{
have_int += pad;
have_frac = -pad;
pad = 0;
}
}
/* Rounding the number */
if (have_frac > need_frac)
{
prgbDig = &rgbDig[have_int + need_frac];
have_frac = need_frac;
if (*prgbDig >= 5)
{
while (prgbDig-- > rgbDig && *prgbDig == 9)
*prgbDig = 0;
if (prgbDig < rgbDig)
{
/* We reached the first digit and that was also a 9 */
rgbDig[0] = 1;
if (numHeader->flags & FMT_FLAG_EXPONENT)
exponent++;
else
{
rgbDig[have_int + need_frac] = 0;
have_int++;
}
}
else
(*prgbDig)++;
}
}
TRACE("have_int=%d,need_int=%d,have_frac=%d,need_frac=%d,pad=%d,exp=%d\n",
have_int, need_int, have_frac, need_frac, pad, exponent);
}
pToken = (const BYTE*)numHeader + sizeof(FMT_NUMBER_HEADER);
prgbDig = rgbDig;
while (SUCCEEDED(hRes) && *pToken != FMT_GEN_END)
{
WCHAR defaultChar = '?';
DWORD boolFlag, localeValue = 0;
if (pToken - rgbTok > header->size)
{
ERR("Ran off the end of the format!\n");
hRes = E_INVALIDARG;
goto VARIANT_FormatNumber_Exit;
}
switch (*pToken)
{
case FMT_GEN_COPY:
TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2]));
memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR));
pBuff += pToken[2];
pToken += 2;
break;
case FMT_GEN_INLINE:
pToken += 2;
TRACE("copy %s\n", debugstr_a((LPCSTR)pToken));
while (*pToken)
*pBuff++ = *pToken++;
break;
case FMT_NUM_YES_NO:
boolFlag = VAR_BOOLYESNO;
goto VARIANT_FormatNumber_Bool;
case FMT_NUM_ON_OFF:
boolFlag = VAR_BOOLONOFF;
goto VARIANT_FormatNumber_Bool;
case FMT_NUM_TRUE_FALSE:
boolFlag = VAR_LOCALBOOL;
VARIANT_FormatNumber_Bool:
{
BSTR boolStr = NULL;
if (pToken[1] != FMT_GEN_END)
{
ERR("Boolean token not at end of format!\n");
hRes = E_INVALIDARG;
goto VARIANT_FormatNumber_Exit;
}
hRes = VarBstrFromBool(V_BOOL(&vBool), lcid, boolFlag, &boolStr);
if (SUCCEEDED(hRes))
{
strcpyW(pBuff, boolStr);
SysFreeString(boolStr);
while (*pBuff)
pBuff++;
}
}
break;
case FMT_NUM_DECIMAL:
TRACE("write decimal separator\n");
localeValue = LOCALE_SDECIMAL;
defaultChar = '.';
dwState |= NUM_WROTE_DEC;
break;
case FMT_NUM_CURRENCY:
TRACE("write currency symbol\n");
localeValue = LOCALE_SCURRENCY;
defaultChar = '$';
break;
case FMT_NUM_EXP_POS_U:
case FMT_NUM_EXP_POS_L:
case FMT_NUM_EXP_NEG_U:
case FMT_NUM_EXP_NEG_L:
if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_NEG_L)
*pBuff++ = 'e';
else
*pBuff++ = 'E';
if (exponent < 0)
{
*pBuff++ = '-';
sprintfW(pBuff, szPercentZeroStar_d, pToken[1], -exponent);
}
else
{
if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_POS_U)
*pBuff++ = '+';
sprintfW(pBuff, szPercentZeroStar_d, pToken[1], exponent);
}
while (*pBuff)
pBuff++;
pToken++;
break;
case FMT_NUM_COPY_ZERO:
dwState |= NUM_WRITE_ON;
/* Fall through */
case FMT_NUM_COPY_SKIP:
TRACE("write %d %sdigits or %s\n", pToken[1],
dwState & NUM_WROTE_DEC ? "fractional " : "",
*pToken == FMT_NUM_COPY_ZERO ? "0" : "skip");
if (dwState & NUM_WROTE_DEC)
{
int count, i;
if (!(numHeader->flags & FMT_FLAG_EXPONENT) && exponent < 0)
{
/* Pad with 0 before writing the fractional digits */
pad = max(exponent, -pToken[1]);
exponent -= pad;
count = min(have_frac, pToken[1] + pad);
for (i = 0; i > pad; i--)
*pBuff++ = '0';
}
else
count = min(have_frac, pToken[1]);
pad += pToken[1] - count;
have_frac -= count;
while (count--)
*pBuff++ = '0' + *prgbDig++;
if (*pToken == FMT_NUM_COPY_ZERO)
{
for (; pad > 0; pad--)
*pBuff++ = '0'; /* Write zeros for missing trailing digits */
}
}
else
{
int count, count_max;
need_int -= pToken[1];
count_max = have_int + pad - need_int;
if (count_max < 0)
count_max = 0;
if (dwState & NUM_WRITE_ON)
{
count = pToken[1] - count_max;
TRACE("write %d leading zeros\n", count);
while (count-- > 0)
*pBuff++ = '0';
}
if (*pToken == FMT_NUM_COPY_ZERO || have_int > 1 || *prgbDig > 0)
{
dwState |= NUM_WRITE_ON;
count = min(count_max, have_int);
count_max -= count;
have_int -= count;
TRACE("write %d whole number digits\n", count);
while (count--)
*pBuff++ = '0' + *prgbDig++;
}
count = min(count_max, pad);
count_max -= count;
pad -= count;
TRACE("write %d whole trailing 0's\n", count);
while (count--)
*pBuff++ = '0';
}
pToken++;
break;
default:
ERR("Unknown token 0x%02x!\n", *pToken);
hRes = E_INVALIDARG;
goto VARIANT_FormatNumber_Exit;
}
if (localeValue)
{
if (GetLocaleInfoW(lcid, localeValue, pBuff,
sizeof(buff)/sizeof(WCHAR)-(pBuff-buff)))
{
TRACE("added %s\n", debugstr_w(pBuff));
while (*pBuff)
pBuff++;
}
else
{
TRACE("added %d '%c'\n", defaultChar, defaultChar);
*pBuff++ = defaultChar;
}
}
pToken++;
}
VARIANT_FormatNumber_Exit:
VariantClear(&vString);
*pBuff = '\0';
TRACE("buff is %s\n", debugstr_w(buff));
if (SUCCEEDED(hRes))
{
*pbstrOut = SysAllocString(buff);
if (!*pbstrOut)
hRes = E_OUTOFMEMORY;
}
return hRes;
}
/* Format a variant using a date format */
static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat,
LPBYTE rgbTok, ULONG dwFlags,
BSTR *pbstrOut, LCID lcid)
{
WCHAR buff[256], *pBuff = buff;
VARIANT vDate;
UDATE udate;
FMT_HEADER *header = (FMT_HEADER*)rgbTok;
FMT_DATE_HEADER *dateHeader;
const BYTE* pToken = NULL;
HRESULT hRes;
TRACE("(%p->(%s%s),%s,%p,0x%08x,%p,0x%08x)\n", pVarIn, debugstr_VT(pVarIn),
debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut,
lcid);
V_VT(&vDate) = VT_EMPTY;
if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL)
{
dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetNegative(header));
V_DATE(&vDate) = 0;
}
else
{
USHORT usFlags = dwFlags & VARIANT_CALENDAR_HIJRI ? VAR_CALENDAR_HIJRI : 0;
hRes = VariantChangeTypeEx(&vDate, pVarIn, LCID_US, usFlags, VT_DATE);
if (FAILED(hRes))
return hRes;
dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetPositive(header));
}
hRes = VarUdateFromDate(V_DATE(&vDate), 0 /* FIXME: flags? */, &udate);
if (FAILED(hRes))
return hRes;
pToken = (const BYTE*)dateHeader + sizeof(FMT_DATE_HEADER);
while (*pToken != FMT_GEN_END)
{
DWORD dwVal = 0, localeValue = 0, dwFmt = 0;
LPCWSTR szPrintFmt = NULL;
WCHAR defaultChar = '?';
if (pToken - rgbTok > header->size)
{
ERR("Ran off the end of the format!\n");
hRes = E_INVALIDARG;
goto VARIANT_FormatDate_Exit;
}
switch (*pToken)
{
case FMT_GEN_COPY:
TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2]));
memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR));
pBuff += pToken[2];
pToken += 2;
break;
case FMT_DATE_TIME_SEP:
TRACE("time separator\n");
localeValue = LOCALE_STIME;
defaultChar = ':';
break;
case FMT_DATE_DATE_SEP:
TRACE("date separator\n");
localeValue = LOCALE_SDATE;
defaultChar = '/';
break;
case FMT_DATE_GENERAL:
{
BSTR date = NULL;
WCHAR *pDate;
hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, &date);
if (FAILED(hRes))
goto VARIANT_FormatDate_Exit;
pDate = date;
while (*pDate)
*pBuff++ = *pDate++;
SysFreeString(date);
}
break;
case FMT_DATE_QUARTER:
if (udate.st.wMonth <= 3)
*pBuff++ = '1';
else if (udate.st.wMonth <= 6)
*pBuff++ = '2';
else if (udate.st.wMonth <= 9)
*pBuff++ = '3';
else
*pBuff++ = '4';
break;
case FMT_DATE_TIME_SYS:
{
/* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
BSTR date = NULL;
WCHAR *pDate;
hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, &date);
if (FAILED(hRes))
goto VARIANT_FormatDate_Exit;
pDate = date;
while (*pDate)
*pBuff++ = *pDate++;
SysFreeString(date);
}
break;
case FMT_DATE_DAY:
szPrintFmt = szPercent_d;
dwVal = udate.st.wDay;
break;
case FMT_DATE_DAY_0:
szPrintFmt = szPercentZeroTwo_d;
dwVal = udate.st.wDay;
break;
case FMT_DATE_DAY_SHORT:
/* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -