comparison lib/xvasprintf.c @ 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 a48fb0e98c8c
children 6c0cb059c9ea
comparison
equal deleted inserted replaced
6778:3f44368390a2 6779:1807d27bf1ec
1 /* vasprintf and asprintf with out-of-memory checking. 1 /* vasprintf and asprintf with out-of-memory checking.
2 Copyright (C) 1999, 2002-2004 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002-2004, 2006 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option) 6 the Free Software Foundation; either version 2, or (at your option)
7 any later version. 7 any later version.
21 21
22 /* Specification. */ 22 /* Specification. */
23 #include "xvasprintf.h" 23 #include "xvasprintf.h"
24 24
25 #include <errno.h> 25 #include <errno.h>
26 #include <limits.h>
27 #include <string.h>
26 28
27 #include "vasprintf.h" 29 #include "vasprintf.h"
28 #include "xalloc.h" 30 #include "xalloc.h"
31
32 /* Checked size_t computations. */
33 #include "xsize.h"
34
35 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
36 #ifndef EOVERFLOW
37 # define EOVERFLOW E2BIG
38 #endif
39
40 static inline char *
41 xstrcat (size_t argcount, va_list args)
42 {
43 char *result;
44 va_list ap;
45 size_t totalsize;
46 size_t i;
47 char *p;
48
49 /* Determine the total size. */
50 totalsize = 0;
51 va_copy (ap, args);
52 for (i = argcount; i > 0; i--)
53 {
54 const char *next = va_arg (ap, const char *);
55 totalsize = xsum (totalsize, strlen (next));
56 }
57 va_end (ap);
58
59 /* Test for overflow in the summing pass above or in (totalsize + 1) below.
60 Also, don't return a string longer than INT_MAX, for consistency with
61 vasprintf(). */
62 if (totalsize == SIZE_MAX || totalsize > INT_MAX)
63 {
64 errno = EOVERFLOW;
65 return NULL;
66 }
67
68 /* Allocate and fill the result string. */
69 result = (char *) xmalloc (totalsize + 1);
70 p = result;
71 for (i = argcount; i > 0; i--)
72 {
73 const char *next = va_arg (args, const char *);
74 size_t len = strlen (next);
75 memcpy (p, next, len);
76 p += len;
77 }
78 *p = '\0';
79
80 return result;
81 }
29 82
30 char * 83 char *
31 xvasprintf (const char *format, va_list args) 84 xvasprintf (const char *format, va_list args)
32 { 85 {
33 char *result; 86 char *result;
87
88 /* Recognize the special case format = "%s...%s". It is a frequently used
89 idiom for string concatenation and needs to be fast. We don't want to
90 have a separate function xstrcat() for this purpose. */
91 {
92 size_t argcount = 0;
93 const char *f;
94
95 for (f = format;;)
96 {
97 if (*f == '\0')
98 /* Recognized the special case of string concatenation. */
99 return xstrcat (argcount, args);
100 if (*f != '%')
101 break;
102 f++;
103 if (*f != 's')
104 break;
105 f++;
106 argcount++;
107 }
108 }
34 109
35 if (vasprintf (&result, format, args) < 0) 110 if (vasprintf (&result, format, args) < 0)
36 { 111 {
37 if (errno == ENOMEM) 112 if (errno == ENOMEM)
38 xalloc_die (); 113 xalloc_die ();