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).
|
* (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);
|
||||||
*state.s = '\0';
|
if (state.s != NULL)
|
||||||
if (ret)
|
*state.s = '\0';
|
||||||
return sz;
|
return ret;
|
||||||
else
|
|
||||||
return state.s - state.str;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user