include: Added inspectable.idl file.
[wine.git] / dlls / msvcrt / printf.h
blob4757931ea7693c1ec5a3b6342116a9f758a0730b
1 /*
2 * Copyright 2011 Piotr Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #ifdef PRINTF_WIDE
20 #define APICHAR MSVCRT_wchar_t
21 #define CONVCHAR char
22 #define FUNC_NAME(func) func ## _w
23 #else
24 #define APICHAR char
25 #define CONVCHAR MSVCRT_wchar_t
26 #define FUNC_NAME(func) func ## _a
27 #endif
29 #ifndef signbit
30 #define signbit(x) ((x) < 0)
31 #endif
33 typedef struct FUNC_NAME(pf_flags_t)
35 APICHAR Sign, LeftAlign, Alternate, PadZero;
36 int FieldLength, Precision;
37 APICHAR IntegerLength, IntegerDouble;
38 APICHAR WideString;
39 APICHAR Format;
40 } FUNC_NAME(pf_flags);
42 struct FUNC_NAME(_str_ctx) {
43 MSVCRT_size_t len;
44 APICHAR *buf;
47 static int FUNC_NAME(puts_clbk_str)(void *ctx, int len, const APICHAR *str)
49 struct FUNC_NAME(_str_ctx) *out = ctx;
51 if(!out->buf)
52 return len;
54 if(out->len < len) {
55 memcpy(out->buf, str, out->len*sizeof(APICHAR));
56 out->buf += out->len;
57 out->len = 0;
58 return -1;
61 memcpy(out->buf, str, len*sizeof(APICHAR));
62 out->buf += len;
63 out->len -= len;
64 return len;
67 static inline const APICHAR* FUNC_NAME(pf_parse_int)(const APICHAR *fmt, int *val)
69 *val = 0;
71 while(isdigit(*fmt)) {
72 *val *= 10;
73 *val += *fmt++ - '0';
76 return fmt;
79 /* pf_fill: takes care of signs, alignment, zero and field padding */
80 static inline int FUNC_NAME(pf_fill)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
81 int len, FUNC_NAME(pf_flags) *flags, BOOL left)
83 int i, r = 0, written;
85 if(flags->Sign && !strchr("diaeEfgG", flags->Format))
86 flags->Sign = 0;
88 if(left && flags->Sign) {
89 flags->FieldLength--;
90 if(flags->PadZero)
91 r = pf_puts(puts_ctx, 1, &flags->Sign);
93 written = r;
95 if((!left && flags->LeftAlign) || (left && !flags->LeftAlign)) {
96 APICHAR ch;
98 if(left && flags->PadZero)
99 ch = '0';
100 else
101 ch = ' ';
103 for(i=0; i<flags->FieldLength-len && r>=0; i++) {
104 r = pf_puts(puts_ctx, 1, &ch);
105 written += r;
110 if(r>=0 && left && flags->Sign && !flags->PadZero) {
111 r = pf_puts(puts_ctx, 1, &flags->Sign);
112 written += r;
115 return r>=0 ? written : r;
118 static inline int FUNC_NAME(pf_output_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
119 const MSVCRT_wchar_t *str, int len, MSVCRT_pthreadlocinfo locinfo)
121 #ifdef PRINTF_WIDE
122 return pf_puts(puts_ctx, len, str);
123 #else
124 LPSTR out;
125 int len_a = WideCharToMultiByte(locinfo->lc_codepage, 0, str, len, NULL, 0, NULL, NULL);
127 out = HeapAlloc(GetProcessHeap(), 0, len_a);
128 if(!out)
129 return -1;
131 WideCharToMultiByte(locinfo->lc_codepage, 0, str, len, out, len_a, NULL, NULL);
132 len = pf_puts(puts_ctx, len_a, out);
133 HeapFree(GetProcessHeap(), 0, out);
134 return len;
135 #endif
138 static inline int FUNC_NAME(pf_output_str)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
139 const char *str, int len, MSVCRT_pthreadlocinfo locinfo)
141 #ifdef PRINTF_WIDE
142 LPWSTR out;
143 int len_w = MultiByteToWideChar(locinfo->lc_codepage, 0, str, len, NULL, 0);
145 out = HeapAlloc(GetProcessHeap(), 0, len_w*sizeof(WCHAR));
146 if(!out)
147 return -1;
149 MultiByteToWideChar(locinfo->lc_codepage, 0, str, len, out, len_w);
150 len = pf_puts(puts_ctx, len_w, out);
151 HeapFree(GetProcessHeap(), 0, out);
152 return len;
153 #else
154 return pf_puts(puts_ctx, len, str);
155 #endif
158 static inline int FUNC_NAME(pf_output_format_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
159 const MSVCRT_wchar_t *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
161 int r, ret;
163 if(len < 0)
164 len = strlenW(str);
166 if(flags->Precision>=0 && flags->Precision<len)
167 len = flags->Precision;
169 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, TRUE);
170 ret = r;
171 if(r >= 0) {
172 r = FUNC_NAME(pf_output_wstr)(pf_puts, puts_ctx, str, len, locinfo);
173 ret += r;
175 if(r >= 0) {
176 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, FALSE);
177 ret += r;
180 return r>=0 ? ret : r;
183 static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
184 const char *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
186 int r, ret;
188 if(len < 0)
189 len = strlen(str);
191 if(flags->Precision>=0 && flags->Precision<len)
192 len = flags->Precision;
194 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, TRUE);
195 ret = r;
196 if(r >= 0) {
197 r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, str, len, locinfo);
198 ret += r;
200 if(r >= 0) {
201 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, FALSE);
202 ret += r;
205 return r>=0 ? ret : r;
208 static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
209 const void *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
211 #ifdef PRINTF_WIDE
212 static const MSVCRT_wchar_t nullW[] = {'(','n','u','l','l',')',0};
214 if(!str)
215 return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, nullW, 6, flags, locinfo);
216 #else
217 if(!str)
218 return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, "(null)", 6, flags, locinfo);
219 #endif
221 if(flags->WideString || flags->IntegerLength=='l')
222 return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locinfo);
223 if(flags->IntegerLength == 'h')
224 return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locinfo);
226 if((flags->Format=='S' || flags->Format=='C') == (sizeof(APICHAR)==sizeof(MSVCRT_wchar_t)))
227 return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locinfo);
228 else
229 return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locinfo);
232 static inline void FUNC_NAME(pf_rebuild_format_string)(char *p, FUNC_NAME(pf_flags) *flags)
234 *p++ = '%';
235 if(flags->Alternate)
236 *p++ = flags->Alternate;
237 if(flags->Precision >= 0) {
238 sprintf(p, ".%d", flags->Precision);
239 p += strlen(p);
241 *p++ = flags->Format;
242 *p++ = 0;
245 /* pf_integer_conv: prints x to buf, including alternate formats and
246 additional precision digits, but not field characters or the sign */
247 static inline void FUNC_NAME(pf_integer_conv)(APICHAR *buf, int buf_len,
248 FUNC_NAME(pf_flags) *flags, LONGLONG x)
250 unsigned int base;
251 const char *digits;
252 int i, j, k;
254 if(flags->Format == 'o')
255 base = 8;
256 else if(flags->Format=='x' || flags->Format=='X')
257 base = 16;
258 else
259 base = 10;
261 if(flags->Format == 'X')
262 digits = "0123456789ABCDEFX";
263 else
264 digits = "0123456789abcdefx";
266 if(x<0 && (flags->Format=='d' || flags->Format=='i')) {
267 x = -x;
268 flags->Sign = '-';
271 i = 0;
272 if(x == 0) {
273 flags->Alternate = 0;
274 if(flags->Precision)
275 buf[i++] = '0';
276 } else {
277 while(x != 0) {
278 j = (ULONGLONG)x%base;
279 x = (ULONGLONG)x/base;
280 buf[i++] = digits[j];
283 k = flags->Precision-i;
284 while(k-- > 0)
285 buf[i++] = '0';
286 if(flags->Alternate) {
287 if(base == 16) {
288 buf[i++] = digits[16];
289 buf[i++] = '0';
290 } else if(base==8 && buf[i-1]!='0')
291 buf[i++] = '0';
294 /* Adjust precision so pf_fill won't truncate the number later */
295 flags->Precision = i;
297 buf[i] = '\0';
298 j = 0;
299 while(--i > j) {
300 APICHAR tmp = buf[j];
301 buf[j] = buf[i];
302 buf[i] = tmp;
303 j++;
307 static inline void FUNC_NAME(pf_fixup_exponent)(char *buf)
309 char* tmp = buf;
311 while(tmp[0] && toupper(tmp[0])!='E')
312 tmp++;
314 if(tmp[0] && (tmp[1]=='+' || tmp[1]=='-') &&
315 isdigit(tmp[2]) && isdigit(tmp[3])) {
316 BOOL two_digit_exp = (MSVCRT__get_output_format() == MSVCRT__TWO_DIGIT_EXPONENT);
318 tmp += 2;
319 if(isdigit(tmp[2])) {
320 if(two_digit_exp && tmp[0]=='0') {
321 tmp[0] = tmp[1];
322 tmp[1] = tmp[2];
323 tmp[2] = tmp[3];
326 return; /* Exponent already 3 digits */
327 }else if(two_digit_exp) {
328 return;
331 tmp[3] = tmp[2];
332 tmp[2] = tmp[1];
333 tmp[1] = tmp[0];
334 tmp[0] = '0';
338 int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const APICHAR *fmt,
339 MSVCRT__locale_t locale, BOOL positional_params, BOOL invoke_invalid_param_handler,
340 args_clbk pf_args, void *args_ctx, __ms_va_list *valist)
342 MSVCRT_pthreadlocinfo locinfo;
343 const APICHAR *q, *p = fmt;
344 APICHAR buf[32];
345 int written = 0, pos, i;
346 FUNC_NAME(pf_flags) flags;
348 TRACE("Format is: %s\n", FUNC_NAME(debugstr)(fmt));
350 if(!locale)
351 locinfo = get_locinfo();
352 else
353 locinfo = locale->locinfo;
355 while(*p) {
356 /* output characters before '%' */
357 for(q=p; *q && *q!='%'; q++);
358 if(p != q) {
359 i = pf_puts(puts_ctx, q-p, p);
360 if(i < 0)
361 return i;
363 written += i;
364 p = q;
365 continue;
368 /* *p == '%' here */
369 p++;
371 /* output a single '%' character */
372 if(*p == '%') {
373 i = pf_puts(puts_ctx, 1, p++);
374 if(i < 0)
375 return i;
377 written += i;
378 continue;
381 /* check parameter position */
382 if(positional_params && (q = FUNC_NAME(pf_parse_int)(p, &pos)) && *q=='$')
383 p = q+1;
384 else
385 pos = -1;
387 /* parse the flags */
388 memset(&flags, 0, sizeof(flags));
389 while(*p) {
390 if(*p=='+' || *p==' ') {
391 if(flags.Sign != '+')
392 flags.Sign = *p;
393 } else if(*p == '-')
394 flags.LeftAlign = *p;
395 else if(*p == '0')
396 flags.PadZero = *p;
397 else if(*p == '#')
398 flags.Alternate = *p;
399 else
400 break;
402 p++;
405 /* parse the width */
406 if(*p == '*') {
407 p++;
408 if(positional_params && (q = FUNC_NAME(pf_parse_int)(p, &i)) && *q=='$')
409 p = q+1;
410 else
411 i = -1;
413 flags.FieldLength = pf_args(args_ctx, i, VT_INT, valist).get_int;
414 if(flags.FieldLength < 0) {
415 flags.LeftAlign = '-';
416 flags.FieldLength = -flags.FieldLength;
418 } else while(isdigit(*p)) {
419 flags.FieldLength *= 10;
420 flags.FieldLength += *p++ - '0';
423 /* parse the precision */
424 flags.Precision = -1;
425 if(*p == '.') {
426 flags.Precision = 0;
427 p++;
428 if(*p == '*') {
429 p++;
430 if(positional_params && (q = FUNC_NAME(pf_parse_int)(p, &i)) && *q=='$')
431 p = q+1;
432 else
433 i = -1;
435 flags.Precision = pf_args(args_ctx, i, VT_INT, valist).get_int;
436 } else while(isdigit(*p)) {
437 flags.Precision *= 10;
438 flags.Precision += *p++ - '0';
442 /* parse argument size modifier */
443 while(*p) {
444 if(*p=='l' && *(p+1)=='l') {
445 flags.IntegerDouble++;
446 p += 2;
447 } else if(*p=='h' || *p=='l' || *p=='L') {
448 flags.IntegerLength = *p;
449 p++;
450 } else if(*p == 'I') {
451 if(*(p+1)=='6' && *(p+2)=='4') {
452 flags.IntegerDouble++;
453 p += 3;
454 } else if(*(p+1)=='3' && *(p+2)=='2')
455 p += 3;
456 else if(isdigit(*(p+1)) || !*(p+1))
457 break;
458 else
459 p++;
460 } else if(*p == 'w')
461 flags.WideString = *p++;
462 else if(*p == 'F')
463 p++; /* ignore */
464 else
465 break;
468 flags.Format = *p;
470 if(flags.Format == 's' || flags.Format == 'S') {
471 i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx,
472 pf_args(args_ctx, pos, VT_PTR, valist).get_ptr,
473 -1, &flags, locinfo);
474 } else if(flags.Format == 'c' || flags.Format == 'C') {
475 int ch = pf_args(args_ctx, pos, VT_INT, valist).get_int;
477 if((ch&0xff) != ch)
478 FIXME("multibyte characters printing not supported\n");
480 i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, &ch, 1, &flags, locinfo);
481 } else if(flags.Format == 'p') {
482 flags.Format = 'X';
483 flags.PadZero = '0';
484 i = flags.Precision;
485 flags.Precision = 2*sizeof(void*);
486 FUNC_NAME(pf_integer_conv)(buf, sizeof(buf)/sizeof(APICHAR), &flags,
487 (ULONG_PTR)pf_args(args_ctx, pos, VT_PTR, valist).get_ptr);
488 flags.PadZero = 0;
489 flags.Precision = i;
491 #ifdef PRINTF_WIDE
492 i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, buf, -1, &flags, locinfo);
493 #else
494 i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, buf, -1, &flags, locinfo);
495 #endif
496 } else if(flags.Format == 'n') {
497 int *used;
499 if(!n_format_enabled) {
500 MSVCRT_INVALID_PMT("\'n\' format specifier disabled", MSVCRT_EINVAL);
501 return -1;
504 used = pf_args(args_ctx, pos, VT_PTR, valist).get_ptr;
505 *used = written;
506 i = 0;
507 } else if(flags.Format && strchr("diouxX", flags.Format)) {
508 APICHAR *tmp = buf;
509 int max_len;
511 /* 0 padding is added after '0x' if Alternate flag is in use */
512 if((flags.Format=='x' || flags.Format=='X') && flags.PadZero && flags.Alternate
513 && !flags.LeftAlign && flags.Precision<flags.FieldLength-2)
514 flags.Precision = flags.FieldLength - 2;
516 max_len = (flags.FieldLength>flags.Precision ? flags.FieldLength : flags.Precision) + 10;
517 if(max_len > sizeof(buf)/sizeof(APICHAR))
518 tmp = HeapAlloc(GetProcessHeap(), 0, max_len);
519 if(!tmp)
520 return -1;
522 if(flags.IntegerDouble)
523 FUNC_NAME(pf_integer_conv)(tmp, max_len, &flags, pf_args(args_ctx, pos,
524 VT_I8, valist).get_longlong);
525 else if(flags.Format=='d' || flags.Format=='i')
526 FUNC_NAME(pf_integer_conv)(tmp, max_len, &flags, flags.IntegerLength!='h' ?
527 pf_args(args_ctx, pos, VT_INT, valist).get_int :
528 (short)pf_args(args_ctx, pos, VT_INT, valist).get_int);
529 else
530 FUNC_NAME(pf_integer_conv)(tmp, max_len, &flags, flags.IntegerLength!='h' ?
531 (unsigned)pf_args(args_ctx, pos, VT_INT, valist).get_int :
532 (unsigned short)pf_args(args_ctx, pos, VT_INT, valist).get_int);
534 #ifdef PRINTF_WIDE
535 i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, tmp, -1, &flags, locinfo);
536 #else
537 i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, tmp, -1, &flags, locinfo);
538 #endif
539 if(tmp != buf)
540 HeapFree(GetProcessHeap(), 0, tmp);
541 } else if(flags.Format && strchr("aeEfgG", flags.Format)) {
542 char float_fmt[20], buf_a[32], *tmp = buf_a, *decimal_point;
543 int len = flags.Precision + 10;
544 double val = pf_args(args_ctx, pos, VT_R8, valist).get_double;
545 int r;
546 BOOL inf = FALSE, nan = FALSE, ind = FALSE;
548 if(isinf(val))
549 inf = TRUE;
550 else if(isnan(val)) {
551 if(!signbit(val))
552 nan = TRUE;
553 else
554 ind = TRUE;
557 if(inf || nan || ind) {
558 if(ind || val<0)
559 flags.Sign = '-';
561 if(flags.Format=='g' || flags.Format=='G')
562 val = (nan ? 1.12345 : 1.1234); /* fraction will be overwritten with #INF, #IND or #QNAN string */
563 else
564 val = 1;
566 if(flags.Format=='a') {
567 if(flags.Precision==-1)
568 flags.Precision = 6; /* strlen("#INF00") */
572 if(flags.Format=='f') {
573 if(val>-10.0 && val<10.0)
574 i = 1;
575 else
576 i = 1 + log10(val<0 ? -val : val);
577 /* Default precision is 6, additional space for sign, separator and nullbyte is required */
578 i += (flags.Precision==-1 ? 6 : flags.Precision) + 3;
580 if(i > len)
581 len = i;
584 if(len > sizeof(buf_a))
585 tmp = HeapAlloc(GetProcessHeap(), 0, len);
586 if(!tmp)
587 return -1;
589 FUNC_NAME(pf_rebuild_format_string)(float_fmt, &flags);
590 if(val < 0) {
591 flags.Sign = '-';
592 val = -val;
595 sprintf(tmp, float_fmt, val);
596 if(toupper(flags.Format)=='E' || toupper(flags.Format)=='G')
597 FUNC_NAME(pf_fixup_exponent)(tmp);
599 decimal_point = strchr(tmp, '.');
600 if(decimal_point) {
601 *decimal_point = *locinfo->lconv->decimal_point;
603 if(inf || nan || ind) {
604 static const char inf_str[] = "#INF";
605 static const char ind_str[] = "#IND";
606 static const char nan_str[] = "#QNAN";
608 const char *str;
609 int size;
611 if(inf) {
612 str = inf_str;
613 size = sizeof(inf_str);
614 }else if(ind) {
615 str = ind_str;
616 size = sizeof(ind_str);
617 }else {
618 str = nan_str;
619 size = sizeof(nan_str);
622 for(i=1; i<size; i++) {
623 if(decimal_point[i]<'0' || decimal_point[i]>'9')
624 break;
626 decimal_point[i] = str[i-1];
629 if(i!=size && i!=1)
630 decimal_point[i-1]++;
634 len = strlen(tmp);
635 i = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, &flags, TRUE);
636 if(i < 0)
637 return i;
638 r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, tmp, len, locinfo);
639 if(r < 0)
640 return r;
641 i += r;
642 if(tmp != buf_a)
643 HeapFree(GetProcessHeap(), 0, tmp);
644 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, &flags, FALSE);
645 if(r < 0)
646 return r;
647 i += r;
648 } else {
649 if(invoke_invalid_param_handler) {
650 MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
651 *MSVCRT__errno() = MSVCRT_EINVAL;
652 return -1;
655 continue;
658 if(i < 0)
659 return i;
660 written += i;
661 p++;
664 return written;
667 #ifndef PRINTF_WIDE
668 enum types_clbk_flags {
669 TYPE_CLBK_VA_LIST = 1,
670 TYPE_CLBK_POSITIONAL = 2,
671 TYPE_CLBK_ERROR_POS = 4,
672 TYPE_CLBK_ERROR_TYPE = 8
675 /* This functions stores types of arguments. It uses args[0] internally */
676 static printf_arg arg_clbk_type(void *ctx, int pos, int type, __ms_va_list *valist)
678 static const printf_arg ret;
679 printf_arg *args = ctx;
681 if(pos == -1) {
682 args[0].get_int |= TYPE_CLBK_VA_LIST;
683 return ret;
684 } else
685 args[0].get_int |= TYPE_CLBK_POSITIONAL;
687 if(pos<1 || pos>MSVCRT__ARGMAX)
688 args[0].get_int |= TYPE_CLBK_ERROR_POS;
689 else if(args[pos].get_int && args[pos].get_int!=type)
690 args[0].get_int |= TYPE_CLBK_ERROR_TYPE;
691 else
692 args[pos].get_int = type;
694 return ret;
696 #endif
698 static int FUNC_NAME(create_positional_ctx)(void *args_ctx, const APICHAR *format, __ms_va_list valist)
700 struct FUNC_NAME(_str_ctx) puts_ctx = {INT_MAX, NULL};
701 printf_arg *args = args_ctx;
702 int i, j;
704 i = FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk_str), &puts_ctx, format, NULL, TRUE, FALSE,
705 arg_clbk_type, args_ctx, NULL);
706 if(i < 0)
707 return i;
709 if(args[0].get_int==0 || args[0].get_int==TYPE_CLBK_VA_LIST)
710 return 0;
711 if(args[0].get_int != TYPE_CLBK_POSITIONAL)
712 return -1;
714 for(i=MSVCRT__ARGMAX; i>0; i--)
715 if(args[i].get_int)
716 break;
718 for(j=1; j<=i; j++) {
719 switch(args[j].get_int) {
720 case VT_I8:
721 args[j].get_longlong = va_arg(valist, LONGLONG);
722 break;
723 case VT_INT:
724 args[j].get_int = va_arg(valist, int);
725 break;
726 case VT_R8:
727 args[j].get_double = va_arg(valist, double);
728 break;
729 case VT_PTR:
730 args[j].get_ptr = va_arg(valist, void*);
731 break;
732 default:
733 return -1;
737 return j;
740 #undef APICHAR
741 #undef CONVCHAR
742 #undef FUNC_NAME