* src/SDCCasm.[ch]: renamed from asm[ch], use dbuf_getline(), ...
[fw/sdcc] / support / Util / dbuf_string.c
1 /*
2   dbuf_string.c - Append formatted string to the dynamic buffer
3   version 1.1.0, December 29th, 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 #ifdef va_copy
70   va_copy (ap, args);
71 #else
72   memcpy (&ap, &args, sizeof (va_list));
73 #endif
74
75   while (*p != '\0')
76     {
77       if (*p++ == '%')
78         {
79           while (strchr ("-+ #0", *p))
80             ++p;
81           if (*p == '*')
82             {
83               ++p;
84               total_width += abs (va_arg (ap, int));
85             }
86           else
87             total_width += strtoul (p, (char **) &p, 10);
88           if (*p == '.')
89             {
90               ++p;
91               if (*p == '*')
92                 {
93                   ++p;
94                   total_width += abs (va_arg (ap, int));
95                 }
96               else
97               total_width += strtoul (p, (char **) &p, 10);
98             }
99           while (strchr ("hlL", *p))
100             ++p;
101           /* Should be big enough for any format specifier except %s and floats.  */
102           total_width += 30;
103           switch (*p)
104             {
105             case 'd':
106             case 'i':
107             case 'o':
108             case 'u':
109             case 'x':
110             case 'X':
111             case 'c':
112               (void) va_arg (ap, int);
113               break;
114             case 'f':
115             case 'e':
116             case 'E':
117             case 'g':
118             case 'G':
119               (void) va_arg (ap, double);
120               /* Since an ieee double can have an exponent of 307, we'll
121                  make the buffer wide enough to cover the gross case. */
122               total_width += 307;
123               break;
124             case 's':
125               total_width += strlen (va_arg (ap, char *));
126               break;
127             case 'p':
128             case 'n':
129               (void) va_arg (ap, char *);
130               break;
131             }
132           p++;
133         }
134     }
135 #ifdef va_copy
136   va_end (ap);
137 #endif
138   return total_width;
139 }
140
141
142 /*
143  * Append the formatted string to the end of the buffer.
144  */
145
146 int
147 dbuf_vprintf (struct dbuf_s *dbuf, const char *format, va_list args)
148 {
149   int size = calc_result_length (format, args);
150
151   assert (dbuf != NULL);
152   assert (dbuf->alloc != 0);
153   assert (dbuf->buf != NULL);
154
155   if (0 != _dbuf_expand (dbuf, size))
156     {
157       int len = vsprintf (&(((char *)dbuf->buf)[dbuf->len]), format, args);
158
159       if (len >= 0)
160         {
161           /* if written length is greater then the calculated one,
162              we have a buffer overrun! */
163           assert (len <= size);
164           dbuf->len += len;
165         }
166       return len;
167     }
168
169   return 0;
170 }
171
172
173 /*
174  * Append the formatted string to the end of the buffer.
175  */
176
177 int
178 dbuf_printf (struct dbuf_s *dbuf, const char *format, ...)
179 {
180   va_list arg;
181   int len;
182
183   va_start (arg, format);
184   len = dbuf_vprintf (dbuf, format, arg);
185   va_end (arg);
186
187   return len;
188 }
189
190
191 /*
192  * Append line from file to the dynamic buffer
193  */
194
195 size_t
196 dbuf_getline (struct dbuf_s *dbuf, FILE *infp)
197 {
198   int c;
199   char chr;
200
201   while ((c = getc (infp)) != '\n' && c != EOF)
202     {
203       chr = c;
204
205       dbuf_append (dbuf, &chr, 1);
206     }
207
208   /* add trailing NL */
209   if (c == '\n')
210     {
211       chr = c;
212
213       dbuf_append (dbuf, &chr, 1);
214     }
215
216   /* terminate the line without increasing the length */
217   if (0 != _dbuf_expand (dbuf, 1))
218     ((char *)dbuf->buf)[dbuf->len] = '\0';
219
220   return dbuf_get_length (dbuf);
221 }
222
223
224 /*
225  * Write dynamic buffer to the file.
226  */
227
228 void
229 dbuf_write (struct dbuf_s *dbuf, FILE *dest)
230 {
231   fwrite (dbuf_get_buf (dbuf), 1, dbuf_get_length (dbuf), dest);
232 }
233
234
235 /*
236  * Write dynamic buffer to the file and destroy it.
237  */
238
239 void
240 dbuf_write_and_destroy (struct dbuf_s *dbuf, FILE *dest)
241 {
242   dbuf_write (dbuf, dest);
243
244   dbuf_destroy (dbuf);
245 }