155682Smarkm/*
2233294Sstas * Copyright (c) 1995-2003 Kungliga Tekniska H��gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
5233294Sstas *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
9233294Sstas *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
12233294Sstas *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
16233294Sstas *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
20233294Sstas *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include <config.h>
3555682Smarkm#include <stdio.h>
3655682Smarkm#include <stdarg.h>
3755682Smarkm#include <stdlib.h>
3855682Smarkm#include <string.h>
3955682Smarkm#include <ctype.h>
40178825Sdfr#include "roken.h"
41178825Sdfr#include <assert.h>
4255682Smarkm
4355682Smarkmenum format_flags {
4455682Smarkm    minus_flag     =  1,
4555682Smarkm    plus_flag      =  2,
4655682Smarkm    space_flag     =  4,
4755682Smarkm    alternate_flag =  8,
4855682Smarkm    zero_flag      = 16
4955682Smarkm};
5055682Smarkm
5155682Smarkm/*
5255682Smarkm * Common state
5355682Smarkm */
5455682Smarkm
5590926Snectarstruct snprintf_state {
56178825Sdfr    unsigned char *str;
57178825Sdfr    unsigned char *s;
58178825Sdfr    unsigned char *theend;
59178825Sdfr    size_t sz;
60178825Sdfr    size_t max_sz;
61178825Sdfr    void (*append_char)(struct snprintf_state *, unsigned char);
62178825Sdfr    /* XXX - methods */
6355682Smarkm};
6455682Smarkm
6590926Snectar#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
6655682Smarkmstatic int
6790926Snectarsn_reserve (struct snprintf_state *state, size_t n)
6855682Smarkm{
69178825Sdfr    return state->s + n > state->theend;
7055682Smarkm}
7155682Smarkm
7290926Snectarstatic void
7390926Snectarsn_append_char (struct snprintf_state *state, unsigned char c)
7455682Smarkm{
75178825Sdfr    if (!sn_reserve (state, 1))
76178825Sdfr	*state->s++ = c;
7755682Smarkm}
7855682Smarkm#endif
7955682Smarkm
8055682Smarkmstatic int
8190926Snectaras_reserve (struct snprintf_state *state, size_t n)
8255682Smarkm{
83178825Sdfr    if (state->s + n > state->theend) {
84178825Sdfr	int off = state->s - state->str;
85178825Sdfr	unsigned char *tmp;
8655682Smarkm
87178825Sdfr	if (state->max_sz && state->sz >= state->max_sz)
88178825Sdfr	    return 1;
8955682Smarkm
90178825Sdfr	state->sz = max(state->sz * 2, state->sz + n);
91178825Sdfr	if (state->max_sz)
92178825Sdfr	    state->sz = min(state->sz, state->max_sz);
93178825Sdfr	tmp = realloc (state->str, state->sz);
94178825Sdfr	if (tmp == NULL)
95178825Sdfr	    return 1;
96178825Sdfr	state->str = tmp;
97178825Sdfr	state->s = state->str + off;
98178825Sdfr	state->theend = state->str + state->sz - 1;
99178825Sdfr    }
100178825Sdfr    return 0;
10155682Smarkm}
10255682Smarkm
10390926Snectarstatic void
10490926Snectaras_append_char (struct snprintf_state *state, unsigned char c)
10555682Smarkm{
106178825Sdfr    if(!as_reserve (state, 1))
107178825Sdfr	*state->s++ = c;
10855682Smarkm}
10955682Smarkm
11090926Snectar/* longest integer types */
11190926Snectar
11290926Snectar#ifdef HAVE_LONG_LONG
11390926Snectartypedef unsigned long long u_longest;
11490926Snectartypedef long long longest;
11590926Snectar#else
11690926Snectartypedef unsigned long u_longest;
11790926Snectartypedef long longest;
11890926Snectar#endif
11990926Snectar
12090926Snectar
121178825Sdfr
122233294Sstasstatic size_t
123178825Sdfrpad(struct snprintf_state *state, int width, char c)
124178825Sdfr{
125233294Sstas    size_t len = 0;
126178825Sdfr    while(width-- > 0){
127178825Sdfr	(*state->append_char)(state,  c);
128178825Sdfr	++len;
129178825Sdfr    }
130178825Sdfr    return len;
131178825Sdfr}
132178825Sdfr
133178825Sdfr/* return true if we should use alternatve hex form */
134178825Sdfrstatic int
13590926Snectaruse_alternative (int flags, u_longest num, unsigned base)
13690926Snectar{
137178825Sdfr    return (flags & alternate_flag) && base == 16 && num != 0;
13890926Snectar}
13990926Snectar
14090926Snectarstatic int
14190926Snectarappend_number(struct snprintf_state *state,
142102644Snectar	      u_longest num, unsigned base, const char *rep,
14355682Smarkm	      int width, int prec, int flags, int minusp)
14455682Smarkm{
145178825Sdfr    int len = 0;
146178825Sdfr    u_longest n = num;
147178825Sdfr    char nstr[64]; /* enough for <192 bit octal integers */
148178825Sdfr    int nstart, nlen;
149178825Sdfr    char signchar;
15055682Smarkm
151178825Sdfr    /* given precision, ignore zero flag */
152178825Sdfr    if(prec != -1)
153178825Sdfr	flags &= ~zero_flag;
154178825Sdfr    else
155178825Sdfr	prec = 1;
156178825Sdfr
157178825Sdfr    /* format number as string */
158178825Sdfr    nstart = sizeof(nstr);
159178825Sdfr    nlen = 0;
160178825Sdfr    nstr[--nstart] = '\0';
161178825Sdfr    do {
162178825Sdfr	assert(nstart > 0);
163178825Sdfr	nstr[--nstart] = rep[n % base];
164178825Sdfr	++nlen;
165178825Sdfr	n /= base;
166178825Sdfr    } while(n);
167178825Sdfr
168178825Sdfr    /* zero value with zero precision should produce no digits */
169178825Sdfr    if(prec == 0 && num == 0) {
170178825Sdfr	nlen--;
171178825Sdfr	nstart++;
17255682Smarkm    }
173178825Sdfr
174178825Sdfr    /* figure out what char to use for sign */
175178825Sdfr    if(minusp)
176178825Sdfr	signchar = '-';
177178825Sdfr    else if((flags & plus_flag))
178178825Sdfr	signchar = '+';
179178825Sdfr    else if((flags & space_flag))
180178825Sdfr	signchar = ' ';
181178825Sdfr    else
182178825Sdfr	signchar = '\0';
183233294Sstas
184178825Sdfr    if((flags & alternate_flag) && base == 8) {
185233294Sstas	/* if necessary, increase the precision to
186178825Sdfr	   make first digit a zero */
187178825Sdfr
188178825Sdfr	/* XXX C99 claims (regarding # and %o) that "if the value and
189178825Sdfr           precision are both 0, a single 0 is printed", but there is
190178825Sdfr           no such wording for %x. This would mean that %#.o would
191178825Sdfr           output "0", but %#.x "". This does not make sense, and is
192178825Sdfr           also not what other printf implementations are doing. */
193233294Sstas
194178825Sdfr	if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0')
195178825Sdfr	    prec = nlen + 1;
19655682Smarkm    }
197178825Sdfr
198178825Sdfr    /* possible formats:
199178825Sdfr       pad | sign | alt | zero | digits
200178825Sdfr       sign | alt | zero | digits | pad   minus_flag
201178825Sdfr       sign | alt | zero | digits zero_flag */
202178825Sdfr
203178825Sdfr    /* if not right justifying or padding with zeros, we need to
204178825Sdfr       compute the length of the rest of the string, and then pad with
205178825Sdfr       spaces */
206178825Sdfr    if(!(flags & (minus_flag | zero_flag))) {
207178825Sdfr	if(prec > nlen)
208178825Sdfr	    width -= prec;
209178825Sdfr	else
210178825Sdfr	    width -= nlen;
211233294Sstas
212178825Sdfr	if(use_alternative(flags, num, base))
213178825Sdfr	    width -= 2;
214233294Sstas
215178825Sdfr	if(signchar != '\0')
216178825Sdfr	    width--;
217233294Sstas
218178825Sdfr	/* pad to width */
219178825Sdfr	len += pad(state, width, ' ');
22055682Smarkm    }
221178825Sdfr    if(signchar != '\0') {
222178825Sdfr	(*state->append_char)(state, signchar);
223178825Sdfr	++len;
224178825Sdfr    }
225178825Sdfr    if(use_alternative(flags, num, base)) {
226178825Sdfr	(*state->append_char)(state, '0');
227178825Sdfr	(*state->append_char)(state, rep[10] + 23); /* XXX */
228178825Sdfr	len += 2;
229178825Sdfr    }
230178825Sdfr    if(flags & zero_flag) {
231178825Sdfr	/* pad to width with zeros */
232178825Sdfr	if(prec - nlen > width - len - nlen)
233178825Sdfr	    len += pad(state, prec - nlen, '0');
234178825Sdfr	else
235178825Sdfr	    len += pad(state, width - len - nlen, '0');
236178825Sdfr    } else
237178825Sdfr	/* pad to prec with zeros */
238178825Sdfr	len += pad(state, prec - nlen, '0');
239233294Sstas
240178825Sdfr    while(nstr[nstart] != '\0') {
241178825Sdfr	(*state->append_char)(state, nstr[nstart++]);
242178825Sdfr	++len;
243178825Sdfr    }
244233294Sstas
245178825Sdfr    if(flags & minus_flag)
246178825Sdfr	len += pad(state, width - len, ' ');
247178825Sdfr
248178825Sdfr    return len;
24955682Smarkm}
25055682Smarkm
25190926Snectar/*
25290926Snectar * return length
25390926Snectar */
25490926Snectar
255233294Sstasstatic size_t
25690926Snectarappend_string (struct snprintf_state *state,
25790926Snectar	       const unsigned char *arg,
25855682Smarkm	       int width,
25955682Smarkm	       int prec,
26055682Smarkm	       int flags)
26155682Smarkm{
262233294Sstas    size_t len = 0;
26390926Snectar
26472445Sassar    if(arg == NULL)
26590926Snectar	arg = (const unsigned char*)"(null)";
26672445Sassar
26772445Sassar    if(prec != -1)
26872445Sassar	width -= prec;
26972445Sassar    else
27090926Snectar	width -= strlen((const char *)arg);
27172445Sassar    if(!(flags & minus_flag))
272178825Sdfr	len += pad(state, width, ' ');
273178825Sdfr
27472445Sassar    if (prec != -1) {
27590926Snectar	while (*arg && prec--) {
27690926Snectar	    (*state->append_char) (state, *arg++);
27790926Snectar	    ++len;
27890926Snectar	}
27972445Sassar    } else {
28090926Snectar	while (*arg) {
28190926Snectar	    (*state->append_char) (state, *arg++);
28290926Snectar	    ++len;
28390926Snectar	}
28472445Sassar    }
28572445Sassar    if(flags & minus_flag)
286178825Sdfr	len += pad(state, width, ' ');
28790926Snectar    return len;
28855682Smarkm}
28955682Smarkm
29055682Smarkmstatic int
29190926Snectarappend_char(struct snprintf_state *state,
29255682Smarkm	    unsigned char arg,
29355682Smarkm	    int width,
29455682Smarkm	    int flags)
29555682Smarkm{
296178825Sdfr    int len = 0;
29790926Snectar
298178825Sdfr    while(!(flags & minus_flag) && --width > 0) {
299178825Sdfr	(*state->append_char) (state, ' ')    ;
300178825Sdfr	++len;
301178825Sdfr    }
302178825Sdfr    (*state->append_char) (state, arg);
30390926Snectar    ++len;
304178825Sdfr    while((flags & minus_flag) && --width > 0) {
305178825Sdfr	(*state->append_char) (state, ' ');
306178825Sdfr	++len;
307178825Sdfr    }
308178825Sdfr    return 0;
30955682Smarkm}
31055682Smarkm
31155682Smarkm/*
31255682Smarkm * This can't be made into a function...
31355682Smarkm */
31455682Smarkm
31590926Snectar#ifdef HAVE_LONG_LONG
31690926Snectar
31755682Smarkm#define PARSE_INT_FORMAT(res, arg, unsig) \
31890926Snectarif (long_long_flag) \
31990926Snectar     res = (unsig long long)va_arg(arg, unsig long long); \
32090926Snectarelse if (long_flag) \
32190926Snectar     res = (unsig long)va_arg(arg, unsig long); \
322178825Sdfrelse if (size_t_flag) \
323178825Sdfr     res = (unsig long)va_arg(arg, size_t); \
32490926Snectarelse if (short_flag) \
32590926Snectar     res = (unsig short)va_arg(arg, unsig int); \
32690926Snectarelse \
32790926Snectar     res = (unsig int)va_arg(arg, unsig int)
32890926Snectar
32990926Snectar#else
33090926Snectar
33190926Snectar#define PARSE_INT_FORMAT(res, arg, unsig) \
33255682Smarkmif (long_flag) \
33355682Smarkm     res = (unsig long)va_arg(arg, unsig long); \
334178825Sdfrelse if (size_t_flag) \
335178825Sdfr     res = (unsig long)va_arg(arg, size_t); \
33655682Smarkmelse if (short_flag) \
33757422Smarkm     res = (unsig short)va_arg(arg, unsig int); \
33855682Smarkmelse \
33955682Smarkm     res = (unsig int)va_arg(arg, unsig int)
34055682Smarkm
34190926Snectar#endif
34290926Snectar
34355682Smarkm/*
34490926Snectar * zyxprintf - return length, as snprintf
34555682Smarkm */
34655682Smarkm
347233294Sstasstatic size_t
34890926Snectarxyzprintf (struct snprintf_state *state, const char *char_format, va_list ap)
34955682Smarkm{
350178825Sdfr    const unsigned char *format = (const unsigned char *)char_format;
351178825Sdfr    unsigned char c;
352233294Sstas    size_t len = 0;
35355682Smarkm
354178825Sdfr    while((c = *format++)) {
355178825Sdfr	if (c == '%') {
356178825Sdfr	    int flags          = 0;
357178825Sdfr	    int width          = 0;
358178825Sdfr	    int prec           = -1;
359178825Sdfr	    int size_t_flag    = 0;
360178825Sdfr	    int long_long_flag = 0;
361178825Sdfr	    int long_flag      = 0;
362178825Sdfr	    int short_flag     = 0;
36355682Smarkm
364178825Sdfr	    /* flags */
365178825Sdfr	    while((c = *format++)){
366178825Sdfr		if(c == '-')
367178825Sdfr		    flags |= minus_flag;
368178825Sdfr		else if(c == '+')
369178825Sdfr		    flags |= plus_flag;
370178825Sdfr		else if(c == ' ')
371178825Sdfr		    flags |= space_flag;
372178825Sdfr		else if(c == '#')
373178825Sdfr		    flags |= alternate_flag;
374178825Sdfr		else if(c == '0')
375178825Sdfr		    flags |= zero_flag;
376178825Sdfr		else if(c == '\'')
377178825Sdfr		    ; /* just ignore */
378178825Sdfr		else
379178825Sdfr		    break;
380178825Sdfr	    }
381233294Sstas
382178825Sdfr	    if((flags & space_flag) && (flags & plus_flag))
383178825Sdfr		flags ^= space_flag;
38455682Smarkm
385178825Sdfr	    if((flags & minus_flag) && (flags & zero_flag))
386178825Sdfr		flags ^= zero_flag;
38755682Smarkm
388178825Sdfr	    /* width */
389178825Sdfr	    if (isdigit(c))
390178825Sdfr		do {
391178825Sdfr		    width = width * 10 + c - '0';
392178825Sdfr		    c = *format++;
393178825Sdfr		} while(isdigit(c));
394178825Sdfr	    else if(c == '*') {
395178825Sdfr		width = va_arg(ap, int);
396178825Sdfr		c = *format++;
397178825Sdfr	    }
39855682Smarkm
399178825Sdfr	    /* precision */
400178825Sdfr	    if (c == '.') {
401178825Sdfr		prec = 0;
402178825Sdfr		c = *format++;
403178825Sdfr		if (isdigit(c))
404178825Sdfr		    do {
405178825Sdfr			prec = prec * 10 + c - '0';
406178825Sdfr			c = *format++;
407178825Sdfr		    } while(isdigit(c));
408178825Sdfr		else if (c == '*') {
409178825Sdfr		    prec = va_arg(ap, int);
410178825Sdfr		    c = *format++;
411178825Sdfr		}
412178825Sdfr	    }
41355682Smarkm
414178825Sdfr	    /* size */
41555682Smarkm
416178825Sdfr	    if (c == 'h') {
417178825Sdfr		short_flag = 1;
418178825Sdfr		c = *format++;
419178825Sdfr	    } else if (c == 'z') {
420178825Sdfr		size_t_flag = 1;
421178825Sdfr		c = *format++;
422178825Sdfr	    } else if (c == 'l') {
423178825Sdfr		long_flag = 1;
424178825Sdfr		c = *format++;
425178825Sdfr		if (c == 'l') {
426178825Sdfr		    long_long_flag = 1;
427178825Sdfr		    c = *format++;
428178825Sdfr		}
429178825Sdfr	    }
43055682Smarkm
431178825Sdfr	    if(c != 'd' && c != 'i')
432178825Sdfr		flags &= ~(plus_flag | space_flag);
43355682Smarkm
434178825Sdfr	    switch (c) {
435178825Sdfr	    case 'c' :
436178825Sdfr		append_char(state, va_arg(ap, int), width, flags);
437178825Sdfr		++len;
438178825Sdfr		break;
439178825Sdfr	    case 's' :
440178825Sdfr		len += append_string(state,
441178825Sdfr				     va_arg(ap, unsigned char*),
442178825Sdfr				     width,
443233294Sstas				     prec,
444178825Sdfr				     flags);
445178825Sdfr		break;
446178825Sdfr	    case 'd' :
447178825Sdfr	    case 'i' : {
448178825Sdfr		longest arg;
449178825Sdfr		u_longest num;
450178825Sdfr		int minusp = 0;
45155682Smarkm
452178825Sdfr		PARSE_INT_FORMAT(arg, ap, signed);
45355682Smarkm
454178825Sdfr		if (arg < 0) {
455178825Sdfr		    minusp = 1;
456178825Sdfr		    num = -arg;
457178825Sdfr		} else
458178825Sdfr		    num = arg;
45955682Smarkm
460178825Sdfr		len += append_number (state, num, 10, "0123456789",
461178825Sdfr				      width, prec, flags, minusp);
462178825Sdfr		break;
463178825Sdfr	    }
464178825Sdfr	    case 'u' : {
465178825Sdfr		u_longest arg;
46655682Smarkm
467178825Sdfr		PARSE_INT_FORMAT(arg, ap, unsigned);
46855682Smarkm
469178825Sdfr		len += append_number (state, arg, 10, "0123456789",
470178825Sdfr				      width, prec, flags, 0);
471178825Sdfr		break;
472178825Sdfr	    }
473178825Sdfr	    case 'o' : {
474178825Sdfr		u_longest arg;
47555682Smarkm
476178825Sdfr		PARSE_INT_FORMAT(arg, ap, unsigned);
47755682Smarkm
478178825Sdfr		len += append_number (state, arg, 010, "01234567",
479178825Sdfr				      width, prec, flags, 0);
480178825Sdfr		break;
481178825Sdfr	    }
482178825Sdfr	    case 'x' : {
483178825Sdfr		u_longest arg;
48455682Smarkm
485178825Sdfr		PARSE_INT_FORMAT(arg, ap, unsigned);
48655682Smarkm
487178825Sdfr		len += append_number (state, arg, 0x10, "0123456789abcdef",
488178825Sdfr				      width, prec, flags, 0);
489178825Sdfr		break;
490178825Sdfr	    }
491178825Sdfr	    case 'X' :{
492178825Sdfr		u_longest arg;
49355682Smarkm
494178825Sdfr		PARSE_INT_FORMAT(arg, ap, unsigned);
49555682Smarkm
496178825Sdfr		len += append_number (state, arg, 0x10, "0123456789ABCDEF",
497178825Sdfr				      width, prec, flags, 0);
498178825Sdfr		break;
499178825Sdfr	    }
500178825Sdfr	    case 'p' : {
501233294Sstas		u_longest arg = (u_longest)va_arg(ap, void*);
502178825Sdfr
503178825Sdfr		len += append_number (state, arg, 0x10, "0123456789ABCDEF",
504178825Sdfr				      width, prec, flags, 0);
505178825Sdfr		break;
506178825Sdfr	    }
507178825Sdfr	    case 'n' : {
508178825Sdfr		int *arg = va_arg(ap, int*);
509178825Sdfr		*arg = state->s - state->str;
510178825Sdfr		break;
511178825Sdfr	    }
512178825Sdfr	    case '\0' :
513178825Sdfr		--format;
514178825Sdfr		/* FALLTHROUGH */
515178825Sdfr	    case '%' :
516178825Sdfr		(*state->append_char)(state, c);
517178825Sdfr		++len;
518178825Sdfr		break;
519178825Sdfr	    default :
520178825Sdfr		(*state->append_char)(state, '%');
521178825Sdfr		(*state->append_char)(state, c);
522178825Sdfr		len += 2;
523178825Sdfr		break;
524178825Sdfr	    }
525178825Sdfr	} else {
526178825Sdfr	    (*state->append_char) (state, c);
527178825Sdfr	    ++len;
528178825Sdfr	}
52990926Snectar    }
530178825Sdfr    return len;
53155682Smarkm}
53255682Smarkm
53390926Snectar#if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
534233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
535233294Sstasrk_snprintf (char *str, size_t sz, const char *format, ...)
53655682Smarkm{
537178825Sdfr    va_list args;
538178825Sdfr    int ret;
53955682Smarkm
540178825Sdfr    va_start(args, format);
541178825Sdfr    ret = vsnprintf (str, sz, format, args);
542178825Sdfr    va_end(args);
54355682Smarkm
54455682Smarkm#ifdef PARANOIA
545178825Sdfr    {
546178825Sdfr	int ret2;
547178825Sdfr	char *tmp;
54855682Smarkm
549178825Sdfr	tmp = malloc (sz);
550178825Sdfr	if (tmp == NULL)
551178825Sdfr	    abort ();
55255682Smarkm
553178825Sdfr	va_start(args, format);
554178825Sdfr	ret2 = vsprintf (tmp, format, args);
555178825Sdfr	va_end(args);
556178825Sdfr	if (ret != ret2 || strcmp(str, tmp))
557178825Sdfr	    abort ();
558178825Sdfr	free (tmp);
559178825Sdfr    }
56055682Smarkm#endif
56155682Smarkm
562178825Sdfr    return ret;
56355682Smarkm}
56455682Smarkm#endif
56555682Smarkm
56690926Snectar#if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
567233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
568233294Sstasrk_asprintf (char **ret, const char *format, ...)
56955682Smarkm{
570178825Sdfr    va_list args;
571178825Sdfr    int val;
57255682Smarkm
573178825Sdfr    va_start(args, format);
574178825Sdfr    val = vasprintf (ret, format, args);
575178825Sdfr    va_end(args);
57655682Smarkm
57755682Smarkm#ifdef PARANOIA
578178825Sdfr    {
579178825Sdfr	int ret2;
580178825Sdfr	char *tmp;
581178825Sdfr	tmp = malloc (val + 1);
582178825Sdfr	if (tmp == NULL)
583178825Sdfr	    abort ();
58455682Smarkm
585178825Sdfr	va_start(args, format);
586178825Sdfr	ret2 = vsprintf (tmp, format, args);
587178825Sdfr	va_end(args);
588178825Sdfr	if (val != ret2 || strcmp(*ret, tmp))
589178825Sdfr	    abort ();
590178825Sdfr	free (tmp);
591178825Sdfr    }
59255682Smarkm#endif
59355682Smarkm
594178825Sdfr    return val;
59555682Smarkm}
59655682Smarkm#endif
59755682Smarkm
59890926Snectar#if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
599233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
600233294Sstasrk_asnprintf (char **ret, size_t max_sz, const char *format, ...)
60155682Smarkm{
602178825Sdfr    va_list args;
603178825Sdfr    int val;
60455682Smarkm
605178825Sdfr    va_start(args, format);
606178825Sdfr    val = vasnprintf (ret, max_sz, format, args);
60755682Smarkm
60855682Smarkm#ifdef PARANOIA
609178825Sdfr    {
610178825Sdfr	int ret2;
611178825Sdfr	char *tmp;
612178825Sdfr	tmp = malloc (val + 1);
613178825Sdfr	if (tmp == NULL)
614178825Sdfr	    abort ();
61555682Smarkm
616178825Sdfr	ret2 = vsprintf (tmp, format, args);
617178825Sdfr	if (val != ret2 || strcmp(*ret, tmp))
618178825Sdfr	    abort ();
619178825Sdfr	free (tmp);
620178825Sdfr    }
62155682Smarkm#endif
62255682Smarkm
623178825Sdfr    va_end(args);
624178825Sdfr    return val;
62555682Smarkm}
62655682Smarkm#endif
62755682Smarkm
62890926Snectar#if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
629233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
630233294Sstasrk_vasprintf (char **ret, const char *format, va_list args)
63155682Smarkm{
632178825Sdfr    return vasnprintf (ret, 0, format, args);
63355682Smarkm}
63455682Smarkm#endif
63555682Smarkm
63655682Smarkm
63790926Snectar#if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
638233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
639233294Sstasrk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
64055682Smarkm{
641233294Sstas    size_t st;
642178825Sdfr    struct snprintf_state state;
64355682Smarkm
644178825Sdfr    state.max_sz = max_sz;
645178825Sdfr    state.sz     = 1;
646178825Sdfr    state.str    = malloc(state.sz);
647178825Sdfr    if (state.str == NULL) {
648178825Sdfr	*ret = NULL;
649178825Sdfr	return -1;
650178825Sdfr    }
651178825Sdfr    state.s = state.str;
652178825Sdfr    state.theend = state.s + state.sz - 1;
653178825Sdfr    state.append_char = as_append_char;
65455682Smarkm
655178825Sdfr    st = xyzprintf (&state, format, args);
656178825Sdfr    if (st > state.sz) {
657178825Sdfr	free (state.str);
658178825Sdfr	*ret = NULL;
659178825Sdfr	return -1;
660178825Sdfr    } else {
661178825Sdfr	char *tmp;
66255682Smarkm
663178825Sdfr	*state.s = '\0';
664178825Sdfr	tmp = realloc (state.str, st+1);
665178825Sdfr	if (tmp == NULL) {
666178825Sdfr	    free (state.str);
667178825Sdfr	    *ret = NULL;
668178825Sdfr	    return -1;
669178825Sdfr	}
670178825Sdfr	*ret = tmp;
671178825Sdfr	return st;
67255682Smarkm    }
67355682Smarkm}
67455682Smarkm#endif
67555682Smarkm
67690926Snectar#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
677233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
678233294Sstasrk_vsnprintf (char *str, size_t sz, const char *format, va_list args)
67955682Smarkm{
680178825Sdfr    struct snprintf_state state;
681178825Sdfr    int ret;
682178825Sdfr    unsigned char *ustr = (unsigned char *)str;
68355682Smarkm
684178825Sdfr    state.max_sz = 0;
685178825Sdfr    state.sz     = sz;
686178825Sdfr    state.str    = ustr;
687178825Sdfr    state.s      = ustr;
688178825Sdfr    state.theend = ustr + sz - (sz > 0);
689178825Sdfr    state.append_char = sn_append_char;
69055682Smarkm
691178825Sdfr    ret = xyzprintf (&state, format, args);
692178825Sdfr    if (state.s != NULL && sz != 0)
693178825Sdfr	*state.s = '\0';
694178825Sdfr    return ret;
69555682Smarkm}
69655682Smarkm#endif
697