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