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