ReactOS  0.4.13-dev-257-gfabbd7c
varformat.c
Go to the documentation of this file.
1 /*
2  * Variant formatting functions
3  *
4  * Copyright 2008 Damjan Jovanovic
5  * Copyright 2003 Jon Griffiths
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES
22  * Since the formatting functions aren't properly documented, I used the
23  * Visual Basic documentation as a guide to implementing these functions. This
24  * means that some named or user-defined formats may work slightly differently.
25  * Please submit a test case if you find a difference.
26  */
27 
28 #include "config.h"
29 
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/unicode.h"
38 #include "winerror.h"
39 #include "variant.h"
40 #include "wine/debug.h"
41 
43 
44 /* Make sure internal conversions to strings use the '.','+'/'-' and ','
45  * format chars from the US locale. This enables us to parse the created
46  * strings to determine the number of decimal places, exponent, etc.
47  */
48 #define LCID_US MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT)
49 
50 static const WCHAR szPercent_d[] = { '%','d','\0' };
51 static const WCHAR szPercentZeroTwo_d[] = { '%','0','2','d','\0' };
52 static const WCHAR szPercentZeroStar_d[] = { '%','0','*','d','\0' };
53 
54 /******************************************************************************
55  * Variant-Formats {OLEAUT32}
56  *
57  * NOTES
58  * When formatting a variant a variety of format strings may be used to generate
59  * different kinds of formatted output. A format string consists of either a named
60  * format, or a user-defined format.
61  *
62  * The following named formats are defined:
63  *| Name Description
64  *| ---- -----------
65  *| General Date Display Date, and time for non-integer values
66  *| Short Date Short date format as defined by locale settings
67  *| Medium Date Medium date format as defined by locale settings
68  *| Long Date Long date format as defined by locale settings
69  *| Short Time Short Time format as defined by locale settings
70  *| Medium Time Medium time format as defined by locale settings
71  *| Long Time Long time format as defined by locale settings
72  *| True/False Localised text of "True" or "False"
73  *| Yes/No Localised text of "Yes" or "No"
74  *| On/Off Localised text of "On" or "Off"
75  *| General Number No thousands separator. No decimal points for integers
76  *| Currency General currency format using localised characters
77  *| Fixed At least one whole and two fractional digits
78  *| Standard Same as 'Fixed', but including decimal separators
79  *| Percent Multiply by 100 and display a trailing '%' character
80  *| Scientific Display with exponent
81  *
82  * User-defined formats consist of a combination of tokens and literal
83  * characters. Literal characters are copied unmodified to the formatted
84  * output at the position they occupy in the format string. Any character
85  * that is not recognised as a token is treated as a literal. A literal can
86  * also be specified by preceding it with a backslash character
87  * (e.g. "\L\i\t\e\r\a\l") or enclosing it in double quotes.
88  *
89  * A user-defined format can have up to 4 sections, depending on the type of
90  * format. The following table lists sections and their meaning:
91  *| Format Type Sections Meaning
92  *| ----------- -------- -------
93  *| Number 1 Use the same format for all numbers
94  *| Number 2 Use format 1 for positive and 2 for negative numbers
95  *| Number 3 Use format 1 for positive, 2 for zero, and 3
96  *| for negative numbers.
97  *| Number 4 Use format 1 for positive, 2 for zero, 3 for
98  *| negative, and 4 for null numbers.
99  *| String 1 Use the same format for all strings
100  *| String 2 Use format 2 for null and empty strings, otherwise
101  *| use format 1.
102  *| Date 1 Use the same format for all dates
103  *
104  * The formatting tokens fall into several categories depending on the type
105  * of formatted output. For more information on each type, see
106  * VarFormat-Dates(), VarFormat-Strings() and VarFormat-Numbers().
107  *
108  * SEE ALSO
109  * VarTokenizeFormatString(), VarFormatFromTokens(), VarFormat(),
110  * VarFormatDateTime(), VarFormatNumber(), VarFormatCurrency().
111  */
112 
113 /******************************************************************************
114  * VarFormat-Strings {OLEAUT32}
115  *
116  * NOTES
117  * When formatting a variant as a string, it is first converted to a VT_BSTR.
118  * The user-format string defines which characters are copied into which
119  * positions in the output string. Literals may be inserted in the format
120  * string. When creating the formatted string, excess characters in the string
121  * (those not consumed by a token) are appended to the end of the output. If
122  * there are more tokens than characters in the string to format, spaces will
123  * be inserted at the start of the string if the '@' token was used.
124  *
125  * By default strings are converted to lowercase, or uppercase if the '>' token
126  * is encountered. This applies to the whole string: it is not possible to
127  * generate a mixed-case output string.
128  *
129  * In user-defined string formats, the following tokens are recognised:
130  *| Token Description
131  *| ----- -----------
132  *| '@' Copy a char from the source, or a space if no chars are left.
133  *| '&' Copy a char from the source, or write nothing if no chars are left.
134  *| '<' Output the whole string as lower-case (the default).
135  *| '>' Output the whole string as upper-case.
136  *| '!' MSDN indicates that this character should cause right-to-left
137  *| copying, however tests show that it is tokenised but not processed.
138  */
139 
140 /*
141  * Common format definitions
142  */
143 
144  /* Format types */
145 #define FMT_TYPE_UNKNOWN 0x0
146 #define FMT_TYPE_GENERAL 0x1
147 #define FMT_TYPE_NUMBER 0x2
148 #define FMT_TYPE_DATE 0x3
149 #define FMT_TYPE_STRING 0x4
150 
151 #define FMT_TO_STRING 0x0 /* If header->size == this, act like VB's Str() fn */
152 
153 typedef struct tagFMT_SHORT_HEADER
154 {
155  BYTE size; /* Size of tokenised block (including header), or FMT_TO_STRING */
156  BYTE type; /* Allowable types (FMT_TYPE_*) */
157  BYTE offset[1]; /* Offset of the first (and only) format section */
159 
160 typedef struct tagFMT_HEADER
161 {
162  BYTE size; /* Total size of the whole tokenised block (including header) */
163  BYTE type; /* Allowable types (FMT_TYPE_*) */
164  BYTE starts[4]; /* Offset of each of the 4 format sections, or 0 if none */
165 } FMT_HEADER;
166 
167 #define FmtGetPositive(x) (x->starts[0])
168 #define FmtGetNegative(x) (x->starts[1] ? x->starts[1] : x->starts[0])
169 #define FmtGetZero(x) (x->starts[2] ? x->starts[2] : x->starts[0])
170 #define FmtGetNull(x) (x->starts[3] ? x->starts[3] : x->starts[0])
171 
172 /*
173  * String formats
174  */
175 
176 #define FMT_FLAG_LT 0x1 /* Has '<' (lower case) */
177 #define FMT_FLAG_GT 0x2 /* Has '>' (upper case) */
178 #define FMT_FLAG_RTL 0x4 /* Has '!' (Copy right to left) */
179 
180 typedef struct tagFMT_STRING_HEADER
181 {
182  BYTE flags; /* LT, GT, RTL */
185  BYTE copy_chars; /* Number of chars to be copied */
188 
189 /*
190  * Number formats
191  */
192 
193 #define FMT_FLAG_PERCENT 0x1 /* Has '%' (Percentage) */
194 #define FMT_FLAG_EXPONENT 0x2 /* Has 'e' (Exponent/Scientific notation) */
195 #define FMT_FLAG_THOUSANDS 0x4 /* Has ',' (Standard use of the thousands separator) */
196 #define FMT_FLAG_BOOL 0x20 /* Boolean format */
197 
198 typedef struct tagFMT_NUMBER_HEADER
199 {
200  BYTE flags; /* PERCENT, EXPONENT, THOUSANDS, BOOL */
201  BYTE multiplier; /* Multiplier, 100 for percentages */
202  BYTE divisor; /* Divisor, 1000 if '%%' was used */
203  BYTE whole; /* Number of digits before the decimal point */
204  BYTE fractional; /* Number of digits after the decimal point */
206 
207 /*
208  * Date Formats
209  */
210 typedef struct tagFMT_DATE_HEADER
211 {
218 
219 /*
220  * Format token values
221  */
222 #define FMT_GEN_COPY 0x00 /* \n, "lit" => 0,pos,len: Copy len chars from input+pos */
223 #define FMT_GEN_INLINE 0x01 /* => 1,len,[chars]: Copy len chars from token stream */
224 #define FMT_GEN_END 0x02 /* \0,; => 2: End of the tokenised format */
225 #define FMT_DATE_TIME_SEP 0x03 /* Time separator char */
226 #define FMT_DATE_DATE_SEP 0x04 /* Date separator char */
227 #define FMT_DATE_GENERAL 0x05 /* General format date */
228 #define FMT_DATE_QUARTER 0x06 /* Quarter of the year from 1-4 */
229 #define FMT_DATE_TIME_SYS 0x07 /* System long time format */
230 #define FMT_DATE_DAY 0x08 /* Day with no leading 0 */
231 #define FMT_DATE_DAY_0 0x09 /* Day with leading 0 */
232 #define FMT_DATE_DAY_SHORT 0x0A /* Short day name */
233 #define FMT_DATE_DAY_LONG 0x0B /* Long day name */
234 #define FMT_DATE_SHORT 0x0C /* Short date format */
235 #define FMT_DATE_LONG 0x0D /* Long date format */
236 #define FMT_DATE_MEDIUM 0x0E /* Medium date format */
237 #define FMT_DATE_DAY_WEEK 0x0F /* First day of the week */
238 #define FMT_DATE_WEEK_YEAR 0x10 /* First week of the year */
239 #define FMT_DATE_MON 0x11 /* Month with no leading 0 */
240 #define FMT_DATE_MON_0 0x12 /* Month with leading 0 */
241 #define FMT_DATE_MON_SHORT 0x13 /* Short month name */
242 #define FMT_DATE_MON_LONG 0x14 /* Long month name */
243 #define FMT_DATE_YEAR_DOY 0x15 /* Day of the year with no leading 0 */
244 #define FMT_DATE_YEAR_0 0x16 /* 2 digit year with leading 0 */
245 /* NOTE: token 0x17 is not defined, 'yyy' is not valid */
246 #define FMT_DATE_YEAR_LONG 0x18 /* 4 digit year */
247 #define FMT_DATE_MIN 0x1A /* Minutes with no leading 0 */
248 #define FMT_DATE_MIN_0 0x1B /* Minutes with leading 0 */
249 #define FMT_DATE_SEC 0x1C /* Seconds with no leading 0 */
250 #define FMT_DATE_SEC_0 0x1D /* Seconds with leading 0 */
251 #define FMT_DATE_HOUR 0x1E /* Hours with no leading 0 */
252 #define FMT_DATE_HOUR_0 0x1F /* Hours with leading 0 */
253 #define FMT_DATE_HOUR_12 0x20 /* Hours with no leading 0, 12 hour clock */
254 #define FMT_DATE_HOUR_12_0 0x21 /* Hours with leading 0, 12 hour clock */
255 #define FMT_DATE_TIME_UNK2 0x23 /* same as FMT_DATE_HOUR_0, for "short time" format */
256 /* FIXME: probably missing some here */
257 #define FMT_DATE_AMPM_SYS1 0x2E /* AM/PM as defined by system settings */
258 #define FMT_DATE_AMPM_UPPER 0x2F /* Upper-case AM or PM */
259 #define FMT_DATE_A_UPPER 0x30 /* Upper-case A or P */
260 #define FMT_DATE_AMPM_SYS2 0x31 /* AM/PM as defined by system settings */
261 #define FMT_DATE_AMPM_LOWER 0x32 /* Lower-case AM or PM */
262 #define FMT_DATE_A_LOWER 0x33 /* Lower-case A or P */
263 #define FMT_NUM_COPY_ZERO 0x34 /* Copy 1 digit or 0 if no digit */
264 #define FMT_NUM_COPY_SKIP 0x35 /* Copy 1 digit or skip if no digit */
265 #define FMT_NUM_DECIMAL 0x36 /* Decimal separator */
266 #define FMT_NUM_EXP_POS_U 0x37 /* Scientific notation, uppercase, + sign */
267 #define FMT_NUM_EXP_NEG_U 0x38 /* Scientific notation, uppercase, - sign */
268 #define FMT_NUM_EXP_POS_L 0x39 /* Scientific notation, lowercase, + sign */
269 #define FMT_NUM_EXP_NEG_L 0x3A /* Scientific notation, lowercase, - sign */
270 #define FMT_NUM_CURRENCY 0x3B /* Currency symbol */
271 #define FMT_NUM_TRUE_FALSE 0x3D /* Convert to "True" or "False" */
272 #define FMT_NUM_YES_NO 0x3E /* Convert to "Yes" or "No" */
273 #define FMT_NUM_ON_OFF 0x3F /* Convert to "On" or "Off" */
274 #define FMT_STR_COPY_SPACE 0x40 /* Copy len chars with space if no char */
275 #define FMT_STR_COPY_SKIP 0x41 /* Copy len chars or skip if no char */
276 
277 /* Named Formats and their tokenised values */
278 static const WCHAR szGeneralDate[] = { 'G','e','n','e','r','a','l',' ','D','a','t','e','\0' };
279 static const BYTE fmtGeneralDate[0x0a] =
280 {
281  0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
282  0x0,0x0,0x0,0x0,0x0,
284 };
285 
286 static const WCHAR szShortDate[] = { 'S','h','o','r','t',' ','D','a','t','e','\0' };
287 static const BYTE fmtShortDate[0x0a] =
288 {
289  0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
290  0x0,0x0,0x0,0x0,0x0,
292 };
293 
294 static const WCHAR szMediumDate[] = { 'M','e','d','i','u','m',' ','D','a','t','e','\0' };
295 static const BYTE fmtMediumDate[0x0a] =
296 {
297  0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
298  0x0,0x0,0x0,0x0,0x0,
300 };
301 
302 static const WCHAR szLongDate[] = { 'L','o','n','g',' ','D','a','t','e','\0' };
303 static const BYTE fmtLongDate[0x0a] =
304 {
305  0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
306  0x0,0x0,0x0,0x0,0x0,
308 };
309 
310 static const WCHAR szShortTime[] = { 'S','h','o','r','t',' ','T','i','m','e','\0' };
311 static const BYTE fmtShortTime[0x0c] =
312 {
313  0x0c,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
314  0x0,0x0,0x0,0x0,0x0,
316 };
317 
318 static const WCHAR szMediumTime[] = { 'M','e','d','i','u','m',' ','T','i','m','e','\0' };
319 static const BYTE fmtMediumTime[0x11] =
320 {
321  0x11,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
322  0x0,0x0,0x0,0x0,0x0,
325 };
326 
327 static const WCHAR szLongTime[] = { 'L','o','n','g',' ','T','i','m','e','\0' };
328 static const BYTE fmtLongTime[0x0d] =
329 {
330  0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
331  0x0,0x0,0x0,0x0,0x0,
333 };
334 
335 static const WCHAR szTrueFalse[] = { 'T','r','u','e','/','F','a','l','s','e','\0' };
336 static const BYTE fmtTrueFalse[0x0d] =
337 {
338  0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
339  FMT_FLAG_BOOL,0x0,0x0,0x0,0x0,
341 };
342 
343 static const WCHAR szYesNo[] = { 'Y','e','s','/','N','o','\0' };
344 static const BYTE fmtYesNo[0x0d] =
345 {
346  0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
347  FMT_FLAG_BOOL,0x0,0x0,0x0,0x0,
349 };
350 
351 static const WCHAR szOnOff[] = { 'O','n','/','O','f','f','\0' };
352 static const BYTE fmtOnOff[0x0d] =
353 {
354  0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
355  FMT_FLAG_BOOL,0x0,0x0,0x0,0x0,
357 };
358 
359 static const WCHAR szGeneralNumber[] = { 'G','e','n','e','r','a','l',' ','N','u','m','b','e','r','\0' };
360 static const BYTE fmtGeneralNumber[sizeof(FMT_HEADER)] =
361 {
362  sizeof(FMT_HEADER),FMT_TYPE_GENERAL,sizeof(FMT_HEADER),0x0,0x0,0x0
363 };
364 
365 static const WCHAR szCurrency[] = { 'C','u','r','r','e','n','c','y','\0' };
366 static const BYTE fmtCurrency[0x26] =
367 {
368  0x26,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x12,0x0,0x0,
369  /* Positive numbers */
370  FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2,
372  FMT_GEN_END,
373  /* Negative numbers */
374  FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2,
378 };
379 
380 static const WCHAR szFixed[] = { 'F','i','x','e','d','\0' };
381 static const BYTE fmtFixed[0x11] =
382 {
383  0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
384  0x0,0x0,0x0,0x1,0x2,
386 };
387 
388 static const WCHAR szStandard[] = { 'S','t','a','n','d','a','r','d','\0' };
389 static const BYTE fmtStandard[0x11] =
390 {
391  0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
394 };
395 
396 static const WCHAR szPercent[] = { 'P','e','r','c','e','n','t','\0' };
397 static const BYTE fmtPercent[0x15] =
398 {
399  0x15,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
400  FMT_FLAG_PERCENT,0x1,0x0,0x1,0x2,
402  FMT_GEN_INLINE,0x1,'%','\0',FMT_GEN_END
403 };
404 
405 static const WCHAR szScientific[] = { 'S','c','i','e','n','t','i','f','i','c','\0' };
406 static const BYTE fmtScientific[0x13] =
407 {
408  0x13,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
411 };
412 
413 typedef struct tagNAMED_FORMAT
414 {
416  const BYTE* format;
417 } NAMED_FORMAT;
418 
419 /* Format name to tokenised format. Must be kept sorted by name */
421 {
422  { szCurrency, fmtCurrency },
423  { szFixed, fmtFixed },
426  { szLongDate, fmtLongDate },
427  { szLongTime, fmtLongTime },
430  { szOnOff, fmtOnOff },
431  { szPercent, fmtPercent },
435  { szStandard, fmtStandard },
437  { szYesNo, fmtYesNo }
438 };
440 
441 static int FormatCompareFn(const void *l, const void *r)
442 {
444 }
445 
446 static inline const BYTE *VARIANT_GetNamedFormat(LPCWSTR lpszFormat)
447 {
450 
451  key.name = lpszFormat;
453  sizeof(NAMED_FORMAT), FormatCompareFn);
454  return fmt ? fmt->format : NULL;
455 }
456 
457 /* Return an error if the token for the value will not fit in the destination */
458 #define NEED_SPACE(x) if (cbTok < (int)(x)) return TYPE_E_BUFFERTOOSMALL; cbTok -= (x)
459 
460 /* Non-zero if the format is unknown or a given type */
461 #define COULD_BE(typ) ((!fmt_number && header->type==FMT_TYPE_UNKNOWN)||header->type==typ)
462 
463 /* State during tokenising */
464 #define FMT_STATE_OPEN_COPY 0x1 /* Last token written was a copy */
465 #define FMT_STATE_WROTE_DECIMAL 0x2 /* Already wrote a decimal separator */
466 #define FMT_STATE_SEEN_HOURS 0x4 /* See the hh specifier */
467 #define FMT_STATE_WROTE_MINUTES 0x8 /* Wrote minutes */
468 
469 /**********************************************************************
470  * VarTokenizeFormatString [OLEAUT32.140]
471  *
472  * Convert a format string into tokenised form.
473  *
474  * PARAMS
475  * lpszFormat [I] Format string to tokenise
476  * rgbTok [O] Destination for tokenised format
477  * cbTok [I] Size of rgbTok in bytes
478  * nFirstDay [I] First day of the week (1-7, or 0 for current system default)
479  * nFirstWeek [I] How to treat the first week (see notes)
480  * lcid [I] Locale Id of the format string
481  * pcbActual [O] If non-NULL, filled with the first token generated
482  *
483  * RETURNS
484  * Success: S_OK. rgbTok contains the tokenised format.
485  * Failure: E_INVALIDARG, if any argument is invalid.
486  * TYPE_E_BUFFERTOOSMALL, if rgbTok is not large enough.
487  *
488  * NOTES
489  * Valid values for the nFirstWeek parameter are:
490  *| Value Meaning
491  *| ----- -------
492  *| 0 Use the current system default
493  *| 1 The first week is that containing Jan 1
494  *| 2 Four or more days of the first week are in the current year
495  *| 3 The first week is 7 days long
496  * See Variant-Formats(), VarFormatFromTokens().
497  */
499  int cbTok, int nFirstDay, int nFirstWeek,
500  LCID lcid, int *pcbActual)
501 {
502  /* Note: none of these strings should be NUL terminated */
503  static const WCHAR szTTTTT[] = { 't','t','t','t','t' };
504  static const WCHAR szAMPM[] = { 'A','M','P','M' };
505  static const WCHAR szampm[] = { 'a','m','p','m' };
506  static const WCHAR szAMSlashPM[] = { 'A','M','/','P','M' };
507  static const WCHAR szamSlashpm[] = { 'a','m','/','p','m' };
508  const BYTE *namedFmt;
509  FMT_HEADER *header = (FMT_HEADER*)rgbTok;
510  FMT_STRING_HEADER *str_header = (FMT_STRING_HEADER*)(rgbTok + sizeof(FMT_HEADER));
511  FMT_NUMBER_HEADER *num_header = (FMT_NUMBER_HEADER*)str_header;
512  BYTE* pOut = rgbTok + sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER);
513  BYTE* pLastHours = NULL;
514  BYTE fmt_number = 0;
515  DWORD fmt_state = 0;
516  LPCWSTR pFormat = lpszFormat;
517 
518  TRACE("(%s,%p,%d,%d,%d,0x%08x,%p)\n", debugstr_w(lpszFormat), rgbTok, cbTok,
519  nFirstDay, nFirstWeek, lcid, pcbActual);
520 
521  if (!rgbTok ||
522  nFirstDay < 0 || nFirstDay > 7 || nFirstWeek < 0 || nFirstWeek > 3)
523  return E_INVALIDARG;
524 
525  if (!lpszFormat || !*lpszFormat)
526  {
527  /* An empty string means 'general format' */
528  NEED_SPACE(sizeof(BYTE));
529  *rgbTok = FMT_TO_STRING;
530  if (pcbActual)
531  *pcbActual = FMT_TO_STRING;
532  return S_OK;
533  }
534 
535  if (cbTok > 255)
536  cbTok = 255; /* Ensure we error instead of wrapping */
537 
538  /* Named formats */
539  namedFmt = VARIANT_GetNamedFormat(lpszFormat);
540  if (namedFmt)
541  {
542  NEED_SPACE(namedFmt[0]);
543  memcpy(rgbTok, namedFmt, namedFmt[0]);
544  TRACE("Using pre-tokenised named format %s\n", debugstr_w(lpszFormat));
545  /* FIXME: pcbActual */
546  return S_OK;
547  }
548 
549  /* Insert header */
550  NEED_SPACE(sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER));
551  memset(header, 0, sizeof(FMT_HEADER));
552  memset(str_header, 0, sizeof(FMT_STRING_HEADER));
553 
554  header->starts[fmt_number] = sizeof(FMT_HEADER);
555 
556  while (*pFormat)
557  {
558  /* --------------
559  * General tokens
560  * --------------
561  */
562  if (*pFormat == ';')
563  {
564  while (*pFormat == ';')
565  {
566  TRACE(";\n");
567  if (++fmt_number > 3)
568  return E_INVALIDARG; /* too many formats */
569  pFormat++;
570  }
571  if (*pFormat)
572  {
573  TRACE("New header\n");
574  NEED_SPACE(sizeof(BYTE) + sizeof(FMT_STRING_HEADER));
575  *pOut++ = FMT_GEN_END;
576 
577  header->starts[fmt_number] = pOut - rgbTok;
578  str_header = (FMT_STRING_HEADER*)pOut;
579  num_header = (FMT_NUMBER_HEADER*)pOut;
580  memset(str_header, 0, sizeof(FMT_STRING_HEADER));
581  pOut += sizeof(FMT_STRING_HEADER);
582  fmt_state = 0;
583  pLastHours = NULL;
584  }
585  }
586  else if (*pFormat == '\\')
587  {
588  /* Escaped character */
589  if (pFormat[1])
590  {
591  NEED_SPACE(3 * sizeof(BYTE));
592  pFormat++;
593  *pOut++ = FMT_GEN_COPY;
594  *pOut++ = pFormat - lpszFormat;
595  *pOut++ = 0x1;
596  fmt_state |= FMT_STATE_OPEN_COPY;
597  TRACE("'\\'\n");
598  }
599  else
600  fmt_state &= ~FMT_STATE_OPEN_COPY;
601  pFormat++;
602  }
603  else if (*pFormat == '"')
604  {
605  /* Escaped string
606  * Note: Native encodes "" as a copy of length zero. That's just dumb, so
607  * here we avoid encoding anything in this case.
608  */
609  if (!pFormat[1])
610  pFormat++;
611  else if (pFormat[1] == '"')
612  {
613  pFormat += 2;
614  }
615  else
616  {
617  LPCWSTR start = ++pFormat;
618  while (*pFormat && *pFormat != '"')
619  pFormat++;
620  NEED_SPACE(3 * sizeof(BYTE));
621  *pOut++ = FMT_GEN_COPY;
622  *pOut++ = start - lpszFormat;
623  *pOut++ = pFormat - start;
624  if (*pFormat == '"')
625  pFormat++;
626  TRACE("Quoted string pos %d, len %d\n", pOut[-2], pOut[-1]);
627  }
628  fmt_state &= ~FMT_STATE_OPEN_COPY;
629  }
630  /* -------------
631  * Number tokens
632  * -------------
633  */
634  else if (*pFormat == '0' && COULD_BE(FMT_TYPE_NUMBER))
635  {
636  /* Number formats: Digit from number or '0' if no digits
637  * Other formats: Literal
638  * Types the format if found
639  */
640  header->type = FMT_TYPE_NUMBER;
641  NEED_SPACE(2 * sizeof(BYTE));
642  *pOut++ = FMT_NUM_COPY_ZERO;
643  *pOut = 0x0;
644  while (*pFormat == '0')
645  {
646  *pOut = *pOut + 1;
647  pFormat++;
648  }
649  if (fmt_state & FMT_STATE_WROTE_DECIMAL)
650  num_header->fractional += *pOut;
651  else
652  num_header->whole += *pOut;
653  TRACE("%d 0's\n", *pOut);
654  pOut++;
655  fmt_state &= ~FMT_STATE_OPEN_COPY;
656  }
657  else if (*pFormat == '#' && COULD_BE(FMT_TYPE_NUMBER))
658  {
659  /* Number formats: Digit from number or blank if no digits
660  * Other formats: Literal
661  * Types the format if found
662  */
663  header->type = FMT_TYPE_NUMBER;
664  NEED_SPACE(2 * sizeof(BYTE));
665  *pOut++ = FMT_NUM_COPY_SKIP;
666  *pOut = 0x0;
667  while (*pFormat == '#')
668  {
669  *pOut = *pOut + 1;
670  pFormat++;
671  }
672  if (fmt_state & FMT_STATE_WROTE_DECIMAL)
673  num_header->fractional += *pOut;
674  else
675  num_header->whole += *pOut;
676  TRACE("%d #'s\n", *pOut);
677  pOut++;
678  fmt_state &= ~FMT_STATE_OPEN_COPY;
679  }
680  else if (*pFormat == '.' && COULD_BE(FMT_TYPE_NUMBER) &&
681  !(fmt_state & FMT_STATE_WROTE_DECIMAL))
682  {
683  /* Number formats: Decimal separator when 1st seen, literal thereafter
684  * Other formats: Literal
685  * Types the format if found
686  */
687  header->type = FMT_TYPE_NUMBER;
688  NEED_SPACE(sizeof(BYTE));
689  *pOut++ = FMT_NUM_DECIMAL;
690  fmt_state |= FMT_STATE_WROTE_DECIMAL;
691  fmt_state &= ~FMT_STATE_OPEN_COPY;
692  pFormat++;
693  TRACE("decimal sep\n");
694  }
695  else if ((*pFormat == 'e' || *pFormat == 'E') && (pFormat[1] == '-' ||
696  pFormat[1] == '+') && header->type == FMT_TYPE_NUMBER)
697  {
698  /* Number formats: Exponent specifier
699  * Other formats: Literal
700  */
701  num_header->flags |= FMT_FLAG_EXPONENT;
702  NEED_SPACE(2 * sizeof(BYTE));
703  if (*pFormat == 'e') {
704  if (pFormat[1] == '+')
705  *pOut = FMT_NUM_EXP_POS_L;
706  else
707  *pOut = FMT_NUM_EXP_NEG_L;
708  } else {
709  if (pFormat[1] == '+')
710  *pOut = FMT_NUM_EXP_POS_U;
711  else
712  *pOut = FMT_NUM_EXP_NEG_U;
713  }
714  pFormat += 2;
715  *++pOut = 0x0;
716  while (*pFormat == '0')
717  {
718  *pOut = *pOut + 1;
719  pFormat++;
720  }
721  pOut++;
722  TRACE("exponent\n");
723  }
724  /* FIXME: %% => Divide by 1000 */
725  else if (*pFormat == ',' && header->type == FMT_TYPE_NUMBER)
726  {
727  /* Number formats: Use the thousands separator
728  * Other formats: Literal
729  */
730  num_header->flags |= FMT_FLAG_THOUSANDS;
731  pFormat++;
732  fmt_state &= ~FMT_STATE_OPEN_COPY;
733  TRACE("thousands sep\n");
734  }
735  /* -----------
736  * Date tokens
737  * -----------
738  */
739  else if (*pFormat == '/' && COULD_BE(FMT_TYPE_DATE))
740  {
741  /* Date formats: Date separator
742  * Other formats: Literal
743  * Types the format if found
744  */
745  header->type = FMT_TYPE_DATE;
746  NEED_SPACE(sizeof(BYTE));
747  *pOut++ = FMT_DATE_DATE_SEP;
748  pFormat++;
749  fmt_state &= ~FMT_STATE_OPEN_COPY;
750  TRACE("date sep\n");
751  }
752  else if (*pFormat == ':' && COULD_BE(FMT_TYPE_DATE))
753  {
754  /* Date formats: Time separator
755  * Other formats: Literal
756  * Types the format if found
757  */
758  header->type = FMT_TYPE_DATE;
759  NEED_SPACE(sizeof(BYTE));
760  *pOut++ = FMT_DATE_TIME_SEP;
761  pFormat++;
762  fmt_state &= ~FMT_STATE_OPEN_COPY;
763  TRACE("time sep\n");
764  }
765  else if ((*pFormat == 'a' || *pFormat == 'A') &&
766  !strncmpiW(pFormat, szAMPM, ARRAY_SIZE(szAMPM)))
767  {
768  /* Date formats: System AM/PM designation
769  * Other formats: Literal
770  * Types the format if found
771  */
772  header->type = FMT_TYPE_DATE;
773  NEED_SPACE(sizeof(BYTE));
774  pFormat += ARRAY_SIZE(szAMPM);
775  if (!strncmpW(pFormat, szampm, ARRAY_SIZE(szampm)))
776  *pOut++ = FMT_DATE_AMPM_SYS2;
777  else
778  *pOut++ = FMT_DATE_AMPM_SYS1;
779  if (pLastHours)
780  *pLastHours = *pLastHours + 2;
781  TRACE("ampm\n");
782  }
783  else if (*pFormat == 'a' && pFormat[1] == '/' &&
784  (pFormat[2] == 'p' || pFormat[2] == 'P'))
785  {
786  /* Date formats: lowercase a or p designation
787  * Other formats: Literal
788  * Types the format if found
789  */
790  header->type = FMT_TYPE_DATE;
791  NEED_SPACE(sizeof(BYTE));
792  pFormat += 3;
793  *pOut++ = FMT_DATE_A_LOWER;
794  if (pLastHours)
795  *pLastHours = *pLastHours + 2;
796  TRACE("a/p\n");
797  }
798  else if (*pFormat == 'A' && pFormat[1] == '/' &&
799  (pFormat[2] == 'p' || pFormat[2] == 'P'))
800  {
801  /* Date formats: Uppercase a or p designation
802  * Other formats: Literal
803  * Types the format if found
804  */
805  header->type = FMT_TYPE_DATE;
806  NEED_SPACE(sizeof(BYTE));
807  pFormat += 3;
808  *pOut++ = FMT_DATE_A_UPPER;
809  if (pLastHours)
810  *pLastHours = *pLastHours + 2;
811  TRACE("A/P\n");
812  }
813  else if (*pFormat == 'a' && !strncmpW(pFormat, szamSlashpm, ARRAY_SIZE(szamSlashpm)))
814  {
815  /* Date formats: lowercase AM or PM designation
816  * Other formats: Literal
817  * Types the format if found
818  */
819  header->type = FMT_TYPE_DATE;
820  NEED_SPACE(sizeof(BYTE));
821  pFormat += ARRAY_SIZE(szamSlashpm);
822  *pOut++ = FMT_DATE_AMPM_LOWER;
823  if (pLastHours)
824  *pLastHours = *pLastHours + 2;
825  TRACE("AM/PM\n");
826  }
827  else if (*pFormat == 'A' && !strncmpW(pFormat, szAMSlashPM, ARRAY_SIZE(szAMSlashPM)))
828  {
829  /* Date formats: Uppercase AM or PM designation
830  * Other formats: Literal
831  * Types the format if found
832  */
833  header->type = FMT_TYPE_DATE;
834  NEED_SPACE(sizeof(BYTE));
835  pFormat += ARRAY_SIZE(szAMSlashPM);
836  *pOut++ = FMT_DATE_AMPM_UPPER;
837  TRACE("AM/PM\n");
838  }
839  else if ((*pFormat == 'c' || *pFormat == 'C') && COULD_BE(FMT_TYPE_DATE))
840  {
841  /* Date formats: General date format
842  * Other formats: Literal
843  * Types the format if found
844  */
845  header->type = FMT_TYPE_DATE;
846  NEED_SPACE(sizeof(BYTE));
847  pFormat += ARRAY_SIZE(szAMSlashPM);
848  *pOut++ = FMT_DATE_GENERAL;
849  TRACE("gen date\n");
850  }
851  else if ((*pFormat == 'd' || *pFormat == 'D') && COULD_BE(FMT_TYPE_DATE))
852  {
853  /* Date formats: Day specifier
854  * Other formats: Literal
855  * Types the format if found
856  */
857  int count = -1;
858  header->type = FMT_TYPE_DATE;
859  while ((*pFormat == 'd' || *pFormat == 'D') && count < 6)
860  {
861  pFormat++;
862  count++;
863  }
864  NEED_SPACE(sizeof(BYTE));
865  *pOut++ = FMT_DATE_DAY + count;
866  fmt_state &= ~FMT_STATE_OPEN_COPY;
867  /* When we find the days token, reset the seen hours state so that
868  * 'mm' is again written as month when encountered.
869  */
870  fmt_state &= ~FMT_STATE_SEEN_HOURS;
871  TRACE("%d d's\n", count + 1);
872  }
873  else if ((*pFormat == 'h' || *pFormat == 'H') && COULD_BE(FMT_TYPE_DATE))
874  {
875  /* Date formats: Hour specifier
876  * Other formats: Literal
877  * Types the format if found
878  */
879  header->type = FMT_TYPE_DATE;
880  NEED_SPACE(sizeof(BYTE));
881  pFormat++;
882  /* Record the position of the hours specifier - if we encounter
883  * an am/pm specifier we will change the hours from 24 to 12.
884  */
885  pLastHours = pOut;
886  if (*pFormat == 'h' || *pFormat == 'H')
887  {
888  pFormat++;
889  *pOut++ = FMT_DATE_HOUR_0;
890  TRACE("hh\n");
891  }
892  else
893  {
894  *pOut++ = FMT_DATE_HOUR;
895  TRACE("h\n");
896  }
897  fmt_state &= ~FMT_STATE_OPEN_COPY;
898  /* Note that now we have seen an hours token, the next occurrence of
899  * 'mm' indicates minutes, not months.
900  */
901  fmt_state |= FMT_STATE_SEEN_HOURS;
902  }
903  else if ((*pFormat == 'm' || *pFormat == 'M') && COULD_BE(FMT_TYPE_DATE))
904  {
905  /* Date formats: Month specifier (or Minute specifier, after hour specifier)
906  * Other formats: Literal
907  * Types the format if found
908  */
909  int count = -1;
910  header->type = FMT_TYPE_DATE;
911  while ((*pFormat == 'm' || *pFormat == 'M') && count < 4)
912  {
913  pFormat++;
914  count++;
915  }
916  NEED_SPACE(sizeof(BYTE));
917  if (count <= 1 && fmt_state & FMT_STATE_SEEN_HOURS &&
918  !(fmt_state & FMT_STATE_WROTE_MINUTES))
919  {
920  /* We have seen an hours specifier and not yet written a minutes
921  * specifier. Write this as minutes and thereafter as months.
922  */
923  *pOut++ = count == 1 ? FMT_DATE_MIN_0 : FMT_DATE_MIN;
924  fmt_state |= FMT_STATE_WROTE_MINUTES; /* Hereafter write months */
925  }
926  else
927  *pOut++ = FMT_DATE_MON + count; /* Months */
928  fmt_state &= ~FMT_STATE_OPEN_COPY;
929  TRACE("%d m's\n", count + 1);
930  }
931  else if ((*pFormat == 'n' || *pFormat == 'N') && COULD_BE(FMT_TYPE_DATE))
932  {
933  /* Date formats: Minute specifier
934  * Other formats: Literal
935  * Types the format if found
936  */
937  header->type = FMT_TYPE_DATE;
938  NEED_SPACE(sizeof(BYTE));
939  pFormat++;
940  if (*pFormat == 'n' || *pFormat == 'N')
941  {
942  pFormat++;
943  *pOut++ = FMT_DATE_MIN_0;
944  TRACE("nn\n");
945  }
946  else
947  {
948  *pOut++ = FMT_DATE_MIN;
949  TRACE("n\n");
950  }
951  fmt_state &= ~FMT_STATE_OPEN_COPY;
952  }
953  else if ((*pFormat == 'q' || *pFormat == 'Q') && COULD_BE(FMT_TYPE_DATE))
954  {
955  /* Date formats: Quarter specifier
956  * Other formats: Literal
957  * Types the format if found
958  */
959  header->type = FMT_TYPE_DATE;
960  NEED_SPACE(sizeof(BYTE));
961  *pOut++ = FMT_DATE_QUARTER;
962  pFormat++;
963  fmt_state &= ~FMT_STATE_OPEN_COPY;
964  TRACE("quarter\n");
965  }
966  else if ((*pFormat == 's' || *pFormat == 'S') && COULD_BE(FMT_TYPE_DATE))
967  {
968  /* Date formats: Second specifier
969  * Other formats: Literal
970  * Types the format if found
971  */
972  header->type = FMT_TYPE_DATE;
973  NEED_SPACE(sizeof(BYTE));
974  pFormat++;
975  if (*pFormat == 's' || *pFormat == 'S')
976  {
977  pFormat++;
978  *pOut++ = FMT_DATE_SEC_0;
979  TRACE("ss\n");
980  }
981  else
982  {
983  *pOut++ = FMT_DATE_SEC;
984  TRACE("s\n");
985  }
986  fmt_state &= ~FMT_STATE_OPEN_COPY;
987  }
988  else if ((*pFormat == 't' || *pFormat == 'T') &&
989  !strncmpiW(pFormat, szTTTTT, ARRAY_SIZE(szTTTTT)))
990  {
991  /* Date formats: System time specifier
992  * Other formats: Literal
993  * Types the format if found
994  */
995  header->type = FMT_TYPE_DATE;
996  pFormat += ARRAY_SIZE(szTTTTT);
997  NEED_SPACE(sizeof(BYTE));
998  *pOut++ = FMT_DATE_TIME_SYS;
999  fmt_state &= ~FMT_STATE_OPEN_COPY;
1000  }
1001  else if ((*pFormat == 'w' || *pFormat == 'W') && COULD_BE(FMT_TYPE_DATE))
1002  {
1003  /* Date formats: Week of the year/Day of the week
1004  * Other formats: Literal
1005  * Types the format if found
1006  */
1007  header->type = FMT_TYPE_DATE;
1008  pFormat++;
1009  if (*pFormat == 'w' || *pFormat == 'W')
1010  {
1011  NEED_SPACE(3 * sizeof(BYTE));
1012  pFormat++;
1013  *pOut++ = FMT_DATE_WEEK_YEAR;
1014  *pOut++ = nFirstDay;
1015  *pOut++ = nFirstWeek;
1016  TRACE("ww\n");
1017  }
1018  else
1019  {
1020  NEED_SPACE(2 * sizeof(BYTE));
1021  *pOut++ = FMT_DATE_DAY_WEEK;
1022  *pOut++ = nFirstDay;
1023  TRACE("w\n");
1024  }
1025 
1026  fmt_state &= ~FMT_STATE_OPEN_COPY;
1027  }
1028  else if ((*pFormat == 'y' || *pFormat == 'Y') && COULD_BE(FMT_TYPE_DATE))
1029  {
1030  /* Date formats: Day of year/Year specifier
1031  * Other formats: Literal
1032  * Types the format if found
1033  */
1034  int count = -1;
1035  header->type = FMT_TYPE_DATE;
1036  while ((*pFormat == 'y' || *pFormat == 'Y') && count < 4)
1037  {
1038  pFormat++;
1039  count++;
1040  }
1041  if (count == 2)
1042  {
1043  count--; /* 'yyy' has no meaning, despite what MSDN says */
1044  pFormat--;
1045  }
1046  NEED_SPACE(sizeof(BYTE));
1047  *pOut++ = FMT_DATE_YEAR_DOY + count;
1048  fmt_state &= ~FMT_STATE_OPEN_COPY;
1049  TRACE("%d y's\n", count + 1);
1050  }
1051  /* -------------
1052  * String tokens
1053  * -------------
1054  */
1055  else if (*pFormat == '@' && COULD_BE(FMT_TYPE_STRING))
1056  {
1057  /* String formats: Character from string or space if no char
1058  * Other formats: Literal
1059  * Types the format if found
1060  */
1061  header->type = FMT_TYPE_STRING;
1062  NEED_SPACE(2 * sizeof(BYTE));
1063  *pOut++ = FMT_STR_COPY_SPACE;
1064  *pOut = 0x0;
1065  while (*pFormat == '@')
1066  {
1067  *pOut = *pOut + 1;
1068  str_header->copy_chars++;
1069  pFormat++;
1070  }
1071  TRACE("%d @'s\n", *pOut);
1072  pOut++;
1073  fmt_state &= ~FMT_STATE_OPEN_COPY;
1074  }
1075  else if (*pFormat == '&' && COULD_BE(FMT_TYPE_STRING))
1076  {
1077  /* String formats: Character from string or skip if no char
1078  * Other formats: Literal
1079  * Types the format if found
1080  */
1081  header->type = FMT_TYPE_STRING;
1082  NEED_SPACE(2 * sizeof(BYTE));
1083  *pOut++ = FMT_STR_COPY_SKIP;
1084  *pOut = 0x0;
1085  while (*pFormat == '&')
1086  {
1087  *pOut = *pOut + 1;
1088  str_header->copy_chars++;
1089  pFormat++;
1090  }
1091  TRACE("%d &'s\n", *pOut);
1092  pOut++;
1093  fmt_state &= ~FMT_STATE_OPEN_COPY;
1094  }
1095  else if ((*pFormat == '<' || *pFormat == '>') && COULD_BE(FMT_TYPE_STRING))
1096  {
1097  /* String formats: Use upper/lower case
1098  * Other formats: Literal
1099  * Types the format if found
1100  */
1101  header->type = FMT_TYPE_STRING;
1102  if (*pFormat == '<')
1103  str_header->flags |= FMT_FLAG_LT;
1104  else
1105  str_header->flags |= FMT_FLAG_GT;
1106  TRACE("to %s case\n", *pFormat == '<' ? "lower" : "upper");
1107  pFormat++;
1108  fmt_state &= ~FMT_STATE_OPEN_COPY;
1109  }
1110  else if (*pFormat == '!' && COULD_BE(FMT_TYPE_STRING))
1111  {
1112  /* String formats: Copy right to left
1113  * Other formats: Literal
1114  * Types the format if found
1115  */
1116  header->type = FMT_TYPE_STRING;
1117  str_header->flags |= FMT_FLAG_RTL;
1118  pFormat++;
1119  fmt_state &= ~FMT_STATE_OPEN_COPY;
1120  TRACE("copy right-to-left\n");
1121  }
1122  /* --------
1123  * Literals
1124  * --------
1125  */
1126  /* FIXME: [ seems to be ignored */
1127  else
1128  {
1129  if (*pFormat == '%' && header->type == FMT_TYPE_NUMBER)
1130  {
1131  /* Number formats: Percentage indicator, also a literal
1132  * Other formats: Literal
1133  * Doesn't type the format
1134  */
1135  num_header->flags |= FMT_FLAG_PERCENT;
1136  }
1137 
1138  if (fmt_state & FMT_STATE_OPEN_COPY)
1139  {
1140  pOut[-1] = pOut[-1] + 1; /* Increase the length of the open copy */
1141  TRACE("extend copy (char '%c'), length now %d\n", *pFormat, pOut[-1]);
1142  }
1143  else
1144  {
1145  /* Create a new open copy */
1146  TRACE("New copy (char '%c')\n", *pFormat);
1147  NEED_SPACE(3 * sizeof(BYTE));
1148  *pOut++ = FMT_GEN_COPY;
1149  *pOut++ = pFormat - lpszFormat;
1150  *pOut++ = 0x1;
1151  fmt_state |= FMT_STATE_OPEN_COPY;
1152  }
1153  pFormat++;
1154  }
1155  }
1156 
1157  *pOut++ = FMT_GEN_END;
1158 
1159  header->size = pOut - rgbTok;
1160  if (pcbActual)
1161  *pcbActual = header->size;
1162 
1163  return S_OK;
1164 }
1165 
1166 /* Number formatting state flags */
1167 #define NUM_WROTE_DEC 0x01 /* Written the decimal separator */
1168 #define NUM_WRITE_ON 0x02 /* Started to write the number */
1169 #define NUM_WROTE_SIGN 0x04 /* Written the negative sign */
1170 
1171 /* Format a variant using a number format */
1173  LPBYTE rgbTok, ULONG dwFlags,
1174  BSTR *pbstrOut, LCID lcid)
1175 {
1176  BYTE rgbDig[256], *prgbDig;
1177  NUMPARSE np;
1178  int have_int, need_int = 0, have_frac, need_frac, exponent = 0, pad = 0;
1179  WCHAR buff[256], *pBuff = buff;
1180  WCHAR thousandSeparator[32];
1181  VARIANT vString, vBool;
1182  DWORD dwState = 0;
1183  FMT_HEADER *header = (FMT_HEADER*)rgbTok;
1184  FMT_NUMBER_HEADER *numHeader;
1185  const BYTE* pToken = NULL;
1186  HRESULT hRes = S_OK;
1187 
1188  TRACE("(%s,%s,%p,0x%08x,%p,0x%08x)\n", debugstr_variant(pVarIn), debugstr_w(lpszFormat),
1189  rgbTok, dwFlags, pbstrOut, lcid);
1190 
1191  V_VT(&vString) = VT_EMPTY;
1192  V_VT(&vBool) = VT_BOOL;
1193 
1194  if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL)
1195  {
1196  have_int = have_frac = 0;
1197  numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNull(header));
1198  V_BOOL(&vBool) = VARIANT_FALSE;
1199  }
1200  else
1201  {
1202  /* Get a number string from pVarIn, and parse it */
1203  hRes = VariantChangeTypeEx(&vString, pVarIn, lcid, VARIANT_NOUSEROVERRIDE, VT_BSTR);
1204  if (FAILED(hRes))
1205  return hRes;
1206 
1207  np.cDig = sizeof(rgbDig);
1208  np.dwInFlags = NUMPRS_STD;
1209  hRes = VarParseNumFromStr(V_BSTR(&vString), lcid, 0, &np, rgbDig);
1210  if (FAILED(hRes))
1211  return hRes;
1212 
1213  have_int = np.cDig;
1214  have_frac = 0;
1215  exponent = np.nPwr10;
1216 
1217  /* Figure out which format to use */
1218  if (np.dwOutFlags & NUMPRS_NEG)
1219  {
1220  numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNegative(header));
1221  V_BOOL(&vBool) = VARIANT_TRUE;
1222  }
1223  else if (have_int == 1 && !exponent && rgbDig[0] == 0)
1224  {
1225  numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetZero(header));
1226  V_BOOL(&vBool) = VARIANT_FALSE;
1227  }
1228  else
1229  {
1230  numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetPositive(header));
1231  V_BOOL(&vBool) = VARIANT_TRUE;
1232  }
1233 
1234  TRACE("num header: flags = 0x%x, mult=%d, div=%d, whole=%d, fract=%d\n",
1235  numHeader->flags, numHeader->multiplier, numHeader->divisor,
1236  numHeader->whole, numHeader->fractional);
1237 
1238  need_int = numHeader->whole;
1239  need_frac = numHeader->fractional;
1240 
1241  if (numHeader->flags & FMT_FLAG_PERCENT &&
1242  !(have_int == 1 && !exponent && rgbDig[0] == 0))
1243  exponent += 2;
1244 
1245  if (numHeader->flags & FMT_FLAG_EXPONENT)
1246  {
1247  /* Exponent format: length of the integral number part is fixed and
1248  specified by the format. */
1249  pad = need_int - have_int;
1250  exponent -= pad;
1251  if (pad < 0)
1252  {
1253  have_int = need_int;
1254  have_frac -= pad;
1255  pad = 0;
1256  }
1257  }
1258  else
1259  {
1260  /* Convert the exponent */
1261  pad = max(exponent, -have_int);
1262  exponent -= pad;
1263  if (pad < 0)
1264  {
1265  have_int += pad;
1266  have_frac = -pad;
1267  pad = 0;
1268  }
1269  if(exponent < 0 && exponent > (-256 + have_int + have_frac))
1270  {
1271  /* Remove exponent notation */
1272  memmove(rgbDig - exponent, rgbDig, have_int + have_frac);
1273  ZeroMemory(rgbDig, -exponent);
1274  have_frac -= exponent;
1275  exponent = 0;
1276  }
1277  }
1278 
1279  /* Rounding the number */
1280  if (have_frac > need_frac)
1281  {
1282  prgbDig = &rgbDig[have_int + need_frac];
1283  have_frac = need_frac;
1284  if (*prgbDig >= 5)
1285  {
1286  while (prgbDig-- > rgbDig && *prgbDig == 9)
1287  *prgbDig = 0;
1288  if (prgbDig < rgbDig)
1289  {
1290  /* We reached the first digit and that was also a 9 */
1291  rgbDig[0] = 1;
1292  if (numHeader->flags & FMT_FLAG_EXPONENT)
1293  exponent++;
1294  else
1295  {
1296  rgbDig[have_int + need_frac] = 0;
1297  if (exponent < 0)
1298  exponent++;
1299  else
1300  have_int++;
1301  }
1302  }
1303  else
1304  (*prgbDig)++;
1305  }
1306  /* We converted trailing digits to zeroes => have_frac has changed */
1307  while (have_frac > 0 && rgbDig[have_int + have_frac - 1] == 0)
1308  have_frac--;
1309  }
1310  TRACE("have_int=%d,need_int=%d,have_frac=%d,need_frac=%d,pad=%d,exp=%d\n",
1311  have_int, need_int, have_frac, need_frac, pad, exponent);
1312  }
1313 
1314  if (numHeader->flags & FMT_FLAG_THOUSANDS)
1315  {
1316  if (!GetLocaleInfoW(lcid, LOCALE_STHOUSAND, thousandSeparator, ARRAY_SIZE(thousandSeparator)))
1317  {
1318  thousandSeparator[0] = ',';
1319  thousandSeparator[1] = 0;
1320  }
1321  }
1322 
1323  pToken = (const BYTE*)numHeader + sizeof(FMT_NUMBER_HEADER);
1324  prgbDig = rgbDig;
1325 
1326  while (SUCCEEDED(hRes) && *pToken != FMT_GEN_END)
1327  {
1328  WCHAR defaultChar = '?';
1329  DWORD boolFlag, localeValue = 0;
1330  BOOL shouldAdvance = TRUE;
1331 
1332  if (pToken - rgbTok > header->size)
1333  {
1334  ERR("Ran off the end of the format!\n");
1335  hRes = E_INVALIDARG;
1336  goto VARIANT_FormatNumber_Exit;
1337  }
1338 
1339  switch (*pToken)
1340  {
1341  case FMT_GEN_COPY:
1342  TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2]));
1343  memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR));
1344  pBuff += pToken[2];
1345  pToken += 2;
1346  break;
1347 
1348  case FMT_GEN_INLINE:
1349  pToken += 2;
1350  TRACE("copy %s\n", debugstr_a((LPCSTR)pToken));
1351  while (*pToken)
1352  *pBuff++ = *pToken++;
1353  break;
1354 
1355  case FMT_NUM_YES_NO:
1356  boolFlag = VAR_BOOLYESNO;
1357  goto VARIANT_FormatNumber_Bool;
1358 
1359  case FMT_NUM_ON_OFF:
1360  boolFlag = VAR_BOOLONOFF;
1361  goto VARIANT_FormatNumber_Bool;
1362 
1363  case FMT_NUM_TRUE_FALSE:
1364  boolFlag = VAR_LOCALBOOL;
1365 
1366 VARIANT_FormatNumber_Bool:
1367  {
1368  BSTR boolStr = NULL;
1369 
1370  if (pToken[1] != FMT_GEN_END)
1371  {
1372  ERR("Boolean token not at end of format!\n");
1373  hRes = E_INVALIDARG;
1374  goto VARIANT_FormatNumber_Exit;
1375  }
1376  hRes = VarBstrFromBool(V_BOOL(&vBool), lcid, boolFlag, &boolStr);
1377  if (SUCCEEDED(hRes))
1378  {
1379  strcpyW(pBuff, boolStr);
1380  SysFreeString(boolStr);
1381  while (*pBuff)
1382  pBuff++;
1383  }
1384  }
1385  break;
1386 
1387  case FMT_NUM_DECIMAL:
1388  if ((np.dwOutFlags & NUMPRS_NEG) && !(dwState & NUM_WROTE_SIGN) && !header->starts[1])
1389  {
1390  /* last chance for a negative sign in the .# case */
1391  TRACE("write negative sign\n");
1392  localeValue = LOCALE_SNEGATIVESIGN;
1393  defaultChar = '-';
1394  dwState |= NUM_WROTE_SIGN;
1395  shouldAdvance = FALSE;
1396  break;
1397  }
1398  TRACE("write decimal separator\n");
1399  localeValue = LOCALE_SDECIMAL;
1400  defaultChar = '.';
1401  dwState |= NUM_WROTE_DEC;
1402  break;
1403 
1404  case FMT_NUM_CURRENCY:
1405  TRACE("write currency symbol\n");
1406  localeValue = LOCALE_SCURRENCY;
1407  defaultChar = '$';
1408  break;
1409 
1410  case FMT_NUM_EXP_POS_U:
1411  case FMT_NUM_EXP_POS_L:
1412  case FMT_NUM_EXP_NEG_U:
1413  case FMT_NUM_EXP_NEG_L:
1414  if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_NEG_L)
1415  *pBuff++ = 'e';
1416  else
1417  *pBuff++ = 'E';
1418  if (exponent < 0)
1419  {
1420  *pBuff++ = '-';
1421  sprintfW(pBuff, szPercentZeroStar_d, pToken[1], -exponent);
1422  }
1423  else
1424  {
1425  if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_POS_U)
1426  *pBuff++ = '+';
1427  sprintfW(pBuff, szPercentZeroStar_d, pToken[1], exponent);
1428  }
1429  while (*pBuff)
1430  pBuff++;
1431  pToken++;
1432  break;
1433 
1434  case FMT_NUM_COPY_ZERO:
1435  dwState |= NUM_WRITE_ON;
1436  /* Fall through */
1437 
1438  case FMT_NUM_COPY_SKIP:
1439  TRACE("write %d %sdigits or %s\n", pToken[1],
1440  dwState & NUM_WROTE_DEC ? "fractional " : "",
1441  *pToken == FMT_NUM_COPY_ZERO ? "0" : "skip");
1442 
1443  if (dwState & NUM_WROTE_DEC)
1444  {
1445  int count, i;
1446 
1447  if (!(numHeader->flags & FMT_FLAG_EXPONENT) && exponent < 0)
1448  {
1449  /* Pad with 0 before writing the fractional digits */
1450  pad = max(exponent, -pToken[1]);
1451  exponent -= pad;
1452  count = min(have_frac, pToken[1] + pad);
1453  for (i = 0; i > pad; i--)
1454  *pBuff++ = '0';
1455  }
1456  else
1457  count = min(have_frac, pToken[1]);
1458 
1459  pad += pToken[1] - count;
1460  have_frac -= count;
1461  while (count--)
1462  *pBuff++ = '0' + *prgbDig++;
1463  if (*pToken == FMT_NUM_COPY_ZERO)
1464  {
1465  for (; pad > 0; pad--)
1466  *pBuff++ = '0'; /* Write zeros for missing trailing digits */
1467  }
1468  }
1469  else
1470  {
1471  int count, count_max, position;
1472 
1473  if ((np.dwOutFlags & NUMPRS_NEG) && !(dwState & NUM_WROTE_SIGN) && !header->starts[1])
1474  {
1475  TRACE("write negative sign\n");
1476  localeValue = LOCALE_SNEGATIVESIGN;
1477  defaultChar = '-';
1478  dwState |= NUM_WROTE_SIGN;
1479  shouldAdvance = FALSE;
1480  break;
1481  }
1482 
1483  position = have_int + pad;
1484  if (dwState & NUM_WRITE_ON)
1485  position = max(position, need_int);
1486  need_int -= pToken[1];
1487  count_max = have_int + pad - need_int;
1488  if (count_max < 0)
1489  count_max = 0;
1490  if (dwState & NUM_WRITE_ON)
1491  {
1492  count = pToken[1] - count_max;
1493  TRACE("write %d leading zeros\n", count);
1494  while (count-- > 0)
1495  {
1496  *pBuff++ = '0';
1497  if ((numHeader->flags & FMT_FLAG_THOUSANDS) &&
1498  position > 1 && (--position % 3) == 0)
1499  {
1500  int k;
1501  TRACE("write thousand separator\n");
1502  for (k = 0; thousandSeparator[k]; k++)
1503  *pBuff++ = thousandSeparator[k];
1504  }
1505  }
1506  }
1507  if (*pToken == FMT_NUM_COPY_ZERO || have_int > 1 ||
1508  (have_int > 0 && *prgbDig > 0))
1509  {
1510  count = min(count_max, have_int);
1511  count_max -= count;
1512  have_int -= count;
1513  TRACE("write %d whole number digits\n", count);
1514  while (count--)
1515  {
1516  dwState |= NUM_WRITE_ON;
1517  *pBuff++ = '0' + *prgbDig++;
1518  if ((numHeader->flags & FMT_FLAG_THOUSANDS) &&
1519  position > 1 && (--position % 3) == 0)
1520  {
1521  int k;
1522  TRACE("write thousand separator\n");
1523  for (k = 0; thousandSeparator[k]; k++)
1524  *pBuff++ = thousandSeparator[k];
1525  }
1526  }
1527  }
1528  count = min(count_max, pad);
1529  pad -= count;
1530  TRACE("write %d whole trailing 0's\n", count);
1531  while (count--)
1532  {
1533  *pBuff++ = '0';
1534  if ((numHeader->flags & FMT_FLAG_THOUSANDS) &&
1535  position > 1 && (--position % 3) == 0)
1536  {
1537  int k;
1538  TRACE("write thousand separator\n");
1539  for (k = 0; thousandSeparator[k]; k++)
1540  *pBuff++ = thousandSeparator[k];
1541  }
1542  }
1543  }
1544  pToken++;
1545  break;
1546 
1547  default:
1548  ERR("Unknown token 0x%02x!\n", *pToken);
1549  hRes = E_INVALIDARG;
1550  goto VARIANT_FormatNumber_Exit;
1551  }
1552  if (localeValue)
1553  {
1554  if (GetLocaleInfoW(lcid, localeValue, pBuff, ARRAY_SIZE(buff)-(pBuff-buff)))
1555  {
1556  TRACE("added %s\n", debugstr_w(pBuff));
1557  while (*pBuff)
1558  pBuff++;
1559  }
1560  else
1561  {
1562  TRACE("added %d '%c'\n", defaultChar, defaultChar);
1563  *pBuff++ = defaultChar;
1564  }
1565  }
1566  if (shouldAdvance)
1567  pToken++;
1568  }
1569 
1570 VARIANT_FormatNumber_Exit:
1571  VariantClear(&vString);
1572  *pBuff = '\0';
1573  TRACE("buff is %s\n", debugstr_w(buff));
1574  if (SUCCEEDED(hRes))
1575  {
1576  *pbstrOut = SysAllocString(buff);
1577  if (!*pbstrOut)
1578  hRes = E_OUTOFMEMORY;
1579  }
1580  return hRes;
1581 }
1582 
1583 /* Format a variant using a date format */
1584 static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat,
1585  LPBYTE rgbTok, ULONG dwFlags,
1586  BSTR *pbstrOut, LCID lcid)
1587 {
1588  WCHAR buff[256], *pBuff = buff;
1589  VARIANT vDate;
1590  UDATE udate;
1591  FMT_HEADER *header = (FMT_HEADER*)rgbTok;
1592  FMT_DATE_HEADER *dateHeader;
1593  const BYTE* pToken = NULL;
1594  HRESULT hRes;
1595 
1596  TRACE("(%s,%s,%p,0x%08x,%p,0x%08x)\n", debugstr_variant(pVarIn),
1597  debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, lcid);
1598 
1599  V_VT(&vDate) = VT_EMPTY;
1600 
1601  if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL)
1602  {
1603  dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetNegative(header));
1604  V_DATE(&vDate) = 0;
1605  }
1606  else
1607  {
1609 
1610  hRes = VariantChangeTypeEx(&vDate, pVarIn, lcid, usFlags, VT_DATE);
1611  if (FAILED(hRes))
1612  return hRes;
1613  dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetPositive(header));
1614  }
1615 
1616  hRes = VarUdateFromDate(V_DATE(&vDate), 0 /* FIXME: flags? */, &udate);
1617  if (FAILED(hRes))
1618  return hRes;
1619  pToken = (const BYTE*)dateHeader + sizeof(FMT_DATE_HEADER);
1620 
1621  while (*pToken != FMT_GEN_END)
1622  {
1623  DWORD dwVal = 0, localeValue = 0, dwFmt = 0;
1624  LPCWSTR szPrintFmt = NULL;
1625  WCHAR defaultChar = '?';
1626 
1627  if (pToken - rgbTok > header->size)
1628  {
1629  ERR("Ran off the end of the format!\n");
1630  hRes = E_INVALIDARG;
1631  goto VARIANT_FormatDate_Exit;
1632  }
1633 
1634  switch (*pToken)
1635  {
1636  case FMT_GEN_COPY:
1637  TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2]));
1638  memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR));
1639  pBuff += pToken[2];
1640  pToken += 2;
1641  break;
1642 
1643  case FMT_GEN_INLINE:
1644  pToken += 2;
1645  TRACE("copy %s\n", debugstr_a((LPCSTR)pToken));
1646  while (*pToken)
1647  *pBuff++ = *pToken++;
1648  break;
1649 
1650  case FMT_DATE_TIME_SEP:
1651  TRACE("time separator\n");
1652  localeValue = LOCALE_STIME;
1653  defaultChar = ':';
1654  break;
1655 
1656  case FMT_DATE_DATE_SEP:
1657  TRACE("date separator\n");
1658  localeValue = LOCALE_SDATE;
1659  defaultChar = '/';
1660  break;
1661 
1662  case FMT_DATE_GENERAL:
1663  {
1664  BSTR date = NULL;
1665  WCHAR *pDate;
1666  hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, &date);
1667  if (FAILED(hRes))
1668  goto VARIANT_FormatDate_Exit;
1669  pDate = date;
1670  while (*pDate)
1671  *pBuff++ = *pDate++;
1673  }
1674  break;
1675 
1676  case FMT_DATE_QUARTER:
1677  if (udate.st.wMonth <= 3)
1678  *pBuff++ = '1';
1679  else if (udate.st.wMonth <= 6)
1680  *pBuff++ = '2';
1681  else if (udate.st.wMonth <= 9)
1682  *pBuff++ = '3';
1683  else
1684  *pBuff++ = '4';
1685  break;
1686 
1687  case FMT_DATE_TIME_SYS:
1688  {
1689  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1690  BSTR date = NULL;
1691  WCHAR *pDate;
1692  hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, &date);
1693  if (FAILED(hRes))
1694  goto VARIANT_FormatDate_Exit;
1695  pDate = date;
1696  while (*pDate)
1697  *pBuff++ = *pDate++;
1699  }
1700  break;
1701 
1702  case FMT_DATE_DAY:
1703  szPrintFmt = szPercent_d;
1704  dwVal = udate.st.wDay;
1705  break;
1706 
1707  case FMT_DATE_DAY_0:
1708  szPrintFmt = szPercentZeroTwo_d;
1709  dwVal = udate.st.wDay;
1710  break;
1711 
1712  case FMT_DATE_DAY_SHORT:
1713  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1714  TRACE("short day\n");
1715  localeValue = LOCALE_SABBREVDAYNAME1 + (udate.st.wDayOfWeek + 6)%7;
1716  defaultChar = '?';
1717  break;
1718 
1719  case FMT_DATE_DAY_LONG:
1720  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1721  TRACE("long day\n");
1722  localeValue = LOCALE_SDAYNAME1 + (udate.st.wDayOfWeek + 6)%7;
1723  defaultChar = '?';
1724  break;
1725 
1726  case FMT_DATE_SHORT:
1727  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1728  dwFmt = LOCALE_SSHORTDATE;
1729  break;
1730 
1731  case FMT_DATE_LONG:
1732  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1733  dwFmt = LOCALE_SLONGDATE;
1734  break;
1735 
1736  case FMT_DATE_MEDIUM:
1737  FIXME("Medium date treated as long date\n");
1738  dwFmt = LOCALE_SLONGDATE;
1739  break;
1740 
1741  case FMT_DATE_DAY_WEEK:
1742  szPrintFmt = szPercent_d;
1743  if (pToken[1])
1744  dwVal = udate.st.wDayOfWeek + 2 - pToken[1];
1745  else
1746  {
1747  GetLocaleInfoW(lcid,LOCALE_RETURN_NUMBER|LOCALE_IFIRSTDAYOFWEEK,
1748  (LPWSTR)&dwVal, sizeof(dwVal)/sizeof(WCHAR));
1749  dwVal = udate.st.wDayOfWeek + 1 - dwVal;
1750  }
1751  pToken++;
1752  break;
1753 
1754  case FMT_DATE_WEEK_YEAR:
1755  szPrintFmt = szPercent_d;
1756  dwVal = udate.wDayOfYear / 7 + 1;
1757  pToken += 2;
1758  FIXME("Ignoring nFirstDay of %d, nFirstWeek of %d\n", pToken[0], pToken[1]);
1759  break;
1760 
1761  case FMT_DATE_MON:
1762  szPrintFmt = szPercent_d;
1763  dwVal = udate.st.wMonth;
1764  break;
1765 
1766  case FMT_DATE_MON_0:
1767  szPrintFmt = szPercentZeroTwo_d;
1768  dwVal = udate.st.wMonth;
1769  break;
1770 
1771  case FMT_DATE_MON_SHORT:
1772  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1773  TRACE("short month\n");
1774  localeValue = LOCALE_SABBREVMONTHNAME1 + udate.st.wMonth - 1;
1775  defaultChar = '?';
1776  break;
1777 
1778  case FMT_DATE_MON_LONG:
1779  /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
1780  TRACE("long month\n");
1781  localeValue = LOCALE_SMONTHNAME1 + udate.st.wMonth - 1;
1782  defaultChar = '?';
1783  break;
1784 
1785  case FMT_DATE_YEAR_DOY:
1786  szPrintFmt = szPercent_d;
1787  dwVal = udate.wDayOfYear;
1788  break;
1789 
1790  case FMT_DATE_YEAR_0:
1791  szPrintFmt = szPercentZeroTwo_d;
1792  dwVal = udate.st.wYear % 100;
1793  break;
1794 
1795  case FMT_DATE_YEAR_LONG:
1796  szPrintFmt = szPercent_d;
1797  dwVal = udate.st.wYear;
1798  break;
1799 
1800  case FMT_DATE_MIN:
1801  szPrintFmt = szPercent_d;
1802  dwVal = udate.st.wMinute;
1803  break;
1804 
1805  case FMT_DATE_MIN_0:
1806  szPrintFmt = szPercentZeroTwo_d;
1807  dwVal = udate.st.wMinute;
1808  break;
1809 
1810  case FMT_DATE_SEC:
1811  szPrintFmt = szPercent_d;
1812  dwVal = udate.st.wSecond;
1813  break;
1814 
1815  case FMT_DATE_SEC_0:
1816  szPrintFmt = szPercentZeroTwo_d;
1817  dwVal = udate.st.wSecond;
1818  break;
1819 
1820  case FMT_DATE_HOUR:
1821  szPrintFmt = szPercent_d;
1822  dwVal = udate.st.wHour;
1823  break;
1824 
1825  case FMT_DATE_HOUR_0:
1826  case FMT_DATE_TIME_UNK2:
1827  szPrintFmt = szPercentZeroTwo_d;
1828  dwVal = udate.st.wHour;
1829  break;
1830 
1831  case FMT_DATE_HOUR_12:
1832  szPrintFmt = szPercent_d;
1833  dwVal = udate.st.wHour ? udate.st.wHour > 12 ? udate.st.wHour - 12 : udate.st.wHour : 12;
1834  break;
1835 
1836  case FMT_DATE_HOUR_12_0:
1837  szPrintFmt = szPercentZeroTwo_d;
1838  dwVal = udate.st.wHour ? udate.st.wHour > 12 ? udate.st.wHour - 12 : udate.st.wHour : 12;
1839  break;
1840 
1841  case FMT_DATE_AMPM_SYS1:
1842  case FMT_DATE_AMPM_SYS2:
1843  localeValue = udate.st.wHour < 12 ? LOCALE_S1159 : LOCALE_S2359;
1844  defaultChar = '?';
1845  break;
1846 
1847  case FMT_DATE_AMPM_UPPER:
1848  *pBuff++ = udate.st.wHour < 12 ? 'A' : 'P';
1849  *pBuff++ = 'M';
1850  break;
1851 
1852  case FMT_DATE_A_UPPER:
1853  *pBuff++ = udate.st.wHour < 12 ? 'A' : 'P';
1854  break;
1855 
1856  case FMT_DATE_AMPM_LOWER:
1857  *pBuff++ = udate.st.wHour < 12 ? 'a' : 'p';
1858  *pBuff++ = 'm';
1859  break;
1860 
1861  case FMT_DATE_A_LOWER:
1862  *pBuff++ = udate.st.wHour < 12 ? 'a' : 'p';
1863  break;
1864 
1865  default:
1866  ERR("Unknown token 0x%02x!\n", *pToken);
1867  hRes = E_INVALIDARG;
1868  goto VARIANT_FormatDate_Exit;
1869  }
1870  if (localeValue)
1871  {
1872  *pBuff = '\0';
1873  if (GetLocaleInfoW(lcid, localeValue, pBuff, ARRAY_SIZE(buff)-(pBuff-buff)))
1874  {
1875  TRACE("added %s\n", debugstr_w(pBuff));
1876  while (*pBuff)
1877  pBuff++;
1878  }
1879  else
1880  {
1881  TRACE("added %d %c\n", defaultChar, defaultChar);
1882  *pBuff++ = defaultChar;
1883  }
1884  }
1885  else if (dwFmt)
1886  {
1887  WCHAR fmt_buff[80];
1888 
1889  if (!GetLocaleInfoW(lcid, dwFmt, fmt_buff, ARRAY_SIZE(fmt_buff)) ||
1890  !get_date_format(lcid, 0, &udate.st, fmt_buff, pBuff, ARRAY_SIZE(buff)-(pBuff-buff)))
1891  {
1892  hRes = E_INVALIDARG;
1893  goto VARIANT_FormatDate_Exit;
1894  }
1895  while (*pBuff)
1896  pBuff++;
1897  }
1898  else if (szPrintFmt)
1899  {
1900  sprintfW(pBuff, szPrintFmt, dwVal);
1901  while (*pBuff)
1902  pBuff++;
1903  }
1904  pToken++;
1905  }
1906 
1907 VARIANT_FormatDate_Exit:
1908  *pBuff = '\0';
1909  TRACE("buff is %s\n", debugstr_w(buff));
1910  if (SUCCEEDED(hRes))
1911  {
1912  *pbstrOut = SysAllocString(buff);
1913  if (!*pbstrOut)
1914  hRes = E_OUTOFMEMORY;
1915  }
1916  return hRes;
1917 }
1918 
1919 /* Format a variant using a string format */
1921  LPBYTE rgbTok, ULONG dwFlags,
1922  BSTR *pbstrOut, LCID lcid)
1923 {
1924  static WCHAR szEmpty[] = { '\0' };
1925  WCHAR buff[256], *pBuff = buff;
1926  WCHAR *pSrc;
1927  FMT_HEADER *header = (FMT_HEADER*)rgbTok;
1928  FMT_STRING_HEADER *strHeader;
1929  const BYTE* pToken = NULL;
1930  VARIANT vStr;
1931  int blanks_first;
1932  BOOL bUpper = FALSE;
1933  HRESULT hRes = S_OK;
1934 
1935  TRACE("%s,%s,%p,0x%08x,%p,0x%08x)\n", debugstr_variant(pVarIn), debugstr_w(lpszFormat),
1936  rgbTok, dwFlags, pbstrOut, lcid);
1937 
1938  V_VT(&vStr) = VT_EMPTY;
1939 
1940  if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL)
1941  {
1942  strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetNegative(header));
1943  V_BSTR(&vStr) = szEmpty;
1944  }
1945  else
1946  {
1947  hRes = VariantChangeTypeEx(&vStr, pVarIn, lcid, VARIANT_NOUSEROVERRIDE, VT_BSTR);
1948  if (FAILED(hRes))
1949  return hRes;
1950 
1951  if (V_BSTR(&vStr)[0] == '\0')
1952  strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetNegative(header));
1953  else
1954  strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetPositive(header));
1955  }
1956  pSrc = V_BSTR(&vStr);
1957  if ((strHeader->flags & (FMT_FLAG_LT|FMT_FLAG_GT)) == FMT_FLAG_GT)
1958  bUpper = TRUE;
1959  blanks_first = strHeader->copy_chars - strlenW(pSrc);
1960  pToken = (const BYTE*)strHeader + sizeof(FMT_DATE_HEADER);
1961 
1962  while (*pToken != FMT_GEN_END)
1963  {
1964  int dwCount = 0;
1965 
1966  if (pToken - rgbTok > header->size)
1967  {
1968  ERR("Ran off the end of the format!\n");
1969  hRes = E_INVALIDARG;
1970  goto VARIANT_FormatString_Exit;
1971  }
1972 
1973  switch (*pToken)
1974  {
1975  case FMT_GEN_COPY:
1976  TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2]));
1977  memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR));
1978  pBuff += pToken[2];
1979  pToken += 2;
1980  break;
1981 
1982  case FMT_STR_COPY_SPACE:
1983  case FMT_STR_COPY_SKIP:
1984  dwCount = pToken[1];
1985  if (*pToken == FMT_STR_COPY_SPACE && blanks_first > 0)
1986  {
1987  TRACE("insert %d initial spaces\n", blanks_first);
1988  while (dwCount > 0 && blanks_first > 0)
1989  {
1990  *pBuff++ = ' ';
1991  dwCount--;
1992  blanks_first--;
1993  }
1994  }
1995  TRACE("copy %d chars%s\n", dwCount,
1996  *pToken == FMT_STR_COPY_SPACE ? " with space" :"");
1997  while (dwCount > 0 && *pSrc)
1998  {
1999  if (bUpper)
2000  *pBuff++ = toupperW(*pSrc);
2001  else
2002  *pBuff++ = tolowerW(*pSrc);
2003  dwCount--;
2004  pSrc++;
2005  }
2006  if (*pToken == FMT_STR_COPY_SPACE && dwCount > 0)
2007  {
2008  TRACE("insert %d spaces\n", dwCount);
2009  while (dwCount-- > 0)
2010  *pBuff++ = ' ';
2011  }
2012  pToken++;
2013  break;
2014 
2015  default:
2016  ERR("Unknown token 0x%02x!\n", *pToken);
2017  hRes = E_INVALIDARG;
2018  goto VARIANT_FormatString_Exit;
2019  }
2020  pToken++;
2021  }
2022 
2023 VARIANT_FormatString_Exit:
2024  /* Copy out any remaining chars */
2025  while (*pSrc)
2026  {
2027  if (bUpper)
2028  *pBuff++ = toupperW(*pSrc);
2029  else
2030  *pBuff++ = tolowerW(*pSrc);
2031  pSrc++;
2032  }
2033  VariantClear(&vStr);
2034  *pBuff = '\0';
2035  TRACE("buff is %s\n", debugstr_w(buff));
2036  if (SUCCEEDED(hRes))
2037  {
2038  *pbstrOut = SysAllocString(buff);
2039  if (!*pbstrOut)
2040  hRes = E_OUTOFMEMORY;
2041  }
2042  return hRes;
2043 }
2044 
2045 #define NUMBER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2| \
2046  VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8| \
2047  VTBIT_R4|VTBIT_R8|VTBIT_CY|VTBIT_DECIMAL| \
2048  VTBIT_BOOL|VTBIT_INT|VTBIT_UINT)
2049 
2050 /**********************************************************************
2051  * VarFormatFromTokens [OLEAUT32.139]
2052  */
2054  LPBYTE rgbTok, ULONG dwFlags,
2055  BSTR *pbstrOut, LCID lcid)
2056 {
2058  VARIANT vTmp;
2059  HRESULT hres;
2060 
2061  TRACE("(%p,%s,%p,%x,%p,0x%08x)\n", pVarIn, debugstr_w(lpszFormat),
2062  rgbTok, dwFlags, pbstrOut, lcid);
2063 
2064  if (!pbstrOut)
2065  return E_INVALIDARG;
2066 
2067  *pbstrOut = NULL;
2068 
2069  if (!pVarIn || !rgbTok)
2070  return E_INVALIDARG;
2071 
2072  if (V_VT(pVarIn) == VT_NULL)
2073  return S_OK;
2074 
2075  if (*rgbTok == FMT_TO_STRING || header->type == FMT_TYPE_GENERAL)
2076  {
2077  /* According to MSDN, general format acts somewhat like the 'Str'
2078  * function in Visual Basic.
2079  */
2080 VarFormatFromTokens_AsStr:
2081  V_VT(&vTmp) = VT_EMPTY;
2082  hres = VariantChangeTypeEx(&vTmp, pVarIn, lcid, dwFlags, VT_BSTR);
2083  *pbstrOut = V_BSTR(&vTmp);
2084  }
2085  else
2086  {
2087  if (header->type == FMT_TYPE_NUMBER ||
2088  (header->type == FMT_TYPE_UNKNOWN && ((1 << V_TYPE(pVarIn)) & NUMBER_VTBITS)))
2089  {
2090  hres = VARIANT_FormatNumber(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid);
2091  }
2092  else if (header->type == FMT_TYPE_DATE ||
2093  (header->type == FMT_TYPE_UNKNOWN && V_TYPE(pVarIn) == VT_DATE))
2094  {
2095  hres = VARIANT_FormatDate(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid);
2096  }
2097  else if (header->type == FMT_TYPE_STRING || V_TYPE(pVarIn) == VT_BSTR)
2098  {
2099  hres = VARIANT_FormatString(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid);
2100  }
2101  else
2102  {
2103  ERR("unrecognised format type 0x%02x\n", header->type);
2104  return E_INVALIDARG;
2105  }
2106  /* If the coercion failed, still try to create output, unless the
2107  * VAR_FORMAT_NOSUBSTITUTE flag is set.
2108  */
2109  if ((hres == DISP_E_OVERFLOW || hres == DISP_E_TYPEMISMATCH) &&
2111  goto VarFormatFromTokens_AsStr;
2112  }
2113 
2114  return hres;
2115 }
2116 
2117 /**********************************************************************
2118  * VarFormat [OLEAUT32.87]
2119  *
2120  * Format a variant from a format string.
2121  *
2122  * PARAMS
2123  * pVarIn [I] Variant to format
2124  * lpszFormat [I] Format string (see notes)
2125  * nFirstDay [I] First day of the week, (See VarTokenizeFormatString() for details)
2126  * nFirstWeek [I] First week of the year (See VarTokenizeFormatString() for details)
2127  * dwFlags [I] Flags for the format (VAR_ flags from "oleauto.h")
2128  * pbstrOut [O] Destination for formatted string.
2129  *
2130  * RETURNS
2131  * Success: S_OK. pbstrOut contains the formatted value.
2132  * Failure: E_INVALIDARG, if any parameter is invalid.
2133  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2134  * DISP_E_TYPEMISMATCH, if the variant cannot be formatted.
2135  *
2136  * NOTES
2137  * - See Variant-Formats for details concerning creating format strings.
2138  * - This function uses LOCALE_USER_DEFAULT when calling VarTokenizeFormatString()
2139  * and VarFormatFromTokens().
2140  */
2142  int nFirstDay, int nFirstWeek, ULONG dwFlags,
2143  BSTR *pbstrOut)
2144 {
2145  BYTE buff[256];
2146  HRESULT hres;
2147 
2148  TRACE("(%s,%s,%d,%d,0x%08x,%p)\n", debugstr_variant(pVarIn), debugstr_w(lpszFormat),
2149  nFirstDay, nFirstWeek, dwFlags, pbstrOut);
2150 
2151  if (!pbstrOut)
2152  return E_INVALIDARG;
2153  *pbstrOut = NULL;
2154 
2155  hres = VarTokenizeFormatString(lpszFormat, buff, sizeof(buff), nFirstDay,
2156  nFirstWeek, LOCALE_USER_DEFAULT, NULL);
2157  if (SUCCEEDED(hres))
2158  hres = VarFormatFromTokens(pVarIn, lpszFormat, buff, dwFlags,
2159  pbstrOut, LOCALE_USER_DEFAULT);
2160  TRACE("returning 0x%08x, %s\n", hres, debugstr_w(*pbstrOut));
2161  return hres;
2162 }
2163 
2164 /**********************************************************************
2165  * VarFormatDateTime [OLEAUT32.97]
2166  *
2167  * Format a variant value as a date and/or time.
2168  *
2169  * PARAMS
2170  * pVarIn [I] Variant to format
2171  * nFormat [I] Format type (see notes)
2172  * dwFlags [I] Flags for the format (VAR_ flags from "oleauto.h")
2173  * pbstrOut [O] Destination for formatted string.
2174  *
2175  * RETURNS
2176  * Success: S_OK. pbstrOut contains the formatted value.
2177  * Failure: E_INVALIDARG, if any parameter is invalid.
2178  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2179  * DISP_E_TYPEMISMATCH, if the variant cannot be formatted.
2180  *
2181  * NOTES
2182  * This function uses LOCALE_USER_DEFAULT when determining the date format
2183  * characters to use.
2184  * Possible values for the nFormat parameter are:
2185  *| Value Meaning
2186  *| ----- -------
2187  *| 0 General date format
2188  *| 1 Long date format
2189  *| 2 Short date format
2190  *| 3 Long time format
2191  *| 4 Short time format
2192  */
2194 {
2195  static WCHAR szEmpty[] = { '\0' };
2196  const BYTE* lpFmt = NULL;
2197 
2198  TRACE("%s,%d,0x%08x,%p)\n", debugstr_variant(pVarIn), nFormat, dwFlags, pbstrOut);
2199 
2200  if (!pVarIn || !pbstrOut || nFormat < 0 || nFormat > 4)
2201  return E_INVALIDARG;
2202 
2203  switch (nFormat)
2204  {
2205  case 0: lpFmt = fmtGeneralDate; break;
2206  case 1: lpFmt = fmtLongDate; break;
2207  case 2: lpFmt = fmtShortDate; break;
2208  case 3: lpFmt = fmtLongTime; break;
2209  case 4: lpFmt = fmtShortTime; break;
2210  }
2211  return VarFormatFromTokens(pVarIn, szEmpty, (BYTE*)lpFmt, dwFlags,
2212  pbstrOut, LOCALE_USER_DEFAULT);
2213 }
2214 
2215 #define GETLOCALENUMBER(type,field) GetLocaleInfoW(LOCALE_USER_DEFAULT, \
2216  type|LOCALE_RETURN_NUMBER, \
2217  (LPWSTR)&numfmt.field, \
2218  sizeof(numfmt.field)/sizeof(WCHAR))
2219 
2220 /**********************************************************************
2221  * VarFormatNumber [OLEAUT32.107]
2222  *
2223  * Format a variant value as a number.
2224  *
2225  * PARAMS
2226  * pVarIn [I] Variant to format
2227  * nDigits [I] Number of digits following the decimal point (-1 = user default)
2228  * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no)
2229  * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no)
2230  * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no)
2231  * dwFlags [I] Currently unused, set to zero
2232  * pbstrOut [O] Destination for formatted string.
2233  *
2234  * RETURNS
2235  * Success: S_OK. pbstrOut contains the formatted value.
2236  * Failure: E_INVALIDARG, if any parameter is invalid.
2237  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2238  * DISP_E_TYPEMISMATCH, if the variant cannot be formatted.
2239  *
2240  * NOTES
2241  * This function uses LOCALE_USER_DEFAULT when determining the number format
2242  * characters to use.
2243  */
2244 HRESULT WINAPI VarFormatNumber(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens,
2245  INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
2246 {
2247  HRESULT hRet;
2248  VARIANT vStr;
2249 
2250  TRACE("(%s,%d,%d,%d,%d,0x%08x,%p)\n", debugstr_variant(pVarIn), nDigits, nLeading,
2251  nParens, nGrouping, dwFlags, pbstrOut);
2252 
2253  if (!pVarIn || !pbstrOut || nDigits > 9)
2254  return E_INVALIDARG;
2255 
2256  *pbstrOut = NULL;
2257 
2258  V_VT(&vStr) = VT_EMPTY;
2259  hRet = VariantCopyInd(&vStr, pVarIn);
2260 
2261  if (SUCCEEDED(hRet))
2262  hRet = VariantChangeTypeEx(&vStr, &vStr, LCID_US, 0, VT_BSTR);
2263 
2264  if (SUCCEEDED(hRet))
2265  {
2266  WCHAR buff[256], decimal[8], thousands[8];
2267  NUMBERFMTW numfmt;
2268 
2269  /* Although MSDN makes it clear that the native versions of these functions
2270  * are implemented using VarTokenizeFormatString()/VarFormatFromTokens(),
2271  * using NLS gives us the same result.
2272  */
2273  if (nDigits < 0)
2274  GETLOCALENUMBER(LOCALE_IDIGITS, NumDigits);
2275  else
2276  numfmt.NumDigits = nDigits;
2277 
2278  if (nLeading == -2)
2279  GETLOCALENUMBER(LOCALE_ILZERO, LeadingZero);
2280  else if (nLeading == -1)
2281  numfmt.LeadingZero = 1;
2282  else
2283  numfmt.LeadingZero = 0;
2284 
2285  if (nGrouping == -2)
2286  {
2287  WCHAR grouping[16];
2288  grouping[2] = '\0';
2290  numfmt.Grouping = grouping[2] == '2' ? 32 : grouping[0] - '0';
2291  }
2292  else if (nGrouping == -1)
2293  numfmt.Grouping = 3; /* 3 = "n,nnn.nn" */
2294  else
2295  numfmt.Grouping = 0; /* 0 = No grouping */
2296 
2297  if (nParens == -2)
2298  GETLOCALENUMBER(LOCALE_INEGNUMBER, NegativeOrder);
2299  else if (nParens == -1)
2300  numfmt.NegativeOrder = 0; /* 0 = "(xxx)" */
2301  else
2302  numfmt.NegativeOrder = 1; /* 1 = "-xxx" */
2303 
2304  numfmt.lpDecimalSep = decimal;
2306  numfmt.lpThousandSep = thousands;
2308 
2309  if (GetNumberFormatW(LOCALE_USER_DEFAULT, 0, V_BSTR(&vStr), &numfmt, buff, ARRAY_SIZE(buff)))
2310  {
2311  *pbstrOut = SysAllocString(buff);
2312  if (!*pbstrOut)
2313  hRet = E_OUTOFMEMORY;
2314  }
2315  else
2316  hRet = DISP_E_TYPEMISMATCH;
2317 
2318  SysFreeString(V_BSTR(&vStr));
2319  }
2320  return hRet;
2321 }
2322 
2323 /**********************************************************************
2324  * VarFormatPercent [OLEAUT32.117]
2325  *
2326  * Format a variant value as a percentage.
2327  *
2328  * PARAMS
2329  * pVarIn [I] Variant to format
2330  * nDigits [I] Number of digits following the decimal point (-1 = user default)
2331  * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no)
2332  * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no)
2333  * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no)
2334  * dwFlags [I] Currently unused, set to zero
2335  * pbstrOut [O] Destination for formatted string.
2336  *
2337  * RETURNS
2338  * Success: S_OK. pbstrOut contains the formatted value.
2339  * Failure: E_INVALIDARG, if any parameter is invalid.
2340  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2341  * DISP_E_OVERFLOW, if overflow occurs during the conversion.
2342  * DISP_E_TYPEMISMATCH, if the variant cannot be formatted.
2343  *
2344  * NOTES
2345  * This function uses LOCALE_USER_DEFAULT when determining the number format
2346  * characters to use.
2347  */
2348 HRESULT WINAPI VarFormatPercent(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens,
2349  INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
2350 {
2351  static const WCHAR szPercent[] = { '%','\0' };
2352  static const WCHAR szPercentBracket[] = { '%',')','\0' };
2353  WCHAR buff[256];
2354  HRESULT hRet;
2355  VARIANT vDbl;
2356 
2357  TRACE("(%s,%d,%d,%d,%d,0x%08x,%p)\n", debugstr_variant(pVarIn), nDigits, nLeading,
2358  nParens, nGrouping, dwFlags, pbstrOut);
2359 
2360  if (!pVarIn || !pbstrOut || nDigits > 9)
2361  return E_INVALIDARG;
2362 
2363  *pbstrOut = NULL;
2364 
2365  V_VT(&vDbl) = VT_EMPTY;
2366  hRet = VariantCopyInd(&vDbl, pVarIn);
2367 
2368  if (SUCCEEDED(hRet))
2369  {
2370  hRet = VariantChangeTypeEx(&vDbl, &vDbl, LOCALE_USER_DEFAULT, 0, VT_R8);
2371 
2372  if (SUCCEEDED(hRet))
2373  {
2374  if (V_R8(&vDbl) > (R8_MAX / 100.0))
2375  return DISP_E_OVERFLOW;
2376 
2377  V_R8(&vDbl) *= 100.0;
2378  hRet = VarFormatNumber(&vDbl, nDigits, nLeading, nParens,
2379  nGrouping, dwFlags, pbstrOut);
2380 
2381  if (SUCCEEDED(hRet))
2382  {
2383  DWORD dwLen = strlenW(*pbstrOut);
2384  BOOL bBracket = (*pbstrOut)[dwLen] == ')';
2385 
2386  dwLen -= bBracket;
2387  memcpy(buff, *pbstrOut, dwLen * sizeof(WCHAR));
2388  strcpyW(buff + dwLen, bBracket ? szPercentBracket : szPercent);
2389  SysFreeString(*pbstrOut);
2390  *pbstrOut = SysAllocString(buff);
2391  if (!*pbstrOut)
2392  hRet = E_OUTOFMEMORY;
2393  }
2394  }
2395  }
2396  return hRet;
2397 }
2398 
2399 /**********************************************************************
2400  * VarFormatCurrency [OLEAUT32.127]
2401  *
2402  * Format a variant value as a currency.
2403  *
2404  * PARAMS
2405  * pVarIn [I] Variant to format
2406  * nDigits [I] Number of digits following the decimal point (-1 = user default)
2407  * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no)
2408  * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no)
2409  * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no)
2410  * dwFlags [I] Currently unused, set to zero
2411  * pbstrOut [O] Destination for formatted string.
2412  *
2413  * RETURNS
2414  * Success: S_OK. pbstrOut contains the formatted value.
2415  * Failure: E_INVALIDARG, if any parameter is invalid.
2416  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2417  * DISP_E_TYPEMISMATCH, if the variant cannot be formatted.
2418  *
2419  * NOTES
2420  * This function uses LOCALE_USER_DEFAULT when determining the currency format
2421  * characters to use.
2422  */
2423 HRESULT WINAPI VarFormatCurrency(LPVARIANT pVarIn, INT nDigits, INT nLeading,
2424  INT nParens, INT nGrouping, ULONG dwFlags,
2425  BSTR *pbstrOut)
2426 {
2427  HRESULT hRet;
2428  VARIANT vStr;
2429 
2430  TRACE("(%s,%d,%d,%d,%d,0x%08x,%p)\n", debugstr_variant(pVarIn), nDigits, nLeading,
2431  nParens, nGrouping, dwFlags, pbstrOut);
2432 
2433  if (!pVarIn || !pbstrOut || nDigits > 9)
2434  return E_INVALIDARG;
2435 
2436  *pbstrOut = NULL;
2437 
2438  V_VT(&vStr) = VT_EMPTY;
2439  hRet = VariantCopyInd(&vStr, pVarIn);
2440 
2441  if (SUCCEEDED(hRet))
2442  hRet = VariantChangeTypeEx(&vStr, &vStr, LOCALE_USER_DEFAULT, 0, VT_BSTR);
2443 
2444  if (SUCCEEDED(hRet))
2445  {
2446  WCHAR buff[256], decimal[8], thousands[8], currency[8];
2447  CURRENCYFMTW numfmt;
2448 
2449  if (nDigits < 0)
2450  GETLOCALENUMBER(LOCALE_IDIGITS, NumDigits);
2451  else
2452  numfmt.NumDigits = nDigits;
2453 
2454  if (nLeading == -2)
2455  GETLOCALENUMBER(LOCALE_ILZERO, LeadingZero);
2456  else if (nLeading == -1)
2457  numfmt.LeadingZero = 1;
2458  else
2459  numfmt.LeadingZero = 0;
2460 
2461  if (nGrouping == -2)
2462  {
2463  WCHAR grouping[16];
2464  grouping[2] = '\0';
2466  numfmt.Grouping = grouping[2] == '2' ? 32 : grouping[0] - '0';
2467  }
2468  else if (nGrouping == -1)
2469  numfmt.Grouping = 3; /* 3 = "n,nnn.nn" */
2470  else
2471  numfmt.Grouping = 0; /* 0 = No grouping */
2472 
2473  if (nParens == -2)
2474  GETLOCALENUMBER(LOCALE_INEGCURR, NegativeOrder);
2475  else if (nParens == -1)
2476  numfmt.NegativeOrder = 0; /* 0 = "(xxx)" */
2477  else
2478  numfmt.NegativeOrder = 1; /* 1 = "-xxx" */
2479 
2480  GETLOCALENUMBER(LOCALE_ICURRENCY, PositiveOrder);
2481 
2482  numfmt.lpDecimalSep = decimal;
2484  numfmt.lpThousandSep = thousands;
2486  numfmt.lpCurrencySymbol = currency;
2488 
2489  /* use NLS as per VarFormatNumber() */
2490  if (GetCurrencyFormatW(LOCALE_USER_DEFAULT, 0, V_BSTR(&vStr), &numfmt, buff, ARRAY_SIZE(buff)))
2491  {
2492  *pbstrOut = SysAllocString(buff);
2493  if (!*pbstrOut)
2494  hRet = E_OUTOFMEMORY;
2495  }
2496  else
2497  hRet = DISP_E_TYPEMISMATCH;
2498 
2499  SysFreeString(V_BSTR(&vStr));
2500  }
2501  return hRet;
2502 }
2503 
2504 /**********************************************************************
2505  * VarMonthName [OLEAUT32.129]
2506  *
2507  * Print the specified month as localized name.
2508  *
2509  * PARAMS
2510  * iMonth [I] month number 1..12
2511  * fAbbrev [I] 0 - full name, !0 - abbreviated name
2512  * dwFlags [I] flag stuff. only VAR_CALENDAR_HIJRI possible.
2513  * pbstrOut [O] Destination for month name
2514  *
2515  * RETURNS
2516  * Success: S_OK. pbstrOut contains the name.
2517  * Failure: E_INVALIDARG, if any parameter is invalid.
2518  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2519  */
2520 HRESULT WINAPI VarMonthName(INT iMonth, INT fAbbrev, ULONG dwFlags, BSTR *pbstrOut)
2521 {
2522  DWORD localeValue;
2523  INT size;
2524 
2525  if ((iMonth < 1) || (iMonth > 12))
2526  return E_INVALIDARG;
2527 
2528  if (dwFlags)
2529  FIXME("Does not support dwFlags 0x%x, ignoring.\n", dwFlags);
2530 
2531  if (fAbbrev)
2532  localeValue = LOCALE_SABBREVMONTHNAME1 + iMonth - 1;
2533  else
2534  localeValue = LOCALE_SMONTHNAME1 + iMonth - 1;
2535 
2536  size = GetLocaleInfoW(LOCALE_USER_DEFAULT,localeValue, NULL, 0);
2537  if (!size) {
2538  ERR("GetLocaleInfo 0x%x failed.\n", localeValue);
2539  return HRESULT_FROM_WIN32(GetLastError());
2540  }
2541  *pbstrOut = SysAllocStringLen(NULL,size - 1);
2542  if (!*pbstrOut)
2543  return E_OUTOFMEMORY;
2544  size = GetLocaleInfoW(LOCALE_USER_DEFAULT,localeValue, *pbstrOut, size);
2545  if (!size) {
2546  ERR("GetLocaleInfo of 0x%x failed in 2nd stage?!\n", localeValue);
2547  SysFreeString(*pbstrOut);
2548  return HRESULT_FROM_WIN32(GetLastError());
2549  }
2550  return S_OK;
2551 }
2552 
2553 /**********************************************************************
2554  * VarWeekdayName [OLEAUT32.129]
2555  *
2556  * Print the specified weekday as localized name.
2557  *
2558  * PARAMS
2559  * iWeekday [I] day of week, 1..7, 1="the first day of the week"
2560  * fAbbrev [I] 0 - full name, !0 - abbreviated name
2561  * iFirstDay [I] first day of week,
2562  * 0=system default, 1=Sunday, 2=Monday, .. (contrary to MSDN)
2563  * dwFlags [I] flag stuff. only VAR_CALENDAR_HIJRI possible.
2564  * pbstrOut [O] Destination for weekday name.
2565  *
2566  * RETURNS
2567  * Success: S_OK, pbstrOut contains the name.
2568  * Failure: E_INVALIDARG, if any parameter is invalid.
2569  * E_OUTOFMEMORY, if enough memory cannot be allocated.
2570  */
2571 HRESULT WINAPI VarWeekdayName(INT iWeekday, INT fAbbrev, INT iFirstDay,
2572  ULONG dwFlags, BSTR *pbstrOut)
2573 {
2574  DWORD localeValue;
2575  INT size;
2576 
2577  /* Windows XP oleaut32.dll doesn't allow iWekday==0, contrary to MSDN */
2578  if (iWeekday < 1 || iWeekday > 7)
2579  return E_INVALIDARG;
2580  if (iFirstDay < 0 || iFirstDay > 7)
2581  return E_INVALIDARG;
2582  if (!pbstrOut)
2583  return E_INVALIDARG;
2584 
2585  if (dwFlags)
2586  FIXME("Does not support dwFlags 0x%x, ignoring.\n", dwFlags);
2587 
2588  /* If we have to use the default firstDay, find which one it is */
2589  if (iFirstDay == 0) {
2590  DWORD firstDay;
2591  localeValue = LOCALE_RETURN_NUMBER | LOCALE_IFIRSTDAYOFWEEK;
2592  size = GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue,
2593  (LPWSTR)&firstDay, sizeof(firstDay) / sizeof(WCHAR));
2594  if (!size) {
2595  ERR("GetLocaleInfo 0x%x failed.\n", localeValue);
2596  return HRESULT_FROM_WIN32(GetLastError());
2597  }
2598  iFirstDay = firstDay + 2;
2599  }
2600 
2601  /* Determine what we need to return */
2602  localeValue = fAbbrev ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1;
2603  localeValue += (7 + iWeekday - 1 + iFirstDay - 2) % 7;
2604 
2605  /* Determine the size of the data, allocate memory and retrieve the data */
2606  size = GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, NULL, 0);
2607  if (!size) {
2608  ERR("GetLocaleInfo 0x%x failed.\n", localeValue);
2609  return HRESULT_FROM_WIN32(GetLastError());
2610  }
2611  *pbstrOut = SysAllocStringLen(NULL, size - 1);
2612  if (!*pbstrOut)
2613  return E_OUTOFMEMORY;
2614  size = GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, *pbstrOut, size);
2615  if (!size) {
2616  ERR("GetLocaleInfo 0x%x failed in 2nd stage?!\n", localeValue);
2617  SysFreeString(*pbstrOut);
2618  return HRESULT_FROM_WIN32(GetLastError());
2619  }
2620  return S_OK;
2621 }
#define FMT_DATE_YEAR_LONG
Definition: varformat.c:246
LPWSTR lpThousandSep
Definition: winnls.h:643
#define FmtGetZero(x)
Definition: varformat.c:169
#define FMT_NUM_EXP_POS_U
Definition: varformat.c:266
#define FMT_TYPE_DATE
Definition: varformat.c:148
#define FMT_FLAG_GT
Definition: varformat.c:177
#define FMT_DATE_HOUR_0
Definition: varformat.c:252
#define FMT_DATE_AMPM_SYS1
Definition: varformat.c:257
#define VARIANT_NOUSEROVERRIDE
Definition: oleauto.h:312
#define FMT_NUM_COPY_SKIP
Definition: varformat.c:264
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
HRESULT WINAPI VarTokenizeFormatString(LPOLESTR lpszFormat, LPBYTE rgbTok, int cbTok, int nFirstDay, int nFirstWeek, LCID lcid, int *pcbActual)
Definition: varformat.c:498
#define FMT_FLAG_RTL
Definition: varformat.c:178
#define FMT_TO_STRING
Definition: varformat.c:151
#define NUMPRS_STD
Definition: oleauto.h:748
#define TRUE
Definition: types.h:120
#define FMT_DATE_AMPM_LOWER
Definition: varformat.c:261
HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate)
Definition: variant.c:1430
#define FMT_DATE_HOUR
Definition: varformat.c:251
WINE_DEFAULT_DEBUG_CHANNEL(variant)
#define FMT_GEN_END
Definition: varformat.c:224
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
static const BYTE fmtStandard[0x11]
Definition: varformat.c:389
SYSTEMTIME st
Definition: oleauto.h:721
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
#define LOCALE_SABBREVMONTHNAME1
Definition: winnls.h:104
LPWSTR lpDecimalSep
Definition: winnls.h:642
GLint x0
Definition: linetemp.h:95
static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:1584
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define FMT_FLAG_EXPONENT
Definition: varformat.c:194
BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
Definition: oleaut.c:342
#define FMT_TYPE_STRING
Definition: varformat.c:149
WCHAR * name
Definition: path.c:44
UINT Grouping
Definition: winnls.h:611
#define VAR_CALENDAR_HIJRI
Definition: oleauto.h:329
#define FMT_DATE_MEDIUM
Definition: varformat.c:236
WORD wMonth
Definition: winbase.h:871
UINT NegativeOrder
Definition: winnls.h:614
#define FMT_DATE_AMPM_SYS2
Definition: varformat.c:260
#define FMT_NUM_EXP_NEG_L
Definition: varformat.c:269
static const BYTE fmtGeneralNumber[sizeof(FMT_HEADER)]
Definition: varformat.c:360
#define FMT_FLAG_THOUSANDS
Definition: varformat.c:195
#define FMT_DATE_DATE_SEP
Definition: varformat.c:226
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
UINT LeadingZero
Definition: winnls.h:610
#define LOCALE_SABBREVDAYNAME1
Definition: winnls.h:84
#define LOCALE_USER_DEFAULT
#define FMT_DATE_DAY_SHORT
Definition: varformat.c:232
GLuint GLuint GLsizei count
Definition: gl.h:1545
WORD wDayOfWeek
Definition: winbase.h:872
INT WINAPI GetCurrencyFormatW(LCID lcid, DWORD dwFlags, LPCWSTR lpszValue, const CURRENCYFMTW *lpFormat, LPWSTR lpCurrencyStr, int cchOut)
Definition: lcformat.c:1564
HRESULT WINAPI VarMonthName(INT iMonth, INT fAbbrev, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2520
#define FMT_DATE_TIME_UNK2
Definition: varformat.c:255
#define V_R8(A)
Definition: oleauto.h:262
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
static HRESULT VARIANT_FormatString(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:1920
GLintptr offset
Definition: glext.h:5920
const char * fmt
Definition: wsprintf.c:30
static const WCHAR szPercent[]
Definition: varformat.c:396
static const WCHAR szOnOff[]
Definition: varformat.c:351
#define LOCALE_ILZERO
Definition: winnls.h:46
#define NUM_WROTE_SIGN
Definition: varformat.c:1169
UINT Grouping
Definition: winnls.h:641
#define NUMBER_VTBITS
Definition: varformat.c:2045
#define FMT_NUM_EXP_NEG_U
Definition: varformat.c:267
#define FMT_DATE_GENERAL
Definition: varformat.c:227
HRESULT WINAPI VariantCopyInd(VARIANT *pvargDest, VARIANTARG *pvargSrc)
Definition: variant.c:850
#define FMT_DATE_AMPM_UPPER
Definition: varformat.c:258
static const BYTE fmtShortDate[0x0a]
Definition: varformat.c:287
static BSTR *static LPOLESTR
Definition: varformat.c:44
struct tagFMT_DATE_HEADER FMT_DATE_HEADER
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
#define FMT_NUM_CURRENCY
Definition: varformat.c:270
HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, NUMPARSE *pNumprs, BYTE *rgbDig)
Definition: variant.c:1607
#define VAR_TIMEVALUEONLY
Definition: oleauto.h:326
DWORD LCID
Definition: nls.h:13
OLECHAR * BSTR
Definition: compat.h:1934
LPWSTR lpThousandSep
Definition: winnls.h:613
static const WCHAR szGeneralNumber[]
Definition: varformat.c:359
#define strncmpiW(s1, s2, n)
Definition: unicode.h:40
#define FMT_DATE_YEAR_DOY
Definition: varformat.c:243
HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
Definition: vartype.c:6777
#define FMT_STR_COPY_SKIP
Definition: varformat.c:275
struct tagFMT_STRING_HEADER FMT_STRING_HEADER
int32_t INT
Definition: typedefs.h:56
static int FormatCompareFn(const void *l, const void *r)
Definition: varformat.c:441
static const BYTE fmtYesNo[0x0d]
Definition: varformat.c:344
#define FmtGetPositive(x)
Definition: varformat.c:167
#define LOCALE_SCURRENCY
Definition: winnls.h:49
UINT NegativeOrder
Definition: winnls.h:644
HRESULT WINAPI VarWeekdayName(INT iWeekday, INT fAbbrev, INT iFirstDay, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2571
WINE_UNICODE_INLINE int strncmpW(const WCHAR *str1, const WCHAR *str2, int n)
Definition: unicode.h:235
static const BYTE fmtMediumTime[0x11]
Definition: varformat.c:319
#define LCID_US
Definition: varformat.c:48
static const WCHAR szScientific[]
Definition: varformat.c:405
ULONG dwInFlags
Definition: oleauto.h:728
#define LOCALE_INEGNUMBER
Definition: winnls.h:47
static const BYTE fmtLongDate[0x0a]
Definition: varformat.c:303
#define GETLOCALENUMBER(type, field)
Definition: varformat.c:2215
#define COULD_BE(typ)
Definition: varformat.c:461
#define FMT_TYPE_NUMBER
Definition: varformat.c:147
struct tagFMT_HEADER FMT_HEADER
INT WINAPI GetLocaleInfoW(LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len)
Definition: lang.c:1098
#define FMT_DATE_A_UPPER
Definition: varformat.c:259
#define LOCALE_SDAYNAME1
Definition: winnls.h:77
static const WCHAR szShortDate[]
Definition: varformat.c:286
WORD wYear
Definition: winbase.h:870
struct tagFMT_SHORT_HEADER FMT_SHORT_HEADER
#define FMT_DATE_SHORT
Definition: varformat.c:234
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define LOCALE_SMONTHNAME1
Definition: winnls.h:91
#define LOCALE_STHOUSAND
Definition: winnls.h:43
#define FMT_NUM_TRUE_FALSE
Definition: varformat.c:271
#define FMT_TYPE_GENERAL
Definition: varformat.c:146
unsigned char * LPBYTE
Definition: typedefs.h:52
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
unsigned int BOOL
Definition: ntddk_ex.h:94
static const WCHAR szStandard[]
Definition: varformat.c:388
#define debugstr_w
Definition: kernel32.h:32
UINT NumDigits
Definition: winnls.h:639
#define LOCALE_SLONGDATE
Definition: winnls.h:61
#define FIXME(fmt,...)
Definition: debug.h:110
#define FMT_STATE_OPEN_COPY
Definition: varformat.c:464
#define FMT_DATE_HOUR_12_0
Definition: varformat.c:254
#define E_INVALIDARG
Definition: ddrawi.h:101
WORD wMinute
Definition: winbase.h:875
#define LOCALE_INEGCURR
Definition: winnls.h:57
smooth NULL
Definition: ftsmooth.c:416
#define FMT_DATE_DAY
Definition: varformat.c:230
BSTR WINAPI SysAllocString(LPCOLESTR str)
Definition: oleaut.c:241
#define LOCALE_SDECIMAL
Definition: winnls.h:42
#define FMT_NUM_YES_NO
Definition: varformat.c:272
#define FMT_DATE_TIME_SEP
Definition: varformat.c:225
#define LOCALE_STIME
Definition: winnls.h:59
const char * LPCSTR
Definition: xmlstorage.h:183
static const BYTE fmtMediumDate[0x0a]
Definition: varformat.c:295
struct tagFMT_NUMBER_HEADER FMT_NUMBER_HEADER
struct tagNAMED_FORMAT NAMED_FORMAT
#define NUMPRS_NEG
Definition: oleauto.h:749
HRESULT WINAPI VarFormatPercent(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2348
r l[0]
Definition: byte_order.h:167
WINE_UNICODE_INLINE WCHAR toupperW(WCHAR ch)
Definition: unicode.h:141
static const WCHAR szLongTime[]
Definition: varformat.c:327
static const WCHAR szEmpty[]
Definition: provider.c:47
#define LOCALE_ICURRENCY
Definition: winnls.h:56
#define VAR_FORMAT_NOSUBSTITUTE
Definition: oleauto.h:331
#define FMT_STATE_SEEN_HOURS
Definition: varformat.c:466
static void pad(Char *s)
Definition: bzip2.c:908
#define DISP_E_TYPEMISMATCH
Definition: winerror.h:2514
#define TRACE(s)
Definition: solgame.cpp:4
static const BYTE fmtTrueFalse[0x0d]
Definition: varformat.c:336
GLsizeiptr size
Definition: glext.h:5919
HRESULT hres
Definition: protocol.c:465
BYTE starts[4]
Definition: varformat.c:164
#define FMT_DATE_QUARTER
Definition: varformat.c:228
static const BYTE fmtPercent[0x15]
Definition: varformat.c:397
static const WCHAR szGeneralDate[]
Definition: varformat.c:278
#define R8_MAX
Definition: variant.h:73
#define FMT_NUM_DECIMAL
Definition: varformat.c:265
#define LOCALE_SDATE
Definition: winnls.h:58
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define debugstr_a
Definition: kernel32.h:31
LONG HRESULT
Definition: typedefs.h:77
#define FMT_DATE_MON_SHORT
Definition: varformat.c:241
const NAMED_FORMAT * LPCNAMED_FORMAT
Definition: varformat.c:439
#define VAR_BOOLYESNO
Definition: variant.h:103
LPCWSTR name
Definition: varformat.c:415
#define WINAPI
Definition: msvc.h:8
HRESULT WINAPI VarFormat(LPVARIANT pVarIn, LPOLESTR lpszFormat, int nFirstDay, int nFirstWeek, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2141
HRESULT WINAPI VarFormatDateTime(LPVARIANT pVarIn, INT nFormat, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2193
static const WCHAR szCurrency[]
Definition: varformat.c:365
#define FMT_DATE_DAY_0
Definition: varformat.c:231
#define V_BOOL(A)
Definition: oleauto.h:224
#define FMT_STATE_WROTE_MINUTES
Definition: varformat.c:467
WINE_UNICODE_INLINE WCHAR tolowerW(WCHAR ch)
Definition: unicode.h:135
unsigned long DWORD
Definition: ntddk_ex.h:95
INT cDig
Definition: oleauto.h:727
#define FMT_DATE_DAY_LONG
Definition: varformat.c:233
WORD wSecond
Definition: winbase.h:876
#define FMT_DATE_LONG
Definition: varformat.c:235
#define LOCALE_S1159
Definition: winnls.h:71
static const WCHAR szPercentZeroTwo_d[]
Definition: varformat.c:51
#define FMT_DATE_MON_LONG
Definition: varformat.c:242
#define FMT_DATE_YEAR_0
Definition: varformat.c:244
#define FMT_NUM_EXP_POS_L
Definition: varformat.c:268
LPWSTR lpDecimalSep
Definition: winnls.h:612
#define FMT_TYPE_UNKNOWN
Definition: varformat.c:145
HRESULT WINAPI DECLSPEC_HOTPATCH VariantClear(VARIANTARG *pVarg)
Definition: variant.c:651
#define FMT_DATE_MON_0
Definition: varformat.c:240
#define LOCALE_SNEGATIVESIGN
Definition: winnls.h:118
#define FMT_DATE_MIN_0
Definition: varformat.c:248
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
#define LOCALE_SSHORTDATE
Definition: winnls.h:60
#define V_VT(A)
Definition: oleauto.h:211
HKEY key
Definition: reg.c:42
static const BYTE fmtGeneralDate[0x0a]
Definition: varformat.c:279
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define NEED_SPACE(x)
Definition: varformat.c:458
Definition: oleauto.h:720
unsigned char BYTE
Definition: mem.h:68
static const WCHAR szPercentZeroStar_d[]
Definition: varformat.c:52
#define LOCALE_IDIGITS
Definition: winnls.h:45
#define VAR_LOCALBOOL
Definition: oleauto.h:330
#define FMT_STR_COPY_SPACE
Definition: varformat.c:274
#define FmtGetNegative(x)
Definition: varformat.c:168
#define LOCALE_IFIRSTDAYOFWEEK
Definition: winnls.h:75
#define debugstr_wn
Definition: kernel32.h:33
static const WCHAR szShortTime[]
Definition: varformat.c:310
static const BYTE fmtCurrency[0x26]
Definition: varformat.c:366
#define FMT_FLAG_LT
Definition: varformat.c:176
#define V_BSTR(A)
Definition: oleauto.h:226
#define NUM_WROTE_DEC
Definition: varformat.c:1167
#define NUM_WRITE_ON
Definition: varformat.c:1168
#define strcmpiW(s1, s2)
Definition: unicode.h:39
LPWSTR lpCurrencySymbol
Definition: winnls.h:616
#define ERR(fmt,...)
Definition: debug.h:109
#define FmtGetNull(x)
Definition: varformat.c:170
WORD wDay
Definition: winbase.h:873
#define FMT_NUM_COPY_ZERO
Definition: varformat.c:263
#define FMT_DATE_MON
Definition: varformat.c:239
static const char * debugstr_variant(const VARIANT *var)
Definition: container.c:46
#define S_OK
Definition: intsafe.h:59
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
#define FMT_DATE_SEC_0
Definition: varformat.c:250
#define FMT_STATE_WROTE_DECIMAL
Definition: varformat.c:465
#define FMT_FLAG_PERCENT
Definition: varformat.c:193
static const WCHAR szMediumTime[]
Definition: varformat.c:318
#define FMT_GEN_COPY
Definition: varformat.c:222
unsigned short USHORT
Definition: pedump.c:61
const BYTE * format
Definition: varformat.c:416
#define FMT_DATE_MIN
Definition: varformat.c:247
GLuint start
Definition: gl.h:1545
#define ARRAY_SIZE(a)
Definition: main.h:24
__u16 date
Definition: mkdosfs.c:366
static const BYTE * VARIANT_GetNamedFormat(LPCWSTR lpszFormat)
Definition: varformat.c:446
HRESULT WINAPI VarFormatFromTokens(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:2053
#define FMT_DATE_DAY_WEEK
Definition: varformat.c:237
#define VAR_BOOLONOFF
Definition: variant.h:102
#define sprintfW
Definition: unicode.h:58
WORD wHour
Definition: winbase.h:874
#define FMT_NUM_ON_OFF
Definition: varformat.c:273
static const NAMED_FORMAT VARIANT_NamedFormats[]
Definition: varformat.c:420
#define min(a, b)
Definition: monoChain.cc:55
void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
Definition: oleaut.c:274
#define V_TYPE(v)
Definition: variant.h:30
static const WCHAR szMediumDate[]
Definition: varformat.c:294
#define VARIANT_CALENDAR_HIJRI
Definition: oleauto.h:313
#define FMT_DATE_SEC
Definition: varformat.c:249
HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
Definition: vartype.c:6851
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3706
UINT NumDigits
Definition: winnls.h:609
Definition: name.c:36
#define FMT_GEN_INLINE
Definition: varformat.c:223
static const BYTE fmtFixed[0x11]
Definition: varformat.c:381
#define FMT_DATE_HOUR_12
Definition: varformat.c:253
unsigned int ULONG
Definition: retypes.h:1
UINT LeadingZero
Definition: winnls.h:640
static const WCHAR szFixed[]
Definition: varformat.c:380
#define FMT_FLAG_BOOL
Definition: varformat.c:196
BOOL get_date_format(LCID, DWORD, const SYSTEMTIME *, const WCHAR *, WCHAR *, int) DECLSPEC_HIDDEN
Definition: vartype.c:6667
HRESULT WINAPI VarFormatCurrency(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2423
INT WINAPI GetNumberFormatW(LCID lcid, DWORD dwFlags, LPCWSTR lpszValue, const NUMBERFMTW *lpFormat, LPWSTR lpNumberStr, int cchOut)
Definition: lcformat.c:1198
static const BYTE fmtShortTime[0x0c]
Definition: varformat.c:311
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define memset(x, y, z)
Definition: compat.h:39
USHORT wDayOfYear
Definition: oleauto.h:722
#define DISP_E_OVERFLOW
Definition: winerror.h:2519
static const WCHAR szPercent_d[]
Definition: varformat.c:50
#define LOCALE_S2359
Definition: winnls.h:72
static const WCHAR szYesNo[]
Definition: varformat.c:343
int k
Definition: mpi.c:3369
static unsigned char buff[32768]
Definition: fatten.c:17
#define FMT_DATE_A_LOWER
Definition: varformat.c:262
Definition: dsound.c:943
struct CFHEADER header
Definition: fdi.c:109
#define FMT_DATE_TIME_SYS
Definition: varformat.c:229
#define FMT_DATE_WEEK_YEAR
Definition: varformat.c:238
Definition: compat.h:1941
static const WCHAR szTrueFalse[]
Definition: varformat.c:335
static const BYTE fmtLongTime[0x0d]
Definition: varformat.c:328
#define V_DATE(A)
Definition: oleauto.h:231
#define SUCCEEDED(hr)
Definition: intsafe.h:57
HRESULT WINAPI VarFormatNumber(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2244
static const BYTE fmtOnOff[0x0d]
Definition: varformat.c:352
HRESULT WINAPI VariantChangeTypeEx(VARIANTARG *pvargDest, VARIANTARG *pvargSrc, LCID lcid, USHORT wFlags, VARTYPE vt)
Definition: variant.c:991
static const BYTE fmtScientific[0x13]
Definition: varformat.c:406
INT nPwr10
Definition: oleauto.h:732
Definition: path.c:42
ULONG dwOutFlags
Definition: oleauto.h:729
static const WCHAR szLongDate[]
Definition: varformat.c:302
#define bsearch
static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:1172