Mercurial > code
comparison buffer.c @ 0:a20beb164de8
Added buffer.c and buffer.h:
Various function to manipulate safely string buffers. It is similar to
sbuf(9) on FreeBSD but more portable and simpler.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 05 Sep 2011 23:01:29 +0200 |
parents | |
children | 22d7bb03e569 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a20beb164de8 |
---|---|
1 /* | |
2 * buffer.c -- safe unlimited size string | |
3 * | |
4 * Copyright (c) 2011, David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <stdio.h> | |
20 #include <stdlib.h> | |
21 #include <stdarg.h> | |
22 #include <string.h> | |
23 | |
24 #include "buffer.h" | |
25 | |
26 static int buffer_grow(struct buffer *, size_t); | |
27 | |
28 /* | |
29 * Initialize a new buffer with the optional `str' as begin of buffer. | |
30 */ | |
31 | |
32 struct buffer * | |
33 buffer_new(const char *str, size_t bsize, int flags) | |
34 { | |
35 struct buffer *buf; | |
36 | |
37 if (!(buf = malloc(sizeof (struct buffer)))) | |
38 return NULL; | |
39 | |
40 memset(buf, 0, sizeof (struct buffer)); | |
41 | |
42 if (bsize == 0) | |
43 bsize = BUFFER_DEFAULT_BSIZE; | |
44 | |
45 if (!(buf->data = calloc(bsize + 1, 1))) { | |
46 free(buf); | |
47 return NULL; | |
48 } | |
49 | |
50 buf->size = bsize + 1; | |
51 buf->bsize = bsize; | |
52 buf->flags = flags; | |
53 | |
54 if (str && buffer_strcat(buf, str) < 0) { | |
55 free(buf); | |
56 return NULL; | |
57 } | |
58 | |
59 return buf; | |
60 } | |
61 | |
62 /* | |
63 * Concatenate the string into the buffer. | |
64 */ | |
65 | |
66 int | |
67 buffer_strcat(struct buffer *buf, const char *str) | |
68 { | |
69 size_t length; | |
70 | |
71 length = strlen(str); | |
72 if (buffer_grow(buf, length) < 0) | |
73 return -1; | |
74 | |
75 if (buf->flags & BUFFER_FIXED) | |
76 length = buf->size - buf->length - 1; | |
77 | |
78 strncat(buf->data, str, length); | |
79 buf->length = strlen(buf->data); | |
80 | |
81 return 0; | |
82 } | |
83 | |
84 /* | |
85 * Concatenate the byte pointer into the buffer. | |
86 */ | |
87 | |
88 int | |
89 buffer_bcat(struct buffer *buf, const void *data, size_t size) | |
90 { | |
91 if (buffer_grow(buf, size) < 0) | |
92 return -1; | |
93 | |
94 /* Do not truncate void pointer */ | |
95 if (buf->flags & BUFFER_FIXED && size > (buf->size - buf->length - 1)) | |
96 return -1; | |
97 | |
98 memcpy(buf->data + buf->length, data, size); | |
99 buf->length += size; | |
100 | |
101 return 0; | |
102 } | |
103 | |
104 /* | |
105 * Print into the buffer using va_list from stdarg.h | |
106 */ | |
107 | |
108 int | |
109 buffer_vprintf(struct buffer *buf, const char *fmt, va_list ap) | |
110 { | |
111 va_list ap_save; | |
112 int nb, stop = 0; | |
113 | |
114 /* | |
115 * vsnprintf on windows returns -1 instead of the number of bytes that | |
116 * should be printed... | |
117 */ | |
118 if (buf->flags & BUFFER_AUTO) { | |
119 do { | |
120 va_copy(ap_save, ap); | |
121 nb = vsnprintf(buf->data + buf->length, | |
122 buf->size - buf->length - 1, fmt, ap_save); | |
123 | |
124 if (nb == -1 || nb > strlen(buf->data)) { | |
125 if (buffer_grow(buf, buf->size + buf->bsize)) | |
126 return -1; | |
127 } else | |
128 stop = 1; | |
129 } while (stop == 0); | |
130 } else | |
131 vsnprintf(buf->data + buf->length, buf->size - buf->length - 1, | |
132 fmt, ap); | |
133 | |
134 va_end(ap_save); | |
135 | |
136 return 0; | |
137 } | |
138 | |
139 /* | |
140 * Use printf(3) functions like to write into the buffer. | |
141 */ | |
142 | |
143 int | |
144 buffer_printf(struct buffer *buf, const char *fmt, ...) | |
145 { | |
146 va_list ap; | |
147 int status; | |
148 | |
149 va_start(ap, fmt); | |
150 status = buffer_vprintf(buf, fmt, ap); | |
151 va_end(ap); | |
152 | |
153 return status; | |
154 } | |
155 | |
156 /* | |
157 * Reduce the data buffer to the exact size. Returns -1 on failure. | |
158 */ | |
159 | |
160 int | |
161 buffer_shrink(struct buffer *buf) | |
162 { | |
163 if (!(buf->data = realloc(buf->data, buf->length + 1))) | |
164 return -1; | |
165 | |
166 buf->size = buf->length + 1; | |
167 | |
168 return 0; | |
169 } | |
170 | |
171 /* | |
172 * Returns the buffer data and then free the buffer object. | |
173 */ | |
174 | |
175 char * | |
176 buffer_end(struct buffer *buf) | |
177 { | |
178 char *data; | |
179 | |
180 data = buf->data; | |
181 free(buf); | |
182 | |
183 return data; | |
184 } | |
185 | |
186 /* | |
187 * Reset the struct buffer. | |
188 */ | |
189 | |
190 void | |
191 buffer_clear(struct buffer *buf) | |
192 { | |
193 if (buf->data) | |
194 free(buf->data); | |
195 | |
196 buf->length = 0; | |
197 buf->size = 0; | |
198 } | |
199 | |
200 void | |
201 buffer_free(struct buffer *buf) | |
202 { | |
203 buffer_clear(buf); | |
204 free(buf); | |
205 } | |
206 | |
207 static int | |
208 buffer_grow(struct buffer *buf, size_t needed) | |
209 { | |
210 if ((buf->size - buf->length) > needed) | |
211 return 0; | |
212 | |
213 if (buf->flags & BUFFER_AUTO) { | |
214 while (buf->size - buf->length < needed) | |
215 buf->size += buf->bsize; | |
216 | |
217 if (!(buf->data = realloc(buf->data, buf->size))) | |
218 return -1; | |
219 } | |
220 | |
221 memset(buf->data + buf->length, 0, buf->size - buf->length); | |
222 | |
223 return 0; | |
224 } |