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 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/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ 33#ifndef EOVERFLOW 34# define EOVERFLOW E2BIG 35#endif 36 37static inline char * 38xstrcat (size_t argcount, va_list args) 39{ 40 char *result; 41 va_list ap; 42 size_t totalsize; 43 size_t i; 44 char *p; 45 46 /* Determine the total size. */ 47 totalsize = 0; 48 va_copy (ap, args); 49 for (i = argcount; i > 0; i--) 50 { 51 const char *next = va_arg (ap, const char *); 52 totalsize = xsum (totalsize, strlen (next)); 53 } 54 va_end (ap); 55 56 /* Test for overflow in the summing pass above or in (totalsize + 1) below. 57 Also, don't return a string longer than INT_MAX, for consistency with 58 vasprintf(). */ 59 if (totalsize == SIZE_MAX || totalsize > INT_MAX) 60 { 61 errno = EOVERFLOW; 62 return NULL; 63 } 64 65 /* Allocate and fill the result string. */ 66 result = XNMALLOC (totalsize + 1, char); 67 p = result; 68 for (i = argcount; i > 0; i--) 69 { 70 const char *next = va_arg (args, const char *); 71 size_t len = strlen (next); 72 memcpy (p, next, len); 73 p += len; 74 } 75 *p = '\0'; 76 77 return result; 78} 79 80char * 81xvasprintf (const char *format, va_list args) 82{ 83 char *result; 84 85 /* Recognize the special case format = "%s...%s". It is a frequently used 86 idiom for string concatenation and needs to be fast. We don't want to 87 have a separate function xstrcat() for this purpose. */ 88 { 89 size_t argcount = 0; 90 const char *f; 91 92 for (f = format;;) 93 { 94 if (*f == '\0') 95 /* Recognized the special case of string concatenation. */ 96 return xstrcat (argcount, args); 97 if (*f != '%') 98 break; 99 f++; 100 if (*f != 's') 101 break; 102 f++; 103 argcount++; 104 } 105 } 106 107 if (vasprintf (&result, format, args) < 0) 108 { 109 if (errno == ENOMEM) 110 xalloc_die (); 111 return NULL; 112 } 113 114 return result; 115} 116