[Top][All Lists]
[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)
- extend the scope of xasprintf,
Bruno Haible <=
Re: [bug-gnulib] Re: extend the scope of xasprintf, Bruno Haible, 2006/05/09