Mercurial > code
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 } |