* use dynamic memory buffers instead temporary files
[fw/sdcc] / support / Util / dbuf_string.c
1 /*
2   dbuf_string.c - Append formatted string to the dynamic buffer
3   version 1.0.0, January 6th, 2007
4
5   Copyright (c) 2002-2007 Borut Razem
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "dbuf_string.h"
29
30
31 /*
32  * Append string to the end of the buffer.
33  */
34
35 int
36 dbuf_append_str(struct dbuf_s *dbuf, const char *str)
37 {
38   assert(str != NULL);
39
40   return dbuf_append(dbuf, str, strlen(str));
41 }
42
43
44 /*
45  * Append single character to the end of the buffer.
46  */
47
48 int
49 dbuf_append_char(struct dbuf_s *dbuf, char chr)
50 {
51   return dbuf_append(dbuf, &chr, 1);
52 }
53
54 /*
55  * Calculate length of the resulting formatted string.
56  *
57  * Borrowed from vasprintf.c
58  */
59
60 static int
61 calc_result_length (const char *format, va_list args)
62 {
63   const char *p = format;
64   /* Add one to make sure that it is never zero, which might cause malloc
65      to return NULL.  */
66   int total_width = strlen (format) + 1;
67   va_list ap;
68
69   memcpy (&ap, &args, sizeof (va_list));
70
71   while (*p != '\0')
72     {
73       if (*p++ == '%')
74         {
75           while (strchr ("-+ #0", *p))
76             ++p;
77           if (*p == '*')
78             {
79               ++p;
80               total_width += abs (va_arg (ap, int));
81             }
82           else
83             total_width += strtoul (p, (char **) &p, 10);
84           if (*p == '.')
85             {
86               ++p;
87               if (*p == '*')
88                 {
89                   ++p;
90                   total_width += abs (va_arg (ap, int));
91                 }
92               else
93               total_width += strtoul (p, (char **) &p, 10);
94             }
95           while (strchr ("hlL", *p))
96             ++p;
97           /* Should be big enough for any format specifier except %s and floats.  */
98           total_width += 30;
99           switch (*p)
100             {
101             case 'd':
102             case 'i':
103             case 'o':
104             case 'u':
105             case 'x':
106             case 'X':
107             case 'c':
108               (void) va_arg (ap, int);
109               break;
110             case 'f':
111             case 'e':
112             case 'E':
113             case 'g':
114             case 'G':
115               (void) va_arg (ap, double);
116               /* Since an ieee double can have an exponent of 307, we'll
117                  make the buffer wide enough to cover the gross case. */
118               total_width += 307;
119               break;
120             case 's':
121               total_width += strlen (va_arg (ap, char *));
122               break;
123             case 'p':
124             case 'n':
125               (void) va_arg (ap, char *);
126               break;
127             }
128           p++;
129         }
130     }
131
132   return total_width;
133 }
134
135
136 /*
137  * Append the formatted string to the end of the buffer.
138  */
139
140 int
141 dbuf_vprintf (struct dbuf_s *dbuf, const char *format, va_list args)
142 {
143   int size = calc_result_length (format, args);
144
145   assert(dbuf != NULL);
146   assert(dbuf->alloc != 0);
147   assert(dbuf->buf != NULL);
148
149   if (_dbuf_expand(dbuf, size) != 0) {
150     int len = vsprintf(&(((char *)dbuf->buf)[dbuf->len]), format, args);
151
152     if (len >= 0) {
153       /* if written length is greater then the calculated one,
154         we have a buffer overrun! */
155       assert(len <= size);
156       dbuf->len += len;
157     }
158     return len;
159   }
160
161   return 0;
162 }
163
164
165 /*
166  * Append the formatted string to the end of the buffer.
167  */
168
169 int
170 dbuf_printf (struct dbuf_s *dbuf, const char *format, ...)
171 {
172   va_list arg;
173   int len;
174
175   va_start (arg, format);
176   len = dbuf_vprintf(dbuf, format, arg);
177   va_end (arg);
178
179   return len;
180 }
181
182
183 /*
184  * Write dynamic buffer to the file.
185  */
186
187 void
188 dbuf_write (struct dbuf_s *dbuf, FILE *dest)
189 {
190   fwrite(dbuf_get_buf(dbuf), 1, dbuf_get_length(dbuf), dest);
191 }
192
193
194 /*
195  * Write dynamic buffer to the file and destroy it.
196  */
197
198 void
199 dbuf_write_and_destroy (struct dbuf_s *dbuf, FILE *dest)
200 {
201   dbuf_write (dbuf, dest);
202
203   dbuf_destroy(dbuf);
204 }