Mercurial > hg > octave-kai > gnulib-hg
comparison lib/printf-parse.c @ 4224:83eabea25586
New modules vasnprintf and vasprintf.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Thu, 30 Jan 2003 13:48:21 +0000 |
parents | |
children | e58a1c05a6ba |
comparison
equal
deleted
inserted
replaced
4223:94b829dffa17 | 4224:83eabea25586 |
---|---|
1 /* Formatted output to strings. | |
2 Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc. | |
3 | |
4 This program is free software; you can redistribute it and/or modify it | |
5 under the terms of the GNU Library General Public License as published | |
6 by the Free Software Foundation; either version 2, or (at your option) | |
7 any later version. | |
8 | |
9 This program 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. | |
13 | |
14 You should have received a copy of the GNU Library General Public | |
15 License along with this program; if not, write to the Free Software | |
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
17 USA. */ | |
18 | |
19 #ifdef HAVE_CONFIG_H | |
20 # include <config.h> | |
21 #endif | |
22 | |
23 /* Specification. */ | |
24 #include "printf-parse.h" | |
25 | |
26 /* Get size_t, NULL. */ | |
27 #include <stddef.h> | |
28 | |
29 /* Get intmax_t. */ | |
30 #if HAVE_STDINT_H_WITH_UINTMAX | |
31 # include <stdint.h> | |
32 #endif | |
33 #if HAVE_INTTYPES_H_WITH_UINTMAX | |
34 # include <inttypes.h> | |
35 #endif | |
36 | |
37 /* malloc(), realloc(), free(). */ | |
38 #include <stdlib.h> | |
39 | |
40 #ifdef STATIC | |
41 STATIC | |
42 #endif | |
43 int | |
44 printf_parse (const char *format, char_directives *d, arguments *a) | |
45 { | |
46 const char *cp = format; /* pointer into format */ | |
47 int arg_posn = 0; /* number of regular arguments consumed */ | |
48 unsigned int d_allocated; /* allocated elements of d->dir */ | |
49 unsigned int a_allocated; /* allocated elements of a->arg */ | |
50 unsigned int max_width_length = 0; | |
51 unsigned int max_precision_length = 0; | |
52 | |
53 d->count = 0; | |
54 d_allocated = 1; | |
55 d->dir = malloc (d_allocated * sizeof (char_directive)); | |
56 if (d->dir == NULL) | |
57 /* Out of memory. */ | |
58 return -1; | |
59 | |
60 a->count = 0; | |
61 a_allocated = 0; | |
62 a->arg = NULL; | |
63 | |
64 #define REGISTER_ARG(_index_,_type_) \ | |
65 { \ | |
66 unsigned int n = (_index_); \ | |
67 if (n >= a_allocated) \ | |
68 { \ | |
69 argument *memory; \ | |
70 a_allocated = 2 * a_allocated; \ | |
71 if (a_allocated <= n) \ | |
72 a_allocated = n + 1; \ | |
73 memory = (a->arg \ | |
74 ? realloc (a->arg, a_allocated * sizeof (argument)) \ | |
75 : malloc (a_allocated * sizeof (argument))); \ | |
76 if (memory == NULL) \ | |
77 /* Out of memory. */ \ | |
78 goto error; \ | |
79 a->arg = memory; \ | |
80 } \ | |
81 while (a->count <= n) \ | |
82 a->arg[a->count++].type = TYPE_NONE; \ | |
83 if (a->arg[n].type == TYPE_NONE) \ | |
84 a->arg[n].type = (_type_); \ | |
85 else if (a->arg[n].type != (_type_)) \ | |
86 /* Ambiguous type for positional argument. */ \ | |
87 goto error; \ | |
88 } | |
89 | |
90 while (*cp != '\0') | |
91 { | |
92 char c = *cp++; | |
93 if (c == '%') | |
94 { | |
95 int arg_index = -1; | |
96 char_directive *dp = &d->dir[d->count];/* pointer to next directive */ | |
97 | |
98 /* Initialize the next directive. */ | |
99 dp->dir_start = cp - 1; | |
100 dp->flags = 0; | |
101 dp->width_start = NULL; | |
102 dp->width_end = NULL; | |
103 dp->width_arg_index = -1; | |
104 dp->precision_start = NULL; | |
105 dp->precision_end = NULL; | |
106 dp->precision_arg_index = -1; | |
107 dp->arg_index = -1; | |
108 | |
109 /* Test for positional argument. */ | |
110 if (*cp >= '0' && *cp <= '9') | |
111 { | |
112 const char *np; | |
113 | |
114 for (np = cp; *np >= '0' && *np <= '9'; np++) | |
115 ; | |
116 if (*np == '$') | |
117 { | |
118 unsigned int n = 0; | |
119 | |
120 for (np = cp; *np >= '0' && *np <= '9'; np++) | |
121 n = 10 * n + (*np - '0'); | |
122 if (n == 0) | |
123 /* Positional argument 0. */ | |
124 goto error; | |
125 arg_index = n - 1; | |
126 cp = np + 1; | |
127 } | |
128 } | |
129 | |
130 /* Read the flags. */ | |
131 for (;;) | |
132 { | |
133 if (*cp == '\'') | |
134 { | |
135 dp->flags |= FLAG_GROUP; | |
136 cp++; | |
137 } | |
138 else if (*cp == '-') | |
139 { | |
140 dp->flags |= FLAG_LEFT; | |
141 cp++; | |
142 } | |
143 else if (*cp == '+') | |
144 { | |
145 dp->flags |= FLAG_SHOWSIGN; | |
146 cp++; | |
147 } | |
148 else if (*cp == ' ') | |
149 { | |
150 dp->flags |= FLAG_SPACE; | |
151 cp++; | |
152 } | |
153 else if (*cp == '#') | |
154 { | |
155 dp->flags |= FLAG_ALT; | |
156 cp++; | |
157 } | |
158 else if (*cp == '0') | |
159 { | |
160 dp->flags |= FLAG_ZERO; | |
161 cp++; | |
162 } | |
163 else | |
164 break; | |
165 } | |
166 | |
167 /* Parse the field width. */ | |
168 if (*cp == '*') | |
169 { | |
170 dp->width_start = cp; | |
171 cp++; | |
172 dp->width_end = cp; | |
173 if (max_width_length < 1) | |
174 max_width_length = 1; | |
175 | |
176 /* Test for positional argument. */ | |
177 if (*cp >= '0' && *cp <= '9') | |
178 { | |
179 const char *np; | |
180 | |
181 for (np = cp; *np >= '0' && *np <= '9'; np++) | |
182 ; | |
183 if (*np == '$') | |
184 { | |
185 unsigned int n = 0; | |
186 | |
187 for (np = cp; *np >= '0' && *np <= '9'; np++) | |
188 n = 10 * n + (*np - '0'); | |
189 if (n == 0) | |
190 /* Positional argument 0. */ | |
191 goto error; | |
192 dp->width_arg_index = n - 1; | |
193 cp = np + 1; | |
194 } | |
195 } | |
196 if (dp->width_arg_index < 0) | |
197 dp->width_arg_index = arg_posn++; | |
198 REGISTER_ARG (dp->width_arg_index, TYPE_INT); | |
199 } | |
200 else if (*cp >= '0' && *cp <= '9') | |
201 { | |
202 unsigned int width_length; | |
203 | |
204 dp->width_start = cp; | |
205 for (; *cp >= '0' && *cp <= '9'; cp++) | |
206 ; | |
207 dp->width_end = cp; | |
208 width_length = dp->width_end - dp->width_start; | |
209 if (max_width_length < width_length) | |
210 max_width_length = width_length; | |
211 } | |
212 | |
213 /* Parse the precision. */ | |
214 if (*cp == '.') | |
215 { | |
216 cp++; | |
217 if (*cp == '*') | |
218 { | |
219 dp->precision_start = cp - 1; | |
220 cp++; | |
221 dp->precision_end = cp; | |
222 if (max_precision_length < 2) | |
223 max_precision_length = 2; | |
224 | |
225 /* Test for positional argument. */ | |
226 if (*cp >= '0' && *cp <= '9') | |
227 { | |
228 const char *np; | |
229 | |
230 for (np = cp; *np >= '0' && *np <= '9'; np++) | |
231 ; | |
232 if (*np == '$') | |
233 { | |
234 unsigned int n = 0; | |
235 | |
236 for (np = cp; *np >= '0' && *np <= '9'; np++) | |
237 n = 10 * n + (*np - '0'); | |
238 if (n == 0) | |
239 /* Positional argument 0. */ | |
240 goto error; | |
241 dp->precision_arg_index = n - 1; | |
242 cp = np + 1; | |
243 } | |
244 } | |
245 if (dp->precision_arg_index < 0) | |
246 dp->precision_arg_index = arg_posn++; | |
247 REGISTER_ARG (dp->precision_arg_index, TYPE_INT); | |
248 } | |
249 else | |
250 { | |
251 unsigned int precision_length; | |
252 | |
253 dp->precision_start = cp - 1; | |
254 for (; *cp >= '0' && *cp <= '9'; cp++) | |
255 ; | |
256 dp->precision_end = cp; | |
257 precision_length = dp->precision_end - dp->precision_start; | |
258 if (max_precision_length < precision_length) | |
259 max_precision_length = precision_length; | |
260 } | |
261 } | |
262 | |
263 { | |
264 arg_type type; | |
265 | |
266 /* Parse argument type/size specifiers. */ | |
267 { | |
268 int flags = 0; | |
269 | |
270 for (;;) | |
271 { | |
272 if (*cp == 'h') | |
273 { | |
274 flags |= (1 << (flags & 1)); | |
275 cp++; | |
276 } | |
277 else if (*cp == 'L') | |
278 { | |
279 flags |= 4; | |
280 cp++; | |
281 } | |
282 else if (*cp == 'l') | |
283 { | |
284 flags += 8; | |
285 cp++; | |
286 } | |
287 #ifdef HAVE_INTMAX_T | |
288 else if (*cp == 'j') | |
289 { | |
290 if (sizeof (intmax_t) > sizeof (long)) | |
291 { | |
292 /* intmax_t = long long */ | |
293 flags += 16; | |
294 } | |
295 else if (sizeof (intmax_t) > sizeof (int)) | |
296 { | |
297 /* intmax_t = long */ | |
298 flags += 8; | |
299 } | |
300 cp++; | |
301 } | |
302 #endif | |
303 else if (*cp == 'z' || *cp == 'Z') | |
304 { | |
305 /* 'z' is standardized in ISO C 99, but glibc uses 'Z' | |
306 because the warning facility in gcc-2.95.2 understands | |
307 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ | |
308 if (sizeof (size_t) > sizeof (long)) | |
309 { | |
310 /* size_t = long long */ | |
311 flags += 16; | |
312 } | |
313 else if (sizeof (size_t) > sizeof (int)) | |
314 { | |
315 /* size_t = long */ | |
316 flags += 8; | |
317 } | |
318 cp++; | |
319 } | |
320 else if (*cp == 't') | |
321 { | |
322 if (sizeof (ptrdiff_t) > sizeof (long)) | |
323 { | |
324 /* ptrdiff_t = long long */ | |
325 flags += 16; | |
326 } | |
327 else if (sizeof (ptrdiff_t) > sizeof (int)) | |
328 { | |
329 /* ptrdiff_t = long */ | |
330 flags += 8; | |
331 } | |
332 cp++; | |
333 } | |
334 else | |
335 break; | |
336 } | |
337 | |
338 /* Read the conversion character. */ | |
339 c = *cp++; | |
340 switch (c) | |
341 { | |
342 case 'd': case 'i': | |
343 #ifdef HAVE_LONG_LONG | |
344 if (flags >= 16 || (flags & 4)) | |
345 type = TYPE_LONGLONGINT; | |
346 else | |
347 #endif | |
348 if (flags >= 8) | |
349 type = TYPE_LONGINT; | |
350 else if (flags & 2) | |
351 type = TYPE_SCHAR; | |
352 else if (flags & 1) | |
353 type = TYPE_SHORT; | |
354 else | |
355 type = TYPE_INT; | |
356 break; | |
357 case 'o': case 'u': case 'x': case 'X': | |
358 #ifdef HAVE_LONG_LONG | |
359 if (flags >= 16 || (flags & 4)) | |
360 type = TYPE_ULONGLONGINT; | |
361 else | |
362 #endif | |
363 if (flags >= 8) | |
364 type = TYPE_ULONGINT; | |
365 else if (flags & 2) | |
366 type = TYPE_UCHAR; | |
367 else if (flags & 1) | |
368 type = TYPE_USHORT; | |
369 else | |
370 type = TYPE_UINT; | |
371 break; | |
372 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': | |
373 case 'a': case 'A': | |
374 #ifdef HAVE_LONG_DOUBLE | |
375 if (flags >= 16 || (flags & 4)) | |
376 type = TYPE_LONGDOUBLE; | |
377 else | |
378 #endif | |
379 type = TYPE_DOUBLE; | |
380 break; | |
381 case 'c': | |
382 if (flags >= 8) | |
383 #ifdef HAVE_WINT_T | |
384 type = TYPE_WIDE_CHAR; | |
385 #else | |
386 goto error; | |
387 #endif | |
388 else | |
389 type = TYPE_CHAR; | |
390 break; | |
391 #ifdef HAVE_WINT_T | |
392 case 'C': | |
393 type = TYPE_WIDE_CHAR; | |
394 c = 'c'; | |
395 break; | |
396 #endif | |
397 case 's': | |
398 if (flags >= 8) | |
399 #ifdef HAVE_WCHAR_T | |
400 type = TYPE_WIDE_STRING; | |
401 #else | |
402 goto error; | |
403 #endif | |
404 else | |
405 type = TYPE_STRING; | |
406 break; | |
407 #ifdef HAVE_WCHAR_T | |
408 case 'S': | |
409 type = TYPE_WIDE_STRING; | |
410 c = 's'; | |
411 break; | |
412 #endif | |
413 case 'p': | |
414 type = TYPE_POINTER; | |
415 break; | |
416 case 'n': | |
417 #ifdef HAVE_LONG_LONG | |
418 if (flags >= 16 || (flags & 4)) | |
419 type = TYPE_COUNT_LONGLONGINT_POINTER; | |
420 else | |
421 #endif | |
422 if (flags >= 8) | |
423 type = TYPE_COUNT_LONGINT_POINTER; | |
424 else if (flags & 2) | |
425 type = TYPE_COUNT_SCHAR_POINTER; | |
426 else if (flags & 1) | |
427 type = TYPE_COUNT_SHORT_POINTER; | |
428 else | |
429 type = TYPE_COUNT_INT_POINTER; | |
430 break; | |
431 case '%': | |
432 type = TYPE_NONE; | |
433 break; | |
434 default: | |
435 /* Unknown conversion character. */ | |
436 goto error; | |
437 } | |
438 } | |
439 | |
440 if (type != TYPE_NONE) | |
441 { | |
442 dp->arg_index = arg_index; | |
443 if (dp->arg_index < 0) | |
444 dp->arg_index = arg_posn++; | |
445 REGISTER_ARG (dp->arg_index, type); | |
446 } | |
447 dp->conversion = c; | |
448 dp->dir_end = cp; | |
449 } | |
450 | |
451 d->count++; | |
452 if (d->count >= d_allocated) | |
453 { | |
454 char_directive *memory; | |
455 | |
456 d_allocated = 2 * d_allocated; | |
457 memory = realloc (d->dir, d_allocated * sizeof (char_directive)); | |
458 if (memory == NULL) | |
459 /* Out of memory. */ | |
460 goto error; | |
461 d->dir = memory; | |
462 } | |
463 } | |
464 } | |
465 d->dir[d->count].dir_start = cp; | |
466 | |
467 d->max_width_length = max_width_length; | |
468 d->max_precision_length = max_precision_length; | |
469 return 0; | |
470 | |
471 error: | |
472 if (a->arg) | |
473 free (a->arg); | |
474 if (d->dir) | |
475 free (d->dir); | |
476 return -1; | |
477 } |