comparison C/buf.c @ 186:d4b8416e9ab1

Move C
author David Demelier <markand@malikania.fr>
date Sat, 23 Nov 2013 16:14:05 +0100
parents buf.c@7f214f26a4c0
children
comparison
equal deleted inserted replaced
185:523156bb3af5 186:d4b8416e9ab1
1 /*
2 * buf.c -- easy way to manipulate strings
3 *
4 * Copyright (c) 2011, 2012, 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 <string.h>
22
23 #include "buf.h"
24
25 #define BUF_AVAIL(buf) ((buf)->alsize - (buf)->length)
26 #define BUF_SAFE(buf) (!((buf)->flags & BUF_UNSAFE))
27 #define BUF_FIXED(buf) ((buf)->flags & BUF_FIXED)
28 #define BUF_AUTO(buf) (buf->flags == 0)
29
30 static void copy(struct buf *, const void *, size_t);
31 static int grow(struct buf *, size_t);
32
33 int
34 buf_init(struct buf *buf, const char *txt)
35 {
36 /* Set defaults if needed */
37 buf->chksize = (buf->chksize <= 0) ? 128 : buf->chksize;
38 buf->alsize = buf->chksize + 1;
39 buf->malloc = (buf->malloc == NULL) ? &malloc : buf->malloc;
40 buf->realloc = (buf->realloc == NULL) ? &realloc : buf->realloc;
41
42 if ((buf->text = buf->malloc(buf->alsize)) == NULL)
43 return -1;
44
45 if (txt != NULL)
46 buf_cat(buf, txt);
47
48 memset(buf->text, 0, buf->alsize);
49
50 return 0;
51 }
52
53 void
54 buf_set(struct buf *buf, const char *fmt, ...)
55 {
56 va_list ap;
57 const char *p;
58
59 va_start(ap, fmt);
60 for (p = fmt; *p != '\0'; ++p)
61 switch (*p) {
62 case 'l':
63 buf->chksize = va_arg(ap, int);
64 break;
65 case 'm':
66 buf->malloc = va_arg(ap, void *(*)(size_t));
67 break;
68 case 'r':
69 buf->realloc = va_arg(ap, void *(*)(void *, size_t));
70 break;
71 case 'f':
72 case 't':
73 buf->flags = va_arg(ap, int);
74 break;
75 default:
76 break;
77 }
78 }
79
80 /*
81 * This function appends not more than max characters from str.
82 */
83 int
84 buf_ncat(struct buf *buf, const char *str, size_t max)
85 {
86 size_t tocopy = max;
87
88 for (tocopy = 0; str[tocopy] != '\0' && tocopy < max; ++tocopy)
89 continue;
90
91 if (BUF_AVAIL(buf) <= tocopy) {
92 /* Can't add more */
93 if (BUF_SAFE(buf) && BUF_FIXED(buf))
94 return -1;
95
96 if (BUF_AUTO(buf)) {
97 if (grow(buf, tocopy) < 0)
98 return -1;
99 } else {
100 /* String is unsafe, truncate to the available size */
101 tocopy = BUF_AVAIL(buf) - 1;
102 }
103 }
104
105 copy(buf, str, tocopy);
106
107 return 0;
108 }
109
110 /*
111 * Append the string str to the end of the string buffer.
112 */
113 int
114 buf_cat(struct buf *buf, const char *str)
115 {
116 return buf_ncat(buf, str, strlen(str));
117 }
118
119 /*
120 * Append the caracter c to the end of buffer
121 */
122 int
123 buf_putc(struct buf *buf, int c)
124 {
125 char str[2] = { c, '\0' };
126
127 return buf_ncat(buf, str, 1);
128 }
129
130 /*
131 * Concatenate the printf(3) like call to the string buffer, this function
132 * returns -1 on fixed safe buffer, otherwise 0 is returned if there
133 * is no allocation failure.
134 */
135 int
136 buf_vprintf(struct buf *buf, const char *fmt, va_list ap)
137 {
138 int copied, rv = 0, done = 0;
139
140 if (BUF_FIXED(buf) && BUF_SAFE(buf))
141 return -1;
142
143 do {
144 copied = vsnprintf(&buf->text[buf->length],
145 BUF_AVAIL(buf), fmt, ap);
146
147 if (copied >= (signed int)BUF_AVAIL(buf) || copied == -1) {
148 if (BUF_FIXED(buf))
149 done = 1;
150
151 /*
152 * vsnprintf returns -1 on windows, we need to grow
153 * the buffer by block size.
154 */
155 if (grow(buf, buf->alsize + buf->chksize) < 0) {
156 done = 1;
157 rv = -1;
158 }
159 } else {
160 done = 1;
161 }
162 } while (!done);
163
164 buf->length = strlen(buf->text);
165
166 return rv;
167 }
168
169 int
170 buf_printf(struct buf *buf, const char *fmt, ...)
171 {
172 va_list ap;
173 int rv;
174
175 va_start(ap, fmt);
176 rv = buf_vprintf(buf, fmt, ap);
177 va_end(ap);
178
179 return rv;
180 }
181
182 /*
183 * Realloc the string to it's size and remove useless bytes.
184 */
185 int
186 buf_trim(struct buf *buf)
187 {
188 if ((buf->text = realloc(buf->text, buf->length + 1)) == NULL) {
189 buf->alsize = 0;
190 return -1;
191 }
192
193 buf->alsize = buf->length + 1;
194
195 return 0;
196 }
197
198 /*
199 * Remove `n' characters from the buffer, a positive value will cut the string
200 * from beginning, negative value will cut from end.
201 */
202 void
203 buf_cut(struct buf *buf, int start)
204 {
205 if ((start > 0 && start >= buf->length) ||
206 (start < 0 && (int)buf->length + start < 0))
207 return;
208
209 if (start < 0 && (int)buf->length + start >= 0)
210 start = buf->length + start;
211
212 buf->text[start] = '\0';
213 buf->length -= buf->length - start;
214 }
215
216 /*
217 * Clear the string buffer.
218 */
219 void
220 buf_clear(struct buf *buf)
221 {
222 memset(buf->text, 0, buf->alsize);
223
224 buf->length = 0;
225 }
226
227 void
228 buf_free(struct buf *buf)
229 {
230 if (buf != NULL) {
231 buf_clear(buf);
232 free(buf->text);
233
234 buf->text = NULL;
235 buf->alsize = 0;
236 }
237 }
238
239 /*
240 * Append to the end of buffer the void ptr of count size.
241 */
242 static void
243 copy(struct buf *buf, const void *ptr, size_t count)
244 {
245 memcpy(buf->text + buf->length, ptr, count);
246
247 buf->text[buf->length + count] = '\0';
248 buf->length += count;
249 }
250
251 /*
252 * Grow the text buffer until the available size fit the needed
253 * size. This function may return -1 on allocation failure.
254 */
255 static int
256 grow(struct buf *buf, size_t needed)
257 {
258 while (BUF_AVAIL(buf) <= needed) {
259 buf->text = buf->realloc(buf->text, buf->alsize + buf->chksize);
260
261 if (buf->text == NULL)
262 return -1;
263
264 buf->alsize += buf->chksize;
265 }
266
267 return 0;
268 }