tee: Check for the removed pad flag also in the slow pushing path
[platform/upstream/gstreamer.git] / gst / printf / printf-parse.c
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 #include "gst-printf.h"
24
25 /* Specification.  */
26 #include "printf-parse.h"
27
28 /* Get size_t, NULL.  */
29 #include <stddef.h>
30
31 /* Get intmax_t.  */
32 #ifdef HAVE_STDINT_H_WITH_UINTMAX
33 # include <stdint.h>
34 #endif
35 #ifdef HAVE_INTTYPES_H_WITH_UINTMAX
36 # include <inttypes.h>
37 #endif
38
39 /* malloc(), realloc(), free().  */
40 #include <stdlib.h>
41
42 #ifdef STATIC
43 STATIC
44 #endif
45     int
46 printf_parse (const char *format, char_directives * d, arguments * a)
47 {
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;
54
55   d->count = 0;
56   d_allocated = 1;
57   d->dir = malloc (d_allocated * sizeof (char_directive));
58   if (d->dir == NULL)
59     /* Out of memory.  */
60     return -1;
61
62   a->count = 0;
63   a_allocated = 0;
64   a->arg = NULL;
65
66 #define REGISTER_ARG(_index_,_type_) \
67   {                                                                     \
68     unsigned int n = (_index_);                                         \
69     if (n >= a_allocated)                                               \
70       {                                                                 \
71         argument *memory;                                               \
72         a_allocated = 2 * a_allocated;                                  \
73         if (a_allocated <= n)                                           \
74           a_allocated = n + 1;                                          \
75         memory = (a->arg                                                \
76                   ? realloc (a->arg, a_allocated * sizeof (argument))   \
77                   : malloc (a_allocated * sizeof (argument)));          \
78         if (memory == NULL)                                             \
79           /* Out of memory.  */                                         \
80           goto error;                                                   \
81         a->arg = memory;                                                \
82       }                                                                 \
83     while (a->count <= n) {                             \
84       a->arg[a->count].type = TYPE_NONE;                \
85       a->arg[a->count].ext_string = (char *) 0;         \
86       ++a->count;                                       \
87     }                                                   \
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.  */                    \
92       goto error;                                                       \
93   }
94
95   while (*cp != '\0') {
96     char c = *cp++;
97     if (c == '%') {
98       int arg_index = -1;
99       char_directive *dp = &d->dir[d->count];   /* pointer to next directive */
100
101       /* Initialize the next directive.  */
102       dp->dir_start = cp - 1;
103       dp->flags = 0;
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;
110       dp->arg_index = -1;
111
112       /* Test for positional argument.  */
113       if (*cp >= '0' && *cp <= '9') {
114         const char *np;
115
116         for (np = cp; *np >= '0' && *np <= '9'; np++);
117         if (*np == '$') {
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         if (*cp == '\'') {
133           dp->flags |= FLAG_GROUP;
134           cp++;
135         } else if (*cp == '-') {
136           dp->flags |= FLAG_LEFT;
137           cp++;
138         } else if (*cp == '+') {
139           dp->flags |= FLAG_SHOWSIGN;
140           cp++;
141         } else if (*cp == ' ') {
142           dp->flags |= FLAG_SPACE;
143           cp++;
144         } else if (*cp == '#') {
145           dp->flags |= FLAG_ALT;
146           cp++;
147         } else if (*cp == '0') {
148           dp->flags |= FLAG_ZERO;
149           cp++;
150         } else
151           break;
152       }
153
154       /* Parse the field width.  */
155       if (*cp == '*') {
156         dp->width_start = cp;
157         cp++;
158         dp->width_end = cp;
159         if (max_width_length < 1)
160           max_width_length = 1;
161
162         /* Test for positional argument.  */
163         if (*cp >= '0' && *cp <= '9') {
164           const char *np;
165
166           for (np = cp; *np >= '0' && *np <= '9'; np++);
167           if (*np == '$') {
168             unsigned int n = 0;
169
170             for (np = cp; *np >= '0' && *np <= '9'; np++)
171               n = 10 * n + (*np - '0');
172             if (n == 0)
173               /* Positional argument 0.  */
174               goto error;
175             dp->width_arg_index = n - 1;
176             cp = np + 1;
177           }
178         }
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;
184
185         dp->width_start = cp;
186         for (; *cp >= '0' && *cp <= '9'; cp++);
187         dp->width_end = cp;
188         width_length = dp->width_end - dp->width_start;
189         if (max_width_length < width_length)
190           max_width_length = width_length;
191       }
192
193       /* Parse the precision.  */
194       if (*cp == '.') {
195         cp++;
196         if (*cp == '*') {
197           dp->precision_start = cp - 1;
198           cp++;
199           dp->precision_end = cp;
200           if (max_precision_length < 2)
201             max_precision_length = 2;
202
203           /* Test for positional argument.  */
204           if (*cp >= '0' && *cp <= '9') {
205             const char *np;
206
207             for (np = cp; *np >= '0' && *np <= '9'; np++);
208             if (*np == '$') {
209               unsigned int n = 0;
210
211               for (np = cp; *np >= '0' && *np <= '9'; np++)
212                 n = 10 * n + (*np - '0');
213               if (n == 0)
214                 /* Positional argument 0.  */
215                 goto error;
216               dp->precision_arg_index = n - 1;
217               cp = np + 1;
218             }
219           }
220           if (dp->precision_arg_index < 0)
221             dp->precision_arg_index = arg_posn++;
222           REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
223         } else {
224           unsigned int precision_length;
225
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;
232         }
233       }
234
235       {
236         arg_type type;
237
238         /* Parse argument type/size specifiers.  */
239         {
240           int flags = 0;
241
242           for (;;) {
243             if (*cp == 'h') {
244               flags |= (1 << (flags & 1));
245               cp++;
246             } else if (*cp == 'L') {
247               flags |= 4;
248               cp++;
249             } else if (*cp == 'l') {
250               flags += 8;
251               cp++;
252             }
253 #ifdef HAVE_INT64_AND_I64
254             else if (cp[0] == 'I' && cp[1] == '6' && cp[2] == '4') {
255               flags = 64;
256               cp += 3;
257             }
258 #endif
259             else if (cp[0] == 'I' && cp[1] == '3' && cp[2] == '2') {
260               //flags = 32;
261               cp += 3;
262             }
263 #ifdef HAVE_INTMAX_T
264             else if (*cp == 'j') {
265               if (sizeof (intmax_t) > sizeof (long)) {
266                 /* intmax_t = long long */
267                 flags += 16;
268               } else if (sizeof (intmax_t) > sizeof (int)) {
269                 /* intmax_t = long */
270                 flags += 8;
271               }
272               cp++;
273             }
274 #endif
275             else if (*cp == 'z' || *cp == 'Z') {
276               /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
277                  because the warning facility in gcc-2.95.2 understands
278                  only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
279               if (sizeof (size_t) > sizeof (long)) {
280                 /* size_t = long long */
281                 flags += 16;
282               } else if (sizeof (size_t) > sizeof (int)) {
283                 /* size_t = long */
284                 flags += 8;
285               }
286               cp++;
287             } else if (*cp == 't') {
288               if (sizeof (ptrdiff_t) > sizeof (long)) {
289                 /* ptrdiff_t = long long */
290                 flags += 16;
291               } else if (sizeof (ptrdiff_t) > sizeof (int)) {
292                 /* ptrdiff_t = long */
293                 flags += 8;
294               }
295               cp++;
296             } else
297               break;
298           }
299
300           /* Read the conversion character.  */
301           c = *cp++;
302           switch (c) {
303             case 'd':
304             case 'i':
305 #ifdef HAVE_INT64_AND_I64
306               if (flags == 64)
307                 type = TYPE_INT64;
308               else
309 #endif
310 #ifdef HAVE_LONG_LONG
311               if (flags >= 16 || (flags & 4))
312                 type = TYPE_LONGLONGINT;
313               else
314 #endif
315               if (flags >= 8)
316                 type = TYPE_LONGINT;
317               else if (flags & 2)
318                 type = TYPE_SCHAR;
319               else if (flags & 1)
320                 type = TYPE_SHORT;
321               else
322                 type = TYPE_INT;
323               break;
324             case 'o':
325             case 'u':
326             case 'x':
327             case 'X':
328 #ifdef HAVE_INT64_AND_I64
329               if (flags == 64)
330                 type = TYPE_UINT64;
331               else
332 #endif
333 #ifdef HAVE_LONG_LONG
334               if (flags >= 16 || (flags & 4))
335                 type = TYPE_ULONGLONGINT;
336               else
337 #endif
338               if (flags >= 8)
339                 type = TYPE_ULONGINT;
340               else if (flags & 2)
341                 type = TYPE_UCHAR;
342               else if (flags & 1)
343                 type = TYPE_USHORT;
344               else
345                 type = TYPE_UINT;
346               break;
347             case 'f':
348             case 'F':
349             case 'e':
350             case 'E':
351             case 'g':
352             case 'G':
353             case 'a':
354             case 'A':
355 #ifdef HAVE_LONG_DOUBLE
356               if (flags >= 16 || (flags & 4))
357                 type = TYPE_LONGDOUBLE;
358               else
359 #endif
360                 type = TYPE_DOUBLE;
361               break;
362             case 'c':
363               if (flags >= 8)
364 #ifdef HAVE_WINT_T
365                 type = TYPE_WIDE_CHAR;
366 #else
367                 goto error;
368 #endif
369               else
370                 type = TYPE_CHAR;
371               break;
372 #ifdef HAVE_WINT_T
373             case 'C':
374               type = TYPE_WIDE_CHAR;
375               c = 'c';
376               break;
377 #endif
378             case 's':
379               if (flags >= 8)
380 #ifdef HAVE_WCHAR_T
381                 type = TYPE_WIDE_STRING;
382 #else
383                 goto error;
384 #endif
385               else
386                 type = TYPE_STRING;
387               break;
388 #ifdef HAVE_WCHAR_T
389             case 'S':
390               type = TYPE_WIDE_STRING;
391               c = 's';
392               break;
393 #endif
394               /* Old GST_PTR_FORMAT, handle for binary backwards compatibility */
395             case 'P':
396               type = TYPE_POINTER_EXT;
397               dp->flags |= FLAG_PTR_EXT;
398               dp->ptr_ext_char = 'A';
399               c = 'p';
400               break;
401             case 'p':
402               /* Note: cp points already to the char after the 'p' now */
403               if (cp[0] == POINTER_EXT_SIGNIFIER_CHAR && cp[1] != '\0') {
404                 type = TYPE_POINTER_EXT;
405                 dp->flags |= FLAG_PTR_EXT;
406                 dp->ptr_ext_char = cp[1];
407                 cp += 2;
408                 /* we do not use dp->conversion='s' on purpose here, so we
409                  * can fall back to printing just the pointer with %p if the
410                  * serialisation function returned NULL for some reason */
411               } else {
412                 type = TYPE_POINTER;
413               }
414               break;
415               /* Old GST_SEGMENT_FORMAT, handle for backwards compatibility */
416             case 'Q':
417               type = TYPE_POINTER_EXT;
418               dp->flags |= FLAG_PTR_EXT;
419               dp->ptr_ext_char = 'B';
420               c = 'p';
421               break;
422             case 'n':
423 #ifdef HAVE_LONG_LONG
424               if (flags >= 16 || (flags & 4))
425                 type = TYPE_COUNT_LONGLONGINT_POINTER;
426               else
427 #endif
428               if (flags >= 8)
429                 type = TYPE_COUNT_LONGINT_POINTER;
430               else if (flags & 2)
431                 type = TYPE_COUNT_SCHAR_POINTER;
432               else if (flags & 1)
433                 type = TYPE_COUNT_SHORT_POINTER;
434               else
435                 type = TYPE_COUNT_INT_POINTER;
436               break;
437             case '%':
438               type = TYPE_NONE;
439               break;
440             default:
441               /* Unknown conversion character.  */
442               goto error;
443           }
444         }
445
446         if (type != TYPE_NONE) {
447           dp->arg_index = arg_index;
448           if (dp->arg_index < 0)
449             dp->arg_index = arg_posn++;
450           REGISTER_ARG (dp->arg_index, type);
451         }
452         dp->conversion = c;
453         dp->dir_end = cp;
454       }
455
456       d->count++;
457       if (d->count >= d_allocated) {
458         char_directive *memory;
459
460         d_allocated = 2 * d_allocated;
461         memory = realloc (d->dir, d_allocated * sizeof (char_directive));
462         if (memory == NULL)
463           /* Out of memory.  */
464           goto error;
465         d->dir = memory;
466       }
467     }
468   }
469   d->dir[d->count].dir_start = cp;
470
471   d->max_width_length = max_width_length;
472   d->max_precision_length = max_precision_length;
473   return 0;
474
475 error:
476   if (a->arg)
477     free (a->arg);
478   if (d->dir)
479     free (d->dir);
480   return -1;
481 }