changeset 6779:1807d27bf1ec

Recognize the special case of a string concatenation in xvasprintf.
author Bruno Haible <bruno@clisp.org>
date Tue, 09 May 2006 17:26:15 +0000
parents 3f44368390a2
children 7272c09465f2
files ChangeLog lib/ChangeLog lib/xvasprintf.c m4/ChangeLog m4/xvasprintf.m4 modules/xvasprintf
diffstat 6 files changed, 108 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2006-05-09  Bruno Haible  <bruno@clisp.org>
+
+	* modules/xvasprintf (Files): Add m4/xvasprintf.m4.
+	(Depends-on): Depend also on xsize, stdarg.
+	(configure.ac): Add gl_XVASPRINTF.
+
 2006-05-08  Eric Blake  <ebb9@byu.net>
 
 	* gnulib-tool (func_version): Base copyright year on CVS date.
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,10 @@
+2006-05-09  Bruno Haible  <bruno@clisp.org>
+
+	* xvasprintf.c: Include limits.h, string.h, xsize.h.
+	(EOVERFLOW): Define fallback value.
+	(xstrcat): New function.
+	(xvasprintf): Recognize the special case of a string concatenation.
+
 2006-05-01  Bruno Haible  <bruno@clisp.org>
 
 	* stdint_.h: Shorter URL.
--- a/lib/xvasprintf.c
+++ b/lib/xvasprintf.c
@@ -1,5 +1,5 @@
 /* vasprintf and asprintf with out-of-memory checking.
-   Copyright (C) 1999, 2002-2004 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2002-2004, 2006 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -23,15 +23,90 @@
 #include "xvasprintf.h"
 
 #include <errno.h>
+#include <limits.h>
+#include <string.h>
 
 #include "vasprintf.h"
 #include "xalloc.h"
 
+/* Checked size_t computations.  */
+#include "xsize.h"
+
+/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
+#ifndef EOVERFLOW
+# define EOVERFLOW E2BIG
+#endif
+
+static inline char *
+xstrcat (size_t argcount, va_list args)
+{
+  char *result;
+  va_list ap;
+  size_t totalsize;
+  size_t i;
+  char *p;
+
+  /* Determine the total size.  */
+  totalsize = 0;
+  va_copy (ap, args);
+  for (i = argcount; i > 0; i--)
+    {
+      const char *next = va_arg (ap, const char *);
+      totalsize = xsum (totalsize, strlen (next));
+    }
+  va_end (ap);
+
+  /* Test for overflow in the summing pass above or in (totalsize + 1) below.
+     Also, don't return a string longer than INT_MAX, for consistency with
+     vasprintf().  */
+  if (totalsize == SIZE_MAX || totalsize > INT_MAX)
+    {
+      errno = EOVERFLOW;
+      return NULL;
+    }
+
+  /* Allocate and fill the result string.  */
+  result = (char *) xmalloc (totalsize + 1);
+  p = result;
+  for (i = argcount; i > 0; i--)
+    {
+      const char *next = va_arg (args, const char *);
+      size_t len = strlen (next);
+      memcpy (p, next, len);
+      p += len;
+    }
+  *p = '\0';
+
+  return result;
+}
+
 char *
 xvasprintf (const char *format, va_list args)
 {
   char *result;
 
+  /* Recognize the special case format = "%s...%s".  It is a frequently used
+     idiom for string concatenation and needs to be fast.  We don't want to
+     have a separate function xstrcat() for this purpose.  */
+  {
+    size_t argcount = 0;
+    const char *f;
+
+    for (f = format;;)
+      {
+	if (*f == '\0')
+	  /* Recognized the special case of string concatenation.  */
+	  return xstrcat (argcount, args);
+	if (*f != '%')
+	  break;
+	f++;
+	if (*f != 's')
+	  break;
+	f++;
+	argcount++;
+      }
+  }
+
   if (vasprintf (&result, format, args) < 0)
     {
       if (errno == ENOMEM)
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,7 @@
+2006-05-09  Bruno Haible  <bruno@clisp.org>
+
+	* xvasprintf.m4: New file.
+
 2006-05-08  Bruno Haible  <bruno@clisp.org>
 
 	* stdarg.m4: New file, from GNU gettext.
new file mode 100644
--- /dev/null
+++ b/m4/xvasprintf.m4
@@ -0,0 +1,11 @@
+# xvasprintf.m4 serial 1
+dnl Copyright (C) 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XASPRINTF],
+[
+  dnl Prerequisites of lib/xvasprintf.c.
+  AC_REQUIRE([AC_C_INLINE])
+])
--- a/modules/xvasprintf
+++ b/modules/xvasprintf
@@ -6,12 +6,16 @@
 lib/xvasprintf.c
 lib/xasprintf.c
 lib/xalloc.h
+m4/xvasprintf.m4
 
 Depends-on:
 vasprintf
 xalloc-die
+xsize
+stdarg
 
 configure.ac:
+gl_XVASPRINTF
 
 Makefile.am:
 lib_SOURCES += xvasprintf.h xvasprintf.c xasprintf.c