Move vasprintf prototypes to stdio.
[gnulib.git] / lib / xvasprintf.c
1 /* vasprintf and asprintf with out-of-memory checking.
2    Copyright (C) 1999, 2002-2004, 2006, 2007 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 #include <stdio.h>
27
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 }