From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- third_party/heimdal/lib/roken/snprintf.c | 729 +++++++++++++++++++++++++++++++ 1 file changed, 729 insertions(+) create mode 100644 third_party/heimdal/lib/roken/snprintf.c (limited to 'third_party/heimdal/lib/roken/snprintf.c') diff --git a/third_party/heimdal/lib/roken/snprintf.c b/third_party/heimdal/lib/roken/snprintf.c new file mode 100644 index 0000000..54018ba --- /dev/null +++ b/third_party/heimdal/lib/roken/snprintf.c @@ -0,0 +1,729 @@ +/* + * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "roken.h" +#include + +enum format_flags { + minus_flag = 1, + plus_flag = 2, + space_flag = 4, + alternate_flag = 8, + zero_flag = 16 +}; + +/* + * Common state + */ + +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 */ +}; + +#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) +static int +sn_reserve (struct snprintf_state *state, size_t n) +{ + 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; +} +#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; +} + +static void +as_append_char (struct snprintf_state *state, unsigned char c) +{ + if(!as_reserve (state, 1)) + *state->s++ = c; +} + +/* longest integer types */ + +#ifdef HAVE_LONG_LONG +typedef unsigned long long u_longest; +typedef long long longest; +#else +typedef unsigned long u_longest; +typedef long longest; +#endif + +#ifndef HAVE_UINTPTR_T +typedef u_longest uintptr_t; +#endif + + + +static size_t +pad(struct snprintf_state *state, int width, char c) +{ + size_t 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 && num != 0; +} + +static int +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; + 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++; + } + + /* 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; + } + + /* 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; + } + 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; +} + +/* + * return length + */ + +static size_t +append_string (struct snprintf_state *state, + const unsigned char *arg, + int width, + int prec, + int flags) +{ + size_t len = 0; + + if(arg == NULL) + arg = (const unsigned char*)"(null)"; + + if(prec != -1) + width -= prec; + else + width -= strlen((const char *)arg); + if(!(flags & minus_flag)) + len += pad(state, width, ' '); + + if (prec != -1) { + while (prec-- && *arg) { + (*state->append_char) (state, *arg++); + ++len; + } + } else { + while (*arg) { + (*state->append_char) (state, *arg++); + ++len; + } + } + if(flags & minus_flag) + len += pad(state, width, ' '); + return len; +} + +static int +append_char(struct snprintf_state *state, + unsigned char arg, + int width, + int flags) +{ + 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 len; +} + +/* + * This can't be made into a function... + */ + +#ifdef HAVE_LONG_LONG + +#define PARSE_INT_FORMAT(res, arg, unsig) \ +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 \ + res = (unsig int)va_arg(arg, unsig int) + +#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 \ + res = (unsig int)va_arg(arg, unsig int) + +#endif + +/* + * zyxprintf - return length, as snprintf + */ + +static size_t +xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap) +{ + const unsigned char *format = (const unsigned char *)char_format; + unsigned char c; + size_t 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 == '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' : + len += append_char(state, va_arg(ap, int), width, flags); + break; + case 's' : + len += append_string(state, + va_arg(ap, unsigned char*), + width, + prec, + flags); + break; + case 'd' : + case 'i' : { + int64_t arg; + uint64_t num; + int minusp = 0; + + PARSE_INT_FORMAT(arg, ap, signed); + + if (arg == INT64_MIN) { + minusp = 1; + num = (uint64_t)INT64_MAX + 1; + } else 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' : { + uintptr_t arg = (uintptr_t)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; + HEIM_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; +} + +#if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_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_start(args, format); + ret2 = vsprintf (tmp, format, args); + va_end(args); + if (ret != ret2 || strcmp(str, tmp) != 0) + abort (); + free (tmp); + } +#endif + + return ret; +} +#endif + +#if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_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_start(args, format); + ret2 = vsprintf (tmp, format, args); + va_end(args); + if (val != ret2 || strcmp(*ret, tmp) != 0) + abort (); + free (tmp); + } +#endif + + return val; +} +#endif + +#if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_asnprintf (char **ret, size_t max_sz, const char *format, ...) +{ + va_list args; + int val; + + 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) != 0) + abort (); + free (tmp); + } +#endif + + va_end(args); + return val; +} +#endif + +#if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_vasprintf (char **ret, const char *format, va_list args) +{ + return vasnprintf (ret, 0, format, args); +} +#endif + + +#if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) +{ + size_t 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; + } +} +#endif + +#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_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 && sz != 0) + *state.s = '\0'; + return ret; +} +#endif + +#if !defined(HAVE_EVASPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL +rk_evasprintf(const char *format, va_list args) +{ + char *s = NULL; + + if (vasprintf(&s, format, args) == -1 || s == NULL) + errx(1, "Out of memory"); + return s; +} +#endif + +#if !defined(HAVE_EASPRINTF) || defined(TEST_SNPRINTF) +ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL +rk_easprintf(const char *format, ...) +{ + va_list args; + char *s = NULL; + + va_start(args, format); + if (vasprintf(&s, format, args) == -1 || s == NULL) + errx(1, "Out of memory"); + va_end(args); + return s; +} +#endif -- cgit v1.2.3