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