root/trunk/intl/printf-parse.c

Revision 2, 11.7 kB (checked in by jordi, 2 years ago)

Added the initial source layout with autotools and gettext support. Still no code for the project.

Line 
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
Note: See TracBrowser for help on using the browser.