bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

extend the scope of xasprintf


From: Bruno Haible
Subject: extend the scope of xasprintf
Date: Wed, 3 May 2006 14:07:02 +0200
User-agent: KMail/1.5

Hi Oskar et al.,

In GNU gettext, I've started to use xasprintf nearly everywhere where a
string is constructed from other strings.

     xasprintf (_("creation of file \"%s\" failed"), filename);

     xasprintf ("%s (%s)", aliasname, fullname);

     xasprintf ("%s%s%s", prefix, msgid, suffix);

The only optimization that I allow myself to do manually is

     xasprintf ("%s", string)  =>  xstrdup (string).

For the second and third case, I now use xasprintf instead of manual string
concatenation with xmalloc and memcpy. This makes the code more maintainable:
when I decide later to add some spaces between string parts, or to 
internationalize
a string, I no longer have to choose a different string allocation primitive.

But the third case is frequent, and I wouldn't like it to have a big speed
penalty (due to format string parsing and use of sprintf). Therefore I propose
to put this special case optimization into gnulib's xasprintf.

OK to commit (and update the dependencies of the xvasprintf module to include
'stdarg' and 'xsize')?

Bruno


diff -r -c3 --exclude='*.po*' --exclude='*.info*' --exclude='*_*.html' 
--exclude='*.*.html' --exclude='*.[13]' --exclude='*.1.in' 
--exclude=Makefile.in --exclude=aclocal.m4 --exclude=configure 
--exclude=version.texi --exclude=stamp-vti --exclude='po-*-gen*.[ch]' 
--exclude='*.o' --exclude='*.lo' --exclude='*.gmo' --exclude=ABOUT-NLS 
--exclude='javadoc[12]' --exclude=CVS 
gettext-cvs/gettext-tools/lib/xvasprintf.c 
gettext-6/gettext-tools/lib/xvasprintf.c
*** gettext-cvs/gettext-tools/lib/xvasprintf.c  Sat May 14 08:03:58 2005
--- gettext-6/gettext-tools/lib/xvasprintf.c    Sun Apr 30 20:52:15 2006
***************
*** 1,5 ****
  /* vasprintf and asprintf with out-of-memory checking.
!    Copyright (C) 1999, 2002-2004 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
--- 1,5 ----
  /* vasprintf and asprintf with out-of-memory checking.
!    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,37 ****
--- 23,111 ----
  #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));
+     }
+ 
+   /* Don't return a string longer than INT_MAX, for consistency with
+      vasprintf().  */
+   if (totalsize > INT_MAX)
+     {
+       errno = EOVERFLOW;
+       return NULL;
+     }
+ 
+   /* Allocate and fill the result string.  */
+   result = (char *) xmalloc (totalsize + 1);
+   p = result;
+   va_copy (ap, args);
+   for (i = argcount; i > 0; i--)
+     {
+       const char *next = va_arg (ap, 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)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]