snprintf.c revision 2949f58a438f6fd85f66a8b7ed4708042cde4b37
19189445c0a66d074dcded77b9c7322ef45422727George Mount/*
29189445c0a66d074dcded77b9c7322ef45422727George Mount * Copyright (c) 1995-1999 Kungliga Tekniska H�gskolan
39189445c0a66d074dcded77b9c7322ef45422727George Mount * (Royal Institute of Technology, Stockholm, Sweden).
49189445c0a66d074dcded77b9c7322ef45422727George Mount * All rights reserved.
59189445c0a66d074dcded77b9c7322ef45422727George Mount *
69189445c0a66d074dcded77b9c7322ef45422727George Mount * Redistribution and use in source and binary forms, with or without
79189445c0a66d074dcded77b9c7322ef45422727George Mount * modification, are permitted provided that the following conditions
89189445c0a66d074dcded77b9c7322ef45422727George Mount * are met:
99189445c0a66d074dcded77b9c7322ef45422727George Mount *
109189445c0a66d074dcded77b9c7322ef45422727George Mount * 1. Redistributions of source code must retain the above copyright
119189445c0a66d074dcded77b9c7322ef45422727George Mount *    notice, this list of conditions and the following disclaimer.
129189445c0a66d074dcded77b9c7322ef45422727George Mount *
139189445c0a66d074dcded77b9c7322ef45422727George Mount * 2. Redistributions in binary form must reproduce the above copyright
149189445c0a66d074dcded77b9c7322ef45422727George Mount *    notice, this list of conditions and the following disclaimer in the
159189445c0a66d074dcded77b9c7322ef45422727George Mount *    documentation and/or other materials provided with the distribution.
169189445c0a66d074dcded77b9c7322ef45422727George Mount *
179189445c0a66d074dcded77b9c7322ef45422727George Mount * 3. Neither the name of the Institute nor the names of its contributors
189189445c0a66d074dcded77b9c7322ef45422727George Mount *    may be used to endorse or promote products derived from this software
199189445c0a66d074dcded77b9c7322ef45422727George Mount *    without specific prior written permission.
209189445c0a66d074dcded77b9c7322ef45422727George Mount *
219189445c0a66d074dcded77b9c7322ef45422727George Mount * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
229189445c0a66d074dcded77b9c7322ef45422727George Mount * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239189445c0a66d074dcded77b9c7322ef45422727George Mount * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249189445c0a66d074dcded77b9c7322ef45422727George Mount * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
259189445c0a66d074dcded77b9c7322ef45422727George Mount * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269189445c0a66d074dcded77b9c7322ef45422727George Mount * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279189445c0a66d074dcded77b9c7322ef45422727George Mount * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289189445c0a66d074dcded77b9c7322ef45422727George Mount * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299189445c0a66d074dcded77b9c7322ef45422727George Mount * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309189445c0a66d074dcded77b9c7322ef45422727George Mount * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319189445c0a66d074dcded77b9c7322ef45422727George Mount * SUCH DAMAGE.
329189445c0a66d074dcded77b9c7322ef45422727George Mount */
339189445c0a66d074dcded77b9c7322ef45422727George Mount
349189445c0a66d074dcded77b9c7322ef45422727George Mount/* $Id: snprintf.c,v 1.8 2003/11/16 09:36:51 guy Exp $ */
359189445c0a66d074dcded77b9c7322ef45422727George Mount
369189445c0a66d074dcded77b9c7322ef45422727George Mount#ifdef HAVE_CONFIG_H
379189445c0a66d074dcded77b9c7322ef45422727George Mount#include <config.h>
389189445c0a66d074dcded77b9c7322ef45422727George Mount#endif
399189445c0a66d074dcded77b9c7322ef45422727George Mount
409189445c0a66d074dcded77b9c7322ef45422727George Mount#ifndef lint
419189445c0a66d074dcded77b9c7322ef45422727George Mountstatic const char rcsid[] _U_ =
429189445c0a66d074dcded77b9c7322ef45422727George Mount     "@(#) $Header: /tcpdump/master/tcpdump/missing/snprintf.c,v 1.8 2003/11/16 09:36:51 guy Exp $";
439189445c0a66d074dcded77b9c7322ef45422727George Mount#endif
449189445c0a66d074dcded77b9c7322ef45422727George Mount
459189445c0a66d074dcded77b9c7322ef45422727George Mount#include <stdio.h>
469189445c0a66d074dcded77b9c7322ef45422727George Mount#include <stdarg.h>
479189445c0a66d074dcded77b9c7322ef45422727George Mount#include <stdlib.h>
489189445c0a66d074dcded77b9c7322ef45422727George Mount#include <string.h>
499189445c0a66d074dcded77b9c7322ef45422727George Mount#include <ctype.h>
509189445c0a66d074dcded77b9c7322ef45422727George Mount#include <sys/types.h>
519189445c0a66d074dcded77b9c7322ef45422727George Mount
529189445c0a66d074dcded77b9c7322ef45422727George Mount#include <interface.h>
539189445c0a66d074dcded77b9c7322ef45422727George Mount
549189445c0a66d074dcded77b9c7322ef45422727George Mountenum format_flags {
559189445c0a66d074dcded77b9c7322ef45422727George Mount    minus_flag     =  1,
569189445c0a66d074dcded77b9c7322ef45422727George Mount    plus_flag      =  2,
579189445c0a66d074dcded77b9c7322ef45422727George Mount    space_flag     =  4,
589189445c0a66d074dcded77b9c7322ef45422727George Mount    alternate_flag =  8,
599189445c0a66d074dcded77b9c7322ef45422727George Mount    zero_flag      = 16
609189445c0a66d074dcded77b9c7322ef45422727George Mount};
619189445c0a66d074dcded77b9c7322ef45422727George Mount
629189445c0a66d074dcded77b9c7322ef45422727George Mount/*
639189445c0a66d074dcded77b9c7322ef45422727George Mount * Common state
649189445c0a66d074dcded77b9c7322ef45422727George Mount */
659189445c0a66d074dcded77b9c7322ef45422727George Mount
669189445c0a66d074dcded77b9c7322ef45422727George Mountstruct state {
679189445c0a66d074dcded77b9c7322ef45422727George Mount  unsigned char *str;
689189445c0a66d074dcded77b9c7322ef45422727George Mount  unsigned char *s;
699189445c0a66d074dcded77b9c7322ef45422727George Mount  unsigned char *theend;
709189445c0a66d074dcded77b9c7322ef45422727George Mount  size_t sz;
719189445c0a66d074dcded77b9c7322ef45422727George Mount  size_t max_sz;
729189445c0a66d074dcded77b9c7322ef45422727George Mount  int (*append_char)(struct state *, unsigned char);
739189445c0a66d074dcded77b9c7322ef45422727George Mount  int (*reserve)(struct state *, size_t);
749189445c0a66d074dcded77b9c7322ef45422727George Mount  /* XXX - methods */
759189445c0a66d074dcded77b9c7322ef45422727George Mount};
769189445c0a66d074dcded77b9c7322ef45422727George Mount
779189445c0a66d074dcded77b9c7322ef45422727George Mount#ifndef HAVE_VSNPRINTF
789189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
799189445c0a66d074dcded77b9c7322ef45422727George Mountsn_reserve (struct state *state, size_t n)
809189445c0a66d074dcded77b9c7322ef45422727George Mount{
819189445c0a66d074dcded77b9c7322ef45422727George Mount  return state->s + n > state->theend;
829189445c0a66d074dcded77b9c7322ef45422727George Mount}
839189445c0a66d074dcded77b9c7322ef45422727George Mount
849189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
859189445c0a66d074dcded77b9c7322ef45422727George Mountsn_append_char (struct state *state, unsigned char c)
869189445c0a66d074dcded77b9c7322ef45422727George Mount{
879189445c0a66d074dcded77b9c7322ef45422727George Mount  if (sn_reserve (state, 1)) {
889189445c0a66d074dcded77b9c7322ef45422727George Mount    return 1;
899189445c0a66d074dcded77b9c7322ef45422727George Mount  } else {
909189445c0a66d074dcded77b9c7322ef45422727George Mount    *state->s++ = c;
919189445c0a66d074dcded77b9c7322ef45422727George Mount    return 0;
929189445c0a66d074dcded77b9c7322ef45422727George Mount  }
939189445c0a66d074dcded77b9c7322ef45422727George Mount}
949189445c0a66d074dcded77b9c7322ef45422727George Mount#endif
959189445c0a66d074dcded77b9c7322ef45422727George Mount
969189445c0a66d074dcded77b9c7322ef45422727George Mount#if 0
979189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
989189445c0a66d074dcded77b9c7322ef45422727George Mountas_reserve (struct state *state, size_t n)
999189445c0a66d074dcded77b9c7322ef45422727George Mount{
1009189445c0a66d074dcded77b9c7322ef45422727George Mount  if (state->s + n > state->theend) {
1019189445c0a66d074dcded77b9c7322ef45422727George Mount    int off = state->s - state->str;
1029189445c0a66d074dcded77b9c7322ef45422727George Mount    unsigned char *tmp;
1039189445c0a66d074dcded77b9c7322ef45422727George Mount
1049189445c0a66d074dcded77b9c7322ef45422727George Mount    if (state->max_sz && state->sz >= state->max_sz)
1059189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1069189445c0a66d074dcded77b9c7322ef45422727George Mount
1079189445c0a66d074dcded77b9c7322ef45422727George Mount    state->sz = max(state->sz * 2, state->sz + n);
1089189445c0a66d074dcded77b9c7322ef45422727George Mount    if (state->max_sz)
1099189445c0a66d074dcded77b9c7322ef45422727George Mount      state->sz = min(state->sz, state->max_sz);
1109189445c0a66d074dcded77b9c7322ef45422727George Mount    tmp = realloc (state->str, state->sz);
1119189445c0a66d074dcded77b9c7322ef45422727George Mount    if (tmp == NULL)
1129189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1139189445c0a66d074dcded77b9c7322ef45422727George Mount    state->str = tmp;
1149189445c0a66d074dcded77b9c7322ef45422727George Mount    state->s = state->str + off;
1159189445c0a66d074dcded77b9c7322ef45422727George Mount    state->theend = state->str + state->sz - 1;
1169189445c0a66d074dcded77b9c7322ef45422727George Mount  }
1179189445c0a66d074dcded77b9c7322ef45422727George Mount  return 0;
1189189445c0a66d074dcded77b9c7322ef45422727George Mount}
1199189445c0a66d074dcded77b9c7322ef45422727George Mount
1209189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
1219189445c0a66d074dcded77b9c7322ef45422727George Mountas_append_char (struct state *state, unsigned char c)
1229189445c0a66d074dcded77b9c7322ef45422727George Mount{
1239189445c0a66d074dcded77b9c7322ef45422727George Mount  if(as_reserve (state, 1))
1249189445c0a66d074dcded77b9c7322ef45422727George Mount    return 1;
1259189445c0a66d074dcded77b9c7322ef45422727George Mount  else {
1269189445c0a66d074dcded77b9c7322ef45422727George Mount    *state->s++ = c;
1279189445c0a66d074dcded77b9c7322ef45422727George Mount    return 0;
1289189445c0a66d074dcded77b9c7322ef45422727George Mount  }
1299189445c0a66d074dcded77b9c7322ef45422727George Mount}
1309189445c0a66d074dcded77b9c7322ef45422727George Mount#endif
1319189445c0a66d074dcded77b9c7322ef45422727George Mount
1329189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
1339189445c0a66d074dcded77b9c7322ef45422727George Mountappend_number(struct state *state,
1349189445c0a66d074dcded77b9c7322ef45422727George Mount	      unsigned long num, unsigned base, char *rep,
1359189445c0a66d074dcded77b9c7322ef45422727George Mount	      int width, int prec, int flags, int minusp)
1369189445c0a66d074dcded77b9c7322ef45422727George Mount{
1379189445c0a66d074dcded77b9c7322ef45422727George Mount  int len = 0;
1389189445c0a66d074dcded77b9c7322ef45422727George Mount  int i;
1399189445c0a66d074dcded77b9c7322ef45422727George Mount
1409189445c0a66d074dcded77b9c7322ef45422727George Mount  /* given precision, ignore zero flag */
1419189445c0a66d074dcded77b9c7322ef45422727George Mount  if(prec != -1)
1429189445c0a66d074dcded77b9c7322ef45422727George Mount    flags &= ~zero_flag;
1439189445c0a66d074dcded77b9c7322ef45422727George Mount  else
1449189445c0a66d074dcded77b9c7322ef45422727George Mount    prec = 1;
1459189445c0a66d074dcded77b9c7322ef45422727George Mount  /* zero value with zero precision -> "" */
1469189445c0a66d074dcded77b9c7322ef45422727George Mount  if(prec == 0 && num == 0)
1479189445c0a66d074dcded77b9c7322ef45422727George Mount    return 0;
1489189445c0a66d074dcded77b9c7322ef45422727George Mount  do{
1499189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state, rep[num % base]))
1509189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1519189445c0a66d074dcded77b9c7322ef45422727George Mount    len++;
1529189445c0a66d074dcded77b9c7322ef45422727George Mount    num /= base;
1539189445c0a66d074dcded77b9c7322ef45422727George Mount  }while(num);
1549189445c0a66d074dcded77b9c7322ef45422727George Mount  prec -= len;
1559189445c0a66d074dcded77b9c7322ef45422727George Mount  /* pad with prec zeros */
1569189445c0a66d074dcded77b9c7322ef45422727George Mount  while(prec-- > 0){
1579189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state, '0'))
1589189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1599189445c0a66d074dcded77b9c7322ef45422727George Mount    len++;
1609189445c0a66d074dcded77b9c7322ef45422727George Mount  }
1619189445c0a66d074dcded77b9c7322ef45422727George Mount  /* add length of alternate prefix (added later) to len */
1629189445c0a66d074dcded77b9c7322ef45422727George Mount  if(flags & alternate_flag && (base == 16 || base == 8))
1639189445c0a66d074dcded77b9c7322ef45422727George Mount    len += base / 8;
1649189445c0a66d074dcded77b9c7322ef45422727George Mount  /* pad with zeros */
1659189445c0a66d074dcded77b9c7322ef45422727George Mount  if(flags & zero_flag){
1669189445c0a66d074dcded77b9c7322ef45422727George Mount    width -= len;
1679189445c0a66d074dcded77b9c7322ef45422727George Mount    if(minusp || (flags & space_flag) || (flags & plus_flag))
1689189445c0a66d074dcded77b9c7322ef45422727George Mount      width--;
1699189445c0a66d074dcded77b9c7322ef45422727George Mount    while(width-- > 0){
1709189445c0a66d074dcded77b9c7322ef45422727George Mount      if((*state->append_char)(state, '0'))
1719189445c0a66d074dcded77b9c7322ef45422727George Mount	return 1;
1729189445c0a66d074dcded77b9c7322ef45422727George Mount      len++;
1739189445c0a66d074dcded77b9c7322ef45422727George Mount    }
1749189445c0a66d074dcded77b9c7322ef45422727George Mount  }
1759189445c0a66d074dcded77b9c7322ef45422727George Mount  /* add alternate prefix */
1769189445c0a66d074dcded77b9c7322ef45422727George Mount  if(flags & alternate_flag && (base == 16 || base == 8)){
1779189445c0a66d074dcded77b9c7322ef45422727George Mount    if(base == 16)
1789189445c0a66d074dcded77b9c7322ef45422727George Mount      if((*state->append_char)(state, rep[10] + 23)) /* XXX */
1799189445c0a66d074dcded77b9c7322ef45422727George Mount	return 1;
1809189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state, '0'))
1819189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1829189445c0a66d074dcded77b9c7322ef45422727George Mount  }
1839189445c0a66d074dcded77b9c7322ef45422727George Mount  /* add sign */
1849189445c0a66d074dcded77b9c7322ef45422727George Mount  if(minusp){
1859189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state, '-'))
1869189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1879189445c0a66d074dcded77b9c7322ef45422727George Mount    len++;
1889189445c0a66d074dcded77b9c7322ef45422727George Mount  } else if(flags & plus_flag) {
1899189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state, '+'))
1909189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1919189445c0a66d074dcded77b9c7322ef45422727George Mount    len++;
1929189445c0a66d074dcded77b9c7322ef45422727George Mount  } else if(flags & space_flag) {
1939189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state, ' '))
1949189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
1959189445c0a66d074dcded77b9c7322ef45422727George Mount    len++;
1969189445c0a66d074dcded77b9c7322ef45422727George Mount  }
1979189445c0a66d074dcded77b9c7322ef45422727George Mount  if(flags & minus_flag)
1989189445c0a66d074dcded77b9c7322ef45422727George Mount    /* swap before padding with spaces */
1999189445c0a66d074dcded77b9c7322ef45422727George Mount    for(i = 0; i < len / 2; i++){
2009189445c0a66d074dcded77b9c7322ef45422727George Mount      char c = state->s[-i-1];
2019189445c0a66d074dcded77b9c7322ef45422727George Mount      state->s[-i-1] = state->s[-len+i];
2029189445c0a66d074dcded77b9c7322ef45422727George Mount      state->s[-len+i] = c;
2039189445c0a66d074dcded77b9c7322ef45422727George Mount    }
2049189445c0a66d074dcded77b9c7322ef45422727George Mount  width -= len;
2059189445c0a66d074dcded77b9c7322ef45422727George Mount  while(width-- > 0){
2069189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char)(state,  ' '))
2079189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
2089189445c0a66d074dcded77b9c7322ef45422727George Mount    len++;
2099189445c0a66d074dcded77b9c7322ef45422727George Mount  }
2109189445c0a66d074dcded77b9c7322ef45422727George Mount  if(!(flags & minus_flag))
2119189445c0a66d074dcded77b9c7322ef45422727George Mount    /* swap after padding with spaces */
2129189445c0a66d074dcded77b9c7322ef45422727George Mount    for(i = 0; i < len / 2; i++){
2139189445c0a66d074dcded77b9c7322ef45422727George Mount      char c = state->s[-i-1];
2149189445c0a66d074dcded77b9c7322ef45422727George Mount      state->s[-i-1] = state->s[-len+i];
2159189445c0a66d074dcded77b9c7322ef45422727George Mount      state->s[-len+i] = c;
2169189445c0a66d074dcded77b9c7322ef45422727George Mount    }
2179189445c0a66d074dcded77b9c7322ef45422727George Mount
2189189445c0a66d074dcded77b9c7322ef45422727George Mount  return 0;
2199189445c0a66d074dcded77b9c7322ef45422727George Mount}
2209189445c0a66d074dcded77b9c7322ef45422727George Mount
2219189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
2229189445c0a66d074dcded77b9c7322ef45422727George Mountappend_string (struct state *state,
2239189445c0a66d074dcded77b9c7322ef45422727George Mount	       unsigned char *arg,
2249189445c0a66d074dcded77b9c7322ef45422727George Mount	       int width,
2259189445c0a66d074dcded77b9c7322ef45422727George Mount	       int prec,
2269189445c0a66d074dcded77b9c7322ef45422727George Mount	       int flags)
2279189445c0a66d074dcded77b9c7322ef45422727George Mount{
2289189445c0a66d074dcded77b9c7322ef45422727George Mount  if(prec != -1)
2299189445c0a66d074dcded77b9c7322ef45422727George Mount    width -= prec;
2309189445c0a66d074dcded77b9c7322ef45422727George Mount  else
2319189445c0a66d074dcded77b9c7322ef45422727George Mount    width -= strlen((char *)arg);
2329189445c0a66d074dcded77b9c7322ef45422727George Mount  if(!(flags & minus_flag))
2339189445c0a66d074dcded77b9c7322ef45422727George Mount    while(width-- > 0)
2349189445c0a66d074dcded77b9c7322ef45422727George Mount      if((*state->append_char) (state, ' '))
2359189445c0a66d074dcded77b9c7322ef45422727George Mount	return 1;
2369189445c0a66d074dcded77b9c7322ef45422727George Mount  if (prec != -1) {
2379189445c0a66d074dcded77b9c7322ef45422727George Mount    while (*arg && prec--)
2389189445c0a66d074dcded77b9c7322ef45422727George Mount      if ((*state->append_char) (state, *arg++))
2399189445c0a66d074dcded77b9c7322ef45422727George Mount	return 1;
2409189445c0a66d074dcded77b9c7322ef45422727George Mount  } else {
2419189445c0a66d074dcded77b9c7322ef45422727George Mount    while (*arg)
2429189445c0a66d074dcded77b9c7322ef45422727George Mount      if ((*state->append_char) (state, *arg++))
2439189445c0a66d074dcded77b9c7322ef45422727George Mount	return 1;
2449189445c0a66d074dcded77b9c7322ef45422727George Mount  }
2459189445c0a66d074dcded77b9c7322ef45422727George Mount  if(flags & minus_flag)
2469189445c0a66d074dcded77b9c7322ef45422727George Mount    while(width-- > 0)
2479189445c0a66d074dcded77b9c7322ef45422727George Mount      if((*state->append_char) (state, ' '))
2489189445c0a66d074dcded77b9c7322ef45422727George Mount	return 1;
2499189445c0a66d074dcded77b9c7322ef45422727George Mount  return 0;
2509189445c0a66d074dcded77b9c7322ef45422727George Mount}
2519189445c0a66d074dcded77b9c7322ef45422727George Mount
2529189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
2539189445c0a66d074dcded77b9c7322ef45422727George Mountappend_char(struct state *state,
2549189445c0a66d074dcded77b9c7322ef45422727George Mount	    unsigned char arg,
2559189445c0a66d074dcded77b9c7322ef45422727George Mount	    int width,
2569189445c0a66d074dcded77b9c7322ef45422727George Mount	    int flags)
2579189445c0a66d074dcded77b9c7322ef45422727George Mount{
2589189445c0a66d074dcded77b9c7322ef45422727George Mount  while(!(flags & minus_flag) && --width > 0)
2599189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char) (state, ' '))
2609189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
2619189445c0a66d074dcded77b9c7322ef45422727George Mount
2629189445c0a66d074dcded77b9c7322ef45422727George Mount  if((*state->append_char) (state, arg))
2639189445c0a66d074dcded77b9c7322ef45422727George Mount    return 1;
2649189445c0a66d074dcded77b9c7322ef45422727George Mount  while((flags & minus_flag) && --width > 0)
2659189445c0a66d074dcded77b9c7322ef45422727George Mount    if((*state->append_char) (state, ' '))
2669189445c0a66d074dcded77b9c7322ef45422727George Mount      return 1;
2679189445c0a66d074dcded77b9c7322ef45422727George Mount
2689189445c0a66d074dcded77b9c7322ef45422727George Mount  return 0;
2699189445c0a66d074dcded77b9c7322ef45422727George Mount}
2709189445c0a66d074dcded77b9c7322ef45422727George Mount
2719189445c0a66d074dcded77b9c7322ef45422727George Mount/*
2729189445c0a66d074dcded77b9c7322ef45422727George Mount * This can't be made into a function...
2739189445c0a66d074dcded77b9c7322ef45422727George Mount */
2749189445c0a66d074dcded77b9c7322ef45422727George Mount
2759189445c0a66d074dcded77b9c7322ef45422727George Mount#define PARSE_INT_FORMAT(res, arg, unsig) \
2769189445c0a66d074dcded77b9c7322ef45422727George Mountif (long_flag) \
2779189445c0a66d074dcded77b9c7322ef45422727George Mount     res = (unsig long)va_arg(arg, unsig long); \
2789189445c0a66d074dcded77b9c7322ef45422727George Mountelse if (short_flag) \
2799189445c0a66d074dcded77b9c7322ef45422727George Mount     res = (unsig short)va_arg(arg, unsig int); \
2809189445c0a66d074dcded77b9c7322ef45422727George Mountelse \
2819189445c0a66d074dcded77b9c7322ef45422727George Mount     res = (unsig int)va_arg(arg, unsig int)
2829189445c0a66d074dcded77b9c7322ef45422727George Mount
2839189445c0a66d074dcded77b9c7322ef45422727George Mount/*
2849189445c0a66d074dcded77b9c7322ef45422727George Mount * zyxprintf - return 0 or -1
2859189445c0a66d074dcded77b9c7322ef45422727George Mount */
2869189445c0a66d074dcded77b9c7322ef45422727George Mount
2879189445c0a66d074dcded77b9c7322ef45422727George Mountstatic int
2889189445c0a66d074dcded77b9c7322ef45422727George Mountxyzprintf (struct state *state, const char *char_format, va_list ap)
2899189445c0a66d074dcded77b9c7322ef45422727George Mount{
2909189445c0a66d074dcded77b9c7322ef45422727George Mount  const unsigned char *format = (const unsigned char *)char_format;
2919189445c0a66d074dcded77b9c7322ef45422727George Mount  unsigned char c;
2929189445c0a66d074dcded77b9c7322ef45422727George Mount
2939189445c0a66d074dcded77b9c7322ef45422727George Mount  while((c = *format++)) {
2949189445c0a66d074dcded77b9c7322ef45422727George Mount    if (c == '%') {
2959189445c0a66d074dcded77b9c7322ef45422727George Mount      int flags      = 0;
2969189445c0a66d074dcded77b9c7322ef45422727George Mount      int width      = 0;
2979189445c0a66d074dcded77b9c7322ef45422727George Mount      int prec       = -1;
2989189445c0a66d074dcded77b9c7322ef45422727George Mount      int long_flag  = 0;
2999189445c0a66d074dcded77b9c7322ef45422727George Mount      int short_flag = 0;
3009189445c0a66d074dcded77b9c7322ef45422727George Mount
3019189445c0a66d074dcded77b9c7322ef45422727George Mount      /* flags */
3029189445c0a66d074dcded77b9c7322ef45422727George Mount      while((c = *format++)){
3039189445c0a66d074dcded77b9c7322ef45422727George Mount	if(c == '-')
3049189445c0a66d074dcded77b9c7322ef45422727George Mount	  flags |= minus_flag;
3059189445c0a66d074dcded77b9c7322ef45422727George Mount	else if(c == '+')
3069189445c0a66d074dcded77b9c7322ef45422727George Mount	  flags |= plus_flag;
3079189445c0a66d074dcded77b9c7322ef45422727George Mount	else if(c == ' ')
3089189445c0a66d074dcded77b9c7322ef45422727George Mount	  flags |= space_flag;
3099189445c0a66d074dcded77b9c7322ef45422727George Mount	else if(c == '#')
3109189445c0a66d074dcded77b9c7322ef45422727George Mount	  flags |= alternate_flag;
3119189445c0a66d074dcded77b9c7322ef45422727George Mount	else if(c == '0')
3129189445c0a66d074dcded77b9c7322ef45422727George Mount	  flags |= zero_flag;
3139189445c0a66d074dcded77b9c7322ef45422727George Mount	else
3149189445c0a66d074dcded77b9c7322ef45422727George Mount	  break;
3159189445c0a66d074dcded77b9c7322ef45422727George Mount      }
3169189445c0a66d074dcded77b9c7322ef45422727George Mount
3179189445c0a66d074dcded77b9c7322ef45422727George Mount      if((flags & space_flag) && (flags & plus_flag))
3189189445c0a66d074dcded77b9c7322ef45422727George Mount	flags ^= space_flag;
3199189445c0a66d074dcded77b9c7322ef45422727George Mount
3209189445c0a66d074dcded77b9c7322ef45422727George Mount      if((flags & minus_flag) && (flags & zero_flag))
3219189445c0a66d074dcded77b9c7322ef45422727George Mount	flags ^= zero_flag;
3229189445c0a66d074dcded77b9c7322ef45422727George Mount
3239189445c0a66d074dcded77b9c7322ef45422727George Mount      /* width */
3249189445c0a66d074dcded77b9c7322ef45422727George Mount      if (isdigit(c))
3259189445c0a66d074dcded77b9c7322ef45422727George Mount	do {
3269189445c0a66d074dcded77b9c7322ef45422727George Mount	  width = width * 10 + c - '0';
3279189445c0a66d074dcded77b9c7322ef45422727George Mount	  c = *format++;
3289189445c0a66d074dcded77b9c7322ef45422727George Mount	} while(isdigit(c));
3299189445c0a66d074dcded77b9c7322ef45422727George Mount      else if(c == '*') {
3309189445c0a66d074dcded77b9c7322ef45422727George Mount	width = va_arg(ap, int);
3319189445c0a66d074dcded77b9c7322ef45422727George Mount	c = *format++;
3329189445c0a66d074dcded77b9c7322ef45422727George Mount      }
3339189445c0a66d074dcded77b9c7322ef45422727George Mount
3349189445c0a66d074dcded77b9c7322ef45422727George Mount      /* precision */
3359189445c0a66d074dcded77b9c7322ef45422727George Mount      if (c == '.') {
3369189445c0a66d074dcded77b9c7322ef45422727George Mount	prec = 0;
3379189445c0a66d074dcded77b9c7322ef45422727George Mount	c = *format++;
3389189445c0a66d074dcded77b9c7322ef45422727George Mount	if (isdigit(c))
3399189445c0a66d074dcded77b9c7322ef45422727George Mount	  do {
3409189445c0a66d074dcded77b9c7322ef45422727George Mount	    prec = prec * 10 + c - '0';
3419189445c0a66d074dcded77b9c7322ef45422727George Mount	    c = *format++;
3429189445c0a66d074dcded77b9c7322ef45422727George Mount	  } while(isdigit(c));
3439189445c0a66d074dcded77b9c7322ef45422727George Mount	else if (c == '*') {
3449189445c0a66d074dcded77b9c7322ef45422727George Mount	  prec = va_arg(ap, int);
3459189445c0a66d074dcded77b9c7322ef45422727George Mount	  c = *format++;
3469189445c0a66d074dcded77b9c7322ef45422727George Mount	}
3479189445c0a66d074dcded77b9c7322ef45422727George Mount      }
3489189445c0a66d074dcded77b9c7322ef45422727George Mount
3499189445c0a66d074dcded77b9c7322ef45422727George Mount      /* size */
3509189445c0a66d074dcded77b9c7322ef45422727George Mount
3519189445c0a66d074dcded77b9c7322ef45422727George Mount      if (c == 'h') {
3529189445c0a66d074dcded77b9c7322ef45422727George Mount	short_flag = 1;
3539189445c0a66d074dcded77b9c7322ef45422727George Mount	c = *format++;
3549189445c0a66d074dcded77b9c7322ef45422727George Mount      } else if (c == 'l') {
3559189445c0a66d074dcded77b9c7322ef45422727George Mount	long_flag = 1;
3569189445c0a66d074dcded77b9c7322ef45422727George Mount	c = *format++;
3579189445c0a66d074dcded77b9c7322ef45422727George Mount      }
3589189445c0a66d074dcded77b9c7322ef45422727George Mount
3599189445c0a66d074dcded77b9c7322ef45422727George Mount      switch (c) {
3609189445c0a66d074dcded77b9c7322ef45422727George Mount      case 'c' :
3619189445c0a66d074dcded77b9c7322ef45422727George Mount	if(append_char(state, va_arg(ap, int), width, flags))
3629189445c0a66d074dcded77b9c7322ef45422727George Mount	  return -1;
3639189445c0a66d074dcded77b9c7322ef45422727George Mount	break;
3649189445c0a66d074dcded77b9c7322ef45422727George Mount      case 's' :
3659189445c0a66d074dcded77b9c7322ef45422727George Mount	if (append_string(state,
3669189445c0a66d074dcded77b9c7322ef45422727George Mount			  va_arg(ap, unsigned char*),
3679189445c0a66d074dcded77b9c7322ef45422727George Mount			  width,
3689189445c0a66d074dcded77b9c7322ef45422727George Mount			  prec,
3699189445c0a66d074dcded77b9c7322ef45422727George Mount			  flags))
3709189445c0a66d074dcded77b9c7322ef45422727George Mount	  return -1;
3719189445c0a66d074dcded77b9c7322ef45422727George Mount	break;
3729189445c0a66d074dcded77b9c7322ef45422727George Mount      case 'd' :
3739189445c0a66d074dcded77b9c7322ef45422727George Mount      case 'i' : {
3749189445c0a66d074dcded77b9c7322ef45422727George Mount	long arg;
3759189445c0a66d074dcded77b9c7322ef45422727George Mount	unsigned long num;
3769189445c0a66d074dcded77b9c7322ef45422727George Mount	int minusp = 0;
3779189445c0a66d074dcded77b9c7322ef45422727George Mount
3789189445c0a66d074dcded77b9c7322ef45422727George Mount	PARSE_INT_FORMAT(arg, ap, signed);
3799189445c0a66d074dcded77b9c7322ef45422727George Mount
3809189445c0a66d074dcded77b9c7322ef45422727George Mount	if (arg < 0) {
3819189445c0a66d074dcded77b9c7322ef45422727George Mount	  minusp = 1;
3829189445c0a66d074dcded77b9c7322ef45422727George Mount	  num = -arg;
3839189445c0a66d074dcded77b9c7322ef45422727George Mount	} else
3849189445c0a66d074dcded77b9c7322ef45422727George Mount	  num = arg;
3859189445c0a66d074dcded77b9c7322ef45422727George Mount
3869189445c0a66d074dcded77b9c7322ef45422727George Mount	if (append_number (state, num, 10, "0123456789",
3879189445c0a66d074dcded77b9c7322ef45422727George Mount			   width, prec, flags, minusp))
3889189445c0a66d074dcded77b9c7322ef45422727George Mount	  return -1;
3899189445c0a66d074dcded77b9c7322ef45422727George Mount	break;
3909189445c0a66d074dcded77b9c7322ef45422727George Mount      }
3919189445c0a66d074dcded77b9c7322ef45422727George Mount      case 'u' : {
3929189445c0a66d074dcded77b9c7322ef45422727George Mount	unsigned long arg;
3939189445c0a66d074dcded77b9c7322ef45422727George Mount
3949189445c0a66d074dcded77b9c7322ef45422727George Mount	PARSE_INT_FORMAT(arg, ap, unsigned);
3959189445c0a66d074dcded77b9c7322ef45422727George Mount
396	if (append_number (state, arg, 10, "0123456789",
397			   width, prec, flags, 0))
398	  return -1;
399	break;
400      }
401      case 'o' : {
402	unsigned long arg;
403
404	PARSE_INT_FORMAT(arg, ap, unsigned);
405
406	if (append_number (state, arg, 010, "01234567",
407			   width, prec, flags, 0))
408	  return -1;
409	break;
410      }
411      case 'x' : {
412	unsigned long arg;
413
414	PARSE_INT_FORMAT(arg, ap, unsigned);
415
416	if (append_number (state, arg, 0x10, "0123456789abcdef",
417			   width, prec, flags, 0))
418	  return -1;
419	break;
420      }
421      case 'X' :{
422	unsigned long arg;
423
424	PARSE_INT_FORMAT(arg, ap, unsigned);
425
426	if (append_number (state, arg, 0x10, "0123456789ABCDEF",
427			   width, prec, flags, 0))
428	  return -1;
429	break;
430      }
431      case 'p' : {
432	unsigned long arg = (unsigned long)va_arg(ap, void*);
433
434	if (append_number (state, arg, 0x10, "0123456789ABCDEF",
435			   width, prec, flags, 0))
436	  return -1;
437	break;
438      }
439      case 'n' : {
440	int *arg = va_arg(ap, int*);
441	*arg = state->s - state->str;
442	break;
443      }
444      case '\0' :
445	  --format;
446	  /* FALLTHROUGH */
447      case '%' :
448	if ((*state->append_char)(state, c))
449	  return -1;
450	break;
451      default :
452	if (   (*state->append_char)(state, '%')
453	    || (*state->append_char)(state, c))
454	  return -1;
455	break;
456      }
457    } else
458      if ((*state->append_char) (state, c))
459	return -1;
460  }
461  return 0;
462}
463
464#ifndef HAVE_SNPRINTF
465int
466snprintf (char *str, size_t sz, const char *format, ...)
467{
468  va_list args;
469  int ret;
470
471  va_start(args, format);
472  ret = vsnprintf (str, sz, format, args);
473
474#ifdef PARANOIA
475  {
476    int ret2;
477    char *tmp;
478
479    tmp = malloc (sz);
480    if (tmp == NULL)
481      abort ();
482
483    ret2 = vsprintf (tmp, format, args);
484    if (ret != ret2 || strcmp(str, tmp))
485      abort ();
486    free (tmp);
487  }
488#endif
489
490  va_end(args);
491  return ret;
492}
493#endif
494
495#if 0
496#ifndef HAVE_ASPRINTF
497int
498asprintf (char **ret, const char *format, ...)
499{
500  va_list args;
501  int val;
502
503  va_start(args, format);
504  val = vasprintf (ret, format, args);
505
506#ifdef PARANOIA
507  {
508    int ret2;
509    char *tmp;
510    tmp = malloc (val + 1);
511    if (tmp == NULL)
512      abort ();
513
514    ret2 = vsprintf (tmp, format, args);
515    if (val != ret2 || strcmp(*ret, tmp))
516      abort ();
517    free (tmp);
518  }
519#endif
520
521  va_end(args);
522  return val;
523}
524#endif
525
526#ifndef HAVE_ASNPRINTF
527int
528asnprintf (char **ret, size_t max_sz, const char *format, ...)
529{
530  va_list args;
531  int val;
532
533  va_start(args, format);
534  val = vasnprintf (ret, max_sz, format, args);
535
536#ifdef PARANOIA
537  {
538    int ret2;
539    char *tmp;
540    tmp = malloc (val + 1);
541    if (tmp == NULL)
542      abort ();
543
544    ret2 = vsprintf (tmp, format, args);
545    if (val != ret2 || strcmp(*ret, tmp))
546      abort ();
547    free (tmp);
548  }
549#endif
550
551  va_end(args);
552  return val;
553}
554#endif
555
556#ifndef HAVE_VASPRINTF
557int
558vasprintf (char **ret, const char *format, va_list args)
559{
560  return vasnprintf (ret, 0, format, args);
561}
562#endif
563
564
565#ifndef HAVE_VASNPRINTF
566int
567vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
568{
569  int st;
570  size_t len;
571  struct state state;
572
573  state.max_sz = max_sz;
574  state.sz     = 1;
575  state.str    = malloc(state.sz);
576  if (state.str == NULL) {
577    *ret = NULL;
578    return -1;
579  }
580  state.s = state.str;
581  state.theend = state.s + state.sz - 1;
582  state.append_char = as_append_char;
583  state.reserve     = as_reserve;
584
585  st = xyzprintf (&state, format, args);
586  if (st) {
587    free (state.str);
588    *ret = NULL;
589    return -1;
590  } else {
591    char *tmp;
592
593    *state.s = '\0';
594    len = state.s - state.str;
595    tmp = realloc (state.str, len+1);
596    if (tmp == NULL) {
597      free (state.str);
598      *ret = NULL;
599      return -1;
600    }
601    *ret = tmp;
602    return len;
603  }
604}
605#endif
606#endif
607
608#ifndef HAVE_VSNPRINTF
609int
610vsnprintf (char *str, size_t sz, const char *format, va_list args)
611{
612  struct state state;
613  int ret;
614  unsigned char *ustr = (unsigned char *)str;
615
616  state.max_sz = 0;
617  state.sz     = sz;
618  state.str    = ustr;
619  state.s      = ustr;
620  state.theend = ustr + sz - 1;
621  state.append_char = sn_append_char;
622  state.reserve     = sn_reserve;
623
624  ret = xyzprintf (&state, format, args);
625  *state.s = '\0';
626  if (ret)
627    return sz;
628  else
629    return state.s - state.str;
630}
631#endif
632
633