configure: Add a check for sys/ucontext.h and include it where appropriate.
[wine.git] / dlls / msvcrt / printf.h
blob8a41d3e5745dabb54eae843b3dbe88e85d7a0dc1
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 typedef struct FUNC_NAME(pf_flags_t)
31 APICHAR Sign, LeftAlign, Alternate, PadZero;
32 int FieldLength, Precision;
33 APICHAR IntegerLength, IntegerDouble;
34 APICHAR WideString;
35 APICHAR Format;
36 } FUNC_NAME(pf_flags);
38 struct FUNC_NAME(_str_ctx) {
39 MSVCRT_size_t len;
40 APICHAR *buf;
43 static int FUNC_NAME(puts_clbk_str)(void *ctx, int len, const APICHAR *str)
45 struct FUNC_NAME(_str_ctx) *out = ctx;
47 if(!out->buf)
48 return len;
50 if(out->len < len) {
51 memcpy(out->buf, str, out->len*sizeof(APICHAR));
52 out->buf += out->len;
53 out->len = 0;
54 return -1;
57 memcpy(out->buf, str, len*sizeof(APICHAR));
58 out->buf += len;
59 out->len -= len;
60 return len;
63 static inline const APICHAR* FUNC_NAME(pf_parse_int)(const APICHAR *fmt, int *val)
65 *val = 0;
67 while(isdigit(*fmt)) {
68 *val *= 10;
69 *val += *fmt++ - '0';
72 return fmt;
75 /* pf_fill: takes care of signs, alignment, zero and field padding */
76 static inline int FUNC_NAME(pf_fill)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
77 int len, FUNC_NAME(pf_flags) *flags, BOOL left)
79 int i, r = 0, written;
81 if(flags->Sign && !strchr("diaeEfgG", flags->Format))
82 flags->Sign = 0;
84 if(left && flags->Sign) {
85 flags->FieldLength--;
86 if(flags->PadZero)
87 r = pf_puts(puts_ctx, 1, &flags->Sign);
89 written = r;
91 if((!left && flags->LeftAlign) || (left && !flags->LeftAlign)) {
92 APICHAR ch;
94 if(left && flags->PadZero)
95 ch = '0';
96 else
97 ch = ' ';
99 for(i=0; i<flags->FieldLength-len && r>=0; i++) {
100 r = pf_puts(puts_ctx, 1, &ch);
101 written += r;
106 if(r>=0 && left && flags->Sign && !flags->PadZero) {
107 r = pf_puts(puts_ctx, 1, &flags->Sign);
108 written += r;
111 return r>=0 ? written : r;
114 static inline int FUNC_NAME(pf_output_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
115 const MSVCRT_wchar_t *str, int len, MSVCRT_pthreadlocinfo locinfo)
117 #ifdef PRINTF_WIDE
118 return pf_puts(puts_ctx, len, str);
119 #else
120 LPSTR out;
121 int len_a = WideCharToMultiByte(locinfo->lc_codepage, 0, str, len, NULL, 0, NULL, NULL);
123 out = HeapAlloc(GetProcessHeap(), 0, len_a);
124 if(!out)
125 return -1;
127 WideCharToMultiByte(locinfo->lc_codepage, 0, str, len, out, len_a, NULL, NULL);
128 len = pf_puts(puts_ctx, len_a, out);
129 HeapFree(GetProcessHeap(), 0, out);
130 return len;
131 #endif
134 static inline int FUNC_NAME(pf_output_str)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
135 const char *str, int len, MSVCRT_pthreadlocinfo locinfo)
137 #ifdef PRINTF_WIDE
138 LPWSTR out;
139 int len_w = MultiByteToWideChar(locinfo->lc_codepage, 0, str, len, NULL, 0);
141 out = HeapAlloc(GetProcessHeap(), 0, len_w*sizeof(WCHAR));
142 if(!out)
143 return -1;
145 MultiByteToWideChar(locinfo->lc_codepage, 0, str, len, out, len_w);
146 len = pf_puts(puts_ctx, len_w, out);
147 HeapFree(GetProcessHeap(), 0, out);
148 return len;
149 #else
150 return pf_puts(puts_ctx, len, str);
151 #endif
154 static inline int FUNC_NAME(pf_output_format_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
155 const MSVCRT_wchar_t *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
157 int r, ret;
159 if(len < 0)
160 len = strlenW(str);
162 if(flags->Precision>=0 && flags->Precision<len)
163 len = flags->Precision;
165 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, TRUE);
166 ret = r;
167 if(r >= 0) {
168 r = FUNC_NAME(pf_output_wstr)(pf_puts, puts_ctx, str, len, locinfo);
169 ret += r;
171 if(r >= 0) {
172 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, FALSE);
173 ret += r;
176 return r>=0 ? ret : r;
179 static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
180 const char *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
182 int r, ret;
184 if(len < 0)
185 len = strlen(str);
187 if(flags->Precision>=0 && flags->Precision<len)
188 len = flags->Precision;
190 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, TRUE);
191 ret = r;
192 if(r >= 0) {
193 r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, str, len, locinfo);
194 ret += r;
196 if(r >= 0) {
197 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, FALSE);
198 ret += r;
201 return r>=0 ? ret : r;
204 static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
205 const void *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
207 #ifdef PRINTF_WIDE
208 static const MSVCRT_wchar_t nullW[] = {'(','n','u','l','l',')',0};
210 if(!str)
211 return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, nullW, 6, flags, locinfo);
212 #else
213 if(!str)
214 return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, "(null)", 6, flags, locinfo);
215 #endif
217 if(flags->WideString || flags->IntegerLength=='l')
218 return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locinfo);
219 if(flags->IntegerLength == 'h')
220 return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locinfo);
222 if((flags->Format=='S' || flags->Format=='C') == (sizeof(APICHAR)==sizeof(MSVCRT_wchar_t)))
223 return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locinfo);
224 else
225 return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locinfo);
228 static inline void FUNC_NAME(pf_rebuild_format_string)(char *p, FUNC_NAME(pf_flags) *flags)
230 *p++ = '%';
231 if(flags->Alternate)
232 *p++ = flags->Alternate;
233 if(flags->Precision >= 0) {
234 sprintf(p, ".%d", flags->Precision);
235 p += strlen(p);
237 *p++ = flags->Format;
238 *p++ = 0;
241 /* pf_integer_conv: prints x to buf, including alternate formats and
242 additional precision digits, but not field characters or the sign */
243 static inline void FUNC_NAME(pf_integer_conv)(APICHAR *buf, int buf_len,
244 FUNC_NAME(pf_flags) *flags, LONGLONG x)
246 unsigned int base;
247 const char *digits;
248 int i, j, k;
250 if(flags->Format == 'o')
251 base = 8;
252 else if(flags->Format=='x' || flags->Format=='X')
253 base = 16;
254 else
255 base = 10;
257 if(flags->Format == 'X')
258 digits = "0123456789ABCDEFX";
259 else
260 digits = "0123456789abcdefx";
262 if(x<0 && (flags->Format=='d' || flags->Format=='i')) {
263 x = -x;
264 flags->Sign = '-';
267 i = 0;
268 if(x == 0) {
269 flags->Alternate = 0;
270 if(flags->Precision)
271 buf[i++] = '0';
272 } else {
273 while(x != 0) {
274 j = (ULONGLONG)x%base;
275 x = (ULONGLONG)x/base;
276 buf[i++] = digits[j];
279 k = flags->Precision-i;
280 while(k-- > 0)
281 buf[i++] = '0';
282 if(flags->Alternate) {
283 if(base == 16) {
284 buf[i++] = digits[16];
285 buf[i++] = '0';
286 } else if(base==8 && buf[i-1]!='0')
287 buf[i++] = '0';
290 /* Adjust precision so pf_fill won't truncate the number later */
291 flags->Precision = i;
293 buf[i] = '\0';
294 j = 0;
295 while(--i > j) {
296 APICHAR tmp = buf[j];
297 buf[j] = buf[i];
298 buf[i] = tmp;
299 j++;
303 static inline void FUNC_NAME(pf_fixup_exponent)(char *buf)
305 char* tmp = buf;
307 while(tmp[0] && toupper(tmp[0])!='E')
308 tmp++;
310 if(tmp[0] && (tmp[1]=='+' || tmp[1]=='-') &&
311 isdigit(tmp[2]) && isdigit(tmp[3])) {
312 BOOL two_digit_exp = (MSVCRT__get_output_format() == MSVCRT__TWO_DIGIT_EXPONENT);
314 tmp += 2;
315 if(isdigit(tmp[2])) {
316 if(two_digit_exp && tmp[0]=='0') {
317 tmp[0] = tmp[1];
318 tmp[1] = tmp[2];
319 tmp[2] = tmp[3];
322 return; /* Exponent already 3 digits */
323 }else if(two_digit_exp) {
324 return;
327 tmp[3] = tmp[2];
328 tmp[2] = tmp[1];
329 tmp[1] = tmp[0];
330 tmp[0] = '0';
334 int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const APICHAR *fmt,
335 MSVCRT__locale_t locale, BOOL positional_params, BOOL invoke_invalid_param_handler,
336 args_clbk pf_args, void *args_ctx, __ms_va_list *valist)
338 MSVCRT_pthreadlocinfo locinfo;
339 const APICHAR *q, *p = fmt;
340 APICHAR buf[32];
341 int written = 0, pos, i;
342 FUNC_NAME(pf_flags) flags;
344 TRACE("Format is: %s\n", FUNC_NAME(debugstr)(fmt));
346 if(!locale)
347 locinfo = get_locinfo();
348 else
349 locinfo = locale->locinfo;
351 while(*p) {
352 /* output characters before '%' */
353 for(q=p; *q && *q!='%'; q++);
354 if(p != q) {
355 i = pf_puts(puts_ctx, q-p, p);
356 if(i < 0)
357 return i;
359 written += i;
360 p = q;
361 continue;
364 /* *p == '%' here */
365 p++;
367 /* output a single '%' character */
368 if(*p == '%') {
369 i = pf_puts(puts_ctx, 1, p++);
370 if(i < 0)
371 return i;
373 written += i;
374 continue;
377 /* check parameter position */
378 if(positional_params && (q = FUNC_NAME(pf_parse_int)(p, &pos)) && *q=='$')
379 p = q+1;
380 else
381 pos = -1;
383 /* parse the flags */
384 memset(&flags, 0, sizeof(flags));
385 while(*p) {
386 if(*p=='+' || *p==' ') {
387 if(flags.Sign != '+')
388 flags.Sign = *p;
389 } else if(*p == '-')
390 flags.LeftAlign = *p;
391 else if(*p == '0')
392 flags.PadZero = *p;
393 else if(*p == '#')
394 flags.Alternate = *p;
395 else
396 break;
398 p++;
401 /* parse the widh */
402 if(*p == '*') {
403 p++;
404 if(positional_params && (q = FUNC_NAME(pf_parse_int)(p, &i)) && *q=='$')
405 p = q+1;
406 else
407 i = -1;
409 flags.FieldLength = pf_args(args_ctx, i, VT_INT, valist).get_int;
410 if(flags.FieldLength < 0) {
411 flags.LeftAlign = '-';
412 flags.FieldLength = -flags.FieldLength;
414 } else while(isdigit(*p)) {
415 flags.FieldLength *= 10;
416 flags.FieldLength += *p++ - '0';
419 /* parse the precision */
420 flags.Precision = -1;
421 if(*p == '.') {
422 flags.Precision = 0;
423 p++;
424 if(*p == '*') {
425 p++;
426 if(positional_params && (q = FUNC_NAME(pf_parse_int)(p, &i)) && *q=='$')
427 p = q+1;
428 else
429 i = -1;
431 flags.Precision = pf_args(args_ctx, i, VT_INT, valist).get_int;
432 } else while(isdigit(*p)) {
433 flags.Precision *= 10;
434 flags.Precision += *p++ - '0';
438 /* parse argument size modifier */
439 while(*p) {
440 if(*p=='l' && *(p+1)=='l') {
441 flags.IntegerDouble++;
442 p += 2;
443 } else if(*p=='h' || *p=='l' || *p=='L') {
444 flags.IntegerLength = *p;
445 p++;
446 } else if(*p == 'I') {
447 if(*(p+1)=='6' && *(p+2)=='4') {
448 flags.IntegerDouble++;
449 p += 3;
450 } else if(*(p+1)=='3' && *(p+2)=='2')
451 p += 3;
452 else if(isdigit(*(p+1)) || !*(p+1))
453 break;
454 else
455 p++;
456 } else if(*p == 'w')
457 flags.WideString = *p++;
458 else if(*p == 'F')
459 p++; /* ignore */
460 else
461 break;
464 flags.Format = *p;
466 if(flags.Format == 's' || flags.Format == 'S') {
467 i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx,
468 pf_args(args_ctx, pos, VT_PTR, valist).get_ptr,
469 -1, &flags, locinfo);
470 } else if(flags.Format == 'c' || flags.Format == 'C') {
471 int ch = pf_args(args_ctx, pos, VT_INT, valist).get_int;
473 if((ch&0xff) != ch)
474 FIXME("multibyte characters printing not supported\n");
476 i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, &ch, 1, &flags, locinfo);
477 } else if(flags.Format == 'p') {
478 flags.Format = 'X';
479 flags.PadZero = '0';
480 i = flags.Precision;
481 flags.Precision = 2*sizeof(void*);
482 FUNC_NAME(pf_integer_conv)(buf, sizeof(buf)/sizeof(APICHAR), &flags,
483 (ULONG_PTR)pf_args(args_ctx, pos, VT_PTR, valist).get_ptr);
484 flags.PadZero = 0;
485 flags.Precision = i;
487 #ifdef PRINTF_WIDE
488 i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, buf, -1, &flags, locinfo);
489 #else
490 i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, buf, -1, &flags, locinfo);
491 #endif
492 } else if(flags.Format == 'n') {
493 int *used;
495 if(!n_format_enabled) {
496 MSVCRT_INVALID_PMT("\'n\' format specifier disabled", MSVCRT_EINVAL);
497 return -1;
500 used = pf_args(args_ctx, pos, VT_PTR, valist).get_ptr;
501 *used = written;
502 i = 0;
503 } else if(flags.Format && strchr("diouxX", flags.Format)) {
504 APICHAR *tmp = buf;
505 int max_len;
507 /* 0 padding is added after '0x' if Alternate flag is in use */
508 if((flags.Format=='x' || flags.Format=='X') && flags.PadZero && flags.Alternate
509 && !flags.LeftAlign && flags.Precision<flags.FieldLength-2)
510 flags.Precision = flags.FieldLength - 2;
512 max_len = (flags.FieldLength>flags.Precision ? flags.FieldLength : flags.Precision) + 10;
513 if(max_len > sizeof(buf)/sizeof(APICHAR))
514 tmp = HeapAlloc(GetProcessHeap(), 0, max_len);
515 if(!tmp)
516 return -1;
518 if(flags.IntegerDouble)
519 FUNC_NAME(pf_integer_conv)(tmp, max_len, &flags, pf_args(args_ctx, pos,
520 VT_I8, valist).get_longlong);
521 else if(flags.Format=='d' || flags.Format=='i')
522 FUNC_NAME(pf_integer_conv)(tmp, max_len, &flags, flags.IntegerLength!='h' ?
523 pf_args(args_ctx, pos, VT_INT, valist).get_int :
524 (short)pf_args(args_ctx, pos, VT_INT, valist).get_int);
525 else
526 FUNC_NAME(pf_integer_conv)(tmp, max_len, &flags, flags.IntegerLength!='h' ?
527 (unsigned)pf_args(args_ctx, pos, VT_INT, valist).get_int :
528 (unsigned short)pf_args(args_ctx, pos, VT_INT, valist).get_int);
530 #ifdef PRINTF_WIDE
531 i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, tmp, -1, &flags, locinfo);
532 #else
533 i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, tmp, -1, &flags, locinfo);
534 #endif
535 if(tmp != buf)
536 HeapFree(GetProcessHeap(), 0, tmp);
537 } else if(flags.Format && strchr("aeEfgG", flags.Format)) {
538 char float_fmt[20], buf_a[32], *tmp = buf_a, *decimal_point;
539 int len = flags.Precision + 10;
540 double val = pf_args(args_ctx, pos, VT_R8, valist).get_double;
541 int r;
542 BOOL inf = FALSE, nan = FALSE;
544 if(isinf(val))
545 inf = TRUE;
546 else if(isnan(val))
547 nan = TRUE; /* FIXME: NaN value may be displayed as #IND or #QNAN */
549 if(inf || nan) {
550 if(nan || val<0)
551 flags.Sign = '-';
553 if(flags.Format=='g' || flags.Format=='G')
554 val = 1.1234; /* fraction will be overwritten with #INF or #IND string */
555 else
556 val = 1;
558 if(flags.Format=='a') {
559 if(flags.Precision==-1)
560 flags.Precision = 6; /* strlen("#INF00") */
564 if(flags.Format=='f') {
565 if(val>-10.0 && val<10.0)
566 i = 1;
567 else
568 i = 1 + log10(val<0 ? -val : val);
569 /* Default precision is 6, additional space for sign, separator and nullbyte is required */
570 i += (flags.Precision==-1 ? 6 : flags.Precision) + 3;
572 if(i > len)
573 len = i;
576 if(len > sizeof(buf_a))
577 tmp = HeapAlloc(GetProcessHeap(), 0, len);
578 if(!tmp)
579 return -1;
581 FUNC_NAME(pf_rebuild_format_string)(float_fmt, &flags);
582 if(val < 0) {
583 flags.Sign = '-';
584 val = -val;
587 sprintf(tmp, float_fmt, val);
588 if(toupper(flags.Format)=='E' || toupper(flags.Format)=='G')
589 FUNC_NAME(pf_fixup_exponent)(tmp);
591 decimal_point = strchr(tmp, '.');
592 if(decimal_point) {
593 *decimal_point = *locinfo->lconv->decimal_point;
595 if(inf || nan) {
596 static const char inf_str[] = "#INF";
597 static const char ind_str[] = "#IND";
599 for(i=1; i<(inf ? sizeof(inf_str) : sizeof(ind_str)); i++) {
600 if(decimal_point[i]<'0' || decimal_point[i]>'9')
601 break;
603 decimal_point[i] = inf ? inf_str[i-1] : ind_str[i-1];
606 if(i!=sizeof(inf_str) && i!=1)
607 decimal_point[i-1]++;
611 len = strlen(tmp);
612 i = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, &flags, TRUE);
613 if(i < 0)
614 return i;
615 r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, tmp, len, locinfo);
616 if(r < 0)
617 return r;
618 i += r;
619 if(tmp != buf_a)
620 HeapFree(GetProcessHeap(), 0, tmp);
621 r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, &flags, FALSE);
622 if(r < 0)
623 return r;
624 i += r;
625 } else {
626 if(invoke_invalid_param_handler) {
627 MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
628 *MSVCRT__errno() = MSVCRT_EINVAL;
629 return -1;
632 continue;
635 if(i < 0)
636 return i;
637 written += i;
638 p++;
641 return written;
644 #ifndef PRINTF_WIDE
645 enum types_clbk_flags {
646 TYPE_CLBK_VA_LIST = 1,
647 TYPE_CLBK_POSITIONAL = 2,
648 TYPE_CLBK_ERROR_POS = 4,
649 TYPE_CLBK_ERROR_TYPE = 8
652 /* This functions stores types of arguments. It uses args[0] internally */
653 static printf_arg arg_clbk_type(void *ctx, int pos, int type, __ms_va_list *valist)
655 static const printf_arg ret;
656 printf_arg *args = ctx;
658 if(pos == -1) {
659 args[0].get_int |= TYPE_CLBK_VA_LIST;
660 return ret;
661 } else
662 args[0].get_int |= TYPE_CLBK_POSITIONAL;
664 if(pos<1 || pos>MSVCRT__ARGMAX)
665 args[0].get_int |= TYPE_CLBK_ERROR_POS;
666 else if(args[pos].get_int && args[pos].get_int!=type)
667 args[0].get_int |= TYPE_CLBK_ERROR_TYPE;
668 else
669 args[pos].get_int = type;
671 return ret;
673 #endif
675 static int FUNC_NAME(create_positional_ctx)(void *args_ctx, const APICHAR *format, __ms_va_list valist)
677 struct FUNC_NAME(_str_ctx) puts_ctx = {INT_MAX, NULL};
678 printf_arg *args = args_ctx;
679 int i, j;
681 i = FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk_str), &puts_ctx, format, NULL, TRUE, FALSE,
682 arg_clbk_type, args_ctx, NULL);
683 if(i < 0)
684 return i;
686 if(args[0].get_int==0 || args[0].get_int==TYPE_CLBK_VA_LIST)
687 return 0;
688 if(args[0].get_int != TYPE_CLBK_POSITIONAL)
689 return -1;
691 for(i=MSVCRT__ARGMAX; i>0; i--)
692 if(args[i].get_int)
693 break;
695 for(j=1; j<=i; j++) {
696 switch(args[j].get_int) {
697 case VT_I8:
698 args[j].get_longlong = va_arg(valist, LONGLONG);
699 break;
700 case VT_INT:
701 args[j].get_int = va_arg(valist, int);
702 break;
703 case VT_R8:
704 args[j].get_double = va_arg(valist, double);
705 break;
706 case VT_PTR:
707 args[j].get_ptr = va_arg(valist, void*);
708 break;
709 default:
710 return -1;
714 return j;
717 #undef APICHAR
718 #undef CONVCHAR
719 #undef FUNC_NAME