📄 varformat.c
字号:
*pLastHours = *pLastHours + 2;
TRACE("A/P\n");
}
else if (*pFormat == 'a' &&
!strncmpW(pFormat, szamSlashpm, sizeof(szamSlashpm)/sizeof(WCHAR)))
{
/* Date formats: lowercase AM or PM designation
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
pFormat += sizeof(szamSlashpm)/sizeof(WCHAR);
*pOut++ = FMT_DATE_AMPM_LOWER;
if (pLastHours)
*pLastHours = *pLastHours + 2;
TRACE("AM/PM\n");
}
else if (*pFormat == 'A' &&
!strncmpW(pFormat, szAMSlashPM, sizeof(szAMSlashPM)/sizeof(WCHAR)))
{
/* Date formats: Uppercase AM or PM designation
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
pFormat += sizeof(szAMSlashPM)/sizeof(WCHAR);
*pOut++ = FMT_DATE_AMPM_UPPER;
TRACE("AM/PM\n");
}
else if (*pFormat == 'c' || *pFormat == 'C')
{
/* Date formats: General date format
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
pFormat += sizeof(szAMSlashPM)/sizeof(WCHAR);
*pOut++ = FMT_DATE_GENERAL;
TRACE("gen date\n");
}
else if ((*pFormat == 'd' || *pFormat == 'D') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Day specifier
* Other formats: Literal
* Types the format if found
*/
int count = -1;
header->type = FMT_TYPE_DATE;
while ((*pFormat == 'd' || *pFormat == 'D') && count < 6)
{
pFormat++;
count++;
}
NEED_SPACE(sizeof(BYTE));
*pOut++ = FMT_DATE_DAY + count;
fmt_state &= ~FMT_STATE_OPEN_COPY;
/* When we find the days token, reset the seen hours state so that
* 'mm' is again written as month when encountered.
*/
fmt_state &= ~FMT_STATE_SEEN_HOURS;
TRACE("%d d's\n", count + 1);
}
else if ((*pFormat == 'h' || *pFormat == 'H') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Hour specifier
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
pFormat++;
/* Record the position of the hours specifier - if we encounter
* an am/pm specifier we will change the hours from 24 to 12.
*/
pLastHours = pOut;
if (*pFormat == 'h' || *pFormat == 'H')
{
pFormat++;
*pOut++ = FMT_DATE_HOUR_0;
TRACE("hh\n");
}
else
{
*pOut++ = FMT_DATE_HOUR;
TRACE("h\n");
}
fmt_state &= ~FMT_STATE_OPEN_COPY;
/* Note that now we have seen an hours token, the next occurrence of
* 'mm' indicates minutes, not months.
*/
fmt_state |= FMT_STATE_SEEN_HOURS;
}
else if ((*pFormat == 'm' || *pFormat == 'M') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Month specifier (or Minute specifier, after hour specifier)
* Other formats: Literal
* Types the format if found
*/
int count = -1;
header->type = FMT_TYPE_DATE;
while ((*pFormat == 'm' || *pFormat == 'M') && count < 4)
{
pFormat++;
count++;
}
NEED_SPACE(sizeof(BYTE));
if (count <= 1 && fmt_state & FMT_STATE_SEEN_HOURS &&
!(fmt_state & FMT_STATE_WROTE_MINUTES))
{
/* We have seen an hours specifier and not yet written a minutes
* specifier. Write this as minutes and thereafter as months.
*/
*pOut++ = count == 1 ? FMT_DATE_MIN_0 : FMT_DATE_MIN;
fmt_state |= FMT_STATE_WROTE_MINUTES; /* Hereafter write months */
}
else
*pOut++ = FMT_DATE_MON + count; /* Months */
fmt_state &= ~FMT_STATE_OPEN_COPY;
TRACE("%d m's\n", count + 1);
}
else if ((*pFormat == 'n' || *pFormat == 'N') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Minute specifier
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
pFormat++;
if (*pFormat == 'n' || *pFormat == 'N')
{
pFormat++;
*pOut++ = FMT_DATE_MIN_0;
TRACE("nn\n");
}
else
{
*pOut++ = FMT_DATE_MIN;
TRACE("n\n");
}
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if ((*pFormat == 'q' || *pFormat == 'q') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Quarter specifier
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
*pOut++ = FMT_DATE_QUARTER;
pFormat++;
fmt_state &= ~FMT_STATE_OPEN_COPY;
TRACE("quarter\n");
}
else if ((*pFormat == 's' || *pFormat == 'S') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Second specifier
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
NEED_SPACE(sizeof(BYTE));
pFormat++;
if (*pFormat == 's' || *pFormat == 'S')
{
pFormat++;
*pOut++ = FMT_DATE_SEC_0;
TRACE("ss\n");
}
else
{
*pOut++ = FMT_DATE_SEC;
TRACE("s\n");
}
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if ((*pFormat == 't' || *pFormat == 'T') &&
!strncmpiW(pFormat, szTTTTT, sizeof(szTTTTT)/sizeof(WCHAR)))
{
/* Date formats: System time specifier
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
pFormat += sizeof(szTTTTT)/sizeof(WCHAR);
NEED_SPACE(sizeof(BYTE));
*pOut++ = FMT_DATE_TIME_SYS;
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if ((*pFormat == 'w' || *pFormat == 'W') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Week of the year/Day of the week
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_DATE;
pFormat++;
if (*pFormat == 'w' || *pFormat == 'W')
{
NEED_SPACE(3 * sizeof(BYTE));
pFormat++;
*pOut++ = FMT_DATE_WEEK_YEAR;
*pOut++ = nFirstDay;
*pOut++ = nFirstWeek;
TRACE("ww\n");
}
else
{
NEED_SPACE(2 * sizeof(BYTE));
*pOut++ = FMT_DATE_DAY_WEEK;
*pOut++ = nFirstDay;
TRACE("w\n");
}
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if ((*pFormat == 'y' || *pFormat == 'Y') && COULD_BE(FMT_TYPE_DATE))
{
/* Date formats: Day of year/Year specifier
* Other formats: Literal
* Types the format if found
*/
int count = -1;
header->type = FMT_TYPE_DATE;
while ((*pFormat == 'y' || *pFormat == 'Y') && count < 4)
{
pFormat++;
count++;
}
if (count == 2)
{
count--; /* 'yyy' has no meaning, despite what MSDN says */
pFormat--;
}
NEED_SPACE(sizeof(BYTE));
*pOut++ = FMT_DATE_YEAR_DOY + count;
fmt_state &= ~FMT_STATE_OPEN_COPY;
TRACE("%d y's\n", count + 1);
}
/* -------------
* String tokens
* -------------
*/
else if (*pFormat == '@' && COULD_BE(FMT_TYPE_STRING))
{
/* String formats: Character from string or space if no char
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_STRING;
NEED_SPACE(2 * sizeof(BYTE));
*pOut++ = FMT_STR_COPY_SPACE;
*pOut = 0x0;
while (*pFormat == '@')
{
*pOut = *pOut + 1;
str_header->copy_chars++;
pFormat++;
}
TRACE("%d @'s\n", *pOut);
pOut++;
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if (*pFormat == '&' && COULD_BE(FMT_TYPE_STRING))
{
/* String formats: Character from string or skip if no char
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_STRING;
NEED_SPACE(2 * sizeof(BYTE));
*pOut++ = FMT_STR_COPY_SKIP;
*pOut = 0x0;
while (*pFormat == '&')
{
*pOut = *pOut + 1;
str_header->copy_chars++;
pFormat++;
}
TRACE("%d &'s\n", *pOut);
pOut++;
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if ((*pFormat == '<' || *pFormat == '>') && COULD_BE(FMT_TYPE_STRING))
{
/* String formats: Use upper/lower case
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_STRING;
if (*pFormat == '<')
str_header->flags |= FMT_FLAG_LT;
else
str_header->flags |= FMT_FLAG_GT;
TRACE("to %s case\n", *pFormat == '<' ? "lower" : "upper");
pFormat++;
fmt_state &= ~FMT_STATE_OPEN_COPY;
}
else if (*pFormat == '!' && COULD_BE(FMT_TYPE_STRING))
{
/* String formats: Copy right to left
* Other formats: Literal
* Types the format if found
*/
header->type = FMT_TYPE_STRING;
str_header->flags |= FMT_FLAG_RTL;
pFormat++;
fmt_state &= ~FMT_STATE_OPEN_COPY;
TRACE("copy right-to-left\n");
}
/* --------
* Literals
* --------
*/
/* FIXME: [ seems to be ignored */
else
{
if (*pFormat == '%' && header->type == FMT_TYPE_NUMBER)
{
/* Number formats: Percentage indicator, also a literal
* Other formats: Literal
* Doesn't type the format
*/
num_header->flags |= FMT_FLAG_PERCENT;
}
if (fmt_state & FMT_STATE_OPEN_COPY)
{
pOut[-1] = pOut[-1] + 1; /* Increase the length of the open copy */
TRACE("extend copy (char '%c'), length now %d\n", *pFormat, pOut[-1]);
}
else
{
/* Create a new open copy */
TRACE("New copy (char '%c')\n", *pFormat);
NEED_SPACE(3 * sizeof(BYTE));
*pOut++ = FMT_GEN_COPY;
*pOut++ = pFormat - lpszFormat;
*pOut++ = 0x1;
fmt_state |= FMT_STATE_OPEN_COPY;
}
pFormat++;
}
}
*pOut++ = FMT_GEN_END;
header->size = pOut - rgbTok;
if (pcbActual)
*pcbActual = header->size;
return S_OK;
}
/* Number formatting state flags */
#define NUM_WROTE_DEC 0x01 /* Written the decimal separator */
#define NUM_WRITE_ON 0x02 /* Started to write the number */
/* Format a variant using a number format */
static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat,
LPBYTE rgbTok, ULONG dwFlags,
BSTR *pbstrOut, LCID lcid)
{
BYTE rgbDig[256], *prgbDig;
NUMPARSE np;
int have_int, need_int = 0, have_frac, need_frac, exponent = 0, pad = 0;
WCHAR buff[256], *pBuff = buff;
VARIANT vString, vBool;
DWORD dwState = 0;
FMT_HEADER *header = (FMT_HEADER*)rgbTok;
FMT_NUMBER_HEADER *numHeader;
const BYTE* pToken = NULL;
HRESULT hRes = S_OK;
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(&vString) = VT_EMPTY;
V_VT(&vBool) = VT_BOOL;
if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL)
{
have_int = have_frac = 0;
numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNull(header));
V_BOOL(&vBool) = VARIANT_FALSE;
}
else
{
/* Get a number string from pVarIn, and parse it */
hRes = VariantChangeTypeEx(&vString, pVarIn, LCID_US, VARIANT_NOUSEROVERRIDE, VT_BSTR);
if (FAILED(hRes))
return hRes;
np.cDig = sizeof(rgbDig);
np.dwInFlags = NUMPRS_STD;
hRes = VarParseNumFromStr(V_BSTR(&vString), LCID_US, 0, &np, rgbDig);
if (FAILED(hRes))
return hRes;
have_int = np.cDig;
have_frac = 0;
exponent = np.nPwr10;
/* Figure out which format to use */
if (np.dwOutFlags & NUMPRS_NEG)
{
numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNegative(header));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -