fce56867c5a2e49135fbd945e338447cddee73cd
[gnupg.git] / common / estream-printf.c
1 /* estream-printf.c - Versatile C-99 compliant printf formatting
2  * Copyright (C) 2007 g10 Code GmbH
3  *
4  * This file is part of Libestream.
5  *
6  * Libestream is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * Libestream is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Libestream; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  *
21  * $Id: estream-printf.c 56 2007-05-15 18:38:43Z wk $
22  */
23
24 /*  Required autoconf tests:
25
26     AC_TYPE_LONG_LONG_INT            defines HAVE_LONG_LONG_INT
27     AC_TYPE_LONG_DOUBLE              defines HAVE_LONG_DOUBLE
28     AC_TYPE_INTMAX_T                 defines HAVE_INTMAX_T
29     AC_TYPE_UINTMAX_T                defines HAVE_UINTMAX_T
30     AC_CHECK_TYPES([ptrdiff_t])      defines HAVE_PTRDIFF_T
31     AC_CHECK_SIZEOF([unsigned long]) defines SIZEOF_UNSIGNED_LONG
32     AC_CHECK_SIZEOF([void *])        defines SIZEOF_VOID_P
33                                              HAVE_LANGINFO_THOUSANDS_SEP
34
35     Note that the file estream.m4 provides the autoconf macro
36     ESTREAM_PRINTF_INIT which runs all required checks.
37     See estream-printf.h for ways to tune this code.
38
39   Missing stuff:  wchar and wint_t
40                   thousands_sep in pr_float.
41 */
42
43 #ifdef HAVE_CONFIG_H
44 # include <config.h>
45 #endif
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <stdarg.h>
52 #include <errno.h>
53 #include <stddef.h>
54 #include <assert.h>
55 #if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T)
56 # include <stdint.h>
57 #endif
58 #ifdef HAVE_LANGINFO_THOUSANDS_SEP
59 #include <langinfo.h>
60 #endif
61 #ifdef TEST
62 # include <locale.h>
63 #endif
64 #ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE
65 #include _ESTREAM_PRINTF_EXTRA_INCLUDE
66 #endif
67 #include "estream-printf.h"
68
69 /* Allow redefinition of asprintf used malloc functions.  */
70 #ifdef _ESTREAM_PRINTF_MALLOC
71 #define my_printf_malloc(a) _ESTREAM_PRINTF_MALLOC((a))  
72 #else
73 #define my_printf_malloc(a) malloc((a))
74 #endif
75 #ifdef _ESTREAM_PRINTF_FREE
76 #define my_printf_free(a)   _ESTREAM_PRINTF_FREE((a))  
77 #else
78 #define my_printf_free(a)   free((a))
79 #endif
80
81
82 /* Calculate array dimension.  */
83 #ifndef DIM
84 #define DIM(array) (sizeof (array) / sizeof (*array))
85 #endif
86
87
88 /* We allow for that many args without requiring malloced memory. */
89 #define DEFAULT_MAX_ARGSPECS  5
90
91 /* We allow for that many values without requiring malloced memory. */
92 #define DEFAULT_MAX_VALUES  8
93
94 /* We allocate this many new array argspec elements each time.  */
95 #define ARGSPECS_BUMP_VALUE   10
96
97 /* Special values for the field width and the precision.  */
98 #define NO_FIELD_VALUE   (-1)
99 #define STAR_FIELD_VALUE (-2)
100
101 /* Bit valuues used for the conversion flags. */
102 #define FLAG_GROUPING   1
103 #define FLAG_LEFT_JUST  2
104 #define FLAG_PLUS_SIGN  4
105 #define FLAG_SPACE_PLUS 8
106 #define FLAG_ALT_CONV   16
107 #define FLAG_ZERO_PAD   32
108
109 /* Constants used the length modifiers.  */
110 typedef enum
111   {
112     LENMOD_NONE = 0,
113     LENMOD_CHAR,     /* "hh" */
114     LENMOD_SHORT,    /* "h"  */
115     LENMOD_LONG,     /* "l"  */
116     LENMOD_LONGLONG, /* "ll" */
117     LENMOD_INTMAX,   /* "j"  */
118     LENMOD_SIZET,    /* "z"  */
119     LENMOD_PTRDIFF,  /* "t"  */
120     LENMOD_LONGDBL   /* "L"  */
121   } lenmod_t;
122
123 /* All the conversion specifiers.  */
124 typedef enum
125   {
126     CONSPEC_UNKNOWN = 0,
127     CONSPEC_DECIMAL,
128     CONSPEC_OCTAL,
129     CONSPEC_UNSIGNED,
130     CONSPEC_HEX,
131     CONSPEC_HEX_UP,
132     CONSPEC_FLOAT,
133     CONSPEC_FLOAT_UP,
134     CONSPEC_EXP,
135     CONSPEC_EXP_UP,
136     CONSPEC_F_OR_G,
137     CONSPEC_F_OR_G_UP,
138     CONSPEC_HEX_EXP,
139     CONSPEC_HEX_EXP_UP,
140     CONSPEC_CHAR,
141     CONSPEC_STRING,
142     CONSPEC_POINTER,
143     CONSPEC_STRERROR,
144     CONSPEC_BYTES_SO_FAR
145   } conspec_t;
146
147
148 /* Constants describing all the suppoorted types.  Note that we list
149    all the types we know about even if certain types are not available
150    on this system. */
151 typedef enum
152   {
153     VALTYPE_UNSUPPORTED = 0,  /* Artificial type for error detection.  */
154     VALTYPE_CHAR,
155     VALTYPE_SCHAR,
156     VALTYPE_UCHAR,
157     VALTYPE_SHORT,
158     VALTYPE_USHORT,
159     VALTYPE_INT,
160     VALTYPE_UINT,
161     VALTYPE_LONG,
162     VALTYPE_ULONG,
163     VALTYPE_LONGLONG,
164     VALTYPE_ULONGLONG,
165     VALTYPE_DOUBLE,
166     VALTYPE_LONGDOUBLE,
167     VALTYPE_STRING,
168     VALTYPE_INTMAX,
169     VALTYPE_UINTMAX,
170     VALTYPE_SIZE,
171     VALTYPE_PTRDIFF,
172     VALTYPE_POINTER,
173     VALTYPE_CHAR_PTR,
174     VALTYPE_SCHAR_PTR,
175     VALTYPE_SHORT_PTR,
176     VALTYPE_INT_PTR,
177     VALTYPE_LONG_PTR,
178     VALTYPE_LONGLONG_PTR,
179     VALTYPE_INTMAX_PTR,
180     VALTYPE_SIZE_PTR,
181     VALTYPE_PTRDIFF_PTR
182   } valtype_t;
183
184
185 /* A union used to store the actual values. */
186 typedef union 
187 {
188   char a_char;
189   signed char a_schar;
190   unsigned char a_uchar;
191   short a_short;
192   unsigned short a_ushort;
193   int a_int;
194   unsigned int a_uint;
195   long int a_long;
196   unsigned long int a_ulong;
197 #ifdef HAVE_LONG_LONG_INT
198   long long int a_longlong;
199   unsigned long long int a_ulonglong;
200 #endif
201   double a_double;
202 #ifdef HAVE_LONG_DOUBLE
203   long double a_longdouble;
204 #endif
205   const char *a_string;
206 #ifdef HAVE_INTMAX_T
207   intmax_t a_intmax;
208 #endif
209 #ifdef HAVE_UINTMAX_T
210   intmax_t a_uintmax;
211 #endif
212   size_t a_size;
213 #ifdef HAVE_PTRDIFF_T
214   ptrdiff_t a_ptrdiff;
215 #endif
216   void *a_void_ptr;
217   char *a_char_ptr;
218   signed char *a_schar_ptr;
219   short *a_short_ptr;
220   int  *a_int_ptr;
221   long *a_long_ptr;
222 #ifdef HAVE_LONG_LONG_INT
223   long long int *a_longlong_ptr;
224 #endif
225 #ifdef HAVE_INTMAX_T
226   intmax_t *a_intmax_ptr;
227 #endif
228   size_t *a_size_ptr;
229 #ifdef HAVE_PTRDIFF_T
230   ptrdiff_t *a_ptrdiff_ptr;
231 #endif
232 } value_t;
233
234 /* An object used to keep track of a format option and arguments. */
235 struct argspec_s
236 {
237   size_t length;       /* The length of these args including the percent.  */
238   unsigned int flags;  /* The conversion flags (bits defined by FLAG_foo).  */
239   int width;           /* The field width.  */
240   int precision;       /* The precision.  */
241   lenmod_t lenmod;     /* The length modifier.  */
242   conspec_t conspec;   /* The conversion specifier.  */
243   int arg_pos;         /* The position of the argument.  This one may
244                           be -1 to indicate that no value is expected
245                           (e.g. for "%m").  */
246   int width_pos;       /* The position of the argument for a field
247                           width star's value. 0 for not used.  */
248   int precision_pos;   /* The position of the argument for the a
249                           precision star's value.  0 for not used. */
250   valtype_t vt;        /* The type of the corresponding argument.  */
251 };
252 typedef struct argspec_s *argspec_t;
253
254 /* An object to build up a table of values and their types.  */
255 struct valueitem_s
256 {
257   valtype_t vt;  /* The type of the value.  */
258   value_t value; /* The value.  */
259 };
260 typedef struct valueitem_s *valueitem_t;
261
262
263 #ifdef TEST
264 static int verbose; 
265
266 static void
267 dump_argspecs (argspec_t arg, size_t argcount)
268 {
269   int idx;
270
271   for (idx=0; argcount; argcount--, arg++, idx++)
272     fprintf (stderr, 
273              "%2d: len=%u flags=%u width=%d prec=%d mod=%d "
274              "con=%d vt=%d pos=%d-%d-%d\n",
275              idx,
276              (unsigned int)arg->length,
277              arg->flags,
278              arg->width,
279              arg->precision,
280              arg->lenmod,
281              arg->conspec,
282              arg->vt,
283              arg->arg_pos,
284              arg->width_pos,
285              arg->precision_pos);
286 }
287 #endif /*TEST*/
288
289
290 /* Set the vt field for ARG.  */
291 static void
292 compute_type (argspec_t arg)
293 {
294   switch (arg->conspec)
295     {
296     case CONSPEC_UNKNOWN: 
297       arg->vt = VALTYPE_UNSUPPORTED; 
298       break;
299
300     case CONSPEC_DECIMAL:
301       switch (arg->lenmod)
302         {
303         case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR; break;
304         case LENMOD_SHORT: arg->vt = VALTYPE_SHORT; break;
305         case LENMOD_LONG: arg->vt = VALTYPE_LONG; break;
306         case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG; break;
307         case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX; break;
308         case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;   
309         case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
310         default: arg->vt = VALTYPE_INT; break;
311         }
312       break;
313
314     case CONSPEC_OCTAL:
315     case CONSPEC_UNSIGNED:
316     case CONSPEC_HEX:
317     case CONSPEC_HEX_UP:
318       switch (arg->lenmod)
319         {
320         case LENMOD_CHAR: arg->vt = VALTYPE_UCHAR; break;
321         case LENMOD_SHORT: arg->vt = VALTYPE_USHORT; break;
322         case LENMOD_LONG: arg->vt = VALTYPE_ULONG; break;
323         case LENMOD_LONGLONG: arg->vt = VALTYPE_ULONGLONG; break;
324         case LENMOD_INTMAX: arg->vt = VALTYPE_UINTMAX; break;
325         case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;   
326         case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
327         default: arg->vt = VALTYPE_UINT; break;
328         }
329       break;
330       
331     case CONSPEC_FLOAT:
332     case CONSPEC_FLOAT_UP:
333     case CONSPEC_EXP:
334     case CONSPEC_EXP_UP:
335     case CONSPEC_F_OR_G:
336     case CONSPEC_F_OR_G_UP:
337     case CONSPEC_HEX_EXP:
338     case CONSPEC_HEX_EXP_UP:
339       switch (arg->lenmod)
340         {
341         case LENMOD_LONGDBL: arg->vt = VALTYPE_LONGDOUBLE; break;
342         case LENMOD_LONG: arg->vt = VALTYPE_DOUBLE; break;
343         default: arg->vt = VALTYPE_DOUBLE; break;
344         }
345       break;
346       
347     case CONSPEC_CHAR:
348       arg->vt = VALTYPE_INT; 
349       break;
350
351     case CONSPEC_STRING:
352       arg->vt = VALTYPE_STRING;
353       break;
354
355     case CONSPEC_POINTER:
356       arg->vt = VALTYPE_POINTER;
357       break;
358
359     case CONSPEC_STRERROR:
360       arg->vt = VALTYPE_STRING;
361       break;
362
363     case CONSPEC_BYTES_SO_FAR:
364       switch (arg->lenmod)
365         {
366         case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR_PTR; break;
367         case LENMOD_SHORT: arg->vt = VALTYPE_SHORT_PTR; break;
368         case LENMOD_LONG: arg->vt = VALTYPE_LONG_PTR; break;
369         case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG_PTR; break;
370         case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX_PTR; break;
371         case LENMOD_SIZET: arg->vt = VALTYPE_SIZE_PTR; break;   
372         case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF_PTR; break;
373         default: arg->vt = VALTYPE_INT_PTR; break;
374         }
375       break;
376       
377     }
378 }
379
380
381
382 /* Parse the FORMAT string and populate the specification array stored
383    at the address ARGSPECS_ADDR.  The caller has provided enough space
384    to store up to MAX_ARGSPECS in that buffer.  The function may
385    however ignore the provided buffer and malloc a larger one.  On
386    success the addrrss of that larger buffer will be stored at
387    ARGSPECS_ADDR.  The actual number of specifications will be
388    returned at R_ARGSPECS_COUNT. */
389 static int
390 parse_format (const char *format,
391               argspec_t *argspecs_addr, size_t max_argspecs,
392               size_t *r_argspecs_count)
393 {
394   const char *s;
395   argspec_t argspecs = *argspecs_addr;
396   argspec_t arg;
397   size_t argcount = 0;
398
399   if (!format)
400     goto leave_einval;
401       
402   for (; *format; format++)
403     {
404       unsigned int flags;
405       int width, precision;
406       lenmod_t lenmod;
407       conspec_t conspec;
408       int arg_pos, width_pos, precision_pos;
409       
410       if (*format != '%')
411         continue;
412       s = ++format;
413       if (!*s)
414         goto leave_einval;
415       if (*s == '%')
416         continue; /* Just a quoted percent.  */
417
418       /* First check whether there is a positional argument.  */
419       arg_pos = 0; /* No positional argument given.  */
420       if (*s >= '1' && *s <= '9')
421         {
422           const char *save_s = s;
423           
424           arg_pos = (*s++ - '0');
425           for (; *s >= '0' && *s <= '9'; s++)
426             arg_pos = 10*arg_pos + (*s - '0');
427           if (arg_pos < 0)
428             goto leave_einval; /* Overflow during conversion.  */
429           if (*s == '$')
430             s++;
431           else
432             {
433               arg_pos = 0;
434               s = save_s;
435             }
436         }
437          
438       /* Parse the flags.  */
439       flags = 0;
440       for ( ; *s; s++)
441         {
442           switch (*s)
443             {
444             case '\'': flags |= FLAG_GROUPING; break;
445             case '-': flags |= FLAG_LEFT_JUST; break;
446             case '+': flags |= FLAG_PLUS_SIGN; break;
447             case ' ': flags |= FLAG_SPACE_PLUS; break;
448             case '#': flags |= FLAG_ALT_CONV; break;
449             case '0': flags |= FLAG_ZERO_PAD; break;
450             default:
451               goto flags_parsed;
452             }
453         }
454     flags_parsed:
455       
456       /* Parse the field width.  */
457       width_pos = 0;
458       if (*s == '*')
459         {
460           width = STAR_FIELD_VALUE;
461           s++;
462           /* If we have a positional argument, another one might also
463              be used to give the position of the star's value. */
464           if (arg_pos && *s >= '1' && *s <= '9')
465             {
466               width_pos = (*s++ - '0');
467               for (; *s >= '0' && *s <= '9'; s++)
468                 width_pos = 10*width_pos + (*s - '0');
469               if (width_pos < 1)
470                 goto leave_einval; /* Overflow during conversion.  */
471               if (*s != '$')
472                 goto leave_einval; /* Not followed by $.  */
473               s++;
474             }
475         }
476       else if ( *s >= '0' && *s <= '9')
477         {
478           width = (*s++ - '0');
479           for (; *s >= '0' && *s <= '9'; s++)
480             {
481               if (!width && *s == '0')
482                 goto leave_einval; /* Leading zeroes are not allowed.
483                                       Fixme: check what other
484                                       implementations do. */
485               width = 10*width + (*s - '0');
486             }
487           if (width < 0)
488             goto leave_einval; /* Overflow during conversion.  */
489         }
490       else
491         width = NO_FIELD_VALUE;
492
493       /* Parse the precision.  */
494       precision_pos = 0;
495       precision = NO_FIELD_VALUE;
496       if (*s == '.')
497         {
498           int ignore_value = (s[1] == '-');
499
500           s++;
501           if (*s == '*')
502             {
503               precision = STAR_FIELD_VALUE;
504               s++;
505               /* If we have a positional argument, another one might also
506                  be used to give the position of the star's value. */
507               if (arg_pos && *s >= '1' && *s <= '9')
508                 {
509                   precision_pos = (*s++ - '0');
510                   for (; *s >= '0' && *s <= '9'; s++)
511                     precision_pos = 10*precision_pos + (*s - '0');
512                   if (precision_pos < 1)
513                     goto leave_einval; /* Overflow during conversion.  */
514                   if (*s != '$')
515                     goto leave_einval; /* Not followed by $.  */
516                   s++;
517                 }
518             }
519           else if ( *s >= '0' && *s <= '9')
520             {
521               precision = (*s++ - '0');
522               for (; *s >= '0' && *s <= '9'; s++)
523                 {
524                   if (!precision && *s == '0')
525                     goto leave_einval; /* Leading zeroes are not allowed.
526                                           Fixme: check what other
527                                           implementations do. */
528                   precision = 10*precision + (*s - '0');
529                 }
530               if (precision < 0)
531                 goto leave_einval; /* Overflow during conversion.  */
532             }
533           else
534             precision = 0;
535           if (ignore_value)
536             precision = NO_FIELD_VALUE;
537         }
538       
539       /* Parse the length modifiers.  */
540       switch (*s)
541         {
542         case 'h': 
543           if (s[1] == 'h')
544             {
545               lenmod = LENMOD_CHAR;
546               s++;
547             }
548           else
549             lenmod = LENMOD_SHORT;
550           s++;
551           break;
552         case 'l':
553           if (s[1] == 'l')
554             {
555               lenmod = LENMOD_LONGLONG;
556               s++;
557             }
558           else
559             lenmod = LENMOD_LONG;
560           s++;
561           break;
562         case 'j': lenmod = LENMOD_INTMAX; s++; break;
563         case 'z': lenmod = LENMOD_SIZET; s++; break;
564         case 't': lenmod = LENMOD_PTRDIFF; s++; break;
565         case 'L': lenmod = LENMOD_LONGDBL; s++; break;
566         default:  lenmod = LENMOD_NONE; break;
567         }
568       
569       /* Parse the conversion specifier.  */
570       switch (*s)
571         {
572         case 'd':
573         case 'i': conspec = CONSPEC_DECIMAL; break;
574         case 'o': conspec = CONSPEC_OCTAL; break;
575         case 'u': conspec = CONSPEC_UNSIGNED; break;
576         case 'x': conspec = CONSPEC_HEX; break;
577         case 'X': conspec = CONSPEC_HEX_UP; break;
578         case 'f': conspec = CONSPEC_FLOAT; break;
579         case 'F': conspec = CONSPEC_FLOAT_UP; break;
580         case 'e': conspec = CONSPEC_EXP; break;
581         case 'E': conspec = CONSPEC_EXP_UP; break;
582         case 'g': conspec = CONSPEC_F_OR_G; break;
583         case 'G': conspec = CONSPEC_F_OR_G_UP; break;
584         case 'a': conspec = CONSPEC_HEX_EXP; break;
585         case 'A': conspec = CONSPEC_HEX_EXP_UP; break;
586         case 'c': conspec = CONSPEC_CHAR; break;
587         case 's': conspec = CONSPEC_STRING; break;
588         case 'p': conspec = CONSPEC_POINTER; break;
589         case 'n': conspec = CONSPEC_BYTES_SO_FAR; break;
590         case 'C': conspec = CONSPEC_CHAR; lenmod = LENMOD_LONG; break;
591         case 'S': conspec = CONSPEC_STRING; lenmod = LENMOD_LONG; break;
592         case 'm': conspec = CONSPEC_STRERROR; arg_pos = -1; break;
593         default: conspec = CONSPEC_UNKNOWN;
594         }
595
596       /* Save the args. */
597       if (argcount >= max_argspecs)
598         {
599           /* We either need to allocate a new array instead of the
600              caller provided one or realloc the array.  Instead of
601              using realloc we allocate a new one and release the
602              original one then. */
603           size_t n, newmax;
604           argspec_t newarg;
605
606           newmax = max_argspecs + ARGSPECS_BUMP_VALUE;
607           if (newmax <= max_argspecs)
608             goto leave_einval;  /* Too many arguments. */
609           newarg = calloc (newmax, sizeof *newarg);
610           if (!newarg)
611             goto leave;
612           for (n=0; n < argcount; n++)
613             newarg[n] = argspecs[n];
614           if (argspecs != *argspecs_addr)
615             free (argspecs);
616           argspecs = newarg;
617           max_argspecs = newmax;
618         }
619
620       arg = argspecs + argcount;
621       arg->length = s - format + 2;
622       arg->flags = flags;
623       arg->width = width;
624       arg->precision = precision;
625       arg->lenmod = lenmod;
626       arg->conspec = conspec;
627       arg->arg_pos = arg_pos;
628       arg->width_pos = width_pos;
629       arg->precision_pos = precision_pos;
630       compute_type (arg);
631       argcount++;
632       format = s;
633     }
634
635   *argspecs_addr = argspecs;
636   *r_argspecs_count = argcount;
637   return 0; /* Success.  */
638   
639  leave_einval:
640   errno = EINVAL;
641  leave:
642   if (argspecs != *argspecs_addr)
643     free (argspecs);
644   *argspecs_addr = NULL;
645   return -1;
646 }
647
648 /* This function is used for testing to provide default arguments.  */
649 static int
650 read_dummy_value (value_t *value, valtype_t vt)
651 {
652   switch (vt)
653     {
654     case VALTYPE_CHAR: value->a_char = 'a'; break;
655     case VALTYPE_CHAR_PTR: value->a_char_ptr = NULL; break;
656     case VALTYPE_SCHAR: value->a_schar = 'a'; break;
657     case VALTYPE_SCHAR_PTR: value->a_schar_ptr = NULL; break;
658     case VALTYPE_UCHAR: value->a_uchar = 'a'; break;
659     case VALTYPE_SHORT: value->a_short = -4711; break;
660     case VALTYPE_USHORT: value->a_ushort = 4711; break;
661     case VALTYPE_SHORT_PTR: value->a_short_ptr = NULL; break;
662     case VALTYPE_INT: value->a_int = 42; break;
663     case VALTYPE_INT_PTR: value->a_int_ptr = NULL; break;
664     case VALTYPE_UINT: value->a_uint = 65535; break;
665     case VALTYPE_LONG: value->a_long = 11071961; break;
666     case VALTYPE_ULONG: value->a_ulong = 19610711; break;
667     case VALTYPE_LONG_PTR: value->a_long_ptr = NULL; break;
668 #ifdef HAVE_LONG_LONG_INT
669     case VALTYPE_LONGLONG: value->a_longlong = 11223344; break;
670     case VALTYPE_ULONGLONG: value->a_ulonglong = 2233445566u; break;
671     case VALTYPE_LONGLONG_PTR: value->a_longlong_ptr = NULL; break;
672 #endif
673     case VALTYPE_DOUBLE: value->a_double = 3.1415926535; break;
674 #ifdef HAVE_LONG_DOUBLE
675     case VALTYPE_LONGDOUBLE: value->a_longdouble = 2.7; break;
676 #endif
677     case VALTYPE_STRING: value->a_string = "heart of gold"; break;
678     case VALTYPE_POINTER: value->a_void_ptr = (void*)0xdeadbeef; break;
679 #ifdef HAVE_INTMAX_T
680     case VALTYPE_INTMAX: value->a_intmax = 100; break;
681     case VALTYPE_INTMAX_PTR: value->a_intmax_ptr = NULL; break;
682 #endif
683 #ifdef HAVE_UINTMAX_T
684     case VALTYPE_UINTMAX: value->a_uintmax = 200; break;
685 #endif
686     case VALTYPE_SIZE: value->a_size = 65537; break;
687     case VALTYPE_SIZE_PTR: value->a_size_ptr = NULL; break;
688 #ifdef HAVE_PTRDIFF_T
689     case VALTYPE_PTRDIFF: value->a_ptrdiff = 2; break;
690     case VALTYPE_PTRDIFF_PTR: value->a_ptrdiff_ptr = NULL; break;
691 #endif
692     default: /* Unsupported type.  */
693       return -1;
694     }
695   return 0;
696 }
697
698
699 /* This function reads all the values as specified by VALUETABLE into
700    VALUETABLE.  The values are expected in VAARGS.  The function
701    returns -1 if a specified type is not supported. */
702 static int
703 read_values (valueitem_t valuetable, size_t valuetable_len, va_list vaargs)
704 {
705   int validx;
706
707   for (validx=0; validx < valuetable_len; validx++)
708     {
709       value_t *value = &valuetable[validx].value;
710       valtype_t vt = valuetable[validx].vt;
711
712       if (!vaargs)
713         {
714           if (read_dummy_value (value, vt))
715             return -1;
716         }
717       else
718         {
719           switch (vt)
720             {
721             case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break;
722             case VALTYPE_CHAR_PTR:
723               value->a_char_ptr = va_arg (vaargs, char *);
724               break;
725             case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break;
726             case VALTYPE_SCHAR_PTR: 
727               value->a_schar_ptr = va_arg (vaargs, signed char *); 
728               break;
729             case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break;
730             case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break;
731             case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break;
732             case VALTYPE_SHORT_PTR: 
733               value->a_short_ptr = va_arg (vaargs, short *); 
734               break;
735             case VALTYPE_INT:
736               value->a_int = va_arg (vaargs, int);
737               break;
738             case VALTYPE_INT_PTR:
739               value->a_int_ptr = va_arg (vaargs, int *);
740               break;
741             case VALTYPE_UINT:
742               value->a_uint = va_arg (vaargs, unsigned int);
743               break;
744             case VALTYPE_LONG:
745               value->a_long = va_arg (vaargs, long);
746               break;
747             case VALTYPE_ULONG: 
748               value->a_ulong = va_arg (vaargs, unsigned long);
749               break;
750             case VALTYPE_LONG_PTR: 
751               value->a_long_ptr = va_arg (vaargs, long *); 
752               break;
753 #ifdef HAVE_LONG_LONG_INT
754             case VALTYPE_LONGLONG:
755               value->a_longlong = va_arg (vaargs, long long int);
756               break;
757             case VALTYPE_ULONGLONG: 
758               value->a_ulonglong = va_arg (vaargs, unsigned long long int); 
759               break;
760             case VALTYPE_LONGLONG_PTR: 
761               value->a_longlong_ptr = va_arg (vaargs, long long *);
762               break;
763 #endif
764             case VALTYPE_DOUBLE:
765               value->a_double = va_arg (vaargs, double);
766               break;
767 #ifdef HAVE_LONG_DOUBLE
768             case VALTYPE_LONGDOUBLE:
769               value->a_longdouble = va_arg (vaargs, long double);
770               break;
771 #endif
772             case VALTYPE_STRING:
773               value->a_string = va_arg (vaargs, const char *);
774               break;
775             case VALTYPE_POINTER: 
776               value->a_void_ptr = va_arg (vaargs, void *);
777               break;
778 #ifdef HAVE_INTMAX_T
779             case VALTYPE_INTMAX:
780               value->a_intmax = va_arg (vaargs, intmax_t);
781               break;
782             case VALTYPE_INTMAX_PTR: 
783               value->a_intmax_ptr = va_arg (vaargs, intmax_t *); 
784               break;
785 #endif
786 #ifdef HAVE_UINTMAX_T
787             case VALTYPE_UINTMAX: 
788               value->a_uintmax = va_arg (vaargs, uintmax_t); 
789               break;
790 #endif
791             case VALTYPE_SIZE:
792               value->a_size = va_arg (vaargs, size_t);
793               break;
794             case VALTYPE_SIZE_PTR: 
795               value->a_size_ptr = va_arg (vaargs, size_t *); 
796               break;
797 #ifdef HAVE_PTRDIFF_T
798             case VALTYPE_PTRDIFF:
799               value->a_ptrdiff = va_arg (vaargs, ptrdiff_t); 
800               break;
801             case VALTYPE_PTRDIFF_PTR:
802               value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *);
803               break;
804 #endif
805             default: /* Unsupported type.  */
806               return -1;
807             }
808         }
809     }
810   return 0;
811 }
812
813
814 \f
815 /* Output COUNT padding characters PADCHAR and update NBYTES by the
816    number of bytes actually written.  */
817 static int
818 pad_out (estream_printf_out_t outfnc, void *outfncarg,
819          int padchar, int count, size_t *nbytes)
820 {
821   char buf[32];
822   size_t n;
823   int rc;
824
825   while (count > 0)
826     {
827       n = (count <= sizeof buf)? count : sizeof buf;
828       memset (buf, padchar, n);
829       rc = outfnc (outfncarg, buf, n);
830       if (rc)
831         return rc;
832       *nbytes += n;
833       count -= n;
834     }
835   
836   return 0;
837 }
838
839
840 /* "d,i,o,u,x,X" formatting.  OUTFNC and OUTFNCARG describes the
841    output routine, ARG gives the argument description and VALUE the
842    actual value (its type is available through arg->vt).  */
843 static int
844 pr_integer (estream_printf_out_t outfnc, void *outfncarg,
845             argspec_t arg, value_t value, size_t *nbytes)
846 {
847   int rc;
848 #ifdef HAVE_LONG_LONG_INT
849   unsigned long long aulong;
850 #else
851   unsigned long aulong;
852 #endif
853   char numbuf[100];
854   char *p, *pend;
855   size_t n;
856   char signchar = 0;
857   int n_prec;  /* Number of extra precision digits required.  */
858   int n_extra; /* Extra number of prefix or sign characters.  */
859
860   if (arg->conspec == CONSPEC_DECIMAL)
861     {
862 #ifdef HAVE_LONG_LONG_INT
863       long long along;
864 #else
865       long along;
866 #endif
867
868       switch (arg->vt)
869         {
870         case VALTYPE_SHORT: along = value.a_short; break;
871         case VALTYPE_INT: along = value.a_int; break;
872         case VALTYPE_LONG: along = value.a_long; break;  
873 #ifdef HAVE_LONG_LONG_INT
874         case VALTYPE_LONGLONG: along = value.a_longlong; break;  
875         case VALTYPE_SIZE: along = value.a_size; break;  
876 # ifdef HAVE_INTMAX_T
877         case VALTYPE_INTMAX: along = value.a_intmax; break;  
878 # endif
879 # ifdef HAVE_PTRDIFF_T
880         case VALTYPE_PTRDIFF: along = value.a_ptrdiff; break;  
881 # endif
882 #endif /*HAVE_LONG_LONG_INT*/
883         default: 
884           return -1;
885         }
886       if (along < 0)
887         {
888           aulong = -along;
889           signchar = '-';
890         }
891       else
892         aulong = along;
893     }
894   else
895     {
896       switch (arg->vt)
897         {
898         case VALTYPE_USHORT: aulong = value.a_ushort; break;
899         case VALTYPE_UINT: aulong = value.a_uint; break;
900         case VALTYPE_ULONG: aulong = value.a_ulong; break;  
901 #ifdef HAVE_LONG_LONG_INT
902         case VALTYPE_ULONGLONG: aulong = value.a_ulonglong; break;  
903         case VALTYPE_SIZE: aulong = value.a_size; break;  
904 # ifdef HAVE_UINTMAX_T
905         case VALTYPE_UINTMAX: aulong = value.a_uintmax; break;  
906 # endif
907 # ifdef HAVE_PTRDIFF_T
908         case VALTYPE_PTRDIFF: aulong = value.a_ptrdiff; break;  
909 # endif
910 #endif /*HAVE_LONG_LONG_INT*/
911         default: 
912           return -1;
913         }
914     }
915
916   if (signchar == '-')
917     ;
918   else if ((arg->flags & FLAG_PLUS_SIGN))
919     signchar = '+';
920   else if ((arg->flags & FLAG_SPACE_PLUS))
921     signchar = ' ';
922
923   n_extra = !!signchar;
924
925   /* We build the string up backwards.  */
926   p = pend = numbuf + DIM(numbuf);
927   if ((!aulong && !arg->precision))
928     ;
929   else if (arg->conspec == CONSPEC_DECIMAL
930            || arg->conspec == CONSPEC_UNSIGNED)
931     {
932       int grouping = -1;
933       const char * grouping_string =
934 #ifdef HAVE_LANGINFO_THOUSANDS_SEP
935         nl_langinfo(THOUSANDS_SEP);
936 #else
937         "'";
938 #endif
939
940       do
941         {
942           if ((arg->flags & FLAG_GROUPING) 
943               && (++grouping == 3) && *grouping_string)
944             {
945               *--p = *grouping_string;
946               grouping = 0;
947             }
948           *--p = '0' + (aulong % 10);
949           aulong /= 10;
950         }
951       while (aulong);
952     }
953   else if (arg->conspec == CONSPEC_OCTAL)
954     {
955       do
956         {
957           *--p = '0' + (aulong % 8);
958           aulong /= 8;
959         }
960       while (aulong);
961       if ((arg->flags & FLAG_ALT_CONV) && *p != '0')
962         *--p = '0';
963     }
964   else /* HEX or HEXUP */
965     {
966       const char *digits = ((arg->conspec == CONSPEC_HEX)
967                             ? "0123456789abcdef" : "0123456789ABCDEF");
968       do
969         {
970           *--p = digits[(aulong % 16)];
971           aulong /= 16;
972         }
973       while (aulong);
974       if ((arg->flags & FLAG_ALT_CONV))
975         n_extra += 2;
976     }
977   
978   n = pend - p;
979
980   if ((arg->flags & FLAG_ZERO_PAD)
981       && arg->precision == NO_FIELD_VALUE && !(arg->flags & FLAG_LEFT_JUST)
982       && n && arg->width - n_extra > n )
983     n_prec = arg->width - n_extra - n;
984   else if (arg->precision > 0 && arg->precision > n)
985     n_prec = arg->precision - n;
986   else
987     n_prec = 0;
988
989   if (!(arg->flags & FLAG_LEFT_JUST)
990       && arg->width >= 0 && arg->width - n_extra > n
991       && arg->width - n_extra - n >= n_prec )
992     {
993       rc = pad_out (outfnc, outfncarg, ' ',
994                     arg->width - n_extra - n - n_prec, nbytes);
995       if (rc)
996         return rc;
997     }
998
999   if (signchar)
1000     {
1001       rc = outfnc (outfncarg, &signchar, 1);
1002       if (rc)
1003         return rc;
1004       *nbytes += 1;
1005     }
1006
1007   if ((arg->flags & FLAG_ALT_CONV)
1008       && (arg->conspec == CONSPEC_HEX || arg->conspec == CONSPEC_HEX_UP))
1009     {
1010       rc = outfnc (outfncarg, arg->conspec == CONSPEC_HEX? "0x": "0X", 2);
1011       if (rc)
1012         return rc;
1013       *nbytes += 2;
1014     }
1015
1016   if (n_prec)
1017     {
1018       rc = pad_out (outfnc, outfncarg, '0', n_prec, nbytes);
1019       if (rc)
1020         return rc;
1021     }
1022       
1023   rc = outfnc (outfncarg, p, pend - p);
1024   if (rc)
1025     return rc;
1026   *nbytes += pend - p;
1027
1028   if ((arg->flags & FLAG_LEFT_JUST)
1029       && arg->width >= 0 && arg->width - n_extra - n_prec > n)
1030     {
1031       rc = pad_out (outfnc, outfncarg, ' ',
1032                     arg->width - n_extra - n_prec - n, nbytes);
1033       if (rc)
1034         return rc;
1035     }
1036
1037   return 0;
1038 }
1039
1040
1041 /* "e,E,f,F,g,G,a,A" formatting.  OUTFNC and OUTFNCARG describes the
1042    output routine, ARG gives the argument description and VALUE the
1043    actual value (its type is available through arg->vt).  For
1044    portability reasons sprintf is used for the actual formatting.
1045    This is useful because sprint is the only standard function to
1046    convert a floating number into its ascii representation.  To avoid
1047    using malloc we just pass the precision to sprintf and do the final
1048    formatting with our own code.  */
1049 static int
1050 pr_float (estream_printf_out_t outfnc, void *outfncarg,
1051           argspec_t arg, value_t value, size_t *nbytes)
1052 {
1053   int rc;
1054 #ifdef HAVE_LONG_DOUBLE
1055   long double adblfloat = 0; /* Just to please gcc.  */
1056   int use_dbl = 0;
1057 #endif
1058   double afloat;
1059   char numbuf[200];
1060   char formatstr[20];
1061   char *p, *pend;
1062   size_t n;
1063   char signchar = 0;
1064   int n_extra;  /* Extra number of prefix or sign characters.  */
1065
1066   switch (arg->vt)
1067     {
1068     case VALTYPE_DOUBLE: afloat = value.a_double; break;
1069 #ifdef HAVE_LONG_DOUBLE
1070     case VALTYPE_LONGDOUBLE:
1071       afloat = 0;  /* Just to please gcc.  */
1072       adblfloat = value.a_longdouble;
1073       use_dbl=1; break;
1074 #endif
1075     default: 
1076       return -1;
1077     }
1078
1079   /* We build the string using sprint.  */
1080   p = formatstr + sizeof formatstr;
1081   *--p = 0;
1082   switch (arg->conspec)
1083     {
1084     case CONSPEC_FLOAT:      *--p = 'f'; break;
1085     case CONSPEC_FLOAT_UP:   *--p = 'F'; break;
1086     case CONSPEC_EXP:        *--p = 'e'; break;
1087     case CONSPEC_EXP_UP:     *--p = 'E'; break;
1088     case CONSPEC_F_OR_G:     *--p = 'g'; break;
1089     case CONSPEC_F_OR_G_UP:  *--p = 'G'; break;
1090     case CONSPEC_HEX_EXP:    *--p = 'a'; break;
1091     case CONSPEC_HEX_EXP_UP: *--p = 'A'; break;
1092     default:
1093       return -1; /* Actually a bug.  */
1094     }
1095 #ifdef HAVE_LONG_DOUBLE
1096   if (use_dbl)
1097     *--p = 'L';
1098 #endif
1099   if (arg->precision != NO_FIELD_VALUE)
1100     {
1101       /* Limit it to a meaningful value so that even a stupid sprintf
1102          won't overflow our buffer.  */
1103       n = arg->precision <= 100? arg->precision : 100;
1104       do
1105         {
1106           *--p = '0' + (n % 10);
1107           n /= 10;
1108         }
1109       while (n);
1110       *--p = '.';
1111     }
1112   if ((arg->flags & FLAG_ALT_CONV))
1113     *--p = '#';
1114   *--p = '%';
1115 #ifdef HAVE_LONG_DOUBLE
1116   if (use_dbl)
1117     sprintf (numbuf, p, adblfloat);
1118   else
1119 #endif /*HAVE_LONG_DOUBLE*/
1120     sprintf (numbuf, p, afloat);
1121   p = numbuf;
1122   n = strlen (numbuf);
1123   pend = p + n;
1124
1125   if (*p =='-')
1126     {
1127       signchar = '-';
1128       p++;
1129       n--;
1130     }
1131   else if ((arg->flags & FLAG_PLUS_SIGN))
1132     signchar = '+';
1133   else if ((arg->flags & FLAG_SPACE_PLUS))
1134     signchar = ' ';
1135
1136   n_extra = !!signchar;
1137
1138   if (!(arg->flags & FLAG_LEFT_JUST)
1139       && arg->width >= 0 && arg->width - n_extra > n)
1140     {
1141       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes);
1142       if (rc)
1143         return rc;
1144     }
1145
1146   if (signchar)
1147     {
1148       rc = outfnc (outfncarg, &signchar, 1);
1149       if (rc)
1150         return rc;
1151       *nbytes += 1;
1152     }
1153
1154   rc = outfnc (outfncarg, p, pend - p);
1155   if (rc)
1156     return rc;
1157   *nbytes += pend - p;
1158
1159   if ((arg->flags & FLAG_LEFT_JUST)
1160       && arg->width >= 0 && arg->width - n_extra > n)
1161     {
1162       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes);
1163       if (rc)
1164         return rc;
1165     }
1166
1167   return 0;
1168 }
1169
1170
1171 /* "c" formatting.  */
1172 static int
1173 pr_char (estream_printf_out_t outfnc, void *outfncarg,
1174             argspec_t arg, value_t value, size_t *nbytes)
1175 {
1176   int rc;
1177   char buf[1];
1178
1179   if (arg->vt != VALTYPE_INT)
1180     return -1;
1181   buf[0] = (unsigned int)value.a_int;
1182   rc = outfnc (outfncarg, buf, 1);
1183   if(rc)
1184     return rc;
1185   *nbytes += 1;
1186   
1187   return 0;
1188 }
1189
1190
1191 /* "s" formatting.  */
1192 static int
1193 pr_string (estream_printf_out_t outfnc, void *outfncarg,
1194             argspec_t arg, value_t value, size_t *nbytes)
1195 {
1196   int rc;
1197   size_t n;
1198   const char *string, *s;
1199
1200   if (arg->vt != VALTYPE_STRING)
1201     return -1;
1202   string = value.a_string;
1203   if (!string)
1204     string = "(null)";
1205   if (arg->precision >= 0)
1206     {
1207       for (n=0,s=string; *s && n < arg->precision; s++) 
1208         n++;
1209     }
1210   else
1211     n = strlen (string);
1212
1213   if (!(arg->flags & FLAG_LEFT_JUST)
1214       && arg->width >= 0 && arg->width > n )
1215     {
1216       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes);
1217       if (rc)
1218         return rc;
1219     }
1220
1221   rc = outfnc (outfncarg, string, n);
1222   if (rc)
1223     return rc;
1224   *nbytes += n;
1225
1226   if ((arg->flags & FLAG_LEFT_JUST)
1227       && arg->width >= 0 && arg->width > n)
1228     {
1229       rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes);
1230       if (rc)
1231         return rc;
1232     }
1233   
1234   return 0;
1235 }
1236
1237
1238 /* "p" formatting.  */
1239 static int
1240 pr_pointer (estream_printf_out_t outfnc, void *outfncarg,
1241             argspec_t arg, value_t value, size_t *nbytes)
1242 {
1243   int rc;
1244 #ifdef HAVE_LONG_LONG_INT
1245   unsigned long long aulong;
1246 #else
1247   unsigned long aulong;
1248 #endif
1249   char numbuf[100];
1250   char *p, *pend;
1251
1252   if (arg->vt != VALTYPE_POINTER)
1253     return -1;
1254   /* We assume that a pointer can be converted to an unsigned long.
1255      That is not correct for a 64 bit Windows, but then we assume that
1256      long long is supported and usable for storing a pointer.  */
1257 #if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P)
1258   aulong = (unsigned long long)value.a_void_ptr;
1259 #else
1260   aulong = (unsigned long)value.a_void_ptr;
1261 #endif
1262
1263   p = pend = numbuf + DIM(numbuf);
1264   do
1265     {
1266       *--p = "0123456789abcdefx"[(aulong % 16)];
1267       aulong /= 16;
1268     }
1269   while (aulong);
1270   while ((pend-p) < 2*sizeof (aulong))
1271     *--p = '0';
1272   *--p = 'x';
1273   *--p = '0';
1274   
1275   rc = outfnc (outfncarg, p, pend - p);
1276   if (rc)
1277     return rc;
1278   *nbytes += pend - p;
1279
1280   return 0;
1281 }
1282
1283 /* "n" pesudo format operation.  */
1284 static int
1285 pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg,
1286                  argspec_t arg, value_t value, size_t *nbytes)
1287 {
1288   switch (arg->vt)
1289     {
1290     case VALTYPE_SCHAR_PTR: 
1291       *value.a_schar_ptr = (signed char)(unsigned int)(*nbytes); 
1292       break;
1293     case VALTYPE_SHORT_PTR:  
1294       *value.a_short_ptr = (short)(unsigned int)(*nbytes);
1295       break;
1296     case VALTYPE_LONG_PTR:     
1297       *value.a_long_ptr = (long)(*nbytes); 
1298       break;
1299 #ifdef HAVE_LONG_LONG_INT
1300     case VALTYPE_LONGLONG_PTR:
1301       *value.a_longlong_ptr = (long long)(*nbytes);
1302       break;
1303 #endif
1304 #ifdef HAVE_INTMAX_T
1305     case VALTYPE_INTMAX_PTR:   
1306       *value.a_intmax_ptr = (intmax_t)(*nbytes);
1307       break;
1308 #endif
1309     case VALTYPE_SIZE_PTR:
1310       *value.a_size_ptr = (*nbytes); 
1311       break;
1312 #ifdef HAVE_PTRDIFF_T
1313     case VALTYPE_PTRDIFF_PTR:
1314       *value.a_ptrdiff_ptr = (ptrdiff_t)(*nbytes);
1315       break;
1316 #endif
1317     case VALTYPE_INT_PTR:
1318       *value.a_int_ptr = (int)(*nbytes);
1319       break;
1320     default:
1321       return -1; /* An unsupported type has been used.  */
1322     }
1323
1324   return 0;
1325 }
1326
1327
1328
1329 /* Run the actual formatting.  OUTFNC and OUTFNCARG are the output
1330    functions.  FORMAT is format string ARGSPECS is the parsed format
1331    string, ARGSPECS_LEN the number of items in ARGSPECS.  VALUETABLE
1332    holds the values and may be directly addressed using the poistion
1333    arguments given by ARGSPECS.  MYERRNO is used for the "%m"
1334    conversion. NBYTES well be updated to reflect the number of bytes
1335    send to the output function. */ 
1336 static int 
1337 do_format (estream_printf_out_t outfnc, void *outfncarg,
1338            const char *format, argspec_t argspecs, size_t argspecs_len,
1339            valueitem_t valuetable, int myerrno, size_t *nbytes)
1340 {
1341   int rc = 0;
1342   const char *s;
1343   argspec_t arg = argspecs;
1344   int argidx = 0; /* Only used for assertion.  */
1345   size_t n;
1346   value_t value;
1347
1348   s = format;
1349   while ( *s )
1350     {
1351       if (*s != '%')
1352         {
1353           s++;
1354           continue;
1355         }
1356       if (s != format)
1357         {
1358           rc = outfnc (outfncarg, format, (n=s-format));
1359           if (rc)
1360             return rc;
1361           *nbytes += n;
1362         }
1363       if (s[1] == '%')
1364         {
1365           /* Note that this code ignores one trailing percent escape -
1366              this is however okay as the args parser must have
1367              detected this already.  */
1368           rc = outfnc (outfncarg, s, 1);
1369           if (rc)
1370             return rc;
1371           *nbytes += 1;
1372           s += 2;
1373           format = s;
1374           continue;
1375         }
1376
1377       /* Save the next start.  */
1378       s += arg->length;
1379       format = s;
1380  
1381       assert (argidx < argspecs_len);
1382       argidx++;
1383
1384       /* Apply indirect field width and precision values.  */
1385       if (arg->width == STAR_FIELD_VALUE)
1386         {
1387           assert (valuetable[arg->width_pos-1].vt == VALTYPE_INT);
1388           arg->width = valuetable[arg->width_pos-1].value.a_int;
1389           if (arg->width < 0)
1390             {
1391               arg->width = -arg->width;
1392               arg->flags |= FLAG_LEFT_JUST;
1393             }
1394         }
1395       if (arg->precision == STAR_FIELD_VALUE)
1396         {
1397           assert (valuetable[arg->precision_pos-1].vt == VALTYPE_INT);
1398           arg->precision = valuetable[arg->precision_pos-1].value.a_int;
1399           if (arg->precision < 0)
1400             arg->precision = NO_FIELD_VALUE;
1401         }
1402
1403       if (arg->arg_pos == -1 && arg->conspec == CONSPEC_STRERROR)
1404         value.a_string = strerror (myerrno);
1405       else
1406         {
1407           assert (arg->vt == valuetable[arg->arg_pos-1].vt);
1408           value = valuetable[arg->arg_pos-1].value;
1409         }
1410
1411       switch (arg->conspec)
1412         {
1413         case CONSPEC_UNKNOWN: assert (!"bug"); break;
1414
1415         case CONSPEC_DECIMAL:
1416         case CONSPEC_UNSIGNED:
1417         case CONSPEC_OCTAL:
1418         case CONSPEC_HEX:
1419         case CONSPEC_HEX_UP:
1420           rc = pr_integer (outfnc, outfncarg, arg, value, nbytes);
1421           break;
1422         case CONSPEC_FLOAT:
1423         case CONSPEC_FLOAT_UP:
1424         case CONSPEC_EXP:
1425         case CONSPEC_EXP_UP:
1426         case CONSPEC_F_OR_G:
1427         case CONSPEC_F_OR_G_UP:
1428         case CONSPEC_HEX_EXP:
1429         case CONSPEC_HEX_EXP_UP:
1430           rc = pr_float (outfnc, outfncarg, arg, value, nbytes);
1431           break;
1432         case CONSPEC_CHAR:
1433           rc = pr_char (outfnc, outfncarg, arg, value, nbytes);
1434           break;
1435         case CONSPEC_STRING:
1436         case CONSPEC_STRERROR:
1437           rc = pr_string (outfnc, outfncarg, arg, value, nbytes);
1438           break;
1439         case CONSPEC_POINTER:
1440           rc = pr_pointer (outfnc, outfncarg, arg, value, nbytes);
1441           break;
1442         case CONSPEC_BYTES_SO_FAR:
1443           rc = pr_bytes_so_far (outfnc, outfncarg, arg, value, nbytes);
1444           break;
1445         }
1446       if (rc)
1447         return rc;
1448       arg++;    
1449     }
1450   
1451   /* Print out any trailing stuff. */
1452   s++;  /* Need to output a terminating nul; take it from format.  */
1453   rc = outfnc (outfncarg, format, (n=s - format));
1454   if (!rc)
1455     *nbytes += n;
1456
1457   return rc;
1458 }
1459
1460
1461
1462 \f
1463 /* The versatile printf formatting routine.  It expects a callback
1464    function OUTFNC and an opaque argument OUTFNCARG used for actual
1465    output of the formatted stuff.  FORMAT is the format specification
1466    and VAARGS a variable argumemt list matching the arguments of
1467    FORMAT.  */
1468 int 
1469 estream_format (estream_printf_out_t outfnc,
1470                 void *outfncarg,
1471                 const char *format, va_list vaargs)
1472 {
1473   /* Buffer to hold the argspecs and a pointer to it.*/
1474   struct argspec_s argspecs_buffer[DEFAULT_MAX_ARGSPECS];
1475   argspec_t argspecs = argspecs_buffer;
1476   size_t argspecs_len;  /* Number of specifications in ARGSPECS.  */
1477
1478   /* Buffer to hold the description for the values.  */
1479   struct valueitem_s valuetable_buffer[DEFAULT_MAX_VALUES];
1480   valueitem_t valuetable = valuetable_buffer;
1481
1482   int rc;     /* Return code. */
1483   size_t argidx; /* Used to index the argspecs array.  */
1484   size_t validx; /* Used to index the valuetable.  */
1485   int max_pos;/* Highest argument position.  */
1486
1487   size_t nbytes = 0; /* Keep track of the number of bytes passed to
1488                         the output function.  */
1489
1490   int myerrno = errno; /* Save the errno for use with "%m". */
1491
1492
1493   /* Parse the arguments to come up with descriptive list.  We can't
1494      do this on the fly because we need to support positional
1495      arguments. */
1496   rc = parse_format (format, &argspecs, DIM(argspecs_buffer), &argspecs_len);
1497   if (rc)
1498     goto leave;
1499
1500   /* Check that all ARG_POS fields are set.  */
1501   for (argidx=0,max_pos=0; argidx < argspecs_len; argidx++)
1502     {
1503       if (argspecs[argidx].arg_pos != -1 
1504           && argspecs[argidx].arg_pos > max_pos)
1505         max_pos = argspecs[argidx].arg_pos;
1506       if (argspecs[argidx].width_pos > max_pos)
1507         max_pos = argspecs[argidx].width_pos;
1508       if (argspecs[argidx].precision_pos > max_pos)
1509         max_pos = argspecs[argidx].precision_pos;
1510     }
1511   if (!max_pos)
1512     {
1513       /* Fill in all the positions.  */
1514       for (argidx=0; argidx < argspecs_len; argidx++)
1515         {
1516           if (argspecs[argidx].width == STAR_FIELD_VALUE)
1517             argspecs[argidx].width_pos = ++max_pos;
1518           if (argspecs[argidx].precision == STAR_FIELD_VALUE)
1519             argspecs[argidx].precision_pos = ++max_pos;
1520           if (argspecs[argidx].arg_pos != -1 )
1521             argspecs[argidx].arg_pos = ++max_pos;
1522         }
1523     }
1524   else
1525     {
1526       /* Check that they are all filled.   More test are done later.  */
1527       for (argidx=0; argidx < argspecs_len; argidx++)
1528         {
1529           if (!argspecs[argidx].arg_pos
1530               || (argspecs[argidx].width == STAR_FIELD_VALUE
1531                   && !argspecs[argidx].width_pos)
1532               || (argspecs[argidx].precision == STAR_FIELD_VALUE
1533                   && !argspecs[argidx].precision_pos))
1534             goto leave_einval;
1535         }
1536     }
1537   /* Check that there is no overflow in max_pos and that it has a
1538      reasonable length.  There may never be more elements than the
1539      number of characters in FORMAT.  */
1540   if (max_pos < 0 || max_pos >= strlen (format))
1541     goto leave_einval;
1542
1543 #ifdef TEST
1544   if (verbose > 1)
1545     dump_argspecs (argspecs, argspecs_len);
1546 #endif
1547
1548   /* Allocate a table to hold the values.  If it is small enough we
1549      use a stack allocated buffer.  */
1550   if (max_pos > DIM(valuetable_buffer))
1551     {
1552       valuetable = calloc (max_pos, sizeof *valuetable);
1553       if (!valuetable)
1554         goto leave_error;
1555     }
1556   else
1557     {
1558       for (validx=0; validx < DIM(valuetable_buffer); validx++)
1559         valuetable[validx].vt = VALTYPE_UNSUPPORTED;
1560     }
1561   for (argidx=0; argidx < argspecs_len; argidx++)
1562     {
1563       if (argspecs[argidx].arg_pos != - 1)
1564         {
1565           validx = argspecs[argidx].arg_pos - 1;
1566           if (valuetable[validx].vt)
1567             goto leave_einval; /* Already defined. */
1568           valuetable[validx].vt = argspecs[argidx].vt;
1569         }
1570       if (argspecs[argidx].width == STAR_FIELD_VALUE)
1571         {
1572           validx = argspecs[argidx].width_pos - 1;
1573           if (valuetable[validx].vt)
1574             goto leave_einval; /* Already defined.  */
1575           valuetable[validx].vt = VALTYPE_INT;
1576         }
1577       if (argspecs[argidx].precision == STAR_FIELD_VALUE)
1578         {
1579           validx = argspecs[argidx].precision_pos - 1;
1580           if (valuetable[validx].vt)
1581             goto leave_einval; /* Already defined.  */
1582           valuetable[validx].vt = VALTYPE_INT;
1583         }
1584     }
1585   
1586   /* Read all the arguments.  This will error out for unsupported
1587      types and for not given positional arguments. */
1588   rc = read_values (valuetable, max_pos, vaargs);
1589   if (rc)
1590     goto leave_einval;  
1591   
1592 /*   for (validx=0; validx < max_pos; validx++) */
1593 /*     fprintf (stderr, "%2d: vt=%d\n", validx, valuetable[validx].vt); */
1594
1595   /* Everything has been collected, go ahead with the formatting.  */
1596   rc = do_format (outfnc, outfncarg, format,
1597                   argspecs, argspecs_len, valuetable, myerrno, &nbytes);
1598
1599   goto leave;
1600   
1601  leave_einval:
1602   errno = EINVAL;
1603  leave_error:
1604   rc = -1;
1605  leave:
1606   if (valuetable != valuetable_buffer)
1607     free (valuetable);
1608   if (argspecs != argspecs_buffer)
1609     free (argspecs);
1610   return rc;
1611 }
1612
1613
1614 \f
1615
1616 /* A simple output handler utilizing stdio.  */
1617 static int
1618 plain_stdio_out (void *outfncarg, const char *buf, size_t buflen)
1619 {
1620   FILE *fp = (FILE*)outfncarg;
1621
1622   fputs ("OUT->", fp);
1623   if ( fwrite (buf, buflen, 1, fp) != 1 )
1624     return -1;
1625   fputs ("<-\n", fp);
1626   return 0;
1627 }
1628
1629
1630 /* A replacement for printf.  */
1631 int
1632 estream_printf (const char *format, ...)
1633 {
1634   int rc;
1635   va_list arg_ptr;
1636   
1637   va_start (arg_ptr, format);
1638   rc = estream_format (plain_stdio_out, stderr, format, arg_ptr);
1639   va_end (arg_ptr);
1640   
1641   return rc;
1642 }
1643
1644 /* A replacement for fprintf.  */
1645 int
1646 estream_fprintf (FILE *fp, const char *format, ...)
1647 {
1648   int rc;
1649   va_list arg_ptr;
1650   
1651   va_start (arg_ptr, format);
1652   rc = estream_format (plain_stdio_out, fp, format, arg_ptr);
1653   va_end (arg_ptr);
1654   
1655   return rc;
1656 }
1657
1658 /* A replacement for vfprintf.  */
1659 int 
1660 estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr)
1661 {
1662   return estream_format (plain_stdio_out, fp, format, arg_ptr);
1663 }
1664
1665
1666 \f
1667 /* Communication object used between estream_snprintf and
1668    fixed_buffer_out.  */
1669 struct fixed_buffer_parm_s
1670 {
1671   size_t size;    /* Size of the buffer.  */
1672   size_t count;   /* Number of bytes requested for output.  */
1673   size_t used;    /* Used size of the buffer.  */
1674   char *buffer;   /* Provided buffer.  */
1675 };
1676
1677 /* A simple malloced buffer output handler.  */
1678 static int
1679 fixed_buffer_out (void *outfncarg, const char *buf, size_t buflen)
1680 {
1681   struct fixed_buffer_parm_s *parm = outfncarg;
1682
1683   parm->count += buflen;
1684
1685   if (!parm->buffer)
1686     ;
1687   else if (parm->used + buflen < parm->size)
1688     {
1689       /* Handle the common case that everything fits into the buffer
1690          separately.  */
1691       memcpy (parm->buffer + parm->used, buf, buflen);
1692       parm->used += buflen;
1693     }
1694   else
1695     {
1696       /* The slow version of above.  */
1697       for ( ;buflen && parm->used < parm->size; buflen--)
1698         parm->buffer[parm->used++] = *buf++;
1699     }
1700
1701   return 0;
1702 }
1703
1704
1705 /* A replacement for vsnprintf. */
1706 int 
1707 estream_vsnprintf (char *buf, size_t bufsize,
1708                    const char *format, va_list arg_ptr)
1709 {
1710   struct fixed_buffer_parm_s parm;
1711   int rc;
1712
1713   parm.size = bufsize? bufsize-1:0;
1714   parm.count = 0;
1715   parm.used = 0;
1716   parm.buffer = bufsize?buf:NULL;
1717   rc = estream_format (fixed_buffer_out, &parm, format, arg_ptr);
1718   if (rc == -1)
1719     return -1;
1720   if (bufsize && buf && parm.count >= parm.size)
1721     buf[parm.size-1] = 0;
1722
1723   return (int)parm.count; /* Return number of bytes which would have
1724                              been written.  */
1725 }
1726
1727 /* A replacement for snprintf.  */
1728 int 
1729 estream_snprintf (char *buf, size_t bufsize, const char *format, ...)
1730 {
1731   int rc;
1732   va_list arg_ptr;
1733
1734   va_start (arg_ptr, format);
1735   rc = estream_vsnprintf (buf, bufsize, format, arg_ptr);
1736   va_end (arg_ptr);
1737     
1738   return rc;
1739 }
1740
1741
1742 \f
1743 /* Communication object used between estream_asprintf and
1744    dynamic_buffer_out.  */
1745 struct dynamic_buffer_parm_s
1746 {
1747   int error_flag; /* Internal helper.  */ 
1748   size_t alloced; /* Allocated size of the buffer.  */
1749   size_t used;    /* Used size of the buffer.  */
1750   char *buffer;   /* Malloced buffer.  */
1751 };
1752
1753 /* A simple malloced buffer output handler.  */
1754 static int
1755 dynamic_buffer_out (void *outfncarg, const char *buf, size_t buflen)
1756 {
1757   struct dynamic_buffer_parm_s *parm = outfncarg;
1758
1759   if (parm->error_flag)
1760     {
1761       /* Just in case some formatting routine did not checked for an
1762          error. */
1763       errno = parm->error_flag;
1764       return -1;
1765     }
1766
1767   if (parm->used + buflen >= parm->alloced)
1768     {
1769       char *p;
1770       
1771       parm->alloced += buflen + 512;
1772       p = realloc (parm->buffer, parm->alloced);
1773       if (!p)
1774         {
1775           parm->error_flag = errno ? errno : ENOMEM;
1776           /* Wipe out what we already accumulated.  This is useful in
1777              case sensitive data is formated.  */
1778           memset (parm->buffer, 0, parm->used);
1779           return -1;
1780         }
1781       parm->buffer = p;
1782     }
1783   memcpy (parm->buffer + parm->used, buf, buflen);
1784   parm->used += buflen;
1785
1786   return 0;
1787 }
1788
1789
1790 /* A replacement for vasprintf.  As with the BSD of vasprintf version -1
1791    will be returned on error and NULL stored at BUFP.  On success the
1792    number of bytes printed will be returned. */
1793 int 
1794 estream_vasprintf (char **bufp, const char *format, va_list arg_ptr)
1795 {
1796   struct dynamic_buffer_parm_s parm;
1797   int rc;
1798
1799   parm.error_flag = 0;
1800   parm.alloced = 512;
1801   parm.used = 0;
1802   parm.buffer = my_printf_malloc (parm.alloced);
1803   if (!parm.buffer)
1804     {
1805       *bufp = NULL;
1806       return -1;
1807     }
1808   
1809   rc = estream_format (dynamic_buffer_out, &parm, format, arg_ptr);
1810
1811   if (rc != -1 && parm.error_flag)
1812     {
1813       rc = -1;
1814       errno = parm.error_flag;
1815     }
1816   if (rc == -1)
1817     {
1818       memset (parm.buffer, 0, parm.used);
1819       my_printf_free (parm.buffer);
1820       *bufp = NULL;
1821       return -1;
1822     }
1823   
1824   *bufp = parm.buffer;
1825   return parm.used - 1; /* Do not include the nul. */
1826 }
1827
1828 /* A replacement for asprintf.  As with the BSD of asprintf version -1
1829    will be returned on error and NULL stored at BUFP.  On success the
1830    number of bytes printed will be returned. */
1831 int 
1832 estream_asprintf (char **bufp, const char *format, ...)
1833 {
1834   int rc;
1835   va_list arg_ptr;
1836
1837   va_start (arg_ptr, format);
1838   rc = estream_vasprintf (bufp, format, arg_ptr);
1839   va_end (arg_ptr);
1840     
1841   return rc;
1842 }
1843
1844
1845 #ifdef TEST
1846
1847 static int
1848 one_test (const char *format, ...)
1849 {
1850   int rc1, rc2;
1851   va_list arg_ptr;
1852   char *buf1, *buf2;
1853
1854   if (verbose)
1855     printf ("format: ->%s<-\n", format);
1856
1857   va_start (arg_ptr, format);
1858   rc1 = vasprintf (&buf1, format, arg_ptr);
1859   va_end (arg_ptr);
1860   if (rc1 == -1)
1861     {
1862       printf ("   sys: errno=%d (%s)\n", errno, strerror (errno));
1863       buf1 = NULL;
1864     }
1865   else if (verbose)
1866     printf ("   sys: ->%s<-\n", buf1);
1867   
1868   va_start (arg_ptr, format);
1869   rc2 = estream_vasprintf (&buf2, format, arg_ptr);
1870   va_end (arg_ptr);
1871   if (rc2 == -1)
1872     printf ("   our: errno=%d (%s)\n", errno, strerror (errno));
1873   else if (verbose)
1874     printf ("   our: ->%s<-\n", buf2);
1875
1876   if (rc1 != -1 && rc2 != -1 && strcmp (buf1, buf2))
1877     printf ("error: output does not match\n"
1878             "format: ->%s<-\n   sys: ->%s<-\n   our: ->%s<-\n",
1879             format, buf1, buf2);
1880   else if ( rc1 != rc2 )
1881     printf ("error: return codes are different: sys_rc=%d our_rc=%d\n",
1882             rc1, rc2);
1883
1884   free (buf2);
1885   free (buf1);
1886
1887   return 0;
1888 }
1889
1890
1891 static void
1892 run_tests (void)
1893 {
1894 #if 0
1895   one_test ("%d %% %'d", 17, 19681977);
1896
1897   one_test ("%d %% %d", 17, 768114563);
1898   one_test ("%d %% %d", 17, -768114563);
1899
1900   one_test ("%d", 17);
1901   one_test ("%4d", 17);
1902   one_test ("%40d", 17);
1903   one_test ("%-d", 17);
1904   one_test ("%-4d", 17);
1905   one_test ("%-140d", 17);
1906   one_test ("%d", -17);
1907   one_test ("%4d", -17);
1908   one_test ("%40d", -17);
1909   one_test ("%-d", -17);
1910   one_test ("%-4d", -17);
1911   one_test ("%-40d", -17);
1912
1913   one_test ("%+4d", 17);
1914   one_test ("%+4d", -17);
1915   one_test ("%-+4d", 17);
1916   one_test ("%-+4d", -17);
1917   one_test ("% 4d", 17);
1918   one_test ("% 4d", -17);
1919   one_test ("%- +4d", 17);
1920   one_test ("%- +4d", -17);
1921
1922   one_test ("%.4d", 17);
1923   one_test ("%.0d", 17);
1924   one_test ("%.0d", 0);
1925   one_test ("%.4d", -17);
1926   one_test ("%.0d", -17);
1927   one_test ("%6.4d", 17);
1928   one_test ("%6.4d", -17);
1929   one_test ("%6.0d", 0);
1930   one_test ("%4.6d", 17);
1931   one_test ("%4.6d", -17);
1932
1933   one_test ("% 4.6d", 17);
1934   one_test ("% 6.0d", 0);
1935
1936   one_test ("%.4d", 17);
1937   one_test ("%04d", 17);
1938   one_test ("%.4d", -17);
1939   one_test ("%04d", -17);
1940   one_test ("%0.d", 0);
1941
1942   one_test ("%*d", 7, 42);
1943   one_test ("%*d", -7, 42);
1944   one_test ("%.*d", 7, 42);
1945   one_test ("%.*d", -7, 42);
1946   one_test ("%*.*d", 10, 7, 42);
1947   one_test ("%*.*d", 10, -7, 42);
1948   one_test ("%*.*d", -10, 7, 42);
1949   one_test ("%*.*d", -10, -7, 42);
1950
1951   one_test ("%*x", 7, 42);
1952   one_test ("%*x", -7, 42);
1953   one_test ("%.*x", 7, 42);
1954   one_test ("%.*x", -7, 42);
1955   one_test ("%*.*x", 10, 7, 42);
1956   one_test ("%*.*x", 10, -7, 42);
1957   one_test ("%*.*x", -10, 7, 42);
1958   one_test ("%*.*x", -10, -7, 42);
1959   one_test ("%#*x", 7, 42);
1960   one_test ("%#*x", -7, 42);
1961   one_test ("%#.*x", 7, 42);
1962   one_test ("%#.*x", -7, 42);
1963   one_test ("%#*.*x", 10, 7, 42);
1964   one_test ("%#*.*x", 10, -7, 42);
1965   one_test ("%#*.*x", -10, 7, 42);
1966   one_test ("%#*.*x", -10, -7, 42);
1967
1968   one_test ("%*X", 7, 42);
1969   one_test ("%*X", -7, 42);
1970   one_test ("%.*X", 7, 42);
1971   one_test ("%.*X", -7, 42);
1972   one_test ("%*.*X", 10, 7, 42);
1973   one_test ("%*.*X", 10, -7, 42);
1974   one_test ("%*.*X", -10, 7, 42);
1975   one_test ("%*.*X", -10, -7, 42);
1976   one_test ("%#*X", 7, 42);
1977   one_test ("%#*X", -7, 42);
1978   one_test ("%#.*X", 7, 42);
1979   one_test ("%#.*X", -7, 42);
1980   one_test ("%#*.*X", 10, 7, 42);
1981   one_test ("%#*.*X", 10, -7, 42);
1982   one_test ("%#*.*X", -10, 7, 42);
1983   one_test ("%#*.*X", -10, -7, 42);
1984
1985   one_test ("%*o", 7, 42);
1986   one_test ("%*o", -7, 42);
1987   one_test ("%.*o", 7, 42);
1988   one_test ("%.*o", -7, 42);
1989   one_test ("%*.*o", 10, 7, 42);
1990   one_test ("%*.*o", 10, -7, 42);
1991   one_test ("%*.*o", -10, 7, 42);
1992   one_test ("%*.*o", -10, -7, 42);
1993   one_test ("%#*o", 7, 42);
1994   one_test ("%#*o", -7, 42);
1995   one_test ("%#.*o", 7, 42);
1996   one_test ("%#.*o", -7, 42);
1997   one_test ("%#*.*o", 10, 7, 42);
1998   one_test ("%#*.*o", 10, -7, 42);
1999   one_test ("%#*.*o", -10, 7, 42);
2000   one_test ("%#*.*o", -10, -7, 42);
2001
2002   one_test ("%s", "the quick brown fox jumps over the lazy dogs back");
2003   one_test ("%.0s", "the quick brown fox jumps over the lazy dogs back");
2004   one_test ("%.10s", "the quick brown fox jumps over the lazy dogs back");
2005   one_test ("%.48s", "the quick brown fox jumps over the lazy dogs back");
2006   one_test ("%.49s", "the quick brown fox jumps over the lazy dogs back");
2007   one_test ("%.50s", "the quick brown fox jumps over the lazy dogs back");
2008   one_test ("%.51s", "the quick brown fox jumps over the lazy dogs back");
2009   one_test ("%48s", "the quick brown fox jumps over the lazy dogs back");
2010   one_test ("%49s", "the quick brown fox jumps over the lazy dogs back");
2011   one_test ("%50s", "the quick brown fox jumps over the lazy dogs back");
2012   one_test ("%51s", "the quick brown fox jumps over the lazy dogs back");
2013   one_test ("%-51s", "the quick brown fox jumps over the lazy dogs back");
2014 #endif
2015
2016   one_test ("%f", 3.1415926535);
2017   one_test ("%f", -3.1415926535);
2018   one_test ("%.10f", 3.1415926535);
2019   one_test ("%.2f", 3.1415926535);
2020   one_test ("%.1f", 3.1415926535);
2021   one_test ("%.0f", 3.1415926535);
2022   one_test ("%.20f", 3.1415926535);
2023   one_test ("%10.10f", 3.1415926535);
2024   one_test ("%10.2f", 3.1415926535);
2025   one_test ("%10.1f", 3.1415926535);
2026   one_test ("%10.0f", 3.1415926535);
2027   one_test ("%30.20f", 3.1415926535);
2028   one_test ("%10.10f", -3.1415926535);
2029   one_test ("%10.2f", -3.1415926535);
2030   one_test ("%10.1f", -3.1415926535);
2031   one_test ("%10.0f", -3.1415926535);
2032   one_test ("%30.20f", -3.1415926535);
2033
2034   one_test ("%-10f", 3.1415926535);
2035   one_test ("%-10.10f", 3.1415926535);
2036   one_test ("%-10.2f", 3.1415926535);
2037   one_test ("%-10.1f", 3.1415926535);
2038   one_test ("%-10.0f", 3.1415926535);
2039   one_test ("%-30.20f", 3.1415926535);
2040   one_test ("%-10f", -3.1415926535);
2041   one_test ("%-10.10f", -3.1415926535);
2042   one_test ("%-10.2f", -3.1415926535);
2043   one_test ("%-10.1f", -3.1415926535);
2044   one_test ("%-10.0f", -3.1415926535);
2045   one_test ("%-30.20f", -3.1415926535);
2046
2047   one_test ("%#.0f",  3.1415926535);
2048   one_test ("%#10.0f",  3.1415926535);
2049   one_test ("%#10.0f", -3.1415926535);
2050   one_test ("%-#10.0f",  3.1415926535);
2051   one_test ("%-#10.0f", -3.1415926535);
2052
2053   one_test ("%e", 3.1415926535);
2054   one_test ("%g", 3.1415926535);
2055
2056   one_test ("%a", 1);
2057   one_test ("%a", -1);
2058   one_test ("%a", 3.1415926535);
2059
2060 #ifdef HAVE_LONG_DOUBLE
2061   one_test ("%La", 1);
2062   one_test ("%La", -1);
2063   one_test ("%La", 3.1415926535);
2064 #endif
2065
2066 #ifdef __GLIBC__
2067   /* "%m" is a glibc extension so this _test_ will only work on such a
2068      system.  */
2069   errno = ENOENT;
2070   one_test ("%m");
2071   errno = ENOENT;
2072   one_test ("%d=%m", 17);
2073   errno = ENOENT;
2074   one_test ("%2$d:%m:%1$d", 42, 17);
2075 #endif /*__GLIBC__*/
2076
2077 }
2078
2079 static void
2080 check_snprintf (void)
2081 {
2082   char buffer[20];
2083   int rc;
2084
2085   rc = estream_snprintf (buffer, 0, "%*s", 18, "");
2086   if (rc != 19)
2087     printf ("rc=%d\n", rc );
2088   rc = estream_snprintf (buffer, sizeof buffer, "%*s", 18, "");
2089   if (rc != 19)
2090     printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
2091   rc = estream_snprintf (buffer, sizeof buffer, "%*s", 19, "");
2092   if (rc != 20)
2093     printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
2094   rc = estream_snprintf (buffer, sizeof buffer, "%*s", 20, "");
2095   if (rc != 21)
2096     printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
2097   rc = estream_snprintf (buffer, sizeof buffer, "%*s", 21, "");
2098   if (rc != 22)
2099     printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
2100 }
2101
2102
2103
2104 int
2105 main (int argc, char **argv)
2106 {
2107   int rc;
2108
2109   if (argc) {argc--; argv++; }
2110
2111   setlocale (LC_NUMERIC, "");
2112
2113   while (argc && !strcmp (*argv, "--verbose"))
2114     {
2115       verbose++;
2116       argc--;
2117       argv++;
2118     }
2119
2120   if (!argc)
2121     {
2122       run_tests ();
2123       check_snprintf () ;
2124     }
2125   else
2126     {
2127       rc = estream_vfprintf (stdout, argv[0], NULL);
2128       fflush (stdout);
2129       fprintf (stderr, "[estream_vfprintf returns: %d]\n", rc);
2130     }
2131
2132   return 0;
2133 }
2134 #endif /*TEST*/
2135 /*
2136 Local Variables:
2137 compile-command: "cc -Wall -O3 -g -I.. -DHAVE_CONFIG_H -DTEST -o estream-printf estream-printf.c"
2138 End:
2139 */