* support/Util/dbuf_string.c: fixed for amd64
[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 #ifdef va_copy
70   va_copy (ap, args);
71 #else
72   memcpy ((PTR) &ap, (PTR) &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 (_dbuf_expand(dbuf, size) != 0) {
156     int len = vsprintf(&(((char *)dbuf->buf)[dbuf->len]), format, args);
157
158     if (len >= 0) {
159       /* if written length is greater then the calculated one,
160         we have a buffer overrun! */
161       assert(len <= size);
162       dbuf->len += len;
163     }
164     return len;
165   }
166
167   return 0;
168 }
169
170
171 /*
172  * Append the formatted string to the end of the buffer.
173  */
174
175 int
176 dbuf_printf (struct dbuf_s *dbuf, const char *format, ...)
177 {
178   va_list arg;
179   int len;
180
181   va_start (arg, format);
182   len = dbuf_vprintf(dbuf, format, arg);
183   va_end (arg);
184
185   return len;
186 }
187
188
189 /*
190  * Write dynamic buffer to the file.
191  */
192
193 void
194 dbuf_write (struct dbuf_s *dbuf, FILE *dest)
195 {
196   fwrite(dbuf_get_buf(dbuf), 1, dbuf_get_length(dbuf), dest);
197 }
198
199
200 /*
201  * Write dynamic buffer to the file and destroy it.
202  */
203
204 void
205 dbuf_write_and_destroy (struct dbuf_s *dbuf, FILE *dest)
206 {
207   dbuf_write (dbuf, dest);
208
209   dbuf_destroy(dbuf);
210 }