Patch to add snprintf/vsnprintf to libiberty [take 2]

Kaveh R. Ghazi ghazi@caip.rutgers.edu
Wed Jun 12 20:56:00 GMT 2002


Thanks to everyone who provided feedback!

Here's take 2 of my snprintf libiberty patch.  The only change is for
c99 conformance as pointed out by you all.  Namely to make vsnprintf
return the number of characters that would have been transmitted even
when n is zero.

The other assumptions I made for corner cases seemed to be okay.

Note: I didn't bother checking if n > INT_MAX since I didn't feel it
was worth hacking in limits.h and defining INT_MAX if limits.h is
missing and ditto for EOVERFLOW.  If someone wants to add that for
stricter c99 conformance after it goes in, feel free.

Tested again on solaris2.7 by compiling and running vsnprintf.c -DTEST
using gcc-2.95.2, cc and cc -Xs (traditional mode.)

Ok to install?

		Thanks,
		--Kaveh


>>>>> PS: I'm still looking for licensing feedback on whether
vasprintf.c pollutes libstdc++-v3, but that's not necessary for
checking in this patch.



2002-06-12  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

include:
	* libiberty.h (snprintf, vsnprintf): Declare.

libiberty:
	* snprintf.c, vsnprintf.c: New files.
	* configure.in (funcs): Add snprintf & vsnprintf.
	(AC_CHECK_FUNCS): Likewise.
	* Makefile.in (CFILES): Add snprintf.c & vsnprintf.c.
	(CONFIGURED_OFILES): Add snprintf.o & vsnprintf.o.
	* acconfig.h: New file.

	* config.in, configure: Regenerated.

diff -rup orig/egcc-CVS20020612/include/libiberty.h egcc-CVS20020612/include/libiberty.h
--- orig/egcc-CVS20020612/include/libiberty.h	2002-01-28 16:07:44.000000000 -0500
+++ egcc-CVS20020612/include/libiberty.h	2002-06-12 23:29:29.277520249 -0400
@@ -275,6 +275,15 @@ extern int asprintf PARAMS ((char **, co
 extern int vasprintf PARAMS ((char **, const char *, va_list))
   ATTRIBUTE_PRINTF(2,0);
 
+/* Like sprintf but it accepts a maximum buffer size.  */
+
+extern int snprintf PARAMS ((char *, size_t, const char *, ...)) ATTRIBUTE_PRINTF_3;
+
+/* Like vsprintf but it accepts a maximum buffer size.  */
+
+extern int vsnprintf PARAMS ((char *, size_t, const char *, va_list))
+  ATTRIBUTE_PRINTF(3,0);
+
 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
 
 /* Drastically simplified alloca configurator.  If we're using GCC,
diff -rup orig/egcc-CVS20020612/libiberty/snprintf.c egcc-CVS20020612/libiberty/snprintf.c
--- orig/egcc-CVS20020612/libiberty/snprintf.c	2002-06-12 23:41:05.894878681 -0400
+++ egcc-CVS20020612/libiberty/snprintf.c	2002-06-12 23:29:29.287519622 -0400
@@ -0,0 +1,27 @@
+/* Simple implementation of snprintf for systems without it.
+   By Kaveh Ghazi (ghazi@caip.rutgers.edu) 6/12/2002.
+   This function is in the public domain.  */
+
+#include "ansidecl.h"
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <stdio.h>
+
+#include "libiberty.h"
+
+int
+snprintf VPARAMS ((char *s, size_t n, const char *format, ...))
+{
+  int result;
+  VA_OPEN (ap, format);
+  VA_FIXEDARG (ap, char *, s);
+  VA_FIXEDARG (ap, size_t, n);
+  VA_FIXEDARG (ap, const char *, format);
+  result = vsnprintf (s, n, format, ap);
+  VA_CLOSE (ap);
+  return result;
+}
diff -rup orig/egcc-CVS20020612/libiberty/vsnprintf.c egcc-CVS20020612/libiberty/vsnprintf.c
--- orig/egcc-CVS20020612/libiberty/vsnprintf.c	2002-06-12 23:41:16.265386009 -0400
+++ egcc-CVS20020612/libiberty/vsnprintf.c	2002-06-12 23:37:29.763418660 -0400
@@ -0,0 +1,113 @@
+/* Simple implementation of vsnprintf for systems without it.
+   By Kaveh Ghazi (ghazi@caip.rutgers.edu) 6/12/2002.
+   This function is in the public domain.  */
+
+#include "config.h"
+#include "ansidecl.h"
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "libiberty.h"
+
+/* This implementation relies on a working vasprintf.  */
+int
+vsnprintf (s, n, format, ap)
+     char * s;
+     size_t n;
+     const char *format;
+     va_list ap;
+{
+  char *buf = 0;
+  int result = vasprintf (&buf, format, ap);
+
+  if (!buf)
+    return -1;
+  if (result < 0)
+    {
+      free (buf);
+      return -1;
+    }
+
+  result = strlen (buf);
+  if (n > 0)
+    {
+      strncpy (s, buf, n);
+      if (n - 1 < (size_t) result)
+	s[n - 1] = 0;
+    }
+  free (buf);
+  return result;
+}
+
+#ifdef TEST
+/* Set the buffer to a known state.  */
+#define CLEAR(BUF) do { memset ((BUF), 'X', sizeof (BUF)); (BUF)[14] = '\0'; } while (0)
+/* For assertions.  */
+#define VERIFY(P) do { if (!(P)) abort(); } while (0)
+
+static int ATTRIBUTE_PRINTF_3
+checkit VPARAMS ((char *s, size_t n, const char *format, ...))
+{
+  int result;
+  VA_OPEN (ap, format);
+  VA_FIXEDARG (ap, char *, s);
+  VA_FIXEDARG (ap, size_t, n);
+  VA_FIXEDARG (ap, const char *, format);
+  result = vsnprintf (s, n, format, ap);
+  VA_CLOSE (ap);
+  return result;
+}
+
+extern int main PARAMS ((void));
+int
+main ()
+{
+  char buf[128];
+  int status;
+  
+  CLEAR (buf);
+  status = checkit (buf, 10, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "foobar:9") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 9, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "foobar:9") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 8, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "foobar:") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 7, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "foobar") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 6, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "fooba") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 2, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "f") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 1, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "") == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 0, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && strcmp (buf, "XXXXXXXXXXXXXX") == 0);
+
+  return 0;
+}
+#endif /* TEST */
diff -rup orig/egcc-CVS20020612/libiberty/configure.in egcc-CVS20020612/libiberty/configure.in
--- orig/egcc-CVS20020612/libiberty/configure.in	2002-05-22 23:10:43.000000000 -0400
+++ egcc-CVS20020612/libiberty/configure.in	2002-06-12 23:29:29.287519622 -0400
@@ -174,6 +174,7 @@ funcs="$funcs random"
 funcs="$funcs rename"
 funcs="$funcs rindex"
 funcs="$funcs setenv"
+funcs="$funcs snprintf"
 funcs="$funcs sigsetmask"
 funcs="$funcs strcasecmp"
 funcs="$funcs strchr"
@@ -188,6 +189,7 @@ funcs="$funcs tmpnam"
 funcs="$funcs vasprintf"
 funcs="$funcs vfprintf"
 funcs="$funcs vprintf"
+funcs="$funcs vsnprintf"
 funcs="$funcs vsprintf"
 funcs="$funcs waitpid"
 
@@ -206,7 +208,7 @@ if test "x" = "y"; then
   AC_CHECK_FUNCS(strcasecmp setenv strchr strdup strncasecmp strrchr strstr)
   AC_CHECK_FUNCS(strtod strtol strtoul tmpnam vasprintf vfprintf vprintf)
   AC_CHECK_FUNCS(vsprintf waitpid getrusage on_exit psignal strerror strsignal)
-  AC_CHECK_FUNCS(sysconf times sbrk gettimeofday ffs)
+  AC_CHECK_FUNCS(sysconf times sbrk gettimeofday ffs snprintf vsnprintf)
   AC_DEFINE(HAVE_SYS_ERRLIST, 1, [Define if you have the sys_errlist variable.])
   AC_DEFINE(HAVE_SYS_NERR,    1, [Define if you have the sys_nerr variable.])
   AC_DEFINE(HAVE_SYS_SIGLIST, 1, [Define if you have the sys_siglist variable.])
diff -rup orig/egcc-CVS20020612/libiberty/Makefile.in egcc-CVS20020612/libiberty/Makefile.in
--- orig/egcc-CVS20020612/libiberty/Makefile.in	2002-03-04 18:34:47.000000000 -0500
+++ egcc-CVS20020612/libiberty/Makefile.in	2002-06-12 23:29:29.287519622 -0400
@@ -137,12 +137,12 @@ CFILES = alloca.c argv.c asprintf.c atex
 	objalloc.c obstack.c						\
 	partition.c pexecute.c putenv.c					\
 	random.c regex.c rename.c rindex.c				\
-	safe-ctype.c setenv.c sigsetmask.c sort.c spaces.c		\
+	safe-ctype.c setenv.c sigsetmask.c snprintf.c sort.c spaces.c	\
 	 splay-tree.c strcasecmp.c strchr.c strdup.c strerror.c		\
 	 strncasecmp.c strncmp.c strrchr.c strsignal.c strstr.c		\
 	 strtod.c strtol.c strtoul.c					\
 	ternary.c tmpnam.c						\
-	vasprintf.c vfork.c vfprintf.c vprintf.c vsprintf.c		\
+	vasprintf.c vfork.c vfprintf.c vprintf.c vsnprintf.c vsprintf.c	\
 	waitpid.c							\
 	xatexit.c xexit.c xmalloc.c xmemdup.c xstrdup.c xstrerror.c
 
@@ -177,11 +177,11 @@ CONFIGURED_OFILES = asprintf.o atexit.o	
 	memchr.o memcmp.o memcpy.o memmove.o memset.o mkstemps.o	\
 	putenv.o							\
 	random.o rename.o rindex.o					\
-	setenv.o sigsetmask.o strcasecmp.o strchr.o strdup.o		\
+	setenv.o sigsetmask.o snprintf.o strcasecmp.o strchr.o strdup.o	\
 	 strncasecmp.o strncmp.o strrchr.o strstr.o strtod.o strtol.o	\
 	 strtoul.o							\
 	tmpnam.o							\
-	vasprintf.o vfork.o vfprintf.o vprintf.o vsprintf.o		\
+	vasprintf.o vfork.o vfprintf.o vprintf.o vsnprintf.o vsprintf.o	\
 	waitpid.o
 
 # These files are installed if the library has been configured to do so.
diff -rup orig/egcc-CVS20020612/libiberty/acconfig.h egcc-CVS20020612/libiberty/acconfig.h
--- orig/egcc-CVS20020612/libiberty/acconfig.h	2002-06-12 23:40:56.234371501 -0400
+++ egcc-CVS20020612/libiberty/acconfig.h	2002-06-12 23:29:29.307520208 -0400
@@ -0,0 +1,2 @@
+/* Define to `unsigned long' if <sys/types.h> doesn't define.  */
+#undef uintptr_t



More information about the Gcc-patches mailing list