rewrite so that it does not stop as soon as there are no more

characters to print, we need to figure out how long the string would
have to be.  this also fixes snprintf(NULL, 0


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10247 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Assar Westerlund
2001-07-02 23:13:23 +00:00
parent 26f783c592
commit 609e9edb25

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995-2000 Kungliga Tekniska H<>gskolan * Copyright (c) 1995-2001 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden). * (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved. * All rights reserved.
* *
@@ -60,27 +60,22 @@ struct state {
unsigned char *theend; unsigned char *theend;
size_t sz; size_t sz;
size_t max_sz; size_t max_sz;
int (*append_char)(struct state *, unsigned char); void (*append_char)(struct state *, unsigned char);
int (*reserve)(struct state *, size_t);
/* XXX - methods */ /* XXX - methods */
}; };
#ifndef HAVE_VSNPRINTF #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
static int static int
sn_reserve (struct state *state, size_t n) sn_reserve (struct state *state, size_t n)
{ {
return state->s + n > state->theend; return state->s + n > state->theend;
} }
static int static void
sn_append_char (struct state *state, unsigned char c) sn_append_char (struct state *state, unsigned char c)
{ {
if (sn_reserve (state, 1)) { if (!sn_reserve (state, 1))
return 1;
} else {
*state->s++ = c; *state->s++ = c;
return 0;
}
} }
#endif #endif
@@ -107,15 +102,21 @@ as_reserve (struct state *state, size_t n)
return 0; return 0;
} }
static int static void
as_append_char (struct state *state, unsigned char c) as_append_char (struct state *state, unsigned char c)
{ {
if(as_reserve (state, 1)) if(!as_reserve (state, 1))
return 1;
else {
*state->s++ = c; *state->s++ = c;
return 0; }
}
/*
* is # supposed to do anything?
*/
static int
use_alternative (int flags, unsigned long num, unsigned base)
{
return flags & alternate_flag && (base == 16 || base == 8) && num != 0;
} }
static int static int
@@ -125,6 +126,7 @@ append_number(struct state *state,
{ {
int len = 0; int len = 0;
int i; int i;
unsigned long n = num;
/* given precision, ignore zero flag */ /* given precision, ignore zero flag */
if(prec != -1) if(prec != -1)
@@ -132,23 +134,21 @@ append_number(struct state *state,
else else
prec = 1; prec = 1;
/* zero value with zero precision -> "" */ /* zero value with zero precision -> "" */
if(prec == 0 && num == 0) if(prec == 0 && n == 0)
return 0; return 0;
do{ do{
if((*state->append_char)(state, rep[num % base])) (*state->append_char)(state, rep[n % base]);
return 1; ++len;
len++; n /= base;
num /= base; } while(n);
}while(num);
prec -= len; prec -= len;
/* pad with prec zeros */ /* pad with prec zeros */
while(prec-- > 0){ while(prec-- > 0){
if((*state->append_char)(state, '0')) (*state->append_char)(state, '0');
return 1; ++len;
len++;
} }
/* add length of alternate prefix (added later) to len */ /* add length of alternate prefix (added later) to len */
if(flags & alternate_flag && (base == 16 || base == 8)) if(use_alternative(flags, num, base))
len += base / 8; len += base / 8;
/* pad with zeros */ /* pad with zeros */
if(flags & zero_flag){ if(flags & zero_flag){
@@ -156,32 +156,26 @@ append_number(struct state *state,
if(minusp || (flags & space_flag) || (flags & plus_flag)) if(minusp || (flags & space_flag) || (flags & plus_flag))
width--; width--;
while(width-- > 0){ while(width-- > 0){
if((*state->append_char)(state, '0')) (*state->append_char)(state, '0');
return 1;
len++; len++;
} }
} }
/* add alternate prefix */ /* add alternate prefix */
if(flags & alternate_flag && (base == 16 || base == 8)){ if(use_alternative(flags, num, base)){
if(base == 16) if(base == 16)
if((*state->append_char)(state, rep[10] + 23)) /* XXX */ (*state->append_char)(state, rep[10] + 23); /* XXX */
return 1; (*state->append_char)(state, '0');
if((*state->append_char)(state, '0'))
return 1;
} }
/* add sign */ /* add sign */
if(minusp){ if(minusp){
if((*state->append_char)(state, '-')) (*state->append_char)(state, '-');
return 1; ++len;
len++;
} else if(flags & plus_flag) { } else if(flags & plus_flag) {
if((*state->append_char)(state, '+')) (*state->append_char)(state, '+');
return 1; ++len;
len++;
} else if(flags & space_flag) { } else if(flags & space_flag) {
if((*state->append_char)(state, ' ')) (*state->append_char)(state, ' ');
return 1; ++len;
len++;
} }
if(flags & minus_flag) if(flags & minus_flag)
/* swap before padding with spaces */ /* swap before padding with spaces */
@@ -192,9 +186,8 @@ append_number(struct state *state,
} }
width -= len; width -= len;
while(width-- > 0){ while(width-- > 0){
if((*state->append_char)(state, ' ')) (*state->append_char)(state, ' ');
return 1; ++len;
len++;
} }
if(!(flags & minus_flag)) if(!(flags & minus_flag))
/* swap after padding with spaces */ /* swap after padding with spaces */
@@ -203,42 +196,51 @@ append_number(struct state *state,
state->s[-i-1] = state->s[-len+i]; state->s[-i-1] = state->s[-len+i];
state->s[-len+i] = c; state->s[-len+i] = c;
} }
return len;
return 0;
} }
/*
* return length
*/
static int static int
append_string (struct state *state, append_string (struct state *state,
unsigned char *arg, const unsigned char *arg,
int width, int width,
int prec, int prec,
int flags) int flags)
{ {
int len = 0;
if(arg == NULL) if(arg == NULL)
arg = (unsigned char*)"(null)"; arg = (const unsigned char*)"(null)";
if(prec != -1) if(prec != -1)
width -= prec; width -= prec;
else else
width -= strlen((char *)arg); width -= strlen((const char *)arg);
if(!(flags & minus_flag)) if(!(flags & minus_flag))
while(width-- > 0) while(width-- > 0) {
if((*state->append_char) (state, ' ')) (*state->append_char) (state, ' ');
return 1; ++len;
}
if (prec != -1) { if (prec != -1) {
while (*arg && prec--) while (*arg && prec--) {
if ((*state->append_char) (state, *arg++)) (*state->append_char) (state, *arg++);
return 1; ++len;
}
} else { } else {
while (*arg) while (*arg) {
if ((*state->append_char) (state, *arg++)) (*state->append_char) (state, *arg++);
return 1; ++len;
}
} }
if(flags & minus_flag) if(flags & minus_flag)
while(width-- > 0) while(width-- > 0) {
if((*state->append_char) (state, ' ')) (*state->append_char) (state, ' ');
return 1; ++len;
return 0; }
return len;
} }
static int static int
@@ -247,16 +249,18 @@ append_char(struct state *state,
int width, int width,
int flags) int flags)
{ {
while(!(flags & minus_flag) && --width > 0) int len = 0;
if((*state->append_char) (state, ' '))
return 1;
if((*state->append_char) (state, arg))
return 1;
while((flags & minus_flag) && --width > 0)
if((*state->append_char) (state, ' '))
return 1;
while(!(flags & minus_flag) && --width > 0) {
(*state->append_char) (state, ' ') ;
++len;
}
(*state->append_char) (state, arg);
++len;
while((flags & minus_flag) && --width > 0) {
(*state->append_char) (state, ' ');
++len;
}
return 0; return 0;
} }
@@ -273,7 +277,7 @@ else \
res = (unsig int)va_arg(arg, unsig int) res = (unsig int)va_arg(arg, unsig int)
/* /*
* zyxprintf - return 0 or -1 * zyxprintf - return length, as snprintf
*/ */
static int static int
@@ -281,6 +285,7 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
{ {
const unsigned char *format = (const unsigned char *)char_format; const unsigned char *format = (const unsigned char *)char_format;
unsigned char c; unsigned char c;
int len = 0;
while((c = *format++)) { while((c = *format++)) {
if (c == '%') { if (c == '%') {
@@ -350,16 +355,15 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
switch (c) { switch (c) {
case 'c' : case 'c' :
if(append_char(state, va_arg(ap, int), width, flags)) append_char(state, va_arg(ap, int), width, flags);
return -1; ++len;
break; break;
case 's' : case 's' :
if (append_string(state, len += append_string(state,
va_arg(ap, unsigned char*), va_arg(ap, unsigned char*),
width, width,
prec, prec,
flags)) flags);
return -1;
break; break;
case 'd' : case 'd' :
case 'i' : { case 'i' : {
@@ -375,9 +379,8 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
} else } else
num = arg; num = arg;
if (append_number (state, num, 10, "0123456789", len += append_number (state, num, 10, "0123456789",
width, prec, flags, minusp)) width, prec, flags, minusp);
return -1;
break; break;
} }
case 'u' : { case 'u' : {
@@ -385,9 +388,8 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
PARSE_INT_FORMAT(arg, ap, unsigned); PARSE_INT_FORMAT(arg, ap, unsigned);
if (append_number (state, arg, 10, "0123456789", len += append_number (state, arg, 10, "0123456789",
width, prec, flags, 0)) width, prec, flags, 0);
return -1;
break; break;
} }
case 'o' : { case 'o' : {
@@ -395,9 +397,8 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
PARSE_INT_FORMAT(arg, ap, unsigned); PARSE_INT_FORMAT(arg, ap, unsigned);
if (append_number (state, arg, 010, "01234567", len += append_number (state, arg, 010, "01234567",
width, prec, flags, 0)) width, prec, flags, 0);
return -1;
break; break;
} }
case 'x' : { case 'x' : {
@@ -405,9 +406,8 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
PARSE_INT_FORMAT(arg, ap, unsigned); PARSE_INT_FORMAT(arg, ap, unsigned);
if (append_number (state, arg, 0x10, "0123456789abcdef", len += append_number (state, arg, 0x10, "0123456789abcdef",
width, prec, flags, 0)) width, prec, flags, 0);
return -1;
break; break;
} }
case 'X' :{ case 'X' :{
@@ -415,17 +415,15 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
PARSE_INT_FORMAT(arg, ap, unsigned); PARSE_INT_FORMAT(arg, ap, unsigned);
if (append_number (state, arg, 0x10, "0123456789ABCDEF", len += append_number (state, arg, 0x10, "0123456789ABCDEF",
width, prec, flags, 0)) width, prec, flags, 0);
return -1;
break; break;
} }
case 'p' : { case 'p' : {
unsigned long arg = (unsigned long)va_arg(ap, void*); unsigned long arg = (unsigned long)va_arg(ap, void*);
if (append_number (state, arg, 0x10, "0123456789ABCDEF", len += append_number (state, arg, 0x10, "0123456789ABCDEF",
width, prec, flags, 0)) width, prec, flags, 0);
return -1;
break; break;
} }
case 'n' : { case 'n' : {
@@ -437,23 +435,24 @@ xyzprintf (struct state *state, const char *char_format, va_list ap)
--format; --format;
/* FALLTHROUGH */ /* FALLTHROUGH */
case '%' : case '%' :
if ((*state->append_char)(state, c)) (*state->append_char)(state, c);
return -1; ++len;
break; break;
default : default :
if ( (*state->append_char)(state, '%') (*state->append_char)(state, '%');
|| (*state->append_char)(state, c)) (*state->append_char)(state, c);
return -1; len += 2;
break; break;
} }
} else } else {
if ((*state->append_char) (state, c)) (*state->append_char) (state, c);
return -1; ++len;
} }
return 0; }
return len;
} }
#ifndef HAVE_SNPRINTF #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
int int
snprintf (char *str, size_t sz, const char *format, ...) snprintf (char *str, size_t sz, const char *format, ...)
{ {
@@ -484,7 +483,7 @@ snprintf (char *str, size_t sz, const char *format, ...)
} }
#endif #endif
#ifndef HAVE_ASPRINTF #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
int int
asprintf (char **ret, const char *format, ...) asprintf (char **ret, const char *format, ...)
{ {
@@ -514,7 +513,7 @@ asprintf (char **ret, const char *format, ...)
} }
#endif #endif
#ifndef HAVE_ASNPRINTF #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
int int
asnprintf (char **ret, size_t max_sz, const char *format, ...) asnprintf (char **ret, size_t max_sz, const char *format, ...)
{ {
@@ -544,7 +543,7 @@ asnprintf (char **ret, size_t max_sz, const char *format, ...)
} }
#endif #endif
#ifndef HAVE_VASPRINTF #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
int int
vasprintf (char **ret, const char *format, va_list args) vasprintf (char **ret, const char *format, va_list args)
{ {
@@ -553,12 +552,11 @@ vasprintf (char **ret, const char *format, va_list args)
#endif #endif
#ifndef HAVE_VASNPRINTF #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
int int
vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
{ {
int st; int st;
size_t len;
struct state state; struct state state;
state.max_sz = max_sz; state.max_sz = max_sz;
@@ -571,10 +569,9 @@ vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
state.s = state.str; state.s = state.str;
state.theend = state.s + state.sz - 1; state.theend = state.s + state.sz - 1;
state.append_char = as_append_char; state.append_char = as_append_char;
state.reserve = as_reserve;
st = xyzprintf (&state, format, args); st = xyzprintf (&state, format, args);
if (st) { if (st > state.sz) {
free (state.str); free (state.str);
*ret = NULL; *ret = NULL;
return -1; return -1;
@@ -582,20 +579,19 @@ vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
char *tmp; char *tmp;
*state.s = '\0'; *state.s = '\0';
len = state.s - state.str; tmp = realloc (state.str, st+1);
tmp = realloc (state.str, len+1);
if (tmp == NULL) { if (tmp == NULL) {
free (state.str); free (state.str);
*ret = NULL; *ret = NULL;
return -1; return -1;
} }
*ret = tmp; *ret = tmp;
return len; return st;
} }
} }
#endif #endif
#ifndef HAVE_VSNPRINTF #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
int int
vsnprintf (char *str, size_t sz, const char *format, va_list args) vsnprintf (char *str, size_t sz, const char *format, va_list args)
{ {
@@ -607,16 +603,12 @@ vsnprintf (char *str, size_t sz, const char *format, va_list args)
state.sz = sz; state.sz = sz;
state.str = ustr; state.str = ustr;
state.s = ustr; state.s = ustr;
state.theend = ustr + sz - 1; state.theend = ustr + sz - (sz > 0);
state.append_char = sn_append_char; state.append_char = sn_append_char;
state.reserve = sn_reserve;
ret = xyzprintf (&state, format, args); ret = xyzprintf (&state, format, args);
if (state.s != NULL)
*state.s = '\0'; *state.s = '\0';
if (ret) return ret;
return sz;
else
return state.s - state.str;
} }
#endif #endif