xref: /minix/tools/compat/snprintf.c (revision c8a0e2f4)
1*c8a0e2f4SThomas Veerman /*
2*c8a0e2f4SThomas Veerman  * Copyright (c) 1995-2001 Kungliga Tekniska H�gskolan
3*c8a0e2f4SThomas Veerman  * (Royal Institute of Technology, Stockholm, Sweden).
4*c8a0e2f4SThomas Veerman  * All rights reserved.
5*c8a0e2f4SThomas Veerman  *
6*c8a0e2f4SThomas Veerman  * Redistribution and use in source and binary forms, with or without
7*c8a0e2f4SThomas Veerman  * modification, are permitted provided that the following conditions
8*c8a0e2f4SThomas Veerman  * are met:
9*c8a0e2f4SThomas Veerman  *
10*c8a0e2f4SThomas Veerman  * 1. Redistributions of source code must retain the above copyright
11*c8a0e2f4SThomas Veerman  *    notice, this list of conditions and the following disclaimer.
12*c8a0e2f4SThomas Veerman  *
13*c8a0e2f4SThomas Veerman  * 2. Redistributions in binary form must reproduce the above copyright
14*c8a0e2f4SThomas Veerman  *    notice, this list of conditions and the following disclaimer in the
15*c8a0e2f4SThomas Veerman  *    documentation and/or other materials provided with the distribution.
16*c8a0e2f4SThomas Veerman  *
17*c8a0e2f4SThomas Veerman  * 3. Neither the name of the Institute nor the names of its contributors
18*c8a0e2f4SThomas Veerman  *    may be used to endorse or promote products derived from this software
19*c8a0e2f4SThomas Veerman  *    without specific prior written permission.
20*c8a0e2f4SThomas Veerman  *
21*c8a0e2f4SThomas Veerman  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22*c8a0e2f4SThomas Veerman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*c8a0e2f4SThomas Veerman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*c8a0e2f4SThomas Veerman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25*c8a0e2f4SThomas Veerman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*c8a0e2f4SThomas Veerman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*c8a0e2f4SThomas Veerman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*c8a0e2f4SThomas Veerman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*c8a0e2f4SThomas Veerman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*c8a0e2f4SThomas Veerman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*c8a0e2f4SThomas Veerman  * SUCH DAMAGE.
32*c8a0e2f4SThomas Veerman  */
33*c8a0e2f4SThomas Veerman 
34*c8a0e2f4SThomas Veerman /* From heimdal lib/roken/snprintf.c. */
35*c8a0e2f4SThomas Veerman 
36*c8a0e2f4SThomas Veerman #if HAVE_NBTOOL_CONFIG_H
37*c8a0e2f4SThomas Veerman #include "nbtool_config.h"
38*c8a0e2f4SThomas Veerman #endif
39*c8a0e2f4SThomas Veerman 
40*c8a0e2f4SThomas Veerman #if 0
41*c8a0e2f4SThomas Veerman RCSID("$Id: snprintf.c,v 1.3 2003/10/27 00:12:43 lukem Exp $");
42*c8a0e2f4SThomas Veerman #endif
43*c8a0e2f4SThomas Veerman #include <stdio.h>
44*c8a0e2f4SThomas Veerman #include <stdarg.h>
45*c8a0e2f4SThomas Veerman #include <stdlib.h>
46*c8a0e2f4SThomas Veerman #include <string.h>
47*c8a0e2f4SThomas Veerman #include <ctype.h>
48*c8a0e2f4SThomas Veerman #if 0
49*c8a0e2f4SThomas Veerman #include <roken.h>
50*c8a0e2f4SThomas Veerman #endif
51*c8a0e2f4SThomas Veerman 
52*c8a0e2f4SThomas Veerman #undef min
53*c8a0e2f4SThomas Veerman #define min(a,b) ((a) < (b) ? (a) : (b))
54*c8a0e2f4SThomas Veerman #undef max
55*c8a0e2f4SThomas Veerman #define max(a,b) ((a) > (b) ? (a) : (b))
56*c8a0e2f4SThomas Veerman 
57*c8a0e2f4SThomas Veerman enum format_flags {
58*c8a0e2f4SThomas Veerman     minus_flag     =  1,
59*c8a0e2f4SThomas Veerman     plus_flag      =  2,
60*c8a0e2f4SThomas Veerman     space_flag     =  4,
61*c8a0e2f4SThomas Veerman     alternate_flag =  8,
62*c8a0e2f4SThomas Veerman     zero_flag      = 16
63*c8a0e2f4SThomas Veerman };
64*c8a0e2f4SThomas Veerman 
65*c8a0e2f4SThomas Veerman /*
66*c8a0e2f4SThomas Veerman  * Common state
67*c8a0e2f4SThomas Veerman  */
68*c8a0e2f4SThomas Veerman 
69*c8a0e2f4SThomas Veerman struct state {
70*c8a0e2f4SThomas Veerman   unsigned char *str;
71*c8a0e2f4SThomas Veerman   unsigned char *s;
72*c8a0e2f4SThomas Veerman   unsigned char *theend;
73*c8a0e2f4SThomas Veerman   size_t sz;
74*c8a0e2f4SThomas Veerman   size_t max_sz;
75*c8a0e2f4SThomas Veerman   void (*append_char)(struct state *, unsigned char);
76*c8a0e2f4SThomas Veerman   /* XXX - methods */
77*c8a0e2f4SThomas Veerman };
78*c8a0e2f4SThomas Veerman 
79*c8a0e2f4SThomas Veerman #if TEST_SNPRINTF
80*c8a0e2f4SThomas Veerman #include "snprintf-test.h"
81*c8a0e2f4SThomas Veerman #endif /* TEST_SNPRINTF */
82*c8a0e2f4SThomas Veerman 
83*c8a0e2f4SThomas Veerman #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
84*c8a0e2f4SThomas Veerman static int
sn_reserve(struct state * state,size_t n)85*c8a0e2f4SThomas Veerman sn_reserve (struct state *state, size_t n)
86*c8a0e2f4SThomas Veerman {
87*c8a0e2f4SThomas Veerman   return state->s + n > state->theend;
88*c8a0e2f4SThomas Veerman }
89*c8a0e2f4SThomas Veerman 
90*c8a0e2f4SThomas Veerman static void
sn_append_char(struct state * state,unsigned char c)91*c8a0e2f4SThomas Veerman sn_append_char (struct state *state, unsigned char c)
92*c8a0e2f4SThomas Veerman {
93*c8a0e2f4SThomas Veerman   if (!sn_reserve (state, 1))
94*c8a0e2f4SThomas Veerman     *state->s++ = c;
95*c8a0e2f4SThomas Veerman }
96*c8a0e2f4SThomas Veerman #endif
97*c8a0e2f4SThomas Veerman 
98*c8a0e2f4SThomas Veerman static int
as_reserve(struct state * state,size_t n)99*c8a0e2f4SThomas Veerman as_reserve (struct state *state, size_t n)
100*c8a0e2f4SThomas Veerman {
101*c8a0e2f4SThomas Veerman   if (state->s + n > state->theend) {
102*c8a0e2f4SThomas Veerman     int off = state->s - state->str;
103*c8a0e2f4SThomas Veerman     unsigned char *tmp;
104*c8a0e2f4SThomas Veerman 
105*c8a0e2f4SThomas Veerman     if (state->max_sz && state->sz >= state->max_sz)
106*c8a0e2f4SThomas Veerman       return 1;
107*c8a0e2f4SThomas Veerman 
108*c8a0e2f4SThomas Veerman     state->sz = max(state->sz * 2, state->sz + n);
109*c8a0e2f4SThomas Veerman     if (state->max_sz)
110*c8a0e2f4SThomas Veerman       state->sz = min(state->sz, state->max_sz);
111*c8a0e2f4SThomas Veerman     tmp = realloc (state->str, state->sz);
112*c8a0e2f4SThomas Veerman     if (tmp == NULL)
113*c8a0e2f4SThomas Veerman       return 1;
114*c8a0e2f4SThomas Veerman     state->str = tmp;
115*c8a0e2f4SThomas Veerman     state->s = state->str + off;
116*c8a0e2f4SThomas Veerman     state->theend = state->str + state->sz - 1;
117*c8a0e2f4SThomas Veerman   }
118*c8a0e2f4SThomas Veerman   return 0;
119*c8a0e2f4SThomas Veerman }
120*c8a0e2f4SThomas Veerman 
121*c8a0e2f4SThomas Veerman static void
as_append_char(struct state * state,unsigned char c)122*c8a0e2f4SThomas Veerman as_append_char (struct state *state, unsigned char c)
123*c8a0e2f4SThomas Veerman {
124*c8a0e2f4SThomas Veerman   if(!as_reserve (state, 1))
125*c8a0e2f4SThomas Veerman     *state->s++ = c;
126*c8a0e2f4SThomas Veerman }
127*c8a0e2f4SThomas Veerman 
128*c8a0e2f4SThomas Veerman /* longest integer types */
129*c8a0e2f4SThomas Veerman 
130*c8a0e2f4SThomas Veerman #ifdef HAVE_LONG_LONG
131*c8a0e2f4SThomas Veerman typedef unsigned long long u_longest;
132*c8a0e2f4SThomas Veerman typedef long long longest;
133*c8a0e2f4SThomas Veerman #else
134*c8a0e2f4SThomas Veerman typedef unsigned long u_longest;
135*c8a0e2f4SThomas Veerman typedef long longest;
136*c8a0e2f4SThomas Veerman #endif
137*c8a0e2f4SThomas Veerman 
138*c8a0e2f4SThomas Veerman /*
139*c8a0e2f4SThomas Veerman  * is # supposed to do anything?
140*c8a0e2f4SThomas Veerman  */
141*c8a0e2f4SThomas Veerman 
142*c8a0e2f4SThomas Veerman static int
use_alternative(int flags,u_longest num,unsigned base)143*c8a0e2f4SThomas Veerman use_alternative (int flags, u_longest num, unsigned base)
144*c8a0e2f4SThomas Veerman {
145*c8a0e2f4SThomas Veerman   return flags & alternate_flag && (base == 16 || base == 8) && num != 0;
146*c8a0e2f4SThomas Veerman }
147*c8a0e2f4SThomas Veerman 
148*c8a0e2f4SThomas Veerman static int
append_number(struct state * state,u_longest num,unsigned base,char * rep,int width,int prec,int flags,int minusp)149*c8a0e2f4SThomas Veerman append_number(struct state *state,
150*c8a0e2f4SThomas Veerman 	      u_longest num, unsigned base, char *rep,
151*c8a0e2f4SThomas Veerman 	      int width, int prec, int flags, int minusp)
152*c8a0e2f4SThomas Veerman {
153*c8a0e2f4SThomas Veerman   int len = 0;
154*c8a0e2f4SThomas Veerman   int i;
155*c8a0e2f4SThomas Veerman   u_longest n = num;
156*c8a0e2f4SThomas Veerman 
157*c8a0e2f4SThomas Veerman   /* given precision, ignore zero flag */
158*c8a0e2f4SThomas Veerman   if(prec != -1)
159*c8a0e2f4SThomas Veerman     flags &= ~zero_flag;
160*c8a0e2f4SThomas Veerman   else
161*c8a0e2f4SThomas Veerman     prec = 1;
162*c8a0e2f4SThomas Veerman   /* zero value with zero precision -> "" */
163*c8a0e2f4SThomas Veerman   if(prec == 0 && n == 0)
164*c8a0e2f4SThomas Veerman     return 0;
165*c8a0e2f4SThomas Veerman   do{
166*c8a0e2f4SThomas Veerman     (*state->append_char)(state, rep[n % base]);
167*c8a0e2f4SThomas Veerman     ++len;
168*c8a0e2f4SThomas Veerman     n /= base;
169*c8a0e2f4SThomas Veerman   } while(n);
170*c8a0e2f4SThomas Veerman   prec -= len;
171*c8a0e2f4SThomas Veerman   /* pad with prec zeros */
172*c8a0e2f4SThomas Veerman   while(prec-- > 0){
173*c8a0e2f4SThomas Veerman     (*state->append_char)(state, '0');
174*c8a0e2f4SThomas Veerman     ++len;
175*c8a0e2f4SThomas Veerman   }
176*c8a0e2f4SThomas Veerman   /* add length of alternate prefix (added later) to len */
177*c8a0e2f4SThomas Veerman   if(use_alternative(flags, num, base))
178*c8a0e2f4SThomas Veerman     len += base / 8;
179*c8a0e2f4SThomas Veerman   /* pad with zeros */
180*c8a0e2f4SThomas Veerman   if(flags & zero_flag){
181*c8a0e2f4SThomas Veerman     width -= len;
182*c8a0e2f4SThomas Veerman     if(minusp || (flags & space_flag) || (flags & plus_flag))
183*c8a0e2f4SThomas Veerman       width--;
184*c8a0e2f4SThomas Veerman     while(width-- > 0){
185*c8a0e2f4SThomas Veerman       (*state->append_char)(state, '0');
186*c8a0e2f4SThomas Veerman       len++;
187*c8a0e2f4SThomas Veerman     }
188*c8a0e2f4SThomas Veerman   }
189*c8a0e2f4SThomas Veerman   /* add alternate prefix */
190*c8a0e2f4SThomas Veerman   if(use_alternative(flags, num, base)){
191*c8a0e2f4SThomas Veerman     if(base == 16)
192*c8a0e2f4SThomas Veerman       (*state->append_char)(state, rep[10] + 23); /* XXX */
193*c8a0e2f4SThomas Veerman     (*state->append_char)(state, '0');
194*c8a0e2f4SThomas Veerman   }
195*c8a0e2f4SThomas Veerman   /* add sign */
196*c8a0e2f4SThomas Veerman   if(minusp){
197*c8a0e2f4SThomas Veerman     (*state->append_char)(state, '-');
198*c8a0e2f4SThomas Veerman     ++len;
199*c8a0e2f4SThomas Veerman   } else if(flags & plus_flag) {
200*c8a0e2f4SThomas Veerman     (*state->append_char)(state, '+');
201*c8a0e2f4SThomas Veerman     ++len;
202*c8a0e2f4SThomas Veerman   } else if(flags & space_flag) {
203*c8a0e2f4SThomas Veerman     (*state->append_char)(state, ' ');
204*c8a0e2f4SThomas Veerman     ++len;
205*c8a0e2f4SThomas Veerman   }
206*c8a0e2f4SThomas Veerman   if(flags & minus_flag)
207*c8a0e2f4SThomas Veerman     /* swap before padding with spaces */
208*c8a0e2f4SThomas Veerman     for(i = 0; i < len / 2; i++){
209*c8a0e2f4SThomas Veerman       char c = state->s[-i-1];
210*c8a0e2f4SThomas Veerman       state->s[-i-1] = state->s[-len+i];
211*c8a0e2f4SThomas Veerman       state->s[-len+i] = c;
212*c8a0e2f4SThomas Veerman     }
213*c8a0e2f4SThomas Veerman   width -= len;
214*c8a0e2f4SThomas Veerman   while(width-- > 0){
215*c8a0e2f4SThomas Veerman     (*state->append_char)(state,  ' ');
216*c8a0e2f4SThomas Veerman     ++len;
217*c8a0e2f4SThomas Veerman   }
218*c8a0e2f4SThomas Veerman   if(!(flags & minus_flag))
219*c8a0e2f4SThomas Veerman     /* swap after padding with spaces */
220*c8a0e2f4SThomas Veerman     for(i = 0; i < len / 2; i++){
221*c8a0e2f4SThomas Veerman       char c = state->s[-i-1];
222*c8a0e2f4SThomas Veerman       state->s[-i-1] = state->s[-len+i];
223*c8a0e2f4SThomas Veerman       state->s[-len+i] = c;
224*c8a0e2f4SThomas Veerman     }
225*c8a0e2f4SThomas Veerman   return len;
226*c8a0e2f4SThomas Veerman }
227*c8a0e2f4SThomas Veerman 
228*c8a0e2f4SThomas Veerman /*
229*c8a0e2f4SThomas Veerman  * return length
230*c8a0e2f4SThomas Veerman  */
231*c8a0e2f4SThomas Veerman 
232*c8a0e2f4SThomas Veerman static int
append_string(struct state * state,const unsigned char * arg,int width,int prec,int flags)233*c8a0e2f4SThomas Veerman append_string (struct state *state,
234*c8a0e2f4SThomas Veerman 	       const unsigned char *arg,
235*c8a0e2f4SThomas Veerman 	       int width,
236*c8a0e2f4SThomas Veerman 	       int prec,
237*c8a0e2f4SThomas Veerman 	       int flags)
238*c8a0e2f4SThomas Veerman {
239*c8a0e2f4SThomas Veerman     int len = 0;
240*c8a0e2f4SThomas Veerman 
241*c8a0e2f4SThomas Veerman     if(arg == NULL)
242*c8a0e2f4SThomas Veerman 	arg = (const unsigned char*)"(null)";
243*c8a0e2f4SThomas Veerman 
244*c8a0e2f4SThomas Veerman     if(prec != -1)
245*c8a0e2f4SThomas Veerman 	width -= prec;
246*c8a0e2f4SThomas Veerman     else
247*c8a0e2f4SThomas Veerman 	width -= strlen((const char *)arg);
248*c8a0e2f4SThomas Veerman     if(!(flags & minus_flag))
249*c8a0e2f4SThomas Veerman 	while(width-- > 0) {
250*c8a0e2f4SThomas Veerman 	    (*state->append_char) (state, ' ');
251*c8a0e2f4SThomas Veerman 	    ++len;
252*c8a0e2f4SThomas Veerman 	}
253*c8a0e2f4SThomas Veerman     if (prec != -1) {
254*c8a0e2f4SThomas Veerman 	while (*arg && prec--) {
255*c8a0e2f4SThomas Veerman 	    (*state->append_char) (state, *arg++);
256*c8a0e2f4SThomas Veerman 	    ++len;
257*c8a0e2f4SThomas Veerman 	}
258*c8a0e2f4SThomas Veerman     } else {
259*c8a0e2f4SThomas Veerman 	while (*arg) {
260*c8a0e2f4SThomas Veerman 	    (*state->append_char) (state, *arg++);
261*c8a0e2f4SThomas Veerman 	    ++len;
262*c8a0e2f4SThomas Veerman 	}
263*c8a0e2f4SThomas Veerman     }
264*c8a0e2f4SThomas Veerman     if(flags & minus_flag)
265*c8a0e2f4SThomas Veerman 	while(width-- > 0) {
266*c8a0e2f4SThomas Veerman 	    (*state->append_char) (state, ' ');
267*c8a0e2f4SThomas Veerman 	    ++len;
268*c8a0e2f4SThomas Veerman 	}
269*c8a0e2f4SThomas Veerman     return len;
270*c8a0e2f4SThomas Veerman }
271*c8a0e2f4SThomas Veerman 
272*c8a0e2f4SThomas Veerman static int
append_char(struct state * state,unsigned char arg,int width,int flags)273*c8a0e2f4SThomas Veerman append_char(struct state *state,
274*c8a0e2f4SThomas Veerman 	    unsigned char arg,
275*c8a0e2f4SThomas Veerman 	    int width,
276*c8a0e2f4SThomas Veerman 	    int flags)
277*c8a0e2f4SThomas Veerman {
278*c8a0e2f4SThomas Veerman   int len = 0;
279*c8a0e2f4SThomas Veerman 
280*c8a0e2f4SThomas Veerman   while(!(flags & minus_flag) && --width > 0) {
281*c8a0e2f4SThomas Veerman     (*state->append_char) (state, ' ')    ;
282*c8a0e2f4SThomas Veerman     ++len;
283*c8a0e2f4SThomas Veerman   }
284*c8a0e2f4SThomas Veerman   (*state->append_char) (state, arg);
285*c8a0e2f4SThomas Veerman   ++len;
286*c8a0e2f4SThomas Veerman   while((flags & minus_flag) && --width > 0) {
287*c8a0e2f4SThomas Veerman     (*state->append_char) (state, ' ');
288*c8a0e2f4SThomas Veerman     ++len;
289*c8a0e2f4SThomas Veerman   }
290*c8a0e2f4SThomas Veerman   return 0;
291*c8a0e2f4SThomas Veerman }
292*c8a0e2f4SThomas Veerman 
293*c8a0e2f4SThomas Veerman /*
294*c8a0e2f4SThomas Veerman  * This can't be made into a function...
295*c8a0e2f4SThomas Veerman  */
296*c8a0e2f4SThomas Veerman 
297*c8a0e2f4SThomas Veerman #ifdef HAVE_LONG_LONG
298*c8a0e2f4SThomas Veerman 
299*c8a0e2f4SThomas Veerman #define PARSE_INT_FORMAT(res, arg, unsig) \
300*c8a0e2f4SThomas Veerman if (long_long_flag) \
301*c8a0e2f4SThomas Veerman      res = (unsig long long)va_arg(arg, unsig long long); \
302*c8a0e2f4SThomas Veerman else if (long_flag) \
303*c8a0e2f4SThomas Veerman      res = (unsig long)va_arg(arg, unsig long); \
304*c8a0e2f4SThomas Veerman else if (short_flag) \
305*c8a0e2f4SThomas Veerman      res = (unsig short)va_arg(arg, unsig int); \
306*c8a0e2f4SThomas Veerman else \
307*c8a0e2f4SThomas Veerman      res = (unsig int)va_arg(arg, unsig int)
308*c8a0e2f4SThomas Veerman 
309*c8a0e2f4SThomas Veerman #else
310*c8a0e2f4SThomas Veerman 
311*c8a0e2f4SThomas Veerman #define PARSE_INT_FORMAT(res, arg, unsig) \
312*c8a0e2f4SThomas Veerman if (long_flag) \
313*c8a0e2f4SThomas Veerman      res = (unsig long)va_arg(arg, unsig long); \
314*c8a0e2f4SThomas Veerman else if (short_flag) \
315*c8a0e2f4SThomas Veerman      res = (unsig short)va_arg(arg, unsig int); \
316*c8a0e2f4SThomas Veerman else \
317*c8a0e2f4SThomas Veerman      res = (unsig int)va_arg(arg, unsig int)
318*c8a0e2f4SThomas Veerman 
319*c8a0e2f4SThomas Veerman #endif
320*c8a0e2f4SThomas Veerman 
321*c8a0e2f4SThomas Veerman /*
322*c8a0e2f4SThomas Veerman  * zyxprintf - return length, as snprintf
323*c8a0e2f4SThomas Veerman  */
324*c8a0e2f4SThomas Veerman 
325*c8a0e2f4SThomas Veerman static int
xyzprintf(struct state * state,const char * char_format,va_list ap)326*c8a0e2f4SThomas Veerman xyzprintf (struct state *state, const char *char_format, va_list ap)
327*c8a0e2f4SThomas Veerman {
328*c8a0e2f4SThomas Veerman   const unsigned char *format = (const unsigned char *)char_format;
329*c8a0e2f4SThomas Veerman   unsigned char c;
330*c8a0e2f4SThomas Veerman   int len = 0;
331*c8a0e2f4SThomas Veerman 
332*c8a0e2f4SThomas Veerman   while((c = *format++)) {
333*c8a0e2f4SThomas Veerman     if (c == '%') {
334*c8a0e2f4SThomas Veerman       int flags          = 0;
335*c8a0e2f4SThomas Veerman       int width          = 0;
336*c8a0e2f4SThomas Veerman       int prec           = -1;
337*c8a0e2f4SThomas Veerman       int long_long_flag = 0;
338*c8a0e2f4SThomas Veerman       int long_flag      = 0;
339*c8a0e2f4SThomas Veerman       int short_flag     = 0;
340*c8a0e2f4SThomas Veerman 
341*c8a0e2f4SThomas Veerman       /* flags */
342*c8a0e2f4SThomas Veerman       while((c = *format++)){
343*c8a0e2f4SThomas Veerman 	if(c == '-')
344*c8a0e2f4SThomas Veerman 	  flags |= minus_flag;
345*c8a0e2f4SThomas Veerman 	else if(c == '+')
346*c8a0e2f4SThomas Veerman 	  flags |= plus_flag;
347*c8a0e2f4SThomas Veerman 	else if(c == ' ')
348*c8a0e2f4SThomas Veerman 	  flags |= space_flag;
349*c8a0e2f4SThomas Veerman 	else if(c == '#')
350*c8a0e2f4SThomas Veerman 	  flags |= alternate_flag;
351*c8a0e2f4SThomas Veerman 	else if(c == '0')
352*c8a0e2f4SThomas Veerman 	  flags |= zero_flag;
353*c8a0e2f4SThomas Veerman 	else
354*c8a0e2f4SThomas Veerman 	  break;
355*c8a0e2f4SThomas Veerman       }
356*c8a0e2f4SThomas Veerman 
357*c8a0e2f4SThomas Veerman       if((flags & space_flag) && (flags & plus_flag))
358*c8a0e2f4SThomas Veerman 	flags ^= space_flag;
359*c8a0e2f4SThomas Veerman 
360*c8a0e2f4SThomas Veerman       if((flags & minus_flag) && (flags & zero_flag))
361*c8a0e2f4SThomas Veerman 	flags ^= zero_flag;
362*c8a0e2f4SThomas Veerman 
363*c8a0e2f4SThomas Veerman       /* width */
364*c8a0e2f4SThomas Veerman       if (isdigit(c))
365*c8a0e2f4SThomas Veerman 	do {
366*c8a0e2f4SThomas Veerman 	  width = width * 10 + c - '0';
367*c8a0e2f4SThomas Veerman 	  c = *format++;
368*c8a0e2f4SThomas Veerman 	} while(isdigit(c));
369*c8a0e2f4SThomas Veerman       else if(c == '*') {
370*c8a0e2f4SThomas Veerman 	width = va_arg(ap, int);
371*c8a0e2f4SThomas Veerman 	c = *format++;
372*c8a0e2f4SThomas Veerman       }
373*c8a0e2f4SThomas Veerman 
374*c8a0e2f4SThomas Veerman       /* precision */
375*c8a0e2f4SThomas Veerman       if (c == '.') {
376*c8a0e2f4SThomas Veerman 	prec = 0;
377*c8a0e2f4SThomas Veerman 	c = *format++;
378*c8a0e2f4SThomas Veerman 	if (isdigit(c))
379*c8a0e2f4SThomas Veerman 	  do {
380*c8a0e2f4SThomas Veerman 	    prec = prec * 10 + c - '0';
381*c8a0e2f4SThomas Veerman 	    c = *format++;
382*c8a0e2f4SThomas Veerman 	  } while(isdigit(c));
383*c8a0e2f4SThomas Veerman 	else if (c == '*') {
384*c8a0e2f4SThomas Veerman 	  prec = va_arg(ap, int);
385*c8a0e2f4SThomas Veerman 	  c = *format++;
386*c8a0e2f4SThomas Veerman 	}
387*c8a0e2f4SThomas Veerman       }
388*c8a0e2f4SThomas Veerman 
389*c8a0e2f4SThomas Veerman       /* size */
390*c8a0e2f4SThomas Veerman 
391*c8a0e2f4SThomas Veerman       if (c == 'h') {
392*c8a0e2f4SThomas Veerman 	short_flag = 1;
393*c8a0e2f4SThomas Veerman 	c = *format++;
394*c8a0e2f4SThomas Veerman       } else if (c == 'l') {
395*c8a0e2f4SThomas Veerman 	long_flag = 1;
396*c8a0e2f4SThomas Veerman 	c = *format++;
397*c8a0e2f4SThomas Veerman 	if (c == 'l') {
398*c8a0e2f4SThomas Veerman 	    long_long_flag = 1;
399*c8a0e2f4SThomas Veerman 	    c = *format++;
400*c8a0e2f4SThomas Veerman 	}
401*c8a0e2f4SThomas Veerman       }
402*c8a0e2f4SThomas Veerman 
403*c8a0e2f4SThomas Veerman       switch (c) {
404*c8a0e2f4SThomas Veerman       case 'c' :
405*c8a0e2f4SThomas Veerman 	append_char(state, va_arg(ap, int), width, flags);
406*c8a0e2f4SThomas Veerman 	++len;
407*c8a0e2f4SThomas Veerman 	break;
408*c8a0e2f4SThomas Veerman       case 's' :
409*c8a0e2f4SThomas Veerman 	len += append_string(state,
410*c8a0e2f4SThomas Veerman 			     va_arg(ap, unsigned char*),
411*c8a0e2f4SThomas Veerman 			     width,
412*c8a0e2f4SThomas Veerman 			     prec,
413*c8a0e2f4SThomas Veerman 			     flags);
414*c8a0e2f4SThomas Veerman 	break;
415*c8a0e2f4SThomas Veerman       case 'd' :
416*c8a0e2f4SThomas Veerman       case 'i' : {
417*c8a0e2f4SThomas Veerman 	longest arg;
418*c8a0e2f4SThomas Veerman 	u_longest num;
419*c8a0e2f4SThomas Veerman 	int minusp = 0;
420*c8a0e2f4SThomas Veerman 
421*c8a0e2f4SThomas Veerman 	PARSE_INT_FORMAT(arg, ap, signed);
422*c8a0e2f4SThomas Veerman 
423*c8a0e2f4SThomas Veerman 	if (arg < 0) {
424*c8a0e2f4SThomas Veerman 	  minusp = 1;
425*c8a0e2f4SThomas Veerman 	  num = -arg;
426*c8a0e2f4SThomas Veerman 	} else
427*c8a0e2f4SThomas Veerman 	  num = arg;
428*c8a0e2f4SThomas Veerman 
429*c8a0e2f4SThomas Veerman 	len += append_number (state, num, 10, "0123456789",
430*c8a0e2f4SThomas Veerman 			      width, prec, flags, minusp);
431*c8a0e2f4SThomas Veerman 	break;
432*c8a0e2f4SThomas Veerman       }
433*c8a0e2f4SThomas Veerman       case 'u' : {
434*c8a0e2f4SThomas Veerman 	u_longest arg;
435*c8a0e2f4SThomas Veerman 
436*c8a0e2f4SThomas Veerman 	PARSE_INT_FORMAT(arg, ap, unsigned);
437*c8a0e2f4SThomas Veerman 
438*c8a0e2f4SThomas Veerman 	len += append_number (state, arg, 10, "0123456789",
439*c8a0e2f4SThomas Veerman 			      width, prec, flags, 0);
440*c8a0e2f4SThomas Veerman 	break;
441*c8a0e2f4SThomas Veerman       }
442*c8a0e2f4SThomas Veerman       case 'o' : {
443*c8a0e2f4SThomas Veerman 	u_longest arg;
444*c8a0e2f4SThomas Veerman 
445*c8a0e2f4SThomas Veerman 	PARSE_INT_FORMAT(arg, ap, unsigned);
446*c8a0e2f4SThomas Veerman 
447*c8a0e2f4SThomas Veerman 	len += append_number (state, arg, 010, "01234567",
448*c8a0e2f4SThomas Veerman 			      width, prec, flags, 0);
449*c8a0e2f4SThomas Veerman 	break;
450*c8a0e2f4SThomas Veerman       }
451*c8a0e2f4SThomas Veerman       case 'x' : {
452*c8a0e2f4SThomas Veerman 	u_longest arg;
453*c8a0e2f4SThomas Veerman 
454*c8a0e2f4SThomas Veerman 	PARSE_INT_FORMAT(arg, ap, unsigned);
455*c8a0e2f4SThomas Veerman 
456*c8a0e2f4SThomas Veerman 	len += append_number (state, arg, 0x10, "0123456789abcdef",
457*c8a0e2f4SThomas Veerman 			      width, prec, flags, 0);
458*c8a0e2f4SThomas Veerman 	break;
459*c8a0e2f4SThomas Veerman       }
460*c8a0e2f4SThomas Veerman       case 'X' :{
461*c8a0e2f4SThomas Veerman 	u_longest arg;
462*c8a0e2f4SThomas Veerman 
463*c8a0e2f4SThomas Veerman 	PARSE_INT_FORMAT(arg, ap, unsigned);
464*c8a0e2f4SThomas Veerman 
465*c8a0e2f4SThomas Veerman 	len += append_number (state, arg, 0x10, "0123456789ABCDEF",
466*c8a0e2f4SThomas Veerman 			      width, prec, flags, 0);
467*c8a0e2f4SThomas Veerman 	break;
468*c8a0e2f4SThomas Veerman       }
469*c8a0e2f4SThomas Veerman       case 'p' : {
470*c8a0e2f4SThomas Veerman 	unsigned long arg = (unsigned long)va_arg(ap, void*);
471*c8a0e2f4SThomas Veerman 
472*c8a0e2f4SThomas Veerman 	len += append_number (state, arg, 0x10, "0123456789ABCDEF",
473*c8a0e2f4SThomas Veerman 			      width, prec, flags, 0);
474*c8a0e2f4SThomas Veerman 	break;
475*c8a0e2f4SThomas Veerman       }
476*c8a0e2f4SThomas Veerman       case 'n' : {
477*c8a0e2f4SThomas Veerman 	int *arg = va_arg(ap, int*);
478*c8a0e2f4SThomas Veerman 	*arg = state->s - state->str;
479*c8a0e2f4SThomas Veerman 	break;
480*c8a0e2f4SThomas Veerman       }
481*c8a0e2f4SThomas Veerman       case '\0' :
482*c8a0e2f4SThomas Veerman 	  --format;
483*c8a0e2f4SThomas Veerman 	  /* FALLTHROUGH */
484*c8a0e2f4SThomas Veerman       case '%' :
485*c8a0e2f4SThomas Veerman 	(*state->append_char)(state, c);
486*c8a0e2f4SThomas Veerman 	++len;
487*c8a0e2f4SThomas Veerman 	break;
488*c8a0e2f4SThomas Veerman       default :
489*c8a0e2f4SThomas Veerman 	(*state->append_char)(state, '%');
490*c8a0e2f4SThomas Veerman 	(*state->append_char)(state, c);
491*c8a0e2f4SThomas Veerman 	len += 2;
492*c8a0e2f4SThomas Veerman 	break;
493*c8a0e2f4SThomas Veerman       }
494*c8a0e2f4SThomas Veerman     } else {
495*c8a0e2f4SThomas Veerman       (*state->append_char) (state, c);
496*c8a0e2f4SThomas Veerman       ++len;
497*c8a0e2f4SThomas Veerman     }
498*c8a0e2f4SThomas Veerman   }
499*c8a0e2f4SThomas Veerman   return len;
500*c8a0e2f4SThomas Veerman }
501*c8a0e2f4SThomas Veerman 
502*c8a0e2f4SThomas Veerman #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
503*c8a0e2f4SThomas Veerman int
snprintf(char * str,size_t sz,const char * format,...)504*c8a0e2f4SThomas Veerman snprintf (char *str, size_t sz, const char *format, ...)
505*c8a0e2f4SThomas Veerman {
506*c8a0e2f4SThomas Veerman   va_list args;
507*c8a0e2f4SThomas Veerman   int ret;
508*c8a0e2f4SThomas Veerman 
509*c8a0e2f4SThomas Veerman   va_start(args, format);
510*c8a0e2f4SThomas Veerman   ret = vsnprintf (str, sz, format, args);
511*c8a0e2f4SThomas Veerman   va_end(args);
512*c8a0e2f4SThomas Veerman 
513*c8a0e2f4SThomas Veerman #ifdef PARANOIA
514*c8a0e2f4SThomas Veerman   {
515*c8a0e2f4SThomas Veerman     int ret2;
516*c8a0e2f4SThomas Veerman     char *tmp;
517*c8a0e2f4SThomas Veerman 
518*c8a0e2f4SThomas Veerman     tmp = malloc (sz);
519*c8a0e2f4SThomas Veerman     if (tmp == NULL)
520*c8a0e2f4SThomas Veerman       abort ();
521*c8a0e2f4SThomas Veerman 
522*c8a0e2f4SThomas Veerman     va_start(args, format);
523*c8a0e2f4SThomas Veerman     ret2 = vsprintf (tmp, format, args);
524*c8a0e2f4SThomas Veerman     va_end(args);
525*c8a0e2f4SThomas Veerman     if (ret != ret2 || strcmp(str, tmp))
526*c8a0e2f4SThomas Veerman       abort ();
527*c8a0e2f4SThomas Veerman     free (tmp);
528*c8a0e2f4SThomas Veerman   }
529*c8a0e2f4SThomas Veerman #endif
530*c8a0e2f4SThomas Veerman 
531*c8a0e2f4SThomas Veerman   return ret;
532*c8a0e2f4SThomas Veerman }
533*c8a0e2f4SThomas Veerman #endif
534*c8a0e2f4SThomas Veerman 
535*c8a0e2f4SThomas Veerman #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
536*c8a0e2f4SThomas Veerman int
asprintf(char ** ret,const char * format,...)537*c8a0e2f4SThomas Veerman asprintf (char **ret, const char *format, ...)
538*c8a0e2f4SThomas Veerman {
539*c8a0e2f4SThomas Veerman   va_list args;
540*c8a0e2f4SThomas Veerman   int val;
541*c8a0e2f4SThomas Veerman 
542*c8a0e2f4SThomas Veerman   va_start(args, format);
543*c8a0e2f4SThomas Veerman   val = vasprintf (ret, format, args);
544*c8a0e2f4SThomas Veerman 
545*c8a0e2f4SThomas Veerman #ifdef PARANOIA
546*c8a0e2f4SThomas Veerman   {
547*c8a0e2f4SThomas Veerman     int ret2;
548*c8a0e2f4SThomas Veerman     char *tmp;
549*c8a0e2f4SThomas Veerman     tmp = malloc (val + 1);
550*c8a0e2f4SThomas Veerman     if (tmp == NULL)
551*c8a0e2f4SThomas Veerman       abort ();
552*c8a0e2f4SThomas Veerman 
553*c8a0e2f4SThomas Veerman     ret2 = vsprintf (tmp, format, args);
554*c8a0e2f4SThomas Veerman     if (val != ret2 || strcmp(*ret, tmp))
555*c8a0e2f4SThomas Veerman       abort ();
556*c8a0e2f4SThomas Veerman     free (tmp);
557*c8a0e2f4SThomas Veerman   }
558*c8a0e2f4SThomas Veerman #endif
559*c8a0e2f4SThomas Veerman 
560*c8a0e2f4SThomas Veerman   va_end(args);
561*c8a0e2f4SThomas Veerman   return val;
562*c8a0e2f4SThomas Veerman }
563*c8a0e2f4SThomas Veerman #endif
564*c8a0e2f4SThomas Veerman 
565*c8a0e2f4SThomas Veerman #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
566*c8a0e2f4SThomas Veerman int
asnprintf(char ** ret,size_t max_sz,const char * format,...)567*c8a0e2f4SThomas Veerman asnprintf (char **ret, size_t max_sz, const char *format, ...)
568*c8a0e2f4SThomas Veerman {
569*c8a0e2f4SThomas Veerman   va_list args;
570*c8a0e2f4SThomas Veerman   int val;
571*c8a0e2f4SThomas Veerman 
572*c8a0e2f4SThomas Veerman   va_start(args, format);
573*c8a0e2f4SThomas Veerman   val = vasnprintf (ret, max_sz, format, args);
574*c8a0e2f4SThomas Veerman 
575*c8a0e2f4SThomas Veerman #ifdef PARANOIA
576*c8a0e2f4SThomas Veerman   {
577*c8a0e2f4SThomas Veerman     int ret2;
578*c8a0e2f4SThomas Veerman     char *tmp;
579*c8a0e2f4SThomas Veerman     tmp = malloc (val + 1);
580*c8a0e2f4SThomas Veerman     if (tmp == NULL)
581*c8a0e2f4SThomas Veerman       abort ();
582*c8a0e2f4SThomas Veerman 
583*c8a0e2f4SThomas Veerman     ret2 = vsprintf (tmp, format, args);
584*c8a0e2f4SThomas Veerman     if (val != ret2 || strcmp(*ret, tmp))
585*c8a0e2f4SThomas Veerman       abort ();
586*c8a0e2f4SThomas Veerman     free (tmp);
587*c8a0e2f4SThomas Veerman   }
588*c8a0e2f4SThomas Veerman #endif
589*c8a0e2f4SThomas Veerman 
590*c8a0e2f4SThomas Veerman   va_end(args);
591*c8a0e2f4SThomas Veerman   return val;
592*c8a0e2f4SThomas Veerman }
593*c8a0e2f4SThomas Veerman #endif
594*c8a0e2f4SThomas Veerman 
595*c8a0e2f4SThomas Veerman #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
596*c8a0e2f4SThomas Veerman int
vasprintf(char ** ret,const char * format,va_list args)597*c8a0e2f4SThomas Veerman vasprintf (char **ret, const char *format, va_list args)
598*c8a0e2f4SThomas Veerman {
599*c8a0e2f4SThomas Veerman   return vasnprintf (ret, 0, format, args);
600*c8a0e2f4SThomas Veerman }
601*c8a0e2f4SThomas Veerman #endif
602*c8a0e2f4SThomas Veerman 
603*c8a0e2f4SThomas Veerman 
604*c8a0e2f4SThomas Veerman #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
605*c8a0e2f4SThomas Veerman int
vasnprintf(char ** ret,size_t max_sz,const char * format,va_list args)606*c8a0e2f4SThomas Veerman vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
607*c8a0e2f4SThomas Veerman {
608*c8a0e2f4SThomas Veerman   int st;
609*c8a0e2f4SThomas Veerman   struct state state;
610*c8a0e2f4SThomas Veerman 
611*c8a0e2f4SThomas Veerman   state.max_sz = max_sz;
612*c8a0e2f4SThomas Veerman   state.sz     = 1;
613*c8a0e2f4SThomas Veerman   state.str    = malloc(state.sz);
614*c8a0e2f4SThomas Veerman   if (state.str == NULL) {
615*c8a0e2f4SThomas Veerman     *ret = NULL;
616*c8a0e2f4SThomas Veerman     return -1;
617*c8a0e2f4SThomas Veerman   }
618*c8a0e2f4SThomas Veerman   state.s = state.str;
619*c8a0e2f4SThomas Veerman   state.theend = state.s + state.sz - 1;
620*c8a0e2f4SThomas Veerman   state.append_char = as_append_char;
621*c8a0e2f4SThomas Veerman 
622*c8a0e2f4SThomas Veerman   st = xyzprintf (&state, format, args);
623*c8a0e2f4SThomas Veerman   if (st > state.sz) {
624*c8a0e2f4SThomas Veerman     free (state.str);
625*c8a0e2f4SThomas Veerman     *ret = NULL;
626*c8a0e2f4SThomas Veerman     return -1;
627*c8a0e2f4SThomas Veerman   } else {
628*c8a0e2f4SThomas Veerman     char *tmp;
629*c8a0e2f4SThomas Veerman 
630*c8a0e2f4SThomas Veerman     *state.s = '\0';
631*c8a0e2f4SThomas Veerman     tmp = realloc (state.str, st+1);
632*c8a0e2f4SThomas Veerman     if (tmp == NULL) {
633*c8a0e2f4SThomas Veerman       free (state.str);
634*c8a0e2f4SThomas Veerman       *ret = NULL;
635*c8a0e2f4SThomas Veerman       return -1;
636*c8a0e2f4SThomas Veerman     }
637*c8a0e2f4SThomas Veerman     *ret = tmp;
638*c8a0e2f4SThomas Veerman     return st;
639*c8a0e2f4SThomas Veerman   }
640*c8a0e2f4SThomas Veerman }
641*c8a0e2f4SThomas Veerman #endif
642*c8a0e2f4SThomas Veerman 
643*c8a0e2f4SThomas Veerman #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
644*c8a0e2f4SThomas Veerman int
vsnprintf(char * str,size_t sz,const char * format,va_list args)645*c8a0e2f4SThomas Veerman vsnprintf (char *str, size_t sz, const char *format, va_list args)
646*c8a0e2f4SThomas Veerman {
647*c8a0e2f4SThomas Veerman   struct state state;
648*c8a0e2f4SThomas Veerman   int ret;
649*c8a0e2f4SThomas Veerman   unsigned char *ustr = (unsigned char *)str;
650*c8a0e2f4SThomas Veerman 
651*c8a0e2f4SThomas Veerman   state.max_sz = 0;
652*c8a0e2f4SThomas Veerman   state.sz     = sz;
653*c8a0e2f4SThomas Veerman   state.str    = ustr;
654*c8a0e2f4SThomas Veerman   state.s      = ustr;
655*c8a0e2f4SThomas Veerman   state.theend = ustr + sz - (sz > 0);
656*c8a0e2f4SThomas Veerman   state.append_char = sn_append_char;
657*c8a0e2f4SThomas Veerman 
658*c8a0e2f4SThomas Veerman   ret = xyzprintf (&state, format, args);
659*c8a0e2f4SThomas Veerman   if (state.s != NULL)
660*c8a0e2f4SThomas Veerman     *state.s = '\0';
661*c8a0e2f4SThomas Veerman   return ret;
662*c8a0e2f4SThomas Veerman }
663*c8a0e2f4SThomas Veerman #endif
664