1 /* Like vsprintf but provides a pointer to malloc'd storage, which must
2 	 be freed by the caller.
3 	 Copyright (c) 1994 Free Software Foundation, Inc.
4 
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10 
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
14 Library General Public License for more details.
15 
16 You should have received a copy of the GNU Library General Public
17 License along with libiberty; see the file COPYING.LIB.	If not,
18 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301 USA. */
20 
21 #include <config.h>
22 
23 #ifndef HAVE_VASPRINTF
24 
25 #include <unistd.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
int_vasprintf(char ** result,char * format,va_list args)31 static int int_vasprintf(char **result, char *format, va_list args) {
32 	char *p = format;
33 	/*
34 	** Add one to make sure that it is never zero, which might cause malloc
35 	** to return NULL.
36 	*/
37 	int total_width = strlen(format) + 1;
38 	va_list ap;
39 
40 	memcpy(&ap, args, sizeof(va_list));
41 
42 	while (*p != '\0') {
43 		if (*p++ == '%') {
44 			while (strchr("-+ #0", *p))
45 				++p;
46 				if (*p == '*') {
47 					++p;
48 					total_width += abs(va_arg(ap, int));
49 				} else
50 					total_width += strtoul(p, &p, 10);
51 
52 				if (*p == '.') {
53 					++p;
54 					if (*p == '*') {
55 						++p;
56 						total_width += abs(va_arg(ap, int));
57 					} else
58 						total_width += strtoul(p, &p, 10);
59 				}
60 
61 				while (strchr("hlL", *p))
62 					++p;
63 				/*
64 				** Should be big enough for any format
65 				** specifier except %s and floats.
66 				*/
67 				total_width += 30;
68 
69 				switch (*p) {
70 					case 'd':
71 					case 'i':
72 					case 'o':
73 					case 'u':
74 					case 'x':
75 					case 'X':
76 					case 'c':
77 						(void) va_arg(ap, int);
78 						break;
79 
80 					case 'f':
81 					case 'e':
82 					case 'E':
83 					case 'g':
84 					case 'G':
85 						(void) va_arg(ap, double);
86 						/*
87 						** Since an ieee double can have an exponent of 307,
88 						** we'll make the buffer wide enough to cover
89 						** the gross case.
90 						*/
91 						total_width += 307;
92 						break;
93 
94 					case 's':
95 						total_width += strlen(va_arg(ap, char *));
96 						break;
97 
98 					case 'p':
99 					case 'n':
100 						(void) va_arg(ap, char *);
101 						break;
102 				}
103 			}
104 		}
105 
106 		*result = malloc(total_width);
107 		if (*result != NULL)
108 			return (vsprintf(*result, format, args));
109 		else
110 			return (0);
111 }
112 
vasprintf(char ** strp,const char * fmt,va_list ap)113 int vasprintf(char **strp, const char *fmt, va_list ap) {
114 	return (int_vasprintf(strp, (char *) fmt, ap));
115 }
116 
117 #endif
118