1 | /* vasprintf and asprintf with out-of-memory checking.
|
---|
2 | Copyright (C) 1999, 2002-2004, 2006 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 2, or (at your option)
|
---|
7 | 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 along
|
---|
15 | with this program; if not, write to the Free Software Foundation,
|
---|
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
---|
17 |
|
---|
18 | #include <config.h>
|
---|
19 |
|
---|
20 | /* Specification. */
|
---|
21 | #include "xvasprintf.h"
|
---|
22 |
|
---|
23 | #include <errno.h>
|
---|
24 | #include <limits.h>
|
---|
25 | #include <string.h>
|
---|
26 |
|
---|
27 | #include "vasprintf.h"
|
---|
28 | #include "xalloc.h"
|
---|
29 |
|
---|
30 | /* Checked size_t computations. */
|
---|
31 | #include "xsize.h"
|
---|
32 |
|
---|
33 | /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
|
---|
34 | #ifndef EOVERFLOW
|
---|
35 | # define EOVERFLOW E2BIG
|
---|
36 | #endif
|
---|
37 |
|
---|
38 | static inline char *
|
---|
39 | xstrcat (size_t argcount, va_list args)
|
---|
40 | {
|
---|
41 | char *result;
|
---|
42 | va_list ap;
|
---|
43 | size_t totalsize;
|
---|
44 | size_t i;
|
---|
45 | char *p;
|
---|
46 |
|
---|
47 | /* Determine the total size. */
|
---|
48 | totalsize = 0;
|
---|
49 | va_copy (ap, args);
|
---|
50 | for (i = argcount; i > 0; i--)
|
---|
51 | {
|
---|
52 | const char *next = va_arg (ap, const char *);
|
---|
53 | totalsize = xsum (totalsize, strlen (next));
|
---|
54 | }
|
---|
55 | va_end (ap);
|
---|
56 |
|
---|
57 | /* Test for overflow in the summing pass above or in (totalsize + 1) below.
|
---|
58 | Also, don't return a string longer than INT_MAX, for consistency with
|
---|
59 | vasprintf(). */
|
---|
60 | if (totalsize == SIZE_MAX || totalsize > INT_MAX)
|
---|
61 | {
|
---|
62 | errno = EOVERFLOW;
|
---|
63 | return NULL;
|
---|
64 | }
|
---|
65 |
|
---|
66 | /* Allocate and fill the result string. */
|
---|
67 | result = XNMALLOC (totalsize + 1, char);
|
---|
68 | p = result;
|
---|
69 | for (i = argcount; i > 0; i--)
|
---|
70 | {
|
---|
71 | const char *next = va_arg (args, const char *);
|
---|
72 | size_t len = strlen (next);
|
---|
73 | memcpy (p, next, len);
|
---|
74 | p += len;
|
---|
75 | }
|
---|
76 | *p = '\0';
|
---|
77 |
|
---|
78 | return result;
|
---|
79 | }
|
---|
80 |
|
---|
81 | char *
|
---|
82 | xvasprintf (const char *format, va_list args)
|
---|
83 | {
|
---|
84 | char *result;
|
---|
85 |
|
---|
86 | /* Recognize the special case format = "%s...%s". It is a frequently used
|
---|
87 | idiom for string concatenation and needs to be fast. We don't want to
|
---|
88 | have a separate function xstrcat() for this purpose. */
|
---|
89 | {
|
---|
90 | size_t argcount = 0;
|
---|
91 | const char *f;
|
---|
92 |
|
---|
93 | for (f = format;;)
|
---|
94 | {
|
---|
95 | if (*f == '\0')
|
---|
96 | /* Recognized the special case of string concatenation. */
|
---|
97 | return xstrcat (argcount, args);
|
---|
98 | if (*f != '%')
|
---|
99 | break;
|
---|
100 | f++;
|
---|
101 | if (*f != 's')
|
---|
102 | break;
|
---|
103 | f++;
|
---|
104 | argcount++;
|
---|
105 | }
|
---|
106 | }
|
---|
107 |
|
---|
108 | if (vasprintf (&result, format, args) < 0)
|
---|
109 | {
|
---|
110 | if (errno == ENOMEM)
|
---|
111 | xalloc_die ();
|
---|
112 | return NULL;
|
---|
113 | }
|
---|
114 |
|
---|
115 | return result;
|
---|
116 | }
|
---|