1 /* Formatted output to strings.
2 Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
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)
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.
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,
23 #include "gst-printf.h"
26 #include "printf-parse.h"
28 /* Get size_t, NULL. */
32 #if HAVE_STDINT_H_WITH_UINTMAX
35 #if HAVE_INTTYPES_H_WITH_UINTMAX
36 # include <inttypes.h>
39 /* malloc(), realloc(), free(). */
46 printf_parse (const char *format, char_directives * d, arguments * a)
48 const char *cp = format; /* pointer into format */
49 int arg_posn = 0; /* number of regular arguments consumed */
50 unsigned int d_allocated; /* allocated elements of d->dir */
51 unsigned int a_allocated; /* allocated elements of a->arg */
52 unsigned int max_width_length = 0;
53 unsigned int max_precision_length = 0;
57 d->dir = malloc (d_allocated * sizeof (char_directive));
66 #define REGISTER_ARG(_index_,_type_) \
68 unsigned int n = (_index_); \
69 if (n >= a_allocated) \
72 a_allocated = 2 * a_allocated; \
73 if (a_allocated <= n) \
74 a_allocated = n + 1; \
76 ? realloc (a->arg, a_allocated * sizeof (argument)) \
77 : malloc (a_allocated * sizeof (argument))); \
79 /* Out of memory. */ \
83 while (a->count <= n) { \
84 a->arg[a->count].type = TYPE_NONE; \
85 a->arg[a->count].ext_string = (char *) 0; \
88 if (a->arg[n].type == TYPE_NONE) \
89 a->arg[n].type = (_type_); \
90 else if (a->arg[n].type != (_type_)) \
91 /* Ambiguous type for positional argument. */ \
99 char_directive *dp = &d->dir[d->count]; /* pointer to next directive */
101 /* Initialize the next directive. */
102 dp->dir_start = cp - 1;
104 dp->width_start = NULL;
105 dp->width_end = NULL;
106 dp->width_arg_index = -1;
107 dp->precision_start = NULL;
108 dp->precision_end = NULL;
109 dp->precision_arg_index = -1;
112 /* Test for positional argument. */
113 if (*cp >= '0' && *cp <= '9') {
116 for (np = cp; *np >= '0' && *np <= '9'; np++);
120 for (np = cp; *np >= '0' && *np <= '9'; np++)
121 n = 10 * n + (*np - '0');
123 /* Positional argument 0. */
130 /* Read the flags. */
133 dp->flags |= FLAG_GROUP;
135 } else if (*cp == '-') {
136 dp->flags |= FLAG_LEFT;
138 } else if (*cp == '+') {
139 dp->flags |= FLAG_SHOWSIGN;
141 } else if (*cp == ' ') {
142 dp->flags |= FLAG_SPACE;
144 } else if (*cp == '#') {
145 dp->flags |= FLAG_ALT;
147 } else if (*cp == '0') {
148 dp->flags |= FLAG_ZERO;
154 /* Parse the field width. */
156 dp->width_start = cp;
159 if (max_width_length < 1)
160 max_width_length = 1;
162 /* Test for positional argument. */
163 if (*cp >= '0' && *cp <= '9') {
166 for (np = cp; *np >= '0' && *np <= '9'; np++);
170 for (np = cp; *np >= '0' && *np <= '9'; np++)
171 n = 10 * n + (*np - '0');
173 /* Positional argument 0. */
175 dp->width_arg_index = n - 1;
179 if (dp->width_arg_index < 0)
180 dp->width_arg_index = arg_posn++;
181 REGISTER_ARG (dp->width_arg_index, TYPE_INT);
182 } else if (*cp >= '0' && *cp <= '9') {
183 unsigned int width_length;
185 dp->width_start = cp;
186 for (; *cp >= '0' && *cp <= '9'; cp++);
188 width_length = dp->width_end - dp->width_start;
189 if (max_width_length < width_length)
190 max_width_length = width_length;
193 /* Parse the precision. */
197 dp->precision_start = cp - 1;
199 dp->precision_end = cp;
200 if (max_precision_length < 2)
201 max_precision_length = 2;
203 /* Test for positional argument. */
204 if (*cp >= '0' && *cp <= '9') {
207 for (np = cp; *np >= '0' && *np <= '9'; np++);
211 for (np = cp; *np >= '0' && *np <= '9'; np++)
212 n = 10 * n + (*np - '0');
214 /* Positional argument 0. */
216 dp->precision_arg_index = n - 1;
220 if (dp->precision_arg_index < 0)
221 dp->precision_arg_index = arg_posn++;
222 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
224 unsigned int precision_length;
226 dp->precision_start = cp - 1;
227 for (; *cp >= '0' && *cp <= '9'; cp++);
228 dp->precision_end = cp;
229 precision_length = dp->precision_end - dp->precision_start;
230 if (max_precision_length < precision_length)
231 max_precision_length = precision_length;
238 /* Parse argument type/size specifiers. */
244 flags |= (1 << (flags & 1));
246 } else if (*cp == 'L') {
249 } else if (*cp == 'l') {
253 #ifdef HAVE_INT64_AND_I64
254 else if (cp[0] == 'I' && cp[1] == '6' && cp[2] == '4') {
260 else if (*cp == 'j') {
261 if (sizeof (intmax_t) > sizeof (long)) {
262 /* intmax_t = long long */
264 } else if (sizeof (intmax_t) > sizeof (int)) {
265 /* intmax_t = long */
271 else if (*cp == 'z' || *cp == 'Z') {
272 /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
273 because the warning facility in gcc-2.95.2 understands
274 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
275 if (sizeof (size_t) > sizeof (long)) {
276 /* size_t = long long */
278 } else if (sizeof (size_t) > sizeof (int)) {
283 } else if (*cp == 't') {
284 if (sizeof (ptrdiff_t) > sizeof (long)) {
285 /* ptrdiff_t = long long */
287 } else if (sizeof (ptrdiff_t) > sizeof (int)) {
288 /* ptrdiff_t = long */
296 /* Read the conversion character. */
301 #ifdef HAVE_INT64_AND_I64
306 #ifdef HAVE_LONG_LONG
307 if (flags >= 16 || (flags & 4))
308 type = TYPE_LONGLONGINT;
324 #ifdef HAVE_INT64_AND_I64
329 #ifdef HAVE_LONG_LONG
330 if (flags >= 16 || (flags & 4))
331 type = TYPE_ULONGLONGINT;
335 type = TYPE_ULONGINT;
351 #ifdef HAVE_LONG_DOUBLE
352 if (flags >= 16 || (flags & 4))
353 type = TYPE_LONGDOUBLE;
361 type = TYPE_WIDE_CHAR;
370 type = TYPE_WIDE_CHAR;
377 type = TYPE_WIDE_STRING;
386 type = TYPE_WIDE_STRING;
390 /* Old GST_PTR_FORMAT, handle for binary backwards compatibility */
392 type = TYPE_POINTER_EXT;
393 dp->flags |= FLAG_PTR_EXT;
394 dp->ptr_ext_char = 'A';
395 dp->conversion = 'p';
398 /* Note: cp points already to the char after the 'p' now */
399 if (cp[0] == POINTER_EXT_SIGNIFIER_CHAR && cp[1] != '\0') {
400 type = TYPE_POINTER_EXT;
401 dp->flags |= FLAG_PTR_EXT;
402 dp->ptr_ext_char = cp[1];
404 /* we do not use dp->conversion='s' on purpose here, so we
405 * can fall back to printing just the pointer with %p if the
406 * serialisation function returned NULL for some reason */
411 /* Old GST_SEGMENT_FORMAT, handle for backwards compatibility */
413 type = TYPE_POINTER_EXT;
414 dp->flags |= FLAG_PTR_EXT;
415 dp->ptr_ext_char = 'B';
416 dp->conversion = 'p';
419 #ifdef HAVE_LONG_LONG
420 if (flags >= 16 || (flags & 4))
421 type = TYPE_COUNT_LONGLONGINT_POINTER;
425 type = TYPE_COUNT_LONGINT_POINTER;
427 type = TYPE_COUNT_SCHAR_POINTER;
429 type = TYPE_COUNT_SHORT_POINTER;
431 type = TYPE_COUNT_INT_POINTER;
437 /* Unknown conversion character. */
442 if (type != TYPE_NONE) {
443 dp->arg_index = arg_index;
444 if (dp->arg_index < 0)
445 dp->arg_index = arg_posn++;
446 REGISTER_ARG (dp->arg_index, type);
453 if (d->count >= d_allocated) {
454 char_directive *memory;
456 d_allocated = 2 * d_allocated;
457 memory = realloc (d->dir, d_allocated * sizeof (char_directive));
465 d->dir[d->count].dir_start = cp;
467 d->max_width_length = max_width_length;
468 d->max_precision_length = max_precision_length;