2 * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 /* $Id: snprintf.c 1429 2002-07-23 23:12:20Z strauss $ */
43 #include <sys/types.h>
52 #define MIN(a, b) ((a) < (b) ? (a) : (b))
53 #define MAX(a, b) ((a) < (b) ? (b) : (a))
73 unsigned char *theend;
76 int (*append_char)(struct state *, unsigned char);
77 int (*reserve)(struct state *, size_t);
81 #ifndef HAVE_VSNPRINTF
83 sn_reserve (struct state *state, size_t n)
85 return state->s + n > state->theend;
89 sn_append_char (struct state *state, unsigned char c)
91 if (sn_reserve (state, 1)) {
101 as_reserve (struct state *state, size_t n)
103 if (state->s + n > state->theend) {
104 int off = state->s - state->str;
107 if (state->max_sz && state->sz >= state->max_sz)
110 state->sz = MAX(state->sz * 2, state->sz + n);
112 state->sz = MIN(state->sz, state->max_sz);
113 tmp = realloc (state->str, state->sz);
117 state->s = state->str + off;
118 state->theend = state->str + state->sz - 1;
124 as_append_char (struct state *state, unsigned char c)
126 if(as_reserve (state, 1))
135 append_number(struct state *state,
136 unsigned long num, unsigned base, char *rep,
137 int width, int prec, int flags, int minusp)
142 /* given precision, ignore zero flag */
147 /* zero value with zero precision -> "" */
148 if(prec == 0 && num == 0)
151 if((*state->append_char)(state, rep[num % base]))
157 /* pad with prec zeros */
159 if((*state->append_char)(state, '0'))
163 /* add length of alternate prefix (added later) to len */
164 if(flags & alternate_flag && (base == 16 || base == 8))
167 if(flags & zero_flag){
169 if(minusp || (flags & space_flag) || (flags & plus_flag))
172 if((*state->append_char)(state, '0'))
177 /* add alternate prefix */
178 if(flags & alternate_flag && (base == 16 || base == 8)){
180 if((*state->append_char)(state, rep[10] + 23)) /* XXX */
182 if((*state->append_char)(state, '0'))
187 if((*state->append_char)(state, '-'))
190 } else if(flags & plus_flag) {
191 if((*state->append_char)(state, '+'))
194 } else if(flags & space_flag) {
195 if((*state->append_char)(state, ' '))
199 if(flags & minus_flag)
200 /* swap before padding with spaces */
201 for(i = 0; i < len / 2; i++){
202 char c = state->s[-i-1];
203 state->s[-i-1] = state->s[-len+i];
204 state->s[-len+i] = c;
208 if((*state->append_char)(state, ' '))
212 if(!(flags & minus_flag))
213 /* swap after padding with spaces */
214 for(i = 0; i < len / 2; i++){
215 char c = state->s[-i-1];
216 state->s[-i-1] = state->s[-len+i];
217 state->s[-len+i] = c;
224 append_string (struct state *state,
233 width -= strlen((char *)arg);
234 if(!(flags & minus_flag))
236 if((*state->append_char) (state, ' '))
239 while (*arg && prec--)
240 if ((*state->append_char) (state, *arg++))
244 if ((*state->append_char) (state, *arg++))
247 if(flags & minus_flag)
249 if((*state->append_char) (state, ' '))
255 append_char(struct state *state,
260 while(!(flags & minus_flag) && --width > 0)
261 if((*state->append_char) (state, ' '))
264 if((*state->append_char) (state, arg))
266 while((flags & minus_flag) && --width > 0)
267 if((*state->append_char) (state, ' '))
274 * This can't be made into a function...
277 #define PARSE_INT_FORMAT(res, arg, unsig) \
279 res = (unsig long)va_arg(arg, unsig long); \
280 else if (short_flag) \
281 res = (unsig short)va_arg(arg, unsig int); \
283 res = (unsig int)va_arg(arg, unsig int)
286 * zyxprintf - return 0 or -1
290 xyzprintf (struct state *state, const char *char_format, va_list ap)
292 const unsigned char *format = (const unsigned char *)char_format;
295 while((c = *format++)) {
304 while((c = *format++)){
312 flags |= alternate_flag;
319 if((flags & space_flag) && (flags & plus_flag))
322 if((flags & minus_flag) && (flags & zero_flag))
328 width = width * 10 + c - '0';
332 width = va_arg(ap, int);
342 prec = prec * 10 + c - '0';
346 prec = va_arg(ap, int);
356 } else if (c == 'l') {
363 if(append_char(state, va_arg(ap, int), width, flags))
367 if (append_string(state,
368 va_arg(ap, unsigned char*),
380 PARSE_INT_FORMAT(arg, ap, signed);
388 if (append_number (state, num, 10, "0123456789",
389 width, prec, flags, minusp))
396 PARSE_INT_FORMAT(arg, ap, unsigned);
398 if (append_number (state, arg, 10, "0123456789",
399 width, prec, flags, 0))
406 PARSE_INT_FORMAT(arg, ap, unsigned);
408 if (append_number (state, arg, 010, "01234567",
409 width, prec, flags, 0))
416 PARSE_INT_FORMAT(arg, ap, unsigned);
418 if (append_number (state, arg, 0x10, "0123456789abcdef",
419 width, prec, flags, 0))
426 PARSE_INT_FORMAT(arg, ap, unsigned);
428 if (append_number (state, arg, 0x10, "0123456789ABCDEF",
429 width, prec, flags, 0))
434 unsigned long arg = (unsigned long)va_arg(ap, void*);
436 if (append_number (state, arg, 0x10, "0123456789ABCDEF",
437 width, prec, flags, 0))
442 int *arg = va_arg(ap, int*);
443 *arg = state->s - state->str;
450 if ((*state->append_char)(state, c))
454 if ( (*state->append_char)(state, '%')
455 || (*state->append_char)(state, c))
460 if ((*state->append_char) (state, c))
466 #ifndef HAVE_SNPRINTF
468 snprintf (char *str, size_t sz, const char *format, ...)
473 va_start(args, format);
474 ret = vsnprintf (str, sz, format, args);
485 ret2 = vsprintf (tmp, format, args);
486 if (ret != ret2 || strcmp(str, tmp))
497 #ifndef HAVE_ASPRINTF
499 asprintf (char **ret, const char *format, ...)
504 va_start(args, format);
505 val = vasprintf (ret, format, args);
511 tmp = malloc (val + 1);
515 ret2 = vsprintf (tmp, format, args);
516 if (val != ret2 || strcmp(*ret, tmp))
527 #ifndef HAVE_ASNPRINTF
529 asnprintf (char **ret, size_t max_sz, const char *format, ...)
534 va_start(args, format);
535 val = vasnprintf (ret, max_sz, format, args);
541 tmp = malloc (val + 1);
545 ret2 = vsprintf (tmp, format, args);
546 if (val != ret2 || strcmp(*ret, tmp))
557 #ifndef HAVE_VASPRINTF
559 vasprintf (char **ret, const char *format, va_list args)
561 return vasnprintf (ret, 0, format, args);
566 #ifndef HAVE_VASNPRINTF
568 vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
574 state.max_sz = max_sz;
576 state.str = malloc(state.sz);
577 if (state.str == NULL) {
582 state.theend = state.s + state.sz - 1;
583 state.append_char = as_append_char;
584 state.reserve = as_reserve;
586 st = xyzprintf (&state, format, args);
595 len = state.s - state.str;
596 tmp = realloc (state.str, len+1);
608 #ifndef HAVE_VSNPRINTF
610 vsnprintf (char *str, size_t sz, const char *format, va_list args)
614 unsigned char *ustr = (unsigned char *)str;
620 state.theend = ustr + sz - 1;
621 state.append_char = sn_append_char;
622 state.reserve = sn_reserve;
624 ret = xyzprintf (&state, format, args);
629 return state.s - state.str;