1 /*
2 dbuf_string.c - Append formatted string to the dynamic buffer
3 version 1.2.2, March 20th, 2012
4
5 Copyright (c) 2002-2012 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 * The buffer is null terminated.
34 */
35
36 int
dbuf_append_str(struct dbuf_s * dbuf,const char * str)37 dbuf_append_str (struct dbuf_s *dbuf, const char *str)
38 {
39 size_t len;
40 assert (str != NULL);
41
42 len = strlen (str);
43 if (dbuf_append (dbuf, str, len + 1))
44 {
45 --dbuf->len;
46 return 1;
47 }
48 else
49 return 0;
50 }
51
52 /*
53 * Prepend string to the beginning of the buffer.
54 * The buffer is null terminated.
55 */
56
57 int
dbuf_prepend_str(struct dbuf_s * dbuf,const char * str)58 dbuf_prepend_str (struct dbuf_s *dbuf, const char *str)
59 {
60 size_t len;
61 assert (str != NULL);
62
63 len = strlen (str);
64 return (dbuf_prepend (dbuf, str, len));
65 }
66
67 /*
68 * Append single character to the end of the buffer.
69 * The buffer is null terminated.
70 */
71
72 int
dbuf_append_char(struct dbuf_s * dbuf,char chr)73 dbuf_append_char (struct dbuf_s *dbuf, char chr)
74 {
75 char buf[2];
76 buf[0] = chr;
77 buf[1] = '\0';
78 if (dbuf_append (dbuf, buf, 2))
79 {
80 --dbuf->len;
81 return 1;
82 }
83 else
84 return 0;
85 }
86
87 /*
88 * Prepend single character to the end of the buffer.
89 * The buffer is null terminated.
90 */
91
92 int
dbuf_prepend_char(struct dbuf_s * dbuf,char chr)93 dbuf_prepend_char (struct dbuf_s *dbuf, char chr)
94 {
95 char buf[2];
96 buf[0] = chr;
97 buf[1] = '\0';
98 return (dbuf_prepend_str (dbuf, buf));
99 }
100
101 /*
102 * Calculate length of the resulting formatted string.
103 *
104 * Borrowed from vasprintf.c
105 */
106
107 static int
calc_result_length(const char * format,va_list args)108 calc_result_length (const char *format, va_list args)
109 {
110 const char *p = format;
111 /* Add one to make sure that it is never zero, which might cause malloc
112 to return NULL. */
113 int total_width = strlen (format) + 1;
114 va_list ap;
115
116 #ifdef va_copy
117 va_copy (ap, args);
118 #else
119 memcpy (&ap, &args, sizeof (va_list));
120 #endif
121
122 while (*p != '\0')
123 {
124 if (*p++ == '%')
125 {
126 while (strchr ("-+ #0", *p))
127 ++p;
128 if (*p == '*')
129 {
130 ++p;
131 total_width += abs (va_arg (ap, int));
132 }
133 else
134 total_width += strtoul (p, (char **) &p, 10);
135 if (*p == '.')
136 {
137 ++p;
138 if (*p == '*')
139 {
140 ++p;
141 total_width += abs (va_arg (ap, int));
142 }
143 else
144 total_width += strtoul (p, (char **) &p, 10);
145 }
146 while (strchr ("hlL", *p))
147 ++p;
148 /* Should be big enough for any format specifier except %s and floats. */
149 total_width += 30;
150 switch (*p)
151 {
152 case 'd':
153 case 'i':
154 case 'o':
155 case 'u':
156 case 'x':
157 case 'X':
158 case 'c':
159 (void) va_arg (ap, int);
160 break;
161 case 'f':
162 case 'e':
163 case 'E':
164 case 'g':
165 case 'G':
166 (void) va_arg (ap, double);
167 /* Since an ieee double can have an exponent of 307, we'll
168 make the buffer wide enough to cover the gross case. */
169 total_width += 307;
170 break;
171 case 's':
172 {
173 const char *p = va_arg (ap, char *);
174 total_width += strlen (p ? p : "(null)");
175 }
176 break;
177 case 'p':
178 case 'n':
179 (void) va_arg (ap, char *);
180 break;
181 }
182 p++;
183 }
184 }
185 #ifdef va_copy
186 va_end (ap);
187 #endif
188 return total_width;
189 }
190
191
192 /*
193 * Append the formatted string to the end of the buffer.
194 * The buffer is null terminated.
195 */
196
197 int
dbuf_vprintf(struct dbuf_s * dbuf,const char * format,va_list args)198 dbuf_vprintf (struct dbuf_s *dbuf, const char *format, va_list args)
199 {
200 int size = calc_result_length (format, args);
201
202 assert (dbuf != NULL);
203 assert (dbuf->alloc != 0);
204 assert (dbuf->buf != NULL);
205
206 if (0 != _dbuf_expand (dbuf, size))
207 {
208 int len = vsprintf (&(((char *)dbuf->buf)[dbuf->len]), format, args);
209
210 if (len >= 0)
211 {
212 /* if written length is greater then the calculated one,
213 we have a buffer overrun! */
214 assert (len <= size);
215 dbuf->len += len;
216 }
217 return len;
218 }
219
220 return 0;
221 }
222
223
224 /*
225 * Append the formatted string to the end of the buffer.
226 * The buffer is null terminated.
227 */
228
229 int
dbuf_printf(struct dbuf_s * dbuf,const char * format,...)230 dbuf_printf (struct dbuf_s *dbuf, const char *format, ...)
231 {
232 va_list arg;
233 int len;
234
235 va_start (arg, format);
236 len = dbuf_vprintf (dbuf, format, arg);
237 va_end (arg);
238
239 return len;
240 }
241
242
243 /*
244 * Append line from file to the dynamic buffer
245 * The buffer is null terminated.
246 */
247
248 size_t
dbuf_getline(struct dbuf_s * dbuf,FILE * infp)249 dbuf_getline (struct dbuf_s *dbuf, FILE *infp)
250 {
251 int c;
252 char chr;
253
254 while ((c = getc (infp)) != '\n' && c != EOF)
255 {
256 chr = c;
257
258 dbuf_append (dbuf, &chr, 1);
259 }
260
261 /* add trailing NL */
262 if (c == '\n')
263 {
264 chr = c;
265
266 dbuf_append (dbuf, &chr, 1);
267 }
268
269 /* terminate the line without increasing the length */
270 if (0 != _dbuf_expand (dbuf, 1))
271 ((char *)dbuf->buf)[dbuf->len] = '\0';
272
273 return dbuf_get_length (dbuf);
274 }
275
276
277 /*
278 * Remove trailing newline from the string.
279 * The buffer is null terminated.
280 * It returns the total number of characters removed.
281 */
282
283 size_t
dbuf_chomp(struct dbuf_s * dbuf)284 dbuf_chomp (struct dbuf_s *dbuf)
285 {
286 size_t i = dbuf->len;
287 size_t ret;
288
289 if (i != 0 && '\n' == ((char *)dbuf->buf)[i - 1])
290 {
291 --i;
292 if (i != 0 && '\r' == ((char *)dbuf->buf)[i - 1])
293 {
294 --i;
295 }
296 }
297
298 ret = dbuf->len - i;
299 dbuf->len = i;
300
301 /* terminate the line without increasing the length */
302 if (_dbuf_expand(dbuf, 1) != 0)
303 ((char *)dbuf->buf)[dbuf->len] = '\0';
304
305 return ret;
306 }
307
308
309 /*
310 * Write dynamic buffer to the file.
311 */
312
313 void
dbuf_write(struct dbuf_s * dbuf,FILE * dest)314 dbuf_write (struct dbuf_s *dbuf, FILE *dest)
315 {
316 fwrite (dbuf_get_buf (dbuf), 1, dbuf_get_length (dbuf), dest);
317 }
318
319
320 /*
321 * Write dynamic buffer to the file and destroy it.
322 */
323
324 void
dbuf_write_and_destroy(struct dbuf_s * dbuf,FILE * dest)325 dbuf_write_and_destroy (struct dbuf_s *dbuf, FILE *dest)
326 {
327 dbuf_write (dbuf, dest);
328
329 dbuf_destroy (dbuf);
330 }
331