[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / glib / gnulib / 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, see <http://www.gnu.org/licenses/>.  */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include "g-gnulib.h"
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_INT64_AND_I64
288                   else if (cp[0] == 'I' && 
289                            cp[1] == '6' &&
290                            cp[2] == '4')
291                     {
292                       flags = 64;
293                       cp += 3;
294                     }
295 #endif
296 #ifdef HAVE_INTMAX_T
297                   else if (*cp == 'j')
298                     {
299                       if (sizeof (intmax_t) > sizeof (long))
300                         {
301                           /* intmax_t = long long */
302                           flags += 16;
303                         }
304                       else if (sizeof (intmax_t) > sizeof (int))
305                         {
306                           /* intmax_t = long */
307                           flags += 8;
308                         }
309                       cp++;
310                     }
311 #endif
312                   else if (*cp == 'z' || *cp == 'Z')
313                     {
314                       /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
315                          because the warning facility in gcc-2.95.2 understands
316                          only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
317                       if (sizeof (size_t) > sizeof (long))
318                         {
319                           /* size_t = long long */
320                           flags += 16;
321                         }
322                       else if (sizeof (size_t) > sizeof (int))
323                         {
324                           /* size_t = long */
325                           flags += 8;
326                         }
327                       cp++;
328                     }
329                   else if (*cp == 't')
330                     {
331                       if (sizeof (ptrdiff_t) > sizeof (long))
332                         {
333                           /* ptrdiff_t = long long */
334                           flags += 16;
335                         }
336                       else if (sizeof (ptrdiff_t) > sizeof (int))
337                         {
338                           /* ptrdiff_t = long */
339                           flags += 8;
340                         }
341                       cp++;
342                     }
343                   else
344                     break;
345                 }
346
347               /* Read the conversion character.  */
348               c = *cp++;
349               switch (c)
350                 {
351                 case 'd': case 'i':
352 #ifdef HAVE_INT64_AND_I64
353                   if (flags == 64) 
354                     type = TYPE_INT64;
355                   else
356 #endif
357 #ifdef HAVE_LONG_LONG
358                   if (flags >= 16 || (flags & 4))
359                     type = TYPE_LONGLONGINT;
360                   else
361 #endif
362                   if (flags >= 8)
363                     type = TYPE_LONGINT;
364                   else if (flags & 2)
365                     type = TYPE_SCHAR;
366                   else if (flags & 1)
367                     type = TYPE_SHORT;
368                   else
369                     type = TYPE_INT;
370                   break;
371                 case 'o': case 'u': case 'x': case 'X':
372 #ifdef HAVE_INT64_AND_I64
373                   if (flags == 64)
374                     type = TYPE_UINT64;
375                   else
376 #endif
377 #ifdef HAVE_LONG_LONG
378                   if (flags >= 16 || (flags & 4))
379                     type = TYPE_ULONGLONGINT;
380                   else
381 #endif
382                   if (flags >= 8)
383                     type = TYPE_ULONGINT;
384                   else if (flags & 2)
385                     type = TYPE_UCHAR;
386                   else if (flags & 1)
387                     type = TYPE_USHORT;
388                   else
389                     type = TYPE_UINT;
390                   break;
391                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
392                 case 'a': case 'A':
393 #ifdef HAVE_LONG_DOUBLE
394                   if (flags >= 16 || (flags & 4))
395                     type = TYPE_LONGDOUBLE;
396                   else
397 #endif
398                   type = TYPE_DOUBLE;
399                   break;
400                 case 'c':
401                   if (flags >= 8)
402 #ifdef HAVE_WINT_T
403                     type = TYPE_WIDE_CHAR;
404 #else
405                     goto error;
406 #endif
407                   else
408                     type = TYPE_CHAR;
409                   break;
410 #ifdef HAVE_WINT_T
411                 case 'C':
412                   type = TYPE_WIDE_CHAR;
413                   c = 'c';
414                   break;
415 #endif
416                 case 's':
417                   if (flags >= 8)
418 #ifdef HAVE_WCHAR_T
419                     type = TYPE_WIDE_STRING;
420 #else
421                     goto error;
422 #endif
423                   else
424                     type = TYPE_STRING;
425                   break;
426 #ifdef HAVE_WCHAR_T
427                 case 'S':
428                   type = TYPE_WIDE_STRING;
429                   c = 's';
430                   break;
431 #endif
432                 case 'p':
433                   type = TYPE_POINTER;
434                   break;
435                 case 'n':
436 #ifdef HAVE_LONG_LONG
437                   if (flags >= 16 || (flags & 4))
438                     type = TYPE_COUNT_LONGLONGINT_POINTER;
439                   else
440 #endif
441                   if (flags >= 8)
442                     type = TYPE_COUNT_LONGINT_POINTER;
443                   else if (flags & 2)
444                     type = TYPE_COUNT_SCHAR_POINTER;
445                   else if (flags & 1)
446                     type = TYPE_COUNT_SHORT_POINTER;
447                   else
448                     type = TYPE_COUNT_INT_POINTER;
449                   break;
450                 case '%':
451                   type = TYPE_NONE;
452                   break;
453                 default:
454                   /* Unknown conversion character.  */
455                   goto error;
456                 }
457             }
458
459             if (type != TYPE_NONE)
460               {
461                 dp->arg_index = arg_index;
462                 if (dp->arg_index < 0)
463                   dp->arg_index = arg_posn++;
464                 REGISTER_ARG (dp->arg_index, type);
465               }
466             dp->conversion = c;
467             dp->dir_end = cp;
468           }
469
470           d->count++;
471           if (d->count >= d_allocated)
472             {
473               char_directive *memory;
474
475               d_allocated = 2 * d_allocated;
476               memory = realloc (d->dir, d_allocated * sizeof (char_directive));
477               if (memory == NULL)
478                 /* Out of memory.  */
479                 goto error;
480               d->dir = memory;
481             }
482         }
483     }
484   d->dir[d->count].dir_start = cp;
485
486   d->max_width_length = max_width_length;
487   d->max_precision_length = max_precision_length;
488   return 0;
489
490 error:
491   if (a->arg)
492     free (a->arg);
493   if (d->dir)
494     free (d->dir);
495   return -1;
496 }