Statistics
| Revision:

root / intl / printf-parse.c @ 1

History | View | Annotate | Download (11.7 KB)

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
#if WIDE_CHAR_VERSION
25
# include "wprintf-parse.h"
26
#else
27
# include "printf-parse.h"
28
#endif
29

    
30
/* Get size_t, NULL.  */
31
#include <stddef.h>
32

    
33
/* Get intmax_t.  */
34
#if HAVE_STDINT_H_WITH_UINTMAX
35
# include <stdint.h>
36
#endif
37
#if HAVE_INTTYPES_H_WITH_UINTMAX
38
# include <inttypes.h>
39
#endif
40

    
41
/* malloc(), realloc(), free().  */
42
#include <stdlib.h>
43

    
44
/* Checked size_t computations.  */
45
#include "xsize.h"
46

    
47
#if WIDE_CHAR_VERSION
48
# define PRINTF_PARSE wprintf_parse
49
# define CHAR_T wchar_t
50
# define DIRECTIVE wchar_t_directive
51
# define DIRECTIVES wchar_t_directives
52
#else
53
# define PRINTF_PARSE printf_parse
54
# define CHAR_T char
55
# define DIRECTIVE char_directive
56
# define DIRECTIVES char_directives
57
#endif
58

    
59
#ifdef STATIC
60
STATIC
61
#endif
62
int
63
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
64
{
65
  const CHAR_T *cp = format;                /* pointer into format */
66
  size_t arg_posn = 0;                /* number of regular arguments consumed */
67
  size_t d_allocated;                        /* allocated elements of d->dir */
68
  size_t a_allocated;                        /* allocated elements of a->arg */
69
  size_t max_width_length = 0;
70
  size_t max_precision_length = 0;
71

    
72
  d->count = 0;
73
  d_allocated = 1;
74
  d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
75
  if (d->dir == NULL)
76
    /* Out of memory.  */
77
    return -1;
78

    
79
  a->count = 0;
80
  a_allocated = 0;
81
  a->arg = NULL;
82

    
83
#define REGISTER_ARG(_index_,_type_) \
84
  {                                                                        \
85
    size_t n = (_index_);                                                \
86
    if (n >= a_allocated)                                                \
87
      {                                                                        \
88
        size_t memory_size;                                                \
89
        argument *memory;                                                \
90
                                                                        \
91
        a_allocated = xtimes (a_allocated, 2);                                \
92
        if (a_allocated <= n)                                                \
93
          a_allocated = xsum (n, 1);                                        \
94
        memory_size = xtimes (a_allocated, sizeof (argument));                \
95
        if (size_overflow_p (memory_size))                                \
96
          /* Overflow, would lead to out of memory.  */                        \
97
          goto error;                                                        \
98
        memory = (a->arg                                                \
99
                  ? realloc (a->arg, memory_size)                        \
100
                  : malloc (memory_size));                                \
101
        if (memory == NULL)                                                \
102
          /* Out of memory.  */                                                \
103
          goto error;                                                        \
104
        a->arg = memory;                                                \
105
      }                                                                        \
106
    while (a->count <= n)                                                \
107
      a->arg[a->count++].type = TYPE_NONE;                                \
108
    if (a->arg[n].type == TYPE_NONE)                                        \
109
      a->arg[n].type = (_type_);                                        \
110
    else if (a->arg[n].type != (_type_))                                \
111
      /* Ambiguous type for positional argument.  */                        \
112
      goto error;                                                        \
113
  }
114

    
115
  while (*cp != '\0')
116
    {
117
      CHAR_T c = *cp++;
118
      if (c == '%')
119
        {
120
          size_t arg_index = ARG_NONE;
121
          DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
122

    
123
          /* Initialize the next directive.  */
124
          dp->dir_start = cp - 1;
125
          dp->flags = 0;
126
          dp->width_start = NULL;
127
          dp->width_end = NULL;
128
          dp->width_arg_index = ARG_NONE;
129
          dp->precision_start = NULL;
130
          dp->precision_end = NULL;
131
          dp->precision_arg_index = ARG_NONE;
132
          dp->arg_index = ARG_NONE;
133

    
134
          /* Test for positional argument.  */
135
          if (*cp >= '0' && *cp <= '9')
136
            {
137
              const CHAR_T *np;
138

    
139
              for (np = cp; *np >= '0' && *np <= '9'; np++)
140
                ;
141
              if (*np == '$')
142
                {
143
                  size_t n = 0;
144

    
145
                  for (np = cp; *np >= '0' && *np <= '9'; np++)
146
                    n = xsum (xtimes (n, 10), *np - '0');
147
                  if (n == 0)
148
                    /* Positional argument 0.  */
149
                    goto error;
150
                  if (size_overflow_p (n))
151
                    /* n too large, would lead to out of memory later.  */
152
                    goto error;
153
                  arg_index = n - 1;
154
                  cp = np + 1;
155
                }
156
            }
157

    
158
          /* Read the flags.  */
159
          for (;;)
160
            {
161
              if (*cp == '\'')
162
                {
163
                  dp->flags |= FLAG_GROUP;
164
                  cp++;
165
                }
166
              else if (*cp == '-')
167
                {
168
                  dp->flags |= FLAG_LEFT;
169
                  cp++;
170
                }
171
              else if (*cp == '+')
172
                {
173
                  dp->flags |= FLAG_SHOWSIGN;
174
                  cp++;
175
                }
176
              else if (*cp == ' ')
177
                {
178
                  dp->flags |= FLAG_SPACE;
179
                  cp++;
180
                }
181
              else if (*cp == '#')
182
                {
183
                  dp->flags |= FLAG_ALT;
184
                  cp++;
185
                }
186
              else if (*cp == '0')
187
                {
188
                  dp->flags |= FLAG_ZERO;
189
                  cp++;
190
                }
191
              else
192
                break;
193
            }
194

    
195
          /* Parse the field width.  */
196
          if (*cp == '*')
197
            {
198
              dp->width_start = cp;
199
              cp++;
200
              dp->width_end = cp;
201
              if (max_width_length < 1)
202
                max_width_length = 1;
203

    
204
              /* Test for positional argument.  */
205
              if (*cp >= '0' && *cp <= '9')
206
                {
207
                  const CHAR_T *np;
208

    
209
                  for (np = cp; *np >= '0' && *np <= '9'; np++)
210
                    ;
211
                  if (*np == '$')
212
                    {
213
                      size_t n = 0;
214

    
215
                      for (np = cp; *np >= '0' && *np <= '9'; np++)
216
                        n = xsum (xtimes (n, 10), *np - '0');
217
                      if (n == 0)
218
                        /* Positional argument 0.  */
219
                        goto error;
220
                      if (size_overflow_p (n))
221
                        /* n too large, would lead to out of memory later.  */
222
                        goto error;
223
                      dp->width_arg_index = n - 1;
224
                      cp = np + 1;
225
                    }
226
                }
227
              if (dp->width_arg_index == ARG_NONE)
228
                {
229
                  dp->width_arg_index = arg_posn++;
230
                  if (dp->width_arg_index == ARG_NONE)
231
                    /* arg_posn wrapped around.  */
232
                    goto error;
233
                }
234
              REGISTER_ARG (dp->width_arg_index, TYPE_INT);
235
            }
236
          else if (*cp >= '0' && *cp <= '9')
237
            {
238
              size_t width_length;
239

    
240
              dp->width_start = cp;
241
              for (; *cp >= '0' && *cp <= '9'; cp++)
242
                ;
243
              dp->width_end = cp;
244
              width_length = dp->width_end - dp->width_start;
245
              if (max_width_length < width_length)
246
                max_width_length = width_length;
247
            }
248

    
249
          /* Parse the precision.  */
250
          if (*cp == '.')
251
            {
252
              cp++;
253
              if (*cp == '*')
254
                {
255
                  dp->precision_start = cp - 1;
256
                  cp++;
257
                  dp->precision_end = cp;
258
                  if (max_precision_length < 2)
259
                    max_precision_length = 2;
260

    
261
                  /* Test for positional argument.  */
262
                  if (*cp >= '0' && *cp <= '9')
263
                    {
264
                      const CHAR_T *np;
265

    
266
                      for (np = cp; *np >= '0' && *np <= '9'; np++)
267
                        ;
268
                      if (*np == '$')
269
                        {
270
                          size_t n = 0;
271

    
272
                          for (np = cp; *np >= '0' && *np <= '9'; np++)
273
                            n = xsum (xtimes (n, 10), *np - '0');
274
                          if (n == 0)
275
                            /* Positional argument 0.  */
276
                            goto error;
277
                          if (size_overflow_p (n))
278
                            /* n too large, would lead to out of memory
279
                               later.  */
280
                            goto error;
281
                          dp->precision_arg_index = n - 1;
282
                          cp = np + 1;
283
                        }
284
                    }
285
                  if (dp->precision_arg_index == ARG_NONE)
286
                    {
287
                      dp->precision_arg_index = arg_posn++;
288
                      if (dp->precision_arg_index == ARG_NONE)
289
                        /* arg_posn wrapped around.  */
290
                        goto error;
291
                    }
292
                  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
293
                }
294
              else
295
                {
296
                  size_t precision_length;
297

    
298
                  dp->precision_start = cp - 1;
299
                  for (; *cp >= '0' && *cp <= '9'; cp++)
300
                    ;
301
                  dp->precision_end = cp;
302
                  precision_length = dp->precision_end - dp->precision_start;
303
                  if (max_precision_length < precision_length)
304
                    max_precision_length = precision_length;
305
                }
306
            }
307

    
308
          {
309
            arg_type type;
310

    
311
            /* Parse argument type/size specifiers.  */
312
            {
313
              int flags = 0;
314

    
315
              for (;;)
316
                {
317
                  if (*cp == 'h')
318
                    {
319
                      flags |= (1 << (flags & 1));
320
                      cp++;
321
                    }
322
                  else if (*cp == 'L')
323
                    {
324
                      flags |= 4;
325
                      cp++;
326
                    }
327
                  else if (*cp == 'l')
328
                    {
329
                      flags += 8;
330
                      cp++;
331
                    }
332
#ifdef HAVE_INTMAX_T
333
                  else if (*cp == 'j')
334
                    {
335
                      if (sizeof (intmax_t) > sizeof (long))
336
                        {
337
                          /* intmax_t = long long */
338
                          flags += 16;
339
                        }
340
                      else if (sizeof (intmax_t) > sizeof (int))
341
                        {
342
                          /* intmax_t = long */
343
                          flags += 8;
344
                        }
345
                      cp++;
346
                    }
347
#endif
348
                  else if (*cp == 'z' || *cp == 'Z')
349
                    {
350
                      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
351
                         because the warning facility in gcc-2.95.2 understands
352
                         only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
353
                      if (sizeof (size_t) > sizeof (long))
354
                        {
355
                          /* size_t = long long */
356
                          flags += 16;
357
                        }
358
                      else if (sizeof (size_t) > sizeof (int))
359
                        {
360
                          /* size_t = long */
361
                          flags += 8;
362
                        }
363
                      cp++;
364
                    }
365
                  else if (*cp == 't')
366
                    {
367
                      if (sizeof (ptrdiff_t) > sizeof (long))
368
                        {
369
                          /* ptrdiff_t = long long */
370
                          flags += 16;
371
                        }
372
                      else if (sizeof (ptrdiff_t) > sizeof (int))
373
                        {
374
                          /* ptrdiff_t = long */
375
                          flags += 8;
376
                        }
377
                      cp++;
378
                    }
379
                  else
380
                    break;
381
                }
382

    
383
              /* Read the conversion character.  */
384
              c = *cp++;
385
              switch (c)
386
                {
387
                case 'd': case 'i':
388
#ifdef HAVE_LONG_LONG
389
                  if (flags >= 16 || (flags & 4))
390
                    type = TYPE_LONGLONGINT;
391
                  else
392
#endif
393
                  if (flags >= 8)
394
                    type = TYPE_LONGINT;
395
                  else if (flags & 2)
396
                    type = TYPE_SCHAR;
397
                  else if (flags & 1)
398
                    type = TYPE_SHORT;
399
                  else
400
                    type = TYPE_INT;
401
                  break;
402
                case 'o': case 'u': case 'x': case 'X':
403
#ifdef HAVE_LONG_LONG
404
                  if (flags >= 16 || (flags & 4))
405
                    type = TYPE_ULONGLONGINT;
406
                  else
407
#endif
408
                  if (flags >= 8)
409
                    type = TYPE_ULONGINT;
410
                  else if (flags & 2)
411
                    type = TYPE_UCHAR;
412
                  else if (flags & 1)
413
                    type = TYPE_USHORT;
414
                  else
415
                    type = TYPE_UINT;
416
                  break;
417
                case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
418
                case 'a': case 'A':
419
#ifdef HAVE_LONG_DOUBLE
420
                  if (flags >= 16 || (flags & 4))
421
                    type = TYPE_LONGDOUBLE;
422
                  else
423
#endif
424
                  type = TYPE_DOUBLE;
425
                  break;
426
                case 'c':
427
                  if (flags >= 8)
428
#ifdef HAVE_WINT_T
429
                    type = TYPE_WIDE_CHAR;
430
#else
431
                    goto error;
432
#endif
433
                  else
434
                    type = TYPE_CHAR;
435
                  break;
436
#ifdef HAVE_WINT_T
437
                case 'C':
438
                  type = TYPE_WIDE_CHAR;
439
                  c = 'c';
440
                  break;
441
#endif
442
                case 's':
443
                  if (flags >= 8)
444
#ifdef HAVE_WCHAR_T
445
                    type = TYPE_WIDE_STRING;
446
#else
447
                    goto error;
448
#endif
449
                  else
450
                    type = TYPE_STRING;
451
                  break;
452
#ifdef HAVE_WCHAR_T
453
                case 'S':
454
                  type = TYPE_WIDE_STRING;
455
                  c = 's';
456
                  break;
457
#endif
458
                case 'p':
459
                  type = TYPE_POINTER;
460
                  break;
461
                case 'n':
462
#ifdef HAVE_LONG_LONG
463
                  if (flags >= 16 || (flags & 4))
464
                    type = TYPE_COUNT_LONGLONGINT_POINTER;
465
                  else
466
#endif
467
                  if (flags >= 8)
468
                    type = TYPE_COUNT_LONGINT_POINTER;
469
                  else if (flags & 2)
470
                    type = TYPE_COUNT_SCHAR_POINTER;
471
                  else if (flags & 1)
472
                    type = TYPE_COUNT_SHORT_POINTER;
473
                  else
474
                    type = TYPE_COUNT_INT_POINTER;
475
                  break;
476
                case '%':
477
                  type = TYPE_NONE;
478
                  break;
479
                default:
480
                  /* Unknown conversion character.  */
481
                  goto error;
482
                }
483
            }
484

    
485
            if (type != TYPE_NONE)
486
              {
487
                dp->arg_index = arg_index;
488
                if (dp->arg_index == ARG_NONE)
489
                  {
490
                    dp->arg_index = arg_posn++;
491
                    if (dp->arg_index == ARG_NONE)
492
                      /* arg_posn wrapped around.  */
493
                      goto error;
494
                  }
495
                REGISTER_ARG (dp->arg_index, type);
496
              }
497
            dp->conversion = c;
498
            dp->dir_end = cp;
499
          }
500

    
501
          d->count++;
502
          if (d->count >= d_allocated)
503
            {
504
              size_t memory_size;
505
              DIRECTIVE *memory;
506

    
507
              d_allocated = xtimes (d_allocated, 2);
508
              memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
509
              if (size_overflow_p (memory_size))
510
                /* Overflow, would lead to out of memory.  */
511
                goto error;
512
              memory = realloc (d->dir, memory_size);
513
              if (memory == NULL)
514
                /* Out of memory.  */
515
                goto error;
516
              d->dir = memory;
517
            }
518
        }
519
    }
520
  d->dir[d->count].dir_start = cp;
521

    
522
  d->max_width_length = max_width_length;
523
  d->max_precision_length = max_precision_length;
524
  return 0;
525

    
526
error:
527
  if (a->arg)
528
    free (a->arg);
529
  if (d->dir)
530
    free (d->dir);
531
  return -1;
532
}
533

    
534
#undef DIRECTIVES
535
#undef DIRECTIVE
536
#undef CHAR_T
537
#undef PRINTF_PARSE