initial import
[glibc.git] / stdio / printf-prs.c
blob2f55dd3157ea998b73902aa886891070b8270e8b
1 /* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C 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 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include <ansidecl.h>
20 #include <stdio.h>
21 #include <printf.h>
22 #include <limits.h>
23 #include <string.h>
24 #include <ctype.h>
26 #ifdef __GNUC__
27 #define HAVE_LONGLONG
28 #endif
30 extern printf_arginfo_function *__printf_arginfo_table[];
32 size_t
33 DEFUN(parse_printf_format, (fmt, n, argtypes),
34 CONST char *fmt AND size_t n AND int *argtypes)
36 register CONST char *f;
37 size_t need = 0;
39 for (f = strchr (fmt, '%'); f != NULL; f = strchr (f, '%'))
41 struct printf_info info;
42 printf_arginfo_function *arginfo;
44 ++f;
46 info.space = info.showsign = info.left = info.alt = info.group = 0;
47 info.pad = ' ';
48 while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0' ||
49 *f == '\'')
50 switch (*f++)
52 case ' ':
53 info.space = 1;
54 break;
55 case '+':
56 info.showsign = 1;
57 break;
58 case '-':
59 info.left = 1;
60 break;
61 case '#':
62 info.alt = 1;
63 break;
64 case '\'':
65 info.group = 1;
66 break;
67 case '0':
68 info.pad = '0';
69 break;
71 if (info.left)
72 info.pad = ' ';
74 /* Get the field width. */
75 if (*f == '*')
77 if (++need < n)
78 *argtypes++ = PA_INT;
79 info.width = INT_MIN;
80 ++f;
82 else
84 info.width = 0;
85 while (isdigit(*f))
87 info.width *= 10;
88 info.width += *f++ - '0';
92 /* Get the precision. */
93 /* -1 means none given; 0 means explicit 0. */
94 info.prec = -1;
95 if (*f == '.')
97 ++f;
98 if (*f == '*')
100 /* The precision is given in an argument. */
101 if (++need < n)
102 *argtypes++ = PA_INT;
103 info.prec = INT_MIN;
104 ++f;
106 else if (isdigit(*f))
108 info.prec = 0;
109 while (*f != '\0' && isdigit(*f))
111 info.prec *= 10;
112 info.prec += *f++ - '0';
117 /* Check for type modifiers. */
118 info.is_short = info.is_long = info.is_long_double = 0;
119 while (*f == 'h' || *f == 'l' || *f == 'L')
120 switch (*f++)
122 case 'h':
123 /* int's are short int's. */
124 info.is_short = 1;
125 break;
126 case 'l':
127 #ifdef HAVE_LONGLONG
128 if (info.is_long)
129 /* A double `l' is equivalent to an `L'. */
130 info.is_long_double = 1;
131 else
132 #endif
133 /* int's are long int's. */
134 info.is_long = 1;
135 break;
136 case 'L':
137 /* double's are long double's, and int's are long long int's. */
138 info.is_long_double = 1;
139 break;
142 if (*f == '\0')
143 return need;
145 info.spec = *f++;
147 arginfo = __printf_arginfo_table[info.spec];
148 if (arginfo != NULL)
150 size_t nargs
151 = (*arginfo) (&info, need > n ? 0 : n - need, argtypes);
152 need += nargs;
153 argtypes += nargs;
155 else
157 int type;
158 switch (info.spec)
160 case 'i':
161 case 'd':
162 case 'u':
163 case 'o':
164 case 'X':
165 case 'x':
166 type = PA_INT;
167 break;
169 case 'e':
170 case 'E':
171 case 'f':
172 case 'g':
173 case 'G':
174 type = PA_DOUBLE;
175 break;
177 case 'c':
178 type = PA_CHAR;
179 break;
181 case 's':
182 type = PA_STRING;
183 break;
185 case 'p':
186 type = PA_POINTER;
187 break;
189 case 'n':
190 type = PA_INT | PA_FLAG_PTR;
191 break;
193 default:
194 /* No arg for an unknown spec. */
195 continue;
198 if (info.is_long_double)
199 type |= PA_FLAG_LONG_DOUBLE;
200 if (info.is_long)
201 type |= PA_FLAG_LONG;
202 if (info.is_short)
203 type |= PA_FLAG_SHORT;
205 if (++need < n)
206 *argtypes++ = type;
210 return need;