⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 varformat.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
  FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,
  FMT_GEN_INLINE,0x1,'%','\0',FMT_GEN_END
};

static const WCHAR szScientific[] = { 'S','c','i','e','n','t','i','f','i','c','\0' };
static const BYTE fmtScientific[0x13] =
{
  0x13,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
  FMT_FLAG_EXPONENT,0x0,0x0,0x1,0x2,
  FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_NUM_EXP_POS_U,0x2,FMT_GEN_END
};

typedef struct tagNAMED_FORMAT
{
  LPCWSTR name;
  const BYTE* format;
} NAMED_FORMAT;

/* Format name to tokenised format. Must be kept sorted by name */
static const NAMED_FORMAT VARIANT_NamedFormats[] =
{
  { szCurrency, fmtCurrency },
  { szFixed, fmtFixed },
  { szGeneralDate, fmtGeneralDate },
  { szGeneralNumber, fmtGeneralNumber },
  { szLongDate, fmtLongDate },
  { szLongTime, fmtLongTime },
  { szMediumDate, fmtMediumDate },
  { szMediumTime, fmtMediumTime },
  { szOnOff, fmtOnOff },
  { szPercent, fmtPercent },
  { szScientific, fmtScientific },
  { szShortDate, fmtShortDate },
  { szShortTime, fmtShortTime },
  { szStandard, fmtStandard },
  { szTrueFalse, fmtTrueFalse },
  { szYesNo, fmtYesNo }
};
typedef const NAMED_FORMAT *LPCNAMED_FORMAT;

static int FormatCompareFn(const void *l, const void *r)
{
  return strcmpiW(((LPCNAMED_FORMAT)l)->name, ((LPCNAMED_FORMAT)r)->name);
}

static inline const BYTE *VARIANT_GetNamedFormat(LPCWSTR lpszFormat)
{
  NAMED_FORMAT key;
  LPCNAMED_FORMAT fmt;

  key.name = lpszFormat;
  fmt = (LPCNAMED_FORMAT)bsearch(&key, VARIANT_NamedFormats,
                                 sizeof(VARIANT_NamedFormats)/sizeof(NAMED_FORMAT),
                                 sizeof(NAMED_FORMAT), FormatCompareFn);
  return fmt ? fmt->format : NULL;
}

/* Return an error if the token for the value will not fit in the destination */
#define NEED_SPACE(x) if (cbTok < (int)(x)) return TYPE_E_BUFFERTOOSMALL; cbTok -= (x)

/* Non-zero if the format is unknown or a given type */
#define COULD_BE(typ) ((!fmt_number && header->type==FMT_TYPE_UNKNOWN)||header->type==typ)

/* State during tokenising */
#define FMT_STATE_OPEN_COPY     0x1 /* Last token written was a copy */
#define FMT_STATE_WROTE_DECIMAL 0x2 /* Already wrote a decimal separator */
#define FMT_STATE_SEEN_HOURS    0x4 /* See the hh specifier */
#define FMT_STATE_WROTE_MINUTES 0x8 /* Wrote minutes */

/**********************************************************************
 *              VarTokenizeFormatString [OLEAUT32.140]
 *
 * Convert a format string into tokenised form.
 *
 * PARAMS
 *  lpszFormat [I] Format string to tokenise
 *  rgbTok     [O] Destination for tokenised format
 *  cbTok      [I] Size of rgbTok in bytes
 *  nFirstDay  [I] First day of the week (1-7, or 0 for current system default)
 *  nFirstWeek [I] How to treat the first week (see notes)
 *  lcid       [I] Locale Id of the format string
 *  pcbActual  [O] If non-NULL, filled with the first token generated
 *
 * RETURNS
 *  Success: S_OK. rgbTok contains the tokenised format.
 *  Failure: E_INVALIDARG, if any argument is invalid.
 *           TYPE_E_BUFFERTOOSMALL, if rgbTok is not large enough.
 *
 * NOTES
 * Valid values for the nFirstWeek parameter are:
 *| Value  Meaning
 *| -----  -------
 *|   0    Use the current system default
 *|   1    The first week is that containing Jan 1
 *|   2    Four or more days of the first week are in the current year
 *|   3    The first week is 7 days long
 * See Variant-Formats(), VarFormatFromTokens().
 */
HRESULT WINAPI VarTokenizeFormatString(LPOLESTR lpszFormat, LPBYTE rgbTok,
                                       int cbTok, int nFirstDay, int nFirstWeek,
                                       LCID lcid, int *pcbActual)
{
  /* Note: none of these strings should be NUL terminated */
  static const WCHAR szTTTTT[] = { 't','t','t','t','t' };
  static const WCHAR szAMPM[] = { 'A','M','P','M' };
  static const WCHAR szampm[] = { 'a','m','p','m' };
  static const WCHAR szAMSlashPM[] = { 'A','M','/','P','M' };
  static const WCHAR szamSlashpm[] = { 'a','m','/','p','m' };
  const BYTE *namedFmt;
  FMT_HEADER *header = (FMT_HEADER*)rgbTok;
  FMT_STRING_HEADER *str_header = (FMT_STRING_HEADER*)(rgbTok + sizeof(FMT_HEADER));
  FMT_NUMBER_HEADER *num_header = (FMT_NUMBER_HEADER*)str_header;
  FMT_DATE_HEADER *date_header = (FMT_DATE_HEADER*)str_header;
  BYTE* pOut = rgbTok + sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER);
  BYTE* pLastHours = NULL;
  BYTE fmt_number = 0;
  DWORD fmt_state = 0;
  LPCWSTR pFormat = lpszFormat;

  TRACE("(%s,%p,%d,%d,%d,0x%08x,%p)\n", debugstr_w(lpszFormat), rgbTok, cbTok,
        nFirstDay, nFirstWeek, lcid, pcbActual);

  if (!rgbTok ||
      nFirstDay < 0 || nFirstDay > 7 || nFirstWeek < 0 || nFirstWeek > 3)
    return E_INVALIDARG;

  if (!lpszFormat || !*lpszFormat)
  {
    /* An empty string means 'general format' */
    NEED_SPACE(sizeof(BYTE));
    *rgbTok = FMT_TO_STRING;
    if (pcbActual)
      *pcbActual = FMT_TO_STRING;
    return S_OK;
  }

  if (cbTok > 255)
    cbTok = 255; /* Ensure we error instead of wrapping */

  /* Named formats */
  namedFmt = VARIANT_GetNamedFormat(lpszFormat);
  if (namedFmt)
  {
    NEED_SPACE(namedFmt[0]);
    memcpy(rgbTok, namedFmt, namedFmt[0]);
    TRACE("Using pre-tokenised named format %s\n", debugstr_w(lpszFormat));
    /* FIXME: pcbActual */
    return S_OK;
  }

  /* Insert header */
  NEED_SPACE(sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER));
  memset(header, 0, sizeof(FMT_HEADER));
  memset(str_header, 0, sizeof(FMT_STRING_HEADER));

  header->starts[fmt_number] = sizeof(FMT_HEADER);

  while (*pFormat)
  {
    /* --------------
     * General tokens
     * --------------
     */
    if (*pFormat == ';')
    {
      while (*pFormat == ';')
      {
        TRACE(";\n");
        if (++fmt_number > 3)
          return E_INVALIDARG; /* too many formats */
        pFormat++;
      }
      if (*pFormat)
      {
        TRACE("New header\n");
        NEED_SPACE(sizeof(BYTE) + sizeof(FMT_STRING_HEADER));
        *pOut++ = FMT_GEN_END;

        header->starts[fmt_number] = pOut - rgbTok;
        str_header = (FMT_STRING_HEADER*)pOut;
        num_header = (FMT_NUMBER_HEADER*)pOut;
        date_header = (FMT_DATE_HEADER*)pOut;
        memset(str_header, 0, sizeof(FMT_STRING_HEADER));
        pOut += sizeof(FMT_STRING_HEADER);
        fmt_state = 0;
        pLastHours = NULL;
      }
    }
    else if (*pFormat == '\\')
    {
      /* Escaped character */
      if (pFormat[1])
      {
        NEED_SPACE(3 * sizeof(BYTE));
        pFormat++;
        *pOut++ = FMT_GEN_COPY;
        *pOut++ = pFormat - lpszFormat;
        *pOut++ = 0x1;
        fmt_state |= FMT_STATE_OPEN_COPY;
        TRACE("'\\'\n");
      }
      else
        fmt_state &= ~FMT_STATE_OPEN_COPY;
      pFormat++;
    }
    else if (*pFormat == '"')
    {
      /* Escaped string
       * Note: Native encodes "" as a copy of length zero. That's just dumb, so
       * here we avoid encoding anything in this case.
       */
      if (!pFormat[1])
        pFormat++;
      else if (pFormat[1] == '"')
      {
        pFormat += 2;
      }
      else
      {
        LPCWSTR start = ++pFormat;
        while (*pFormat && *pFormat != '"')
          pFormat++;
        NEED_SPACE(3 * sizeof(BYTE));
        *pOut++ = FMT_GEN_COPY;
        *pOut++ = start - lpszFormat;
        *pOut++ = pFormat - start;
        if (*pFormat == '"')
          pFormat++;
        TRACE("Quoted string pos %d, len %d\n", pOut[-2], pOut[-1]);
      }
      fmt_state &= ~FMT_STATE_OPEN_COPY;
    }
    /* -------------
     * Number tokens
     * -------------
     */
    else if (*pFormat == '0' && COULD_BE(FMT_TYPE_NUMBER))
    {
      /* Number formats: Digit from number or '0' if no digits
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_NUMBER;
      NEED_SPACE(2 * sizeof(BYTE));
      *pOut++ = FMT_NUM_COPY_ZERO;
      *pOut = 0x0;
      while (*pFormat == '0')
      {
        *pOut = *pOut + 1;
        pFormat++;
      }
      if (fmt_state & FMT_STATE_WROTE_DECIMAL)
        num_header->fractional += *pOut;
      else
        num_header->whole += *pOut;
      TRACE("%d 0's\n", *pOut);
      pOut++;
      fmt_state &= ~FMT_STATE_OPEN_COPY;
    }
    else if (*pFormat == '#' && COULD_BE(FMT_TYPE_NUMBER))
    {
      /* Number formats: Digit from number or blank if no digits
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_NUMBER;
      NEED_SPACE(2 * sizeof(BYTE));
      *pOut++ = FMT_NUM_COPY_SKIP;
      *pOut = 0x0;
      while (*pFormat == '#')
      {
        *pOut = *pOut + 1;
        pFormat++;
      }
      if (fmt_state & FMT_STATE_WROTE_DECIMAL)
        num_header->fractional += *pOut;
      else
        num_header->whole += *pOut;
      TRACE("%d #'s\n", *pOut);
      pOut++;
      fmt_state &= ~FMT_STATE_OPEN_COPY;
    }
    else if (*pFormat == '.' && COULD_BE(FMT_TYPE_NUMBER) &&
              !(fmt_state & FMT_STATE_WROTE_DECIMAL))
    {
      /* Number formats: Decimal separator when 1st seen, literal thereafter
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_NUMBER;
      NEED_SPACE(sizeof(BYTE));
      *pOut++ = FMT_NUM_DECIMAL;
      fmt_state |= FMT_STATE_WROTE_DECIMAL;
      fmt_state &= ~FMT_STATE_OPEN_COPY;
      pFormat++;
      TRACE("decimal sep\n");
    }
    else if ((*pFormat == 'e' || *pFormat == 'E') && (pFormat[1] == '-' ||
              pFormat[1] == '+') && header->type == FMT_TYPE_NUMBER)
    {
      /* Number formats: Exponent specifier
       * Other formats: Literal
       */
      num_header->flags |= FMT_FLAG_EXPONENT;
      NEED_SPACE(2 * sizeof(BYTE));
      if (*pFormat == 'e') {
        if (pFormat[1] == '+')
          *pOut = FMT_NUM_EXP_POS_L;
        else
          *pOut = FMT_NUM_EXP_NEG_L;
      } else {
        if (pFormat[1] == '+')
          *pOut = FMT_NUM_EXP_POS_U;
        else
          *pOut = FMT_NUM_EXP_NEG_U;
      }
      pFormat += 2;
      *++pOut = 0x0;
      while (*pFormat == '0')
      {
        *pOut = *pOut + 1;
        pFormat++;
      }
      pOut++;
      TRACE("exponent\n");
    }
    /* FIXME: %% => Divide by 1000 */
    else if (*pFormat == ',' && header->type == FMT_TYPE_NUMBER)
    {
      /* Number formats: Use the thousands separator
       * Other formats: Literal
       */
      num_header->flags |= FMT_FLAG_THOUSANDS;
      pFormat++;
      fmt_state &= ~FMT_STATE_OPEN_COPY;
      TRACE("thousands sep\n");
    }
    /* -----------
     * Date tokens
     * -----------
     */
    else if (*pFormat == '/' && COULD_BE(FMT_TYPE_DATE))
    {
      /* Date formats: Date separator
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_DATE;
      NEED_SPACE(sizeof(BYTE));
      *pOut++ = FMT_DATE_DATE_SEP;
      pFormat++;
      fmt_state &= ~FMT_STATE_OPEN_COPY;
      TRACE("date sep\n");
    }
    else if (*pFormat == ':' && COULD_BE(FMT_TYPE_DATE))
    {
      /* Date formats: Time separator
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_DATE;
      NEED_SPACE(sizeof(BYTE));
      *pOut++ = FMT_DATE_TIME_SEP;
      pFormat++;
      fmt_state &= ~FMT_STATE_OPEN_COPY;
      TRACE("time sep\n");
    }
    else if ((*pFormat == 'a' || *pFormat == 'A') &&
              !strncmpiW(pFormat, szAMPM, sizeof(szAMPM)/sizeof(WCHAR)))
    {
      /* Date formats: System AM/PM designation
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_DATE;
      NEED_SPACE(sizeof(BYTE));
      pFormat += sizeof(szAMPM)/sizeof(WCHAR);
      if (!strncmpW(pFormat, szampm, sizeof(szampm)/sizeof(WCHAR)))
        *pOut++ = FMT_DATE_AMPM_SYS2;
      else
        *pOut++ = FMT_DATE_AMPM_SYS1;
      if (pLastHours)
        *pLastHours = *pLastHours + 2;
      TRACE("ampm\n");
    }
    else if (*pFormat == 'a' && pFormat[1] == '/' &&
              (pFormat[2] == 'p' || pFormat[2] == 'P'))
    {
      /* Date formats: lowercase a or p designation
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_DATE;
      NEED_SPACE(sizeof(BYTE));
      pFormat += 3;
      *pOut++ = FMT_DATE_A_LOWER;
      if (pLastHours)
        *pLastHours = *pLastHours + 2;
      TRACE("a/p\n");
    }
    else if (*pFormat == 'A' && pFormat[1] == '/' &&
              (pFormat[2] == 'p' || pFormat[2] == 'P'))
    {
      /* Date formats: Uppercase a or p designation
       * Other formats: Literal
       * Types the format if found
       */
      header->type = FMT_TYPE_DATE;
      NEED_SPACE(sizeof(BYTE));
      pFormat += 3;
      *pOut++ = FMT_DATE_A_UPPER;
      if (pLastHours)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -