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