1 /* vasprintf and asprintf with out-of-memory checking. 2 Copyright (C) 1999, 2002-2004, 2006-2013 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 char * 33 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 totalsize = 0; 43 va_copy (ap, args); 44 for (i = argcount; i > 0; i--) 45 { 46 const char *next = va_arg (ap, const char *); 47 totalsize = xsum (totalsize, strlen (next)); 48 } 49 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 if (totalsize == SIZE_MAX || totalsize > INT_MAX) 55 { 56 errno = EOVERFLOW; 57 return NULL; 58 } 59 60 /* Allocate and fill the result string. */ 61 result = XNMALLOC (totalsize + 1, char); 62 p = result; 63 for (i = argcount; i > 0; i--) 64 { 65 const char *next = va_arg (args, const char *); 66 size_t len = strlen (next); 67 memcpy (p, next, len); 68 p += len; 69 } 70 *p = '\0'; 71 72 return result; 73 } 74 75 char * 76 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 size_t argcount = 0; 85 const char *f; 86 87 for (f = format;;) 88 { 89 if (*f == '\0') 90 /* Recognized the special case of string concatenation. */ 91 return xstrcat (argcount, args); 92 if (*f != '%') 93 break; 94 f++; 95 if (*f != 's') 96 break; 97 f++; 98 argcount++; 99 } 100 } 101 102 if (vasprintf (&result, format, args) < 0) 103 { 104 if (errno == ENOMEM) 105 xalloc_die (); 106 return NULL; 107 } 108 109 return result; 110 } 111