Code

plugin: Record all loaded plugins and use that for improved error messages.
[sysdb.git] / src / utils / strbuf.c
1 /*
2  * SysDB - src/utils/strbuf.c
3  * Copyright (C) 2012 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include "utils/strbuf.h"
30 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
37 #include <unistd.h>
39 /*
40  * private data structures
41  */
43 struct sdb_strbuf {
44         char  *string;
45         size_t size;
46         size_t pos;
47 };
49 /*
50  * private helper functions
51  */
53 static int
54 strbuf_resize(sdb_strbuf_t *strbuf, size_t new_size)
55 {
56         char *tmp;
58         if (new_size <= strbuf->size)
59                 return 0;
61         tmp = realloc(strbuf->string, new_size);
62         if (! tmp)
63                 return -1;
65         strbuf->string = tmp;
66         strbuf->size = new_size;
67         return 0;
68 } /* strbuf_resize */
70 /*
71  * public API
72  */
74 sdb_strbuf_t *
75 sdb_strbuf_create(size_t size)
76 {
77         sdb_strbuf_t *strbuf;
79         strbuf = calloc(1, sizeof(*strbuf));
80         if (! strbuf)
81                 return NULL;
83         strbuf->string = NULL;
84         if (size) {
85                 strbuf->string = malloc(size);
86                 if (! strbuf->string) {
87                         free(strbuf);
88                         return NULL;
89                 }
91                 strbuf->string[0] = '\0';
92         }
94         strbuf->size = size;
95         strbuf->pos  = 0;
97         return strbuf;
98 } /* sdb_strbuf_create */
100 void
101 sdb_strbuf_destroy(sdb_strbuf_t *strbuf)
103         if (! strbuf)
104                 return;
106         if (strbuf->string)
107                 free(strbuf->string);
108         free(strbuf);
109 } /* sdb_strbuf_destroy */
111 ssize_t
112 sdb_strbuf_vappend(sdb_strbuf_t *strbuf, const char *fmt, va_list ap)
114         va_list aq;
115         int status;
117         if ((! strbuf) || (! fmt))
118                 return -1;
120         assert((strbuf->size == 0) || (strbuf->string[strbuf->pos] == '\0'));
122         if (! strbuf->size) {
123                 /* use some arbitrary but somewhat reasonable default */
124                 if (strbuf_resize(strbuf, 64))
125                         return -1;
126         }
127         /* make sure to reserve space for the nul-byte */
128         else if (strbuf->pos >= strbuf->size - 1)
129                 if (strbuf_resize(strbuf, 2 * strbuf->size))
130                         return -1;
132         assert(strbuf->size && strbuf->string);
133         assert(strbuf->pos < strbuf->size);
135         /* 'ap' is invalid after calling vsnprintf; thus copy before using it */
136         va_copy(aq, ap);
137         status = vsnprintf(strbuf->string + strbuf->pos,
138                         strbuf->size - strbuf->pos, fmt, ap);
140         if (status < 0) {
141                 va_end(aq);
142                 return status;
143         }
145         /* 'status' does not include nul-byte */
146         if ((size_t)status >= strbuf->size - strbuf->pos - 1) {
147                 if (strbuf_resize(strbuf, strbuf->size + (size_t)status)) {
148                         va_end(aq);
149                         return -1;
150                 }
152                 /* reset string and try again */
153                 strbuf->string[strbuf->pos] = '\0';
154                 status = (int)sdb_strbuf_vappend(strbuf, fmt, aq);
155         }
156         else
157                 strbuf->pos += (size_t)status;
159         va_end(aq);
160         return (ssize_t)status;
161 } /* sdb_strbuf_vappend */
163 ssize_t
164 sdb_strbuf_append(sdb_strbuf_t *strbuf, const char *fmt, ...)
166         va_list ap;
167         ssize_t status;
169         va_start(ap, fmt);
170         status = sdb_strbuf_vappend(strbuf, fmt, ap);
171         va_end(ap);
173         return status;
174 } /* sdb_strbuf_append */
176 ssize_t
177 sdb_strbuf_vsprintf(sdb_strbuf_t *strbuf, const char *fmt, va_list ap)
179         if (! strbuf)
180                 return -1;
182         if (strbuf->size) {
183                 strbuf->string[0] = '\0';
184                 strbuf->pos = 0;
185         }
187         return sdb_strbuf_vappend(strbuf, fmt, ap);
188 } /* sdb_strbuf_vsprintf */
190 ssize_t
191 sdb_strbuf_sprintf(sdb_strbuf_t *strbuf, const char *fmt, ...)
193         va_list ap;
194         ssize_t status;
196         va_start(ap, fmt);
197         status = sdb_strbuf_vsprintf(strbuf, fmt, ap);
198         va_end(ap);
200         return status;
201 } /* sdb_strbuf_sprintf */
203 ssize_t
204 sdb_strbuf_memappend(sdb_strbuf_t *strbuf, const void *data, size_t n)
206         if ((! strbuf) || (! data))
207                 return -1;
209         assert((strbuf->size == 0) || (strbuf->string[strbuf->pos] == '\0'));
211         if (strbuf->pos + n + 1 >= strbuf->size) {
212                 size_t newsize = strbuf->size * 2;
214                 if (! newsize)
215                         newsize = 64;
216                 while (strbuf->pos + n + 1 >= newsize)
217                         newsize *= 2;
219                 if (strbuf_resize(strbuf, newsize))
220                         return -1;
221         }
223         assert(strbuf->size && strbuf->string);
224         assert(strbuf->pos < strbuf->size);
226         memcpy((void *)(strbuf->string + strbuf->pos), data, n);
227         strbuf->pos += n;
228         strbuf->string[strbuf->pos] = '\0';
230         return (ssize_t)n;
231 } /* sdb_strbuf_memappend */
233 ssize_t
234 sdb_strbuf_memcpy(sdb_strbuf_t *strbuf, const void *data, size_t n)
236         if ((! strbuf) || (! data))
237                 return -1;
239         if (strbuf->size) {
240                 strbuf->string[0] = '\0';
241                 strbuf->pos = 0;
242         }
244         return sdb_strbuf_memappend(strbuf, data, n);
245 } /* sdb_strbuf_memcpy */
247 ssize_t
248 sdb_strbuf_read(sdb_strbuf_t *strbuf, int fd, size_t n)
250         ssize_t ret;
252         if (! strbuf)
253                 return -1;
255         if (strbuf_resize(strbuf, strbuf->pos + n + 1))
256                 return -1;
258         ret = read(fd, strbuf->string + strbuf->pos, n);
259         if (ret > 0)
260                 strbuf->pos += (size_t)ret;
261         return ret;
262 } /* sdb_strbuf_read */
264 ssize_t
265 sdb_strbuf_chomp(sdb_strbuf_t *strbuf)
267         ssize_t ret = 0;
269         if (! strbuf)
270                 return -1;
272         assert((!strbuf->size) || (strbuf->pos < strbuf->size));
273         assert(strbuf->pos <= strbuf->size);
275         while ((strbuf->pos > 0)
276                         && (strbuf->string[strbuf->pos - 1] == '\n')) {
277                 --strbuf->pos;
278                 strbuf->string[strbuf->pos] = '\0';
279                 ++ret;
280         }
282         return ret;
283 } /* sdb_strbuf_chomp */
285 void
286 sdb_strbuf_skip(sdb_strbuf_t *strbuf, size_t offset, size_t n)
288         char *start;
289         size_t len;
291         if ((! strbuf) || (! n))
292                 return;
294         if (offset >= strbuf->pos)
295                 return;
297         len = strbuf->pos - offset;
299         if (n >= len) {
300                 strbuf->string[offset] = '\0';
301                 strbuf->pos = offset;
302                 return;
303         }
305         assert(offset + n < strbuf->pos);
306         assert(offset < strbuf->pos);
308         start = strbuf->string + offset;
309         memmove(start, start + n, strbuf->pos - n);
310         strbuf->pos -= n;
311         strbuf->string[strbuf->pos] = '\0';
312 } /* sdb_strbuf_skip */
314 const char *
315 sdb_strbuf_string(sdb_strbuf_t *strbuf)
317         if (! strbuf)
318                 return NULL;
319         if (! strbuf->size)
320                 return "";
321         return strbuf->string;
322 } /* sdb_strbuf_string */
324 size_t
325 sdb_strbuf_len(sdb_strbuf_t *strbuf)
327         if (! strbuf)
328                 return 0;
329         return strbuf->pos;
330 } /* sdb_strbuf_string */
332 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */