1 /* sprintf_alloc.c -- like sprintf with memory allocation
2 
3    Copyright 2001 Carl Worth
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <string.h>
20 
21 #include "sprintf_alloc.h"
22 
23 #ifdef DMALLOC
24 #include "dmalloc.h"
25 #endif
26 
27 static int vsprintf_alloc(char **str, const char *fmt, va_list ap);
28 
sprintf_alloc(char ** str,const char * fmt,...)29 int sprintf_alloc(char **str, const char *fmt, ...)
30 {
31     int ret;
32     va_list ap;
33 
34     va_start(ap, fmt);
35     ret = vsprintf_alloc(str, fmt, ap);
36     va_end(ap);
37 
38     return ret;
39 }
40 
sprintf_append_alloc(char ** str,const char * fmt,...)41 int sprintf_append_alloc(char **str, const char *fmt, ...)
42 {
43     char *appendage, *new_str;
44     int appendage_len, new_len;
45     va_list ap;
46 
47     va_start(ap, fmt);
48     appendage_len = vsprintf_alloc(&appendage, fmt, ap);
49     va_end(ap);
50 
51     new_len = ((*str) ? strlen(*str) : 0) + appendage_len + 1;
52     if (*str) {
53 	new_str = realloc(*str, new_len);
54     } else {
55 	new_str = malloc(new_len);
56 	if (new_str) {
57 	    new_str[0] = '\0';
58 	}
59     }
60     if (new_str == NULL) {
61 	free(appendage);
62 	return strlen(*str);
63     }
64 
65     *str = new_str;
66     strcat(*str, appendage);
67     free(appendage);
68 
69     return new_len;
70 }
71 
72 /* ripped more or less straight out of PRINTF(3) */
vsprintf_alloc(char ** str,const char * fmt,va_list ap)73 static int vsprintf_alloc(char **str, const char *fmt, va_list ap)
74 {
75     char *new_str;
76     /* Guess we need no more than 100 bytes. */
77     int n, size = 100;
78 
79     if ((*str = malloc (size)) == NULL)
80 	return -1;
81     while (1) {
82 	/* Try to print in the allocated space. */
83 	n = vsnprintf (*str, size, fmt, ap);
84 	/* If that worked, return the size. */
85 	if (n > -1 && n < size)
86 	    return n;
87 	/* Else try again with more space. */
88 	if (n > -1)    /* glibc 2.1 */
89 	    size = n+1; /* precisely what is needed */
90 	else           /* glibc 2.0 */
91 	    size *= 2;  /* twice the old size */
92 	new_str = realloc(*str, size);
93 	if (new_str == NULL) {
94 	    free(*str);
95 	    *str = NULL;
96 	    return -1;
97 	}
98 	*str = new_str;
99     }
100 }
101