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