printf: add our own printf implementation for debug logging
[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 #if HAVE_STDINT_H_WITH_UINTMAX
33 # include <stdint.h>
34 #endif
35 #if 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     if (a->arg[n].type == TYPE_NONE)                                    \
86       a->arg[n].type = (_type_);                                        \
87     else if (a->arg[n].type != (_type_))                                \
88       /* Ambiguous type for positional argument.  */                    \
89       goto error;                                                       \
90   }
91
92   while (*cp != '\0') {
93     char c = *cp++;
94     if (c == '%') {
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         const char *np;
112
113         for (np = cp; *np >= '0' && *np <= '9'; np++);
114         if (*np == '$') {
115           unsigned int n = 0;
116
117           for (np = cp; *np >= '0' && *np <= '9'; np++)
118             n = 10 * n + (*np - '0');
119           if (n == 0)
120             /* Positional argument 0.  */
121             goto error;
122           arg_index = n - 1;
123           cp = np + 1;
124         }
125       }
126
127       /* Read the flags.  */
128       for (;;) {
129         if (*cp == '\'') {
130           dp->flags |= FLAG_GROUP;
131           cp++;
132         } else if (*cp == '-') {
133           dp->flags |= FLAG_LEFT;
134           cp++;
135         } else if (*cp == '+') {
136           dp->flags |= FLAG_SHOWSIGN;
137           cp++;
138         } else if (*cp == ' ') {
139           dp->flags |= FLAG_SPACE;
140           cp++;
141         } else if (*cp == '#') {
142           dp->flags |= FLAG_ALT;
143           cp++;
144         } else if (*cp == '0') {
145           dp->flags |= FLAG_ZERO;
146           cp++;
147         } else
148           break;
149       }
150
151       /* Parse the field width.  */
152       if (*cp == '*') {
153         dp->width_start = cp;
154         cp++;
155         dp->width_end = cp;
156         if (max_width_length < 1)
157           max_width_length = 1;
158
159         /* Test for positional argument.  */
160         if (*cp >= '0' && *cp <= '9') {
161           const char *np;
162
163           for (np = cp; *np >= '0' && *np <= '9'; np++);
164           if (*np == '$') {
165             unsigned int n = 0;
166
167             for (np = cp; *np >= '0' && *np <= '9'; np++)
168               n = 10 * n + (*np - '0');
169             if (n == 0)
170               /* Positional argument 0.  */
171               goto error;
172             dp->width_arg_index = n - 1;
173             cp = np + 1;
174           }
175         }
176         if (dp->width_arg_index < 0)
177           dp->width_arg_index = arg_posn++;
178         REGISTER_ARG (dp->width_arg_index, TYPE_INT);
179       } else if (*cp >= '0' && *cp <= '9') {
180         unsigned int width_length;
181
182         dp->width_start = cp;
183         for (; *cp >= '0' && *cp <= '9'; cp++);
184         dp->width_end = cp;
185         width_length = dp->width_end - dp->width_start;
186         if (max_width_length < width_length)
187           max_width_length = width_length;
188       }
189
190       /* Parse the precision.  */
191       if (*cp == '.') {
192         cp++;
193         if (*cp == '*') {
194           dp->precision_start = cp - 1;
195           cp++;
196           dp->precision_end = cp;
197           if (max_precision_length < 2)
198             max_precision_length = 2;
199
200           /* Test for positional argument.  */
201           if (*cp >= '0' && *cp <= '9') {
202             const char *np;
203
204             for (np = cp; *np >= '0' && *np <= '9'; np++);
205             if (*np == '$') {
206               unsigned int n = 0;
207
208               for (np = cp; *np >= '0' && *np <= '9'; np++)
209                 n = 10 * n + (*np - '0');
210               if (n == 0)
211                 /* Positional argument 0.  */
212                 goto error;
213               dp->precision_arg_index = n - 1;
214               cp = np + 1;
215             }
216           }
217           if (dp->precision_arg_index < 0)
218             dp->precision_arg_index = arg_posn++;
219           REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
220         } else {
221           unsigned int precision_length;
222
223           dp->precision_start = cp - 1;
224           for (; *cp >= '0' && *cp <= '9'; cp++);
225           dp->precision_end = cp;
226           precision_length = dp->precision_end - dp->precision_start;
227           if (max_precision_length < precision_length)
228             max_precision_length = precision_length;
229         }
230       }
231
232       {
233         arg_type type;
234
235         /* Parse argument type/size specifiers.  */
236         {
237           int flags = 0;
238
239           for (;;) {
240             if (*cp == 'h') {
241               flags |= (1 << (flags & 1));
242               cp++;
243             } else if (*cp == 'L') {
244               flags |= 4;
245               cp++;
246             } else if (*cp == 'l') {
247               flags += 8;
248               cp++;
249             }
250 #ifdef HAVE_INT64_AND_I64
251             else if (cp[0] == 'I' && cp[1] == '6' && cp[2] == '4') {
252               flags = 64;
253               cp += 3;
254             }
255 #endif
256 #ifdef HAVE_INTMAX_T
257             else if (*cp == 'j') {
258               if (sizeof (intmax_t) > sizeof (long)) {
259                 /* intmax_t = long long */
260                 flags += 16;
261               } else if (sizeof (intmax_t) > sizeof (int)) {
262                 /* intmax_t = long */
263                 flags += 8;
264               }
265               cp++;
266             }
267 #endif
268             else if (*cp == 'z' || *cp == 'Z') {
269               /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
270                  because the warning facility in gcc-2.95.2 understands
271                  only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
272               if (sizeof (size_t) > sizeof (long)) {
273                 /* size_t = long long */
274                 flags += 16;
275               } else if (sizeof (size_t) > sizeof (int)) {
276                 /* size_t = long */
277                 flags += 8;
278               }
279               cp++;
280             } else if (*cp == 't') {
281               if (sizeof (ptrdiff_t) > sizeof (long)) {
282                 /* ptrdiff_t = long long */
283                 flags += 16;
284               } else if (sizeof (ptrdiff_t) > sizeof (int)) {
285                 /* ptrdiff_t = long */
286                 flags += 8;
287               }
288               cp++;
289             } else
290               break;
291           }
292
293           /* Read the conversion character.  */
294           c = *cp++;
295           switch (c) {
296             case 'd':
297             case 'i':
298 #ifdef HAVE_INT64_AND_I64
299               if (flags == 64)
300                 type = TYPE_INT64;
301               else
302 #endif
303 #ifdef HAVE_LONG_LONG
304               if (flags >= 16 || (flags & 4))
305                 type = TYPE_LONGLONGINT;
306               else
307 #endif
308               if (flags >= 8)
309                 type = TYPE_LONGINT;
310               else if (flags & 2)
311                 type = TYPE_SCHAR;
312               else if (flags & 1)
313                 type = TYPE_SHORT;
314               else
315                 type = TYPE_INT;
316               break;
317             case 'o':
318             case 'u':
319             case 'x':
320             case 'X':
321 #ifdef HAVE_INT64_AND_I64
322               if (flags == 64)
323                 type = TYPE_UINT64;
324               else
325 #endif
326 #ifdef HAVE_LONG_LONG
327               if (flags >= 16 || (flags & 4))
328                 type = TYPE_ULONGLONGINT;
329               else
330 #endif
331               if (flags >= 8)
332                 type = TYPE_ULONGINT;
333               else if (flags & 2)
334                 type = TYPE_UCHAR;
335               else if (flags & 1)
336                 type = TYPE_USHORT;
337               else
338                 type = TYPE_UINT;
339               break;
340             case 'f':
341             case 'F':
342             case 'e':
343             case 'E':
344             case 'g':
345             case 'G':
346             case 'a':
347             case 'A':
348 #ifdef HAVE_LONG_DOUBLE
349               if (flags >= 16 || (flags & 4))
350                 type = TYPE_LONGDOUBLE;
351               else
352 #endif
353                 type = TYPE_DOUBLE;
354               break;
355             case 'c':
356               if (flags >= 8)
357 #ifdef HAVE_WINT_T
358                 type = TYPE_WIDE_CHAR;
359 #else
360                 goto error;
361 #endif
362               else
363                 type = TYPE_CHAR;
364               break;
365 #ifdef HAVE_WINT_T
366             case 'C':
367               type = TYPE_WIDE_CHAR;
368               c = 'c';
369               break;
370 #endif
371             case 's':
372               if (flags >= 8)
373 #ifdef HAVE_WCHAR_T
374                 type = TYPE_WIDE_STRING;
375 #else
376                 goto error;
377 #endif
378               else
379                 type = TYPE_STRING;
380               break;
381 #ifdef HAVE_WCHAR_T
382             case 'S':
383               type = TYPE_WIDE_STRING;
384               c = 's';
385               break;
386 #endif
387             case 'p':
388               type = TYPE_POINTER;
389               break;
390             case 'n':
391 #ifdef HAVE_LONG_LONG
392               if (flags >= 16 || (flags & 4))
393                 type = TYPE_COUNT_LONGLONGINT_POINTER;
394               else
395 #endif
396               if (flags >= 8)
397                 type = TYPE_COUNT_LONGINT_POINTER;
398               else if (flags & 2)
399                 type = TYPE_COUNT_SCHAR_POINTER;
400               else if (flags & 1)
401                 type = TYPE_COUNT_SHORT_POINTER;
402               else
403                 type = TYPE_COUNT_INT_POINTER;
404               break;
405             case '%':
406               type = TYPE_NONE;
407               break;
408             default:
409               /* Unknown conversion character.  */
410               goto error;
411           }
412         }
413
414         if (type != TYPE_NONE) {
415           dp->arg_index = arg_index;
416           if (dp->arg_index < 0)
417             dp->arg_index = arg_posn++;
418           REGISTER_ARG (dp->arg_index, type);
419         }
420         dp->conversion = c;
421         dp->dir_end = cp;
422       }
423
424       d->count++;
425       if (d->count >= d_allocated) {
426         char_directive *memory;
427
428         d_allocated = 2 * d_allocated;
429         memory = realloc (d->dir, d_allocated * sizeof (char_directive));
430         if (memory == NULL)
431           /* Out of memory.  */
432           goto error;
433         d->dir = memory;
434       }
435     }
436   }
437   d->dir[d->count].dir_start = cp;
438
439   d->max_width_length = max_width_length;
440   d->max_precision_length = max_precision_length;
441   return 0;
442
443 error:
444   if (a->arg)
445     free (a->arg);
446   if (d->dir)
447     free (d->dir);
448   return -1;
449 }