mescc: vsnprintf: Compliant implementation.
authorJan Nieuwenhuizen <janneke@gnu.org>
Mon, 22 Oct 2018 16:33:40 +0000 (18:33 +0200)
committerJan Nieuwenhuizen <janneke@gnu.org>
Mon, 22 Oct 2018 16:33:40 +0000 (18:33 +0200)
* 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
lib/stdio/snprintf.c
lib/stdio/vsnprintf.c
lib/stdio/vsprintf.c
scaffold/tests/9a-snprintf.c [new file with mode: 0644]

index ab0c2f465c2d08dcd6b9bdbd7aa2263fdbb5a6d2..9f22536fcc67e0f92cca90b1939488bb1b97a3d7 100755 (executable)
@@ -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
index 0da3c132c886edd51a6c48f85cf488e7c8b5d62e..8afb1fc2e19ccabfe22765610d9f56cfcdb054fd 100644 (file)
@@ -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;
 }
index d375ac76c2cf3a4cf087853e6104991e3b1826a3..e949a3f5daf8e82dc48477e54cdc347cf078b123 100644 (file)
 #include <stdlib.h>
 
 int
-vsnprintf (char *str, size_t size, char const *format, va_list ap)
+vsnprintf (char *str, size_t size, char constformat, 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;
 }
index 41147db8a4826e9de83676f145aecc86d2d995dc..9953c3af01db5c0aa84146a177adcd9ccff5a34d 100644 (file)
 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 (file)
index 0000000..4a55234
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <libmes.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+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;
+}