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