diff options
Diffstat (limited to 'crypto/heimdal/lib/roken/snprintf.c')
-rw-r--r-- | crypto/heimdal/lib/roken/snprintf.c | 871 |
1 files changed, 459 insertions, 412 deletions
diff --git a/crypto/heimdal/lib/roken/snprintf.c b/crypto/heimdal/lib/roken/snprintf.c index 5e4b85e9c9b0..6b3352f96b89 100644 --- a/crypto/heimdal/lib/roken/snprintf.c +++ b/crypto/heimdal/lib/roken/snprintf.c @@ -33,14 +33,18 @@ #ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id: snprintf.c,v 1.35 2003/03/26 10:05:48 joda Exp $"); +RCSID("$Id: snprintf.c 21005 2007-06-08 01:54:35Z lha $"); #endif +#if defined(TEST_SNPRINTF) +#include "snprintf-test.h" +#endif /* TEST_SNPRINTF */ #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <ctype.h> -#include <roken.h> +#include "roken.h" +#include <assert.h> enum format_flags { minus_flag = 1, @@ -55,62 +59,58 @@ enum format_flags { */ struct snprintf_state { - unsigned char *str; - unsigned char *s; - unsigned char *theend; - size_t sz; - size_t max_sz; - void (*append_char)(struct snprintf_state *, unsigned char); - /* XXX - methods */ + unsigned char *str; + unsigned char *s; + unsigned char *theend; + size_t sz; + size_t max_sz; + void (*append_char)(struct snprintf_state *, unsigned char); + /* XXX - methods */ }; -#if TEST_SNPRINTF -#include "snprintf-test.h" -#endif /* TEST_SNPRINTF */ - #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) static int sn_reserve (struct snprintf_state *state, size_t n) { - return state->s + n > state->theend; + return state->s + n > state->theend; } static void sn_append_char (struct snprintf_state *state, unsigned char c) { - if (!sn_reserve (state, 1)) - *state->s++ = c; + if (!sn_reserve (state, 1)) + *state->s++ = c; } #endif static int as_reserve (struct snprintf_state *state, size_t n) { - if (state->s + n > state->theend) { - int off = state->s - state->str; - unsigned char *tmp; - - if (state->max_sz && state->sz >= state->max_sz) - return 1; - - state->sz = max(state->sz * 2, state->sz + n); - if (state->max_sz) - state->sz = min(state->sz, state->max_sz); - tmp = realloc (state->str, state->sz); - if (tmp == NULL) - return 1; - state->str = tmp; - state->s = state->str + off; - state->theend = state->str + state->sz - 1; - } - return 0; + if (state->s + n > state->theend) { + int off = state->s - state->str; + unsigned char *tmp; + + if (state->max_sz && state->sz >= state->max_sz) + return 1; + + state->sz = max(state->sz * 2, state->sz + n); + if (state->max_sz) + state->sz = min(state->sz, state->max_sz); + tmp = realloc (state->str, state->sz); + if (tmp == NULL) + return 1; + state->str = tmp; + state->s = state->str + off; + state->theend = state->str + state->sz - 1; + } + return 0; } static void as_append_char (struct snprintf_state *state, unsigned char c) { - if(!as_reserve (state, 1)) - *state->s++ = c; + if(!as_reserve (state, 1)) + *state->s++ = c; } /* longest integer types */ @@ -123,14 +123,24 @@ typedef unsigned long u_longest; typedef long longest; #endif -/* - * is # supposed to do anything? - */ + +static int +pad(struct snprintf_state *state, int width, char c) +{ + int len = 0; + while(width-- > 0){ + (*state->append_char)(state, c); + ++len; + } + return len; +} + +/* return true if we should use alternatve hex form */ static int use_alternative (int flags, u_longest num, unsigned base) { - return flags & alternate_flag && (base == 16 || base == 8) && num != 0; + return (flags & alternate_flag) && base == 16 && num != 0; } static int @@ -138,79 +148,110 @@ append_number(struct snprintf_state *state, u_longest num, unsigned base, const char *rep, int width, int prec, int flags, int minusp) { - int len = 0; - int i; - u_longest n = num; - - /* given precision, ignore zero flag */ - if(prec != -1) - flags &= ~zero_flag; - else - prec = 1; - /* zero value with zero precision -> "" */ - if(prec == 0 && n == 0) - return 0; - do{ - (*state->append_char)(state, rep[n % base]); - ++len; - n /= base; - } while(n); - prec -= len; - /* pad with prec zeros */ - while(prec-- > 0){ - (*state->append_char)(state, '0'); - ++len; - } - /* add length of alternate prefix (added later) to len */ - if(use_alternative(flags, num, base)) - len += base / 8; - /* pad with zeros */ - if(flags & zero_flag){ - width -= len; - if(minusp || (flags & space_flag) || (flags & plus_flag)) - width--; - while(width-- > 0){ - (*state->append_char)(state, '0'); - len++; + int len = 0; + u_longest n = num; + char nstr[64]; /* enough for <192 bit octal integers */ + int nstart, nlen; + char signchar; + + /* given precision, ignore zero flag */ + if(prec != -1) + flags &= ~zero_flag; + else + prec = 1; + + /* format number as string */ + nstart = sizeof(nstr); + nlen = 0; + nstr[--nstart] = '\0'; + do { + assert(nstart > 0); + nstr[--nstart] = rep[n % base]; + ++nlen; + n /= base; + } while(n); + + /* zero value with zero precision should produce no digits */ + if(prec == 0 && num == 0) { + nlen--; + nstart++; } - } - /* add alternate prefix */ - if(use_alternative(flags, num, base)){ - if(base == 16) - (*state->append_char)(state, rep[10] + 23); /* XXX */ - (*state->append_char)(state, '0'); - } - /* add sign */ - if(minusp){ - (*state->append_char)(state, '-'); - ++len; - } else if(flags & plus_flag) { - (*state->append_char)(state, '+'); - ++len; - } else if(flags & space_flag) { - (*state->append_char)(state, ' '); - ++len; - } - if(flags & minus_flag) - /* swap before padding with spaces */ - for(i = 0; i < len / 2; i++){ - char c = state->s[-i-1]; - state->s[-i-1] = state->s[-len+i]; - state->s[-len+i] = c; + + /* figure out what char to use for sign */ + if(minusp) + signchar = '-'; + else if((flags & plus_flag)) + signchar = '+'; + else if((flags & space_flag)) + signchar = ' '; + else + signchar = '\0'; + + if((flags & alternate_flag) && base == 8) { + /* if necessary, increase the precision to + make first digit a zero */ + + /* XXX C99 claims (regarding # and %o) that "if the value and + precision are both 0, a single 0 is printed", but there is + no such wording for %x. This would mean that %#.o would + output "0", but %#.x "". This does not make sense, and is + also not what other printf implementations are doing. */ + + if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0') + prec = nlen + 1; } - width -= len; - while(width-- > 0){ - (*state->append_char)(state, ' '); - ++len; - } - if(!(flags & minus_flag)) - /* swap after padding with spaces */ - for(i = 0; i < len / 2; i++){ - char c = state->s[-i-1]; - state->s[-i-1] = state->s[-len+i]; - state->s[-len+i] = c; + + /* possible formats: + pad | sign | alt | zero | digits + sign | alt | zero | digits | pad minus_flag + sign | alt | zero | digits zero_flag */ + + /* if not right justifying or padding with zeros, we need to + compute the length of the rest of the string, and then pad with + spaces */ + if(!(flags & (minus_flag | zero_flag))) { + if(prec > nlen) + width -= prec; + else + width -= nlen; + + if(use_alternative(flags, num, base)) + width -= 2; + + if(signchar != '\0') + width--; + + /* pad to width */ + len += pad(state, width, ' '); + } + if(signchar != '\0') { + (*state->append_char)(state, signchar); + ++len; + } + if(use_alternative(flags, num, base)) { + (*state->append_char)(state, '0'); + (*state->append_char)(state, rep[10] + 23); /* XXX */ + len += 2; } - return len; + if(flags & zero_flag) { + /* pad to width with zeros */ + if(prec - nlen > width - len - nlen) + len += pad(state, prec - nlen, '0'); + else + len += pad(state, width - len - nlen, '0'); + } else + /* pad to prec with zeros */ + len += pad(state, prec - nlen, '0'); + + while(nstr[nstart] != '\0') { + (*state->append_char)(state, nstr[nstart++]); + ++len; + } + + if(flags & minus_flag) + len += pad(state, width - len, ' '); + + return len; } /* @@ -234,10 +275,8 @@ append_string (struct snprintf_state *state, else width -= strlen((const char *)arg); if(!(flags & minus_flag)) - while(width-- > 0) { - (*state->append_char) (state, ' '); - ++len; - } + len += pad(state, width, ' '); + if (prec != -1) { while (*arg && prec--) { (*state->append_char) (state, *arg++); @@ -250,10 +289,7 @@ append_string (struct snprintf_state *state, } } if(flags & minus_flag) - while(width-- > 0) { - (*state->append_char) (state, ' '); - ++len; - } + len += pad(state, width, ' '); return len; } @@ -263,19 +299,19 @@ append_char(struct snprintf_state *state, int width, int flags) { - int len = 0; + 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, ' '); + while(!(flags & minus_flag) && --width > 0) { + (*state->append_char) (state, ' ') ; + ++len; + } + (*state->append_char) (state, arg); ++len; - } - return 0; + while((flags & minus_flag) && --width > 0) { + (*state->append_char) (state, ' '); + ++len; + } + return 0; } /* @@ -289,6 +325,8 @@ if (long_long_flag) \ res = (unsig long long)va_arg(arg, unsig long long); \ else if (long_flag) \ res = (unsig long)va_arg(arg, unsig long); \ +else if (size_t_flag) \ + res = (unsig long)va_arg(arg, size_t); \ else if (short_flag) \ res = (unsig short)va_arg(arg, unsig int); \ else \ @@ -299,6 +337,8 @@ else \ #define PARSE_INT_FORMAT(res, arg, unsig) \ if (long_flag) \ res = (unsig long)va_arg(arg, unsig long); \ +else if (size_t_flag) \ + res = (unsig long)va_arg(arg, size_t); \ else if (short_flag) \ res = (unsig short)va_arg(arg, unsig int); \ else \ @@ -313,343 +353,350 @@ else \ static int xyzprintf (struct snprintf_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 == '%') { - int flags = 0; - int width = 0; - int prec = -1; - int long_long_flag = 0; - int long_flag = 0; - int short_flag = 0; - - /* flags */ - while((c = *format++)){ - if(c == '-') - flags |= minus_flag; - else if(c == '+') - flags |= plus_flag; - else if(c == ' ') - flags |= space_flag; - else if(c == '#') - flags |= alternate_flag; - else if(c == '0') - flags |= zero_flag; - else if(c == '\'') - ; /* just ignore */ - else - break; - } + const unsigned char *format = (const unsigned char *)char_format; + unsigned char c; + int len = 0; + + while((c = *format++)) { + if (c == '%') { + int flags = 0; + int width = 0; + int prec = -1; + int size_t_flag = 0; + int long_long_flag = 0; + int long_flag = 0; + int short_flag = 0; + + /* flags */ + while((c = *format++)){ + if(c == '-') + flags |= minus_flag; + else if(c == '+') + flags |= plus_flag; + else if(c == ' ') + flags |= space_flag; + else if(c == '#') + flags |= alternate_flag; + else if(c == '0') + flags |= zero_flag; + else if(c == '\'') + ; /* just ignore */ + else + break; + } - if((flags & space_flag) && (flags & plus_flag)) - flags ^= space_flag; - - if((flags & minus_flag) && (flags & zero_flag)) - flags ^= zero_flag; - - /* width */ - if (isdigit(c)) - do { - width = width * 10 + c - '0'; - c = *format++; - } while(isdigit(c)); - else if(c == '*') { - width = va_arg(ap, int); - c = *format++; - } - - /* precision */ - if (c == '.') { - prec = 0; - c = *format++; - if (isdigit(c)) - do { - prec = prec * 10 + c - '0'; - c = *format++; - } while(isdigit(c)); - else if (c == '*') { - prec = va_arg(ap, int); - c = *format++; - } - } - - /* size */ - - if (c == 'h') { - short_flag = 1; - c = *format++; - } else if (c == 'l') { - long_flag = 1; - c = *format++; - if (c == 'l') { - long_long_flag = 1; - c = *format++; + if((flags & space_flag) && (flags & plus_flag)) + flags ^= space_flag; + + if((flags & minus_flag) && (flags & zero_flag)) + flags ^= zero_flag; + + /* width */ + if (isdigit(c)) + do { + width = width * 10 + c - '0'; + c = *format++; + } while(isdigit(c)); + else if(c == '*') { + width = va_arg(ap, int); + c = *format++; + } + + /* precision */ + if (c == '.') { + prec = 0; + c = *format++; + if (isdigit(c)) + do { + prec = prec * 10 + c - '0'; + c = *format++; + } while(isdigit(c)); + else if (c == '*') { + prec = va_arg(ap, int); + c = *format++; + } + } + + /* size */ + + if (c == 'h') { + short_flag = 1; + c = *format++; + } else if (c == 'z') { + size_t_flag = 1; + c = *format++; + } else if (c == 'l') { + long_flag = 1; + c = *format++; + if (c == 'l') { + long_long_flag = 1; + c = *format++; + } + } + + if(c != 'd' && c != 'i') + flags &= ~(plus_flag | space_flag); + + switch (c) { + case 'c' : + append_char(state, va_arg(ap, int), width, flags); + ++len; + break; + case 's' : + len += append_string(state, + va_arg(ap, unsigned char*), + width, + prec, + flags); + break; + case 'd' : + case 'i' : { + longest arg; + u_longest num; + int minusp = 0; + + PARSE_INT_FORMAT(arg, ap, signed); + + if (arg < 0) { + minusp = 1; + num = -arg; + } else + num = arg; + + len += append_number (state, num, 10, "0123456789", + width, prec, flags, minusp); + break; + } + case 'u' : { + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 10, "0123456789", + width, prec, flags, 0); + break; + } + case 'o' : { + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 010, "01234567", + width, prec, flags, 0); + break; + } + case 'x' : { + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 0x10, "0123456789abcdef", + width, prec, flags, 0); + break; + } + case 'X' :{ + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 0x10, "0123456789ABCDEF", + width, prec, flags, 0); + break; + } + case 'p' : { + unsigned long arg = (unsigned long)va_arg(ap, void*); + + len += append_number (state, arg, 0x10, "0123456789ABCDEF", + width, prec, flags, 0); + break; + } + case 'n' : { + int *arg = va_arg(ap, int*); + *arg = state->s - state->str; + break; + } + case '\0' : + --format; + /* FALLTHROUGH */ + case '%' : + (*state->append_char)(state, c); + ++len; + break; + default : + (*state->append_char)(state, '%'); + (*state->append_char)(state, c); + len += 2; + break; + } + } else { + (*state->append_char) (state, c); + ++len; } - } - - switch (c) { - case 'c' : - append_char(state, va_arg(ap, int), width, flags); - ++len; - break; - case 's' : - len += append_string(state, - va_arg(ap, unsigned char*), - width, - prec, - flags); - break; - case 'd' : - case 'i' : { - longest arg; - u_longest num; - int minusp = 0; - - PARSE_INT_FORMAT(arg, ap, signed); - - if (arg < 0) { - minusp = 1; - num = -arg; - } else - num = arg; - - len += append_number (state, num, 10, "0123456789", - width, prec, flags, minusp); - break; - } - case 'u' : { - u_longest arg; - - PARSE_INT_FORMAT(arg, ap, unsigned); - - len += append_number (state, arg, 10, "0123456789", - width, prec, flags, 0); - break; - } - case 'o' : { - u_longest arg; - - PARSE_INT_FORMAT(arg, ap, unsigned); - - len += append_number (state, arg, 010, "01234567", - width, prec, flags, 0); - break; - } - case 'x' : { - u_longest arg; - - PARSE_INT_FORMAT(arg, ap, unsigned); - - len += append_number (state, arg, 0x10, "0123456789abcdef", - width, prec, flags, 0); - break; - } - case 'X' :{ - u_longest arg; - - PARSE_INT_FORMAT(arg, ap, unsigned); - - len += append_number (state, arg, 0x10, "0123456789ABCDEF", - width, prec, flags, 0); - break; - } - case 'p' : { - unsigned long arg = (unsigned long)va_arg(ap, void*); - - len += append_number (state, arg, 0x10, "0123456789ABCDEF", - width, prec, flags, 0); - break; - } - case 'n' : { - int *arg = va_arg(ap, int*); - *arg = state->s - state->str; - break; - } - case '\0' : - --format; - /* FALLTHROUGH */ - case '%' : - (*state->append_char)(state, c); - ++len; - break; - default : - (*state->append_char)(state, '%'); - (*state->append_char)(state, c); - len += 2; - break; - } - } else { - (*state->append_char) (state, c); - ++len; } - } - return len; + return len; } #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF) -int +int ROKEN_LIB_FUNCTION snprintf (char *str, size_t sz, const char *format, ...) { - va_list args; - int ret; - - va_start(args, format); - ret = vsnprintf (str, sz, format, args); - va_end(args); - -#ifdef PARANOIA - { - int ret2; - char *tmp; - - tmp = malloc (sz); - if (tmp == NULL) - abort (); + va_list args; + int ret; va_start(args, format); - ret2 = vsprintf (tmp, format, args); + ret = vsnprintf (str, sz, format, args); va_end(args); - if (ret != ret2 || strcmp(str, tmp)) - abort (); - free (tmp); - } + +#ifdef PARANOIA + { + int ret2; + char *tmp; + + tmp = malloc (sz); + if (tmp == NULL) + abort (); + + va_start(args, format); + ret2 = vsprintf (tmp, format, args); + va_end(args); + if (ret != ret2 || strcmp(str, tmp)) + abort (); + free (tmp); + } #endif - return ret; + return ret; } #endif #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF) -int +int ROKEN_LIB_FUNCTION asprintf (char **ret, const char *format, ...) { - va_list args; - int val; - - va_start(args, format); - val = vasprintf (ret, format, args); - va_end(args); - -#ifdef PARANOIA - { - int ret2; - char *tmp; - tmp = malloc (val + 1); - if (tmp == NULL) - abort (); + va_list args; + int val; va_start(args, format); - ret2 = vsprintf (tmp, format, args); + val = vasprintf (ret, format, args); va_end(args); - if (val != ret2 || strcmp(*ret, tmp)) - abort (); - free (tmp); - } + +#ifdef PARANOIA + { + int ret2; + char *tmp; + tmp = malloc (val + 1); + if (tmp == NULL) + abort (); + + va_start(args, format); + ret2 = vsprintf (tmp, format, args); + va_end(args); + if (val != ret2 || strcmp(*ret, tmp)) + abort (); + free (tmp); + } #endif - return val; + return val; } #endif #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF) -int +int ROKEN_LIB_FUNCTION asnprintf (char **ret, size_t max_sz, const char *format, ...) { - va_list args; - int val; + va_list args; + int val; - va_start(args, format); - val = vasnprintf (ret, max_sz, format, args); + va_start(args, format); + val = vasnprintf (ret, max_sz, format, args); #ifdef PARANOIA - { - int ret2; - char *tmp; - tmp = malloc (val + 1); - if (tmp == NULL) - abort (); - - ret2 = vsprintf (tmp, format, args); - if (val != ret2 || strcmp(*ret, tmp)) - abort (); - free (tmp); - } + { + int ret2; + char *tmp; + tmp = malloc (val + 1); + if (tmp == NULL) + abort (); + + ret2 = vsprintf (tmp, format, args); + if (val != ret2 || strcmp(*ret, tmp)) + abort (); + free (tmp); + } #endif - va_end(args); - return val; + va_end(args); + return val; } #endif #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF) -int +int ROKEN_LIB_FUNCTION vasprintf (char **ret, const char *format, va_list args) { - return vasnprintf (ret, 0, format, args); + return vasnprintf (ret, 0, format, args); } #endif #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF) -int +int ROKEN_LIB_FUNCTION vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) { - int st; - struct snprintf_state state; - - state.max_sz = max_sz; - state.sz = 1; - state.str = malloc(state.sz); - if (state.str == NULL) { - *ret = NULL; - return -1; - } - state.s = state.str; - state.theend = state.s + state.sz - 1; - state.append_char = as_append_char; - - st = xyzprintf (&state, format, args); - if (st > state.sz) { - free (state.str); - *ret = NULL; - return -1; - } else { - char *tmp; - - *state.s = '\0'; - tmp = realloc (state.str, st+1); - if (tmp == NULL) { - free (state.str); - *ret = NULL; - return -1; + int st; + struct snprintf_state state; + + state.max_sz = max_sz; + state.sz = 1; + state.str = malloc(state.sz); + if (state.str == NULL) { + *ret = NULL; + return -1; + } + state.s = state.str; + state.theend = state.s + state.sz - 1; + state.append_char = as_append_char; + + st = xyzprintf (&state, format, args); + if (st > state.sz) { + free (state.str); + *ret = NULL; + return -1; + } else { + char *tmp; + + *state.s = '\0'; + tmp = realloc (state.str, st+1); + if (tmp == NULL) { + free (state.str); + *ret = NULL; + return -1; + } + *ret = tmp; + return st; } - *ret = tmp; - return st; - } } #endif #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) -int +int ROKEN_LIB_FUNCTION vsnprintf (char *str, size_t sz, const char *format, va_list args) { - struct snprintf_state state; - int ret; - unsigned char *ustr = (unsigned char *)str; - - state.max_sz = 0; - state.sz = sz; - state.str = ustr; - state.s = ustr; - state.theend = ustr + sz - (sz > 0); - state.append_char = sn_append_char; - - ret = xyzprintf (&state, format, args); - if (state.s != NULL) - *state.s = '\0'; - return ret; + struct snprintf_state state; + int ret; + unsigned char *ustr = (unsigned char *)str; + + state.max_sz = 0; + state.sz = sz; + state.str = ustr; + state.s = ustr; + state.theend = ustr + sz - (sz > 0); + state.append_char = sn_append_char; + + ret = xyzprintf (&state, format, args); + if (state.s != NULL && sz != 0) + *state.s = '\0'; + return ret; } #endif |