ReactOS 0.4.15-dev-7842-g558ab78
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
47static const WCHAR szPercent_d[] = { '%','d','\0' };
48static const WCHAR szPercentZeroTwo_d[] = { '%','0','2','d','\0' };
49static 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
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
157typedef 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 */
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
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
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 */
207typedef 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 */
275static const WCHAR szGeneralDate[] = { 'G','e','n','e','r','a','l',' ','D','a','t','e','\0' };
276static const BYTE fmtGeneralDate[0x0a] =
277{
278 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
279 0x0,0x0,0x0,0x0,0x0,
281};
282
283static const WCHAR szShortDate[] = { 'S','h','o','r','t',' ','D','a','t','e','\0' };
284static const BYTE fmtShortDate[0x0a] =
285{
286 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
287 0x0,0x0,0x0,0x0,0x0,
289};
290
291static const WCHAR szMediumDate[] = { 'M','e','d','i','u','m',' ','D','a','t','e','\0' };
292static const BYTE fmtMediumDate[0x0a] =
293{
294 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
295 0x0,0x0,0x0,0x0,0x0,
297};
298
299static const WCHAR szLongDate[] = { 'L','o','n','g',' ','D','a','t','e','\0' };
300static const BYTE fmtLongDate[0x0a] =
301{
302 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
303 0x0,0x0,0x0,0x0,0x0,
305};
306
307static const WCHAR szShortTime[] = { 'S','h','o','r','t',' ','T','i','m','e','\0' };
308static const BYTE fmtShortTime[0x0c] =
309{
310 0x0c,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
311 0x0,0x0,0x0,0x0,0x0,
313};
314
315static const WCHAR szMediumTime[] = { 'M','e','d','i','u','m',' ','T','i','m','e','\0' };
316static const BYTE fmtMediumTime[0x11] =
317{
318 0x11,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
319 0x0,0x0,0x0,0x0,0x0,
322};
323
324static const WCHAR szLongTime[] = { 'L','o','n','g',' ','T','i','m','e','\0' };
325static const BYTE fmtLongTime[0x0d] =
326{
327 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER),
328 0x0,0x0,0x0,0x0,0x0,
330};
331
332static const WCHAR szTrueFalse[] = { 'T','r','u','e','/','F','a','l','s','e','\0' };
333static 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
340static const WCHAR szYesNo[] = { 'Y','e','s','/','N','o','\0' };
341static 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
348static const WCHAR szOnOff[] = { 'O','n','/','O','f','f','\0' };
349static 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
356static const WCHAR szGeneralNumber[] = { 'G','e','n','e','r','a','l',' ','N','u','m','b','e','r','\0' };
357static const BYTE fmtGeneralNumber[sizeof(FMT_HEADER)] =
358{
359 sizeof(FMT_HEADER),FMT_TYPE_GENERAL,sizeof(FMT_HEADER),0x0,0x0,0x0
360};
361
362static const WCHAR szCurrency[] = { 'C','u','r','r','e','n','c','y','\0' };
363static 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,
370 /* Negative numbers */
371 FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2,
375};
376
377static const WCHAR szFixed[] = { 'F','i','x','e','d','\0' };
378static const BYTE fmtFixed[0x11] =
379{
380 0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
381 0x0,0x0,0x0,0x1,0x2,
383};
384
385static const WCHAR szStandard[] = { 'S','t','a','n','d','a','r','d','\0' };
386static const BYTE fmtStandard[0x11] =
387{
388 0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
389 FMT_FLAG_THOUSANDS,0x0,0x0,0x1,0x2,
391};
392
393static const WCHAR szPercent[] = { 'P','e','r','c','e','n','t','\0' };
394static 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
402static const WCHAR szScientific[] = { 'S','c','i','e','n','t','i','f','i','c','\0' };
403static const BYTE fmtScientific[0x13] =
404{
405 0x13,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0,
406 FMT_FLAG_EXPONENT,0x0,0x0,0x1,0x2,
408};
409
410typedef struct tagNAMED_FORMAT
411{
413 const BYTE* format;
415
416/* Format name to tokenised format. Must be kept sorted by name */
418{
420 { szFixed, fmtFixed },
427 { szOnOff, fmtOnOff },
434 { szYesNo, fmtYesNo }
435};
437
438static int __cdecl FormatCompareFn(const void *l, const void *r)
439{
441}
442
443static inline const BYTE *VARIANT_GetNamedFormat(LPCWSTR lpszFormat)
444{
447
448 key.name = lpszFormat;
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
1363VARIANT_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
1567VARIANT_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 */
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
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
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
1904VARIANT_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
2020VARIANT_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 */
2077VarFormatFromTokens_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 */
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 */
2241HRESULT 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 */
2345HRESULT 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 */
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() */
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 */
2517HRESULT 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);
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);
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 */
2568HRESULT 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;
2590 (LPWSTR)&firstDay, sizeof(firstDay) / sizeof(WCHAR));
2591 if (!size) {
2592 ERR("GetLocaleInfo 0x%x failed.\n", localeValue);
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);
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);
2616 }
2617 return S_OK;
2618}
#define __cdecl
Definition: accygwin.h:79
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:33
#define FIXME(fmt,...)
Definition: debug.h:111
#define ERR(fmt,...)
Definition: debug.h:110
r l[0]
Definition: byte_order.h:168
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static const WCHAR szEmpty[]
Definition: provider.c:50
OLECHAR * BSTR
Definition: compat.h:2293
#define lstrcpyW
Definition: compat.h:749
@ VT_BSTR
Definition: compat.h:2303
@ VT_NULL
Definition: compat.h:2296
@ VT_R8
Definition: compat.h:2300
@ VT_DATE
Definition: compat.h:2302
@ VT_BOOL
Definition: compat.h:2306
@ VT_EMPTY
Definition: compat.h:2295
#define wcsicmp
Definition: compat.h:15
#define lstrlenW
Definition: compat.h:750
static const WCHAR szLongDate[]
Definition: varformat.c:299
#define FMT_DATE_DAY
Definition: varformat.c:227
#define FMT_STR_COPY_SPACE
Definition: varformat.c:271
#define FMT_STATE_WROTE_DECIMAL
Definition: varformat.c:462
#define FMT_FLAG_LT
Definition: varformat.c:173
#define FmtGetPositive(x)
Definition: varformat.c:164
#define FMT_DATE_HOUR
Definition: varformat.c:248
static const WCHAR szScientific[]
Definition: varformat.c:402
static const BYTE fmtPercent[0x15]
Definition: varformat.c:394
static const BYTE fmtLongDate[0x0a]
Definition: varformat.c:300
#define FMT_DATE_MON_SHORT
Definition: varformat.c:238
static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:1581
static const BYTE fmtYesNo[0x0d]
Definition: varformat.c:341
const NAMED_FORMAT * LPCNAMED_FORMAT
Definition: varformat.c:436
HRESULT WINAPI VarTokenizeFormatString(LPOLESTR lpszFormat, LPBYTE rgbTok, int cbTok, int nFirstDay, int nFirstWeek, LCID lcid, int *pcbActual)
Definition: varformat.c:495
static const WCHAR szOnOff[]
Definition: varformat.c:348
#define FMT_DATE_SHORT
Definition: varformat.c:231
#define FMT_DATE_A_LOWER
Definition: varformat.c:259
#define FMT_DATE_MON_0
Definition: varformat.c:237
#define FMT_NUM_COPY_SKIP
Definition: varformat.c:261
#define FMT_DATE_AMPM_UPPER
Definition: varformat.c:255
static const BYTE fmtGeneralNumber[sizeof(FMT_HEADER)]
Definition: varformat.c:357
#define FMT_NUM_EXP_POS_L
Definition: varformat.c:265
#define FMT_TYPE_STRING
Definition: varformat.c:146
#define FMT_NUM_EXP_NEG_U
Definition: varformat.c:264
#define FMT_DATE_YEAR_LONG
Definition: varformat.c:243
#define FMT_DATE_HOUR_12
Definition: varformat.c:250
#define FMT_DATE_SEC
Definition: varformat.c:246
HRESULT WINAPI VarFormat(LPVARIANT pVarIn, LPOLESTR lpszFormat, int nFirstDay, int nFirstWeek, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2138
static const BYTE fmtStandard[0x11]
Definition: varformat.c:386
#define FMT_DATE_HOUR_12_0
Definition: varformat.c:251
#define FMT_DATE_MON_LONG
Definition: varformat.c:239
#define FmtGetZero(x)
Definition: varformat.c:166
#define FMT_DATE_DAY_0
Definition: varformat.c:228
#define FmtGetNegative(x)
Definition: varformat.c:165
static const BYTE fmtGeneralDate[0x0a]
Definition: varformat.c:276
#define FMT_DATE_DAY_SHORT
Definition: varformat.c:229
#define FMT_DATE_TIME_SYS
Definition: varformat.c:226
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_TIME_SEP
Definition: varformat.c:222
#define FMT_NUM_CURRENCY
Definition: varformat.c:267
static const WCHAR szShortTime[]
Definition: varformat.c:307
struct tagFMT_HEADER FMT_HEADER
static const BYTE fmtCurrency[0x26]
Definition: varformat.c:363
#define FMT_FLAG_EXPONENT
Definition: varformat.c:191
#define FMT_STATE_SEEN_HOURS
Definition: varformat.c:463
#define NEED_SPACE(x)
Definition: varformat.c:455
static const BYTE fmtShortTime[0x0c]
Definition: varformat.c:308
struct tagFMT_DATE_HEADER FMT_DATE_HEADER
#define FMT_DATE_MEDIUM
Definition: varformat.c:233
#define FMT_NUM_DECIMAL
Definition: varformat.c:262
static const WCHAR szFixed[]
Definition: varformat.c:377
HRESULT WINAPI VarFormatPercent(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2345
#define NUM_WROTE_SIGN
Definition: varformat.c:1166
#define FMT_FLAG_THOUSANDS
Definition: varformat.c:192
static const BYTE fmtShortDate[0x0a]
Definition: varformat.c:284
#define FMT_GEN_COPY
Definition: varformat.c:219
#define FMT_GEN_END
Definition: varformat.c:221
static const BYTE fmtOnOff[0x0d]
Definition: varformat.c:349
#define FMT_STR_COPY_SKIP
Definition: varformat.c:272
struct tagFMT_STRING_HEADER FMT_STRING_HEADER
#define FMT_FLAG_RTL
Definition: varformat.c:175
#define FMT_DATE_YEAR_DOY
Definition: varformat.c:240
HRESULT WINAPI VarWeekdayName(INT iWeekday, INT fAbbrev, INT iFirstDay, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2568
static const WCHAR szCurrency[]
Definition: varformat.c:362
#define FMT_NUM_TRUE_FALSE
Definition: varformat.c:268
static const WCHAR szLongTime[]
Definition: varformat.c:324
static const WCHAR szPercent_d[]
Definition: varformat.c:47
static const WCHAR szShortDate[]
Definition: varformat.c:283
#define FMT_DATE_MON
Definition: varformat.c:236
#define FMT_FLAG_PERCENT
Definition: varformat.c:190
#define FMT_DATE_TIME_UNK2
Definition: varformat.c:252
static const WCHAR szPercent[]
Definition: varformat.c:393
static const WCHAR szPercentZeroStar_d[]
Definition: varformat.c:49
#define FMT_TYPE_NUMBER
Definition: varformat.c:144
#define FMT_TYPE_UNKNOWN
Definition: varformat.c:142
#define FMT_DATE_WEEK_YEAR
Definition: varformat.c:235
#define FMT_NUM_EXP_POS_U
Definition: varformat.c:263
#define FMT_NUM_YES_NO
Definition: varformat.c:269
#define FMT_DATE_QUARTER
Definition: varformat.c:225
static const WCHAR szYesNo[]
Definition: varformat.c:340
#define FMT_DATE_MIN_0
Definition: varformat.c:245
#define FMT_DATE_HOUR_0
Definition: varformat.c:249
HRESULT WINAPI VarFormatDateTime(LPVARIANT pVarIn, INT nFormat, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2190
static HRESULT VARIANT_FormatString(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:1917
struct tagNAMED_FORMAT NAMED_FORMAT
static const BYTE fmtMediumTime[0x11]
Definition: varformat.c:316
#define FMT_FLAG_BOOL
Definition: varformat.c:193
#define FMT_TYPE_GENERAL
Definition: varformat.c:143
#define COULD_BE(typ)
Definition: varformat.c:458
HRESULT WINAPI VarFormatNumber(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2241
HRESULT WINAPI VarMonthName(INT iMonth, INT fAbbrev, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2517
HRESULT WINAPI VarFormatCurrency(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, INT nGrouping, ULONG dwFlags, BSTR *pbstrOut)
Definition: varformat.c:2420
#define FMT_DATE_DAY_WEEK
Definition: varformat.c:234
static const NAMED_FORMAT VARIANT_NamedFormats[]
Definition: varformat.c:417
static const BYTE fmtTrueFalse[0x0d]
Definition: varformat.c:333
static const BYTE fmtMediumDate[0x0a]
Definition: varformat.c:292
static const WCHAR szStandard[]
Definition: varformat.c:385
#define FMT_TYPE_DATE
Definition: varformat.c:145
#define FMT_DATE_AMPM_LOWER
Definition: varformat.c:258
#define NUM_WROTE_DEC
Definition: varformat.c:1164
static const WCHAR szPercentZeroTwo_d[]
Definition: varformat.c:48
#define NUM_WRITE_ON
Definition: varformat.c:1165
static const WCHAR szMediumTime[]
Definition: varformat.c:315
#define FMT_DATE_DAY_LONG
Definition: varformat.c:230
static const WCHAR szTrueFalse[]
Definition: varformat.c:332
static int __cdecl FormatCompareFn(const void *l, const void *r)
Definition: varformat.c:438
#define FMT_DATE_LONG
Definition: varformat.c:232
#define FMT_DATE_GENERAL
Definition: varformat.c:224
#define FMT_DATE_A_UPPER
Definition: varformat.c:256
static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat, LPBYTE rgbTok, ULONG dwFlags, BSTR *pbstrOut, LCID lcid)
Definition: varformat.c:1169
struct tagFMT_SHORT_HEADER FMT_SHORT_HEADER
#define FMT_DATE_DATE_SEP
Definition: varformat.c:223
static const WCHAR szGeneralNumber[]
Definition: varformat.c:356
#define FMT_DATE_AMPM_SYS1
Definition: varformat.c:254
static const BYTE fmtFixed[0x11]
Definition: varformat.c:378
#define FMT_DATE_AMPM_SYS2
Definition: varformat.c:257
#define FMT_NUM_ON_OFF
Definition: varformat.c:270
#define FMT_DATE_YEAR_0
Definition: varformat.c:241
#define NUMBER_VTBITS
Definition: varformat.c:2042
#define FMT_STATE_WROTE_MINUTES
Definition: varformat.c:464
struct tagFMT_NUMBER_HEADER FMT_NUMBER_HEADER
#define FMT_DATE_SEC_0
Definition: varformat.c:247
#define FMT_FLAG_GT
Definition: varformat.c:174
#define FMT_STATE_OPEN_COPY
Definition: varformat.c:461
static const BYTE fmtScientific[0x13]
Definition: varformat.c:403
#define FmtGetNull(x)
Definition: varformat.c:167
#define FMT_GEN_INLINE
Definition: varformat.c:220
#define FMT_DATE_MIN
Definition: varformat.c:244
#define GETLOCALENUMBER(type, field)
Definition: varformat.c:2212
#define FMT_NUM_COPY_ZERO
Definition: varformat.c:260
#define FMT_NUM_EXP_NEG_L
Definition: varformat.c:266
#define FMT_TO_STRING
Definition: varformat.c:148
static const WCHAR szMediumDate[]
Definition: varformat.c:291
static const BYTE fmtLongTime[0x0d]
Definition: varformat.c:325
static const WCHAR szGeneralDate[]
Definition: varformat.c:275
#define LCID_US
Definition: varformat.c:45
HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
Definition: vartype.c:6852
HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
Definition: vartype.c:6778
#define swprintf
Definition: precomp.h:40
static unsigned char buff[32768]
Definition: fatten.c:17
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
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 S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_wn
Definition: kernel32.h:33
#define debugstr_w
Definition: kernel32.h:32
INT WINAPI GetLocaleInfoW(LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len)
Definition: lang.c:1108
INT WINAPI GetNumberFormatW(LCID lcid, DWORD dwFlags, LPCWSTR lpszValue, const NUMBERFMTW *lpFormat, LPWSTR lpNumberStr, int cchOut)
Definition: lcformat.c:1212
INT WINAPI GetCurrencyFormatW(LCID lcid, DWORD dwFlags, LPCWSTR lpszValue, const CURRENCYFMTW *lpFormat, LPWSTR lpCurrencyStr, int cchOut)
Definition: lcformat.c:1578
__u16 date
Definition: mkdosfs.c:8
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
static const char * debugstr_variant(const VARIANT *var)
Definition: container.c:46
HRESULT hres
Definition: protocol.c:465
static LPOLESTR
Definition: stg_prop.c:27
#define min(a, b)
Definition: monoChain.cc:55
int k
Definition: mpi.c:3369
#define LOCALE_USER_DEFAULT
BSTR WINAPI SysAllocString(LPCOLESTR str)
Definition: oleaut.c:238
void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
Definition: oleaut.c:271
BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
Definition: oleaut.c:339
#define V_BOOL(A)
Definition: oleauto.h:224
#define VARIANT_CALENDAR_HIJRI
Definition: oleauto.h:313
#define NUMPRS_NEG
Definition: oleauto.h:749
#define VAR_FORMAT_NOSUBSTITUTE
Definition: oleauto.h:331
#define VARIANT_NOUSEROVERRIDE
Definition: oleauto.h:312
#define V_VT(A)
Definition: oleauto.h:211
#define VAR_LOCALBOOL
Definition: oleauto.h:330
#define V_BSTR(A)
Definition: oleauto.h:226
#define VAR_CALENDAR_HIJRI
Definition: oleauto.h:329
#define V_R8(A)
Definition: oleauto.h:262
#define VAR_TIMEVALUEONLY
Definition: oleauto.h:326
#define V_DATE(A)
Definition: oleauto.h:231
#define NUMPRS_STD
Definition: oleauto.h:748
unsigned short USHORT
Definition: pedump.c:61
_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)
_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)
DWORD LCID
Definition: nls.h:13
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
ULONG dwInFlags
Definition: oleauto.h:728
INT cDig
Definition: oleauto.h:727
ULONG dwOutFlags
Definition: oleauto.h:729
INT nPwr10
Definition: oleauto.h:732
Definition: oleauto.h:720
SYSTEMTIME st
Definition: oleauto.h:721
USHORT wDayOfYear
Definition: oleauto.h:722
WORD wYear
Definition: winbase.h:905
WORD wMonth
Definition: winbase.h:906
WORD wHour
Definition: winbase.h:909
WORD wSecond
Definition: winbase.h:911
WORD wMinute
Definition: winbase.h:910
WORD wDay
Definition: winbase.h:908
WORD wDayOfWeek
Definition: winbase.h:907
UINT LeadingZero
Definition: winnls.h:613
LPWSTR lpDecimalSep
Definition: winnls.h:615
UINT NumDigits
Definition: winnls.h:612
LPWSTR lpCurrencySymbol
Definition: winnls.h:619
UINT Grouping
Definition: winnls.h:614
UINT NegativeOrder
Definition: winnls.h:617
LPWSTR lpThousandSep
Definition: winnls.h:616
UINT NumDigits
Definition: winnls.h:642
LPWSTR lpDecimalSep
Definition: winnls.h:645
UINT Grouping
Definition: winnls.h:644
UINT NegativeOrder
Definition: winnls.h:647
LPWSTR lpThousandSep
Definition: winnls.h:646
UINT LeadingZero
Definition: winnls.h:643
Definition: dsound.c:943
Definition: copy.c:22
WCHAR * name
Definition: path.c:43
Definition: name.c:39
BYTE starts[4]
Definition: varformat.c:161
const BYTE * format
Definition: varformat.c:413
LPCWSTR name
Definition: varformat.c:412
#define max(a, b)
Definition: svc.c:63
#define bsearch
#define towlower(c)
Definition: wctype.h:97
#define towupper(c)
Definition: wctype.h:99
unsigned char * LPBYTE
Definition: typedefs.h:53
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate)
Definition: variant.c:1427
HRESULT WINAPI VariantChangeTypeEx(VARIANTARG *pvargDest, VARIANTARG *pvargSrc, LCID lcid, USHORT wFlags, VARTYPE vt)
Definition: variant.c:988
HRESULT WINAPI DECLSPEC_HOTPATCH VariantClear(VARIANTARG *pVarg)
Definition: variant.c:648
HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, NUMPARSE *pNumprs, BYTE *rgbDig)
Definition: variant.c:1604
HRESULT WINAPI VariantCopyInd(VARIANT *pvargDest, VARIANTARG *pvargSrc)
Definition: variant.c:847
#define V_TYPE(v)
Definition: variant.h:30
BOOL get_date_format(LCID, DWORD, const SYSTEMTIME *, const WCHAR *, WCHAR *, int) DECLSPEC_HIDDEN
Definition: vartype.c:6668
#define R8_MAX
Definition: variant.h:73
#define VAR_BOOLONOFF
Definition: variant.h:102
#define VAR_BOOLYESNO
Definition: variant.h:103
#define ZeroMemory
Definition: winbase.h:1712
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
#define WINAPI
Definition: msvc.h:6
#define DISP_E_OVERFLOW
Definition: winerror.h:2519
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
#define DISP_E_TYPEMISMATCH
Definition: winerror.h:2514
#define LOCALE_SDATE
Definition: winnls.h:58
#define LOCALE_SGROUPING
Definition: winnls.h:44
#define LOCALE_SDECIMAL
Definition: winnls.h:42
#define LOCALE_SDAYNAME1
Definition: winnls.h:77
#define LOCALE_SLONGDATE
Definition: winnls.h:61
#define LOCALE_S1159
Definition: winnls.h:71
#define LOCALE_SSHORTDATE
Definition: winnls.h:60
#define LOCALE_ICURRENCY
Definition: winnls.h:56
#define LOCALE_SMONTHNAME1
Definition: winnls.h:91
#define LOCALE_SABBREVMONTHNAME1
Definition: winnls.h:104
#define LOCALE_IDIGITS
Definition: winnls.h:45
#define LOCALE_STHOUSAND
Definition: winnls.h:43
#define LOCALE_SABBREVDAYNAME1
Definition: winnls.h:84
#define LOCALE_IFIRSTDAYOFWEEK
Definition: winnls.h:75
#define LOCALE_STIME
Definition: winnls.h:59
#define LOCALE_INEGNUMBER
Definition: winnls.h:47
#define LOCALE_SNEGATIVESIGN
Definition: winnls.h:118
#define LOCALE_S2359
Definition: winnls.h:72
#define LOCALE_ILZERO
Definition: winnls.h:46
#define LOCALE_SCURRENCY
Definition: winnls.h:49
#define LOCALE_INEGCURR
Definition: winnls.h:57
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193