1/* Decomposed printf argument list.
2   Copyright (C) 1999, 2002-2003, 2005-2007, 2009-2012 Free Software
3   Foundation, Inc.
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3, or (at your option)
8   any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License along
16   with this program; if not, see <http://www.gnu.org/licenses/>.  */
17
18/* This file can be parametrized with the following macros:
19     ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.
20     PRINTF_FETCHARGS   Name of the function to be defined.
21     STATIC             Set to 'static' to declare the function static.  */
22
23#ifndef PRINTF_FETCHARGS
24# include <config.h>
25#endif
26
27/* Specification.  */
28#ifndef PRINTF_FETCHARGS
29# include "printf-args.h"
30#endif
31
32#ifdef STATIC
33STATIC
34#endif
35int
36PRINTF_FETCHARGS (va_list args, arguments *a)
37{
38  size_t i;
39  argument *ap;
40
41  for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
42    switch (ap->type)
43      {
44      case TYPE_SCHAR:
45        ap->a.a_schar = va_arg (args, /*signed char*/ int);
46        break;
47      case TYPE_UCHAR:
48        ap->a.a_uchar = va_arg (args, /*unsigned char*/ int);
49        break;
50      case TYPE_SHORT:
51        ap->a.a_short = va_arg (args, /*short*/ int);
52        break;
53      case TYPE_USHORT:
54        ap->a.a_ushort = va_arg (args, /*unsigned short*/ int);
55        break;
56      case TYPE_INT:
57        ap->a.a_int = va_arg (args, int);
58        break;
59      case TYPE_UINT:
60        ap->a.a_uint = va_arg (args, unsigned int);
61        break;
62      case TYPE_LONGINT:
63        ap->a.a_longint = va_arg (args, long int);
64        break;
65      case TYPE_ULONGINT:
66        ap->a.a_ulongint = va_arg (args, unsigned long int);
67        break;
68#if HAVE_LONG_LONG_INT
69      case TYPE_LONGLONGINT:
70        ap->a.a_longlongint = va_arg (args, long long int);
71        break;
72      case TYPE_ULONGLONGINT:
73        ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
74        break;
75#endif
76      case TYPE_DOUBLE:
77        ap->a.a_double = va_arg (args, double);
78        break;
79      case TYPE_LONGDOUBLE:
80        ap->a.a_longdouble = va_arg (args, long double);
81        break;
82      case TYPE_CHAR:
83        ap->a.a_char = va_arg (args, int);
84        break;
85#if HAVE_WINT_T
86      case TYPE_WIDE_CHAR:
87        /* Although ISO C 99 7.24.1.(2) says that wint_t is "unchanged by
88           default argument promotions", this is not the case in mingw32,
89           where wint_t is 'unsigned short'.  */
90        ap->a.a_wide_char =
91          (sizeof (wint_t) < sizeof (int)
92           ? (wint_t) va_arg (args, int)
93           : va_arg (args, wint_t));
94        break;
95#endif
96      case TYPE_STRING:
97        ap->a.a_string = va_arg (args, const char *);
98        /* A null pointer is an invalid argument for "%s", but in practice
99           it occurs quite frequently in printf statements that produce
100           debug output.  Use a fallback in this case.  */
101        if (ap->a.a_string == NULL)
102          ap->a.a_string = "(NULL)";
103        break;
104#if HAVE_WCHAR_T
105      case TYPE_WIDE_STRING:
106        ap->a.a_wide_string = va_arg (args, const wchar_t *);
107        /* A null pointer is an invalid argument for "%ls", but in practice
108           it occurs quite frequently in printf statements that produce
109           debug output.  Use a fallback in this case.  */
110        if (ap->a.a_wide_string == NULL)
111          {
112            static const wchar_t wide_null_string[] =
113              {
114                (wchar_t)'(',
115                (wchar_t)'N', (wchar_t)'U', (wchar_t)'L', (wchar_t)'L',
116                (wchar_t)')',
117                (wchar_t)0
118              };
119            ap->a.a_wide_string = wide_null_string;
120          }
121        break;
122#endif
123      case TYPE_POINTER:
124        ap->a.a_pointer = va_arg (args, void *);
125        break;
126      case TYPE_COUNT_SCHAR_POINTER:
127        ap->a.a_count_schar_pointer = va_arg (args, signed char *);
128        break;
129      case TYPE_COUNT_SHORT_POINTER:
130        ap->a.a_count_short_pointer = va_arg (args, short *);
131        break;
132      case TYPE_COUNT_INT_POINTER:
133        ap->a.a_count_int_pointer = va_arg (args, int *);
134        break;
135      case TYPE_COUNT_LONGINT_POINTER:
136        ap->a.a_count_longint_pointer = va_arg (args, long int *);
137        break;
138#if HAVE_LONG_LONG_INT
139      case TYPE_COUNT_LONGLONGINT_POINTER:
140        ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
141        break;
142#endif
143#if ENABLE_UNISTDIO
144      /* The unistdio extensions.  */
145      case TYPE_U8_STRING:
146        ap->a.a_u8_string = va_arg (args, const uint8_t *);
147        /* A null pointer is an invalid argument for "%U", but in practice
148           it occurs quite frequently in printf statements that produce
149           debug output.  Use a fallback in this case.  */
150        if (ap->a.a_u8_string == NULL)
151          {
152            static const uint8_t u8_null_string[] =
153              { '(', 'N', 'U', 'L', 'L', ')', 0 };
154            ap->a.a_u8_string = u8_null_string;
155          }
156        break;
157      case TYPE_U16_STRING:
158        ap->a.a_u16_string = va_arg (args, const uint16_t *);
159        /* A null pointer is an invalid argument for "%lU", but in practice
160           it occurs quite frequently in printf statements that produce
161           debug output.  Use a fallback in this case.  */
162        if (ap->a.a_u16_string == NULL)
163          {
164            static const uint16_t u16_null_string[] =
165              { '(', 'N', 'U', 'L', 'L', ')', 0 };
166            ap->a.a_u16_string = u16_null_string;
167          }
168        break;
169      case TYPE_U32_STRING:
170        ap->a.a_u32_string = va_arg (args, const uint32_t *);
171        /* A null pointer is an invalid argument for "%llU", but in practice
172           it occurs quite frequently in printf statements that produce
173           debug output.  Use a fallback in this case.  */
174        if (ap->a.a_u32_string == NULL)
175          {
176            static const uint32_t u32_null_string[] =
177              { '(', 'N', 'U', 'L', 'L', ')', 0 };
178            ap->a.a_u32_string = u32_null_string;
179          }
180        break;
181#endif
182      default:
183        /* Unknown type.  */
184        return -1;
185      }
186  return 0;
187}
188