Branch data Line data Source code
1 : : /* vasprintf and asprintf with out-of-memory checking.
2 : : Copyright (C) 1999, 2002-2004, 2006-2010 Free Software Foundation, Inc.
3 : :
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
6 : : the Free Software Foundation; either version 3 of the License, or
7 : : (at your option) any later version.
8 : :
9 : : This program is distributed in the hope that it will be useful,
10 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : GNU General Public License for more details.
13 : :
14 : : You should have received a copy of the GNU General Public License
15 : : along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 : :
17 : : #include <config.h>
18 : :
19 : : /* Specification. */
20 : : #include "xvasprintf.h"
21 : :
22 : : #include <errno.h>
23 : : #include <limits.h>
24 : : #include <string.h>
25 : : #include <stdio.h>
26 : :
27 : : #include "xalloc.h"
28 : :
29 : : /* Checked size_t computations. */
30 : : #include "xsize.h"
31 : :
32 : : static inline char *
33 : 0 : xstrcat (size_t argcount, va_list args)
34 : : {
35 : : char *result;
36 : : va_list ap;
37 : : size_t totalsize;
38 : : size_t i;
39 : : char *p;
40 : :
41 : : /* Determine the total size. */
42 : 0 : totalsize = 0;
43 : 0 : va_copy (ap, args);
44 [ # # ]: 0 : for (i = argcount; i > 0; i--)
45 : : {
46 : 0 : const char *next = va_arg (ap, const char *);
47 : 0 : totalsize = xsum (totalsize, strlen (next));
48 : : }
49 : 0 : va_end (ap);
50 : :
51 : : /* Test for overflow in the summing pass above or in (totalsize + 1) below.
52 : : Also, don't return a string longer than INT_MAX, for consistency with
53 : : vasprintf(). */
54 [ # # # # ]: 0 : if (totalsize == SIZE_MAX || totalsize > INT_MAX)
55 : : {
56 : 0 : errno = EOVERFLOW;
57 : 0 : return NULL;
58 : : }
59 : :
60 : : /* Allocate and fill the result string. */
61 : 0 : result = XNMALLOC (totalsize + 1, char);
62 : 0 : p = result;
63 [ # # ]: 0 : for (i = argcount; i > 0; i--)
64 : : {
65 : 0 : const char *next = va_arg (args, const char *);
66 : 0 : size_t len = strlen (next);
67 : 0 : memcpy (p, next, len);
68 : 0 : p += len;
69 : : }
70 : 0 : *p = '\0';
71 : :
72 : 0 : return result;
73 : : }
74 : :
75 : : char *
76 : 74 : xvasprintf (const char *format, va_list args)
77 : : {
78 : : char *result;
79 : :
80 : : /* Recognize the special case format = "%s...%s". It is a frequently used
81 : : idiom for string concatenation and needs to be fast. We don't want to
82 : : have a separate function xstrcat() for this purpose. */
83 : : {
84 : 74 : size_t argcount = 0;
85 : : const char *f;
86 : :
87 : 74 : for (f = format;;)
88 : : {
89 [ - + ]: 89 : if (*f == '\0')
90 : : /* Recognized the special case of string concatenation. */
91 : 0 : return xstrcat (argcount, args);
92 [ + + ]: 89 : if (*f != '%')
93 : 73 : break;
94 : 16 : f++;
95 [ + + ]: 16 : if (*f != 's')
96 : 1 : break;
97 : 15 : f++;
98 : 15 : argcount++;
99 : 15 : }
100 : : }
101 : :
102 [ - + ]: 74 : if (vasprintf (&result, format, args) < 0)
103 : : {
104 [ # # ]: 0 : if (errno == ENOMEM)
105 : 0 : xalloc_die ();
106 : 0 : return NULL;
107 : : }
108 : :
109 : 74 : return result;
110 : : }
|