From 3d528b0257db0aa0385a3162698a7c6df0f83c88 Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Mon, 22 Oct 2018 18:33:40 +0200 Subject: [PATCH] mescc: vsnprintf: Compliant implementation. * lib/stdio/vsnprintf.c (vsnprintf): New, complient implementation, replacing vsnprint. * lib/stdio/vsprintf.c (vsnprint): Forward to vsnprint. * lib/stdio/snprintf.c (snprintf): Likewise. * scaffold/tests/9a-snprintf.c: Test it. * build-aux/check-mescc.sh (tests): Run it. --- build-aux/check-mescc.sh | 1 + lib/stdio/snprintf.c | 8 +- lib/stdio/vsnprintf.c | 197 ++++++++++++++++++++++++++++++++++- lib/stdio/vsprintf.c | 179 +------------------------------ scaffold/tests/9a-snprintf.c | 37 +++++++ 5 files changed, 241 insertions(+), 181 deletions(-) create mode 100644 scaffold/tests/9a-snprintf.c diff --git a/build-aux/check-mescc.sh b/build-aux/check-mescc.sh index ab0c2f46..9f22536f 100755 --- a/build-aux/check-mescc.sh +++ b/build-aux/check-mescc.sh @@ -220,6 +220,7 @@ t 97-fopen 98-fopen 99-readdir +9a-snprintf a0-call-trunc-char a0-call-trunc-short a0-call-trunc-int diff --git a/lib/stdio/snprintf.c b/lib/stdio/snprintf.c index 0da3c132..8afb1fc2 100644 --- a/lib/stdio/snprintf.c +++ b/lib/stdio/snprintf.c @@ -25,8 +25,14 @@ int snprintf (char *str, size_t size, char const *format, ...) { va_list ap; + int r; +#if __GNUC__ && __x86_64__ +#define __FUNCTION_ARGS 3 + ap += (__FOO_VARARGS + (__FUNCTION_ARGS << 1)) << 3; +#undef __FUNCTION_ARGS +#endif va_start (ap, format); - int r = vsprintf (str, format, ap); + r = vsnprintf (str, size, format, ap); va_end (ap); return r; } diff --git a/lib/stdio/vsnprintf.c b/lib/stdio/vsnprintf.c index d375ac76..e949a3f5 100644 --- a/lib/stdio/vsnprintf.c +++ b/lib/stdio/vsnprintf.c @@ -22,7 +22,200 @@ #include int -vsnprintf (char *str, size_t size, char const *format, va_list ap) +vsnprintf (char *str, size_t size, char const* format, va_list ap) { - return vsprintf (str, format, ap); + char const *p = format; + int count = 0; + char c; + while (*p) + if (*p != '%') + { + c = *p++; + if (count < size) + *str++ = c; + count++; + } + else + { + p++; + c = *p; + int left_p = 0; + int precision = -1; + int width = -1; + if (c == '-') + { + left_p = 1; + c = *++p; + } + char pad = ' '; + if (c == '0') + { + pad = c; + c = *p++; + } + if (c >= '0' && c <= '9') + { + width = abtol (&p, 10); + c = *p; + } + else if (c == '*') + { + width = va_arg (ap, long); + c = *++p; + } + if (c == '.') + { + c = *++p; + if (c >= '0' && c <= '9') + { + precision = abtol (&p, 10); + c = *p; + } + else if (c == '*') + { + precision = va_arg (ap, long); + c = *++p; + } + } + if (c == 'l') + c = *++p; + if (c == 'l') + c = *++p; + if (c == 'l') + { + eputs ("vsnprintf: skipping second: l\n"); + c = *++p; + } + switch (c) + { + case '%': + { + if (count < size) + *str++ = *p; + count++; + break; + } + case 'c': + { + c = va_arg (ap, long); + if (count < size) + *str++ = c; + count++; + break; + } + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + { + long d = va_arg (ap, long); + int base = c == 'o' ? 8 + : c == 'x' || c == 'X' ? 16 + : 10; + char const *s = ntoab (d, base, c != 'u' && c != 'x' && c != 'X'); + if (c == 'X') + strupr (s); + int length = strlen (s); + if (precision == -1) + precision = length; + if (!left_p) + { + while (width-- > precision) + { + if (count < size) + *str++ = pad; + count++; + } + while (precision > length) + { + if (count < size) + *str++ = '0'; + precision--; + width--; + count++; + } + } + while (*s) + { + if (precision-- <= 0) + break; + width--; + c = *s++; + if (count < size) + *str++ = c; + count++; + } + while (width > 0) + { + width--; + if (count < size) + *str++ = pad; + count++; + } + break; + } + case 's': + { + char *s = va_arg (ap, char *); + int length = s ? strlen (s) : 0; + if (precision == -1) + precision = length; + if (!left_p) + { + while (width-- > precision) + { + if (count < size) + *str++ = pad; + count++; + } + while (width > length) + { + if (count < size) + *str++ = ' '; + precision--; + width--; + count++; + } + } + while (s && *s) + { + if (precision-- <= 0) + break; + width--; + c = *s++; + if (count < size) + *str++ = c; + count++; + } + while (width > 0) + { + width--; + if (count < size) + *str++ = pad; + count++; + } + break; + } + case 'n': + { + int *n = va_arg (ap, int *); + *n = count; + break; + } + default: + { + eputs ("vsnprintf: not supported: %:"); + eputc (c); + eputs ("\n"); + p++; + } + } + p++; + } + va_end (ap); + if (count < size) + *str = 0; + return count; } diff --git a/lib/stdio/vsprintf.c b/lib/stdio/vsprintf.c index 41147db8..9953c3af 100644 --- a/lib/stdio/vsprintf.c +++ b/lib/stdio/vsprintf.c @@ -24,182 +24,5 @@ int vsprintf (char *str, char const* format, va_list ap) { - char const *p = format; - int count = 0; - while (*p) - if (*p != '%') - { - *str++ = *p++; - count++; - } - else - { - p++; - char c = *p; - int left_p = 0; - int precision = -1; - int width = -1; - if (c == '-') - { - left_p = 1; - c = *++p; - } - char pad = ' '; - if (c == '0') - { - pad = c; - c = *p++; - } - if (c >= '0' && c <= '9') - { - width = abtol (&p, 10); - c = *p; - } - else if (c == '*') - { - width = va_arg (ap, long); - c = *++p; - } - if (c == '.') - { - c = *++p; - if (c >= '0' && c <= '9') - { - precision = abtol (&p, 10); - c = *p; - } - else if (c == '*') - { - precision = va_arg (ap, long); - c = *++p; - } - } - if (c == 'l') - c = *++p; - if (c == 'l') - c = *++p; - if (c == 'l') - { - eputs ("vfprintf: skipping second: l\n"); - c = *++p; - } - switch (c) - { - case '%': - { - *str++ = *p; - count++; - break; - } - case 'c': - { - c = va_arg (ap, long); - *str++ = c; - count++; - break; - } - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - { - long d = va_arg (ap, long); - int base = c == 'o' ? 8 - : c == 'x' || c == 'X' ? 16 - : 10; - char const *s = ntoab (d, base, c != 'u' && c != 'x' && c != 'X'); - if (c == 'X') - strupr (s); - int length = strlen (s); - if (precision == -1) - precision = length; - if (!left_p) - { - while (width-- > precision) - { - *str++ = pad; - count++; - } - while (precision > length) - { - *str++ = '0'; - precision--; - width--; - count++; - } - } - while (*s) - { - if (precision-- <= 0) - break; - width--; - *str++ = *s++; - count++; - } - while (width > 0) - { - width--; - *str++ = pad; - count++; - } - break; - } - case 's': - { - char *s = va_arg (ap, char *); - int length = strlen (s); - if (precision == -1) - precision = length; - if (!left_p) - { - while (width-- > precision) - { - *str++ = pad; - count++; - } - while (width > length) - { - *str++ = ' '; - precision--; - width--; - count++; - } - } - while (*s) - { - if (precision-- <= 0) - break; - width--; - *str++ = *s++; - count++; - } - while (width > 0) - { - width--; - *str++ = pad; - count++; - } - break; - } - case 'n': - { - int *n = va_arg (ap, int *); - *n = count; - break; - } - default: - { - eputs ("vsprintf: not supported: %:"); - eputc (c); - eputs ("\n"); - p++; - } - } - p++; - } - va_end (ap); - *str = 0; - return strlen (str); + return vsnprintf (str, LONG_MAX, format, ap); } diff --git a/scaffold/tests/9a-snprintf.c b/scaffold/tests/9a-snprintf.c new file mode 100644 index 00000000..4a552345 --- /dev/null +++ b/scaffold/tests/9a-snprintf.c @@ -0,0 +1,37 @@ +/* -*-comment-start: "//";comment-end:""-*- + * GNU Mes --- Maxwell Equations of Software + * Copyright © 2018 Jan (janneke) Nieuwenhuizen + * + * This file is part of GNU Mes. + * + * GNU Mes is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * GNU Mes is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Mes. If not, see . + */ + +#include + +#include +#include +#include + +int +main () +{ + int n = snprintf (0, 0, "%s", "0123456"); + eputs ("***n="); eputs (itoa (n)); eputs ("\n"); + exit(n != 7); + + /* if (n) */ + /* return 1; */ + return 0; +}