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