File Coverage

houdini/buffer.c
Criterion Covered Total %
statement 39 109 35.7
branch 13 64 20.3
condition n/a
subroutine n/a
pod n/a
total 52 173 30.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7             #include
8             #include
9             #include
10             #include
11             #include
12             #include
13             #include
14             #include
15              
16             #include "buffer.h"
17              
18             /* Used as default value for gh_buf->ptr so that people can always
19             * assume ptr is non-NULL and zero terminated even for new gh_bufs.
20             */
21             char gh_buf__initbuf[1];
22             char gh_buf__oom[1];
23              
24             #define ENSURE_SIZE(b, d) \
25             if ((d) > buf->asize && gh_buf_grow(b, (d)) < 0)\
26             return -1;
27              
28 27           void gh_buf_init(gh_buf *buf, size_t initial_size)
29             {
30 27           buf->asize = 0;
31 27           buf->size = 0;
32 27           buf->ptr = gh_buf__initbuf;
33              
34 27 50         if (initial_size)
35             gh_buf_grow(buf, initial_size);
36 27           }
37              
38 53           int gh_buf_try_grow(gh_buf *buf, size_t target_size, bool mark_oom)
39             {
40             char *new_ptr;
41             size_t new_size;
42              
43 53 50         if (buf->ptr == gh_buf__oom)
44             return -1;
45              
46 53 50         if (target_size <= buf->asize)
47             return 0;
48              
49 53 100         if (buf->asize == 0) {
50             new_size = target_size;
51             new_ptr = NULL;
52             } else {
53             new_size = buf->asize;
54             new_ptr = buf->ptr;
55             }
56              
57             /* grow the buffer size by 1.5, until it's big enough
58             * to fit our target size */
59 81 100         while (new_size < target_size)
60 28           new_size = (new_size << 1) - (new_size >> 1);
61              
62             /* round allocation up to multiple of 8 */
63 53           new_size = (new_size + 7) & ~7;
64              
65 53           new_ptr = realloc(new_ptr, new_size);
66              
67 53 50         if (!new_ptr) {
68 0 0         if (mark_oom)
69 0           buf->ptr = gh_buf__oom;
70             return -1;
71             }
72              
73 53           buf->asize = new_size;
74 53           buf->ptr = new_ptr;
75              
76             /* truncate the existing buffer size if necessary */
77 53 50         if (buf->size >= buf->asize)
78 0           buf->size = buf->asize - 1;
79 53           buf->ptr[buf->size] = '\0';
80              
81 53           return 0;
82             }
83              
84 27           void gh_buf_free(gh_buf *buf)
85             {
86 27 50         if (!buf) return;
87              
88 27 50         if (buf->ptr != gh_buf__initbuf && buf->ptr != gh_buf__oom)
    50          
89 27           free(buf->ptr);
90              
91 27           gh_buf_init(buf, 0);
92             }
93              
94 0           void gh_buf_clear(gh_buf *buf)
95             {
96 0           buf->size = 0;
97 0 0         if (buf->asize > 0)
98 0           buf->ptr[0] = '\0';
99 0           }
100              
101 0           int gh_buf_set(gh_buf *buf, const char *data, size_t len)
102             {
103 0 0         if (len == 0 || data == NULL) {
104 0           gh_buf_clear(buf);
105             } else {
106 0 0         if (data != buf->ptr) {
107 0           ENSURE_SIZE(buf, len + 1);
108 0           memmove(buf->ptr, data, len);
109             }
110 0           buf->size = len;
111 0           buf->ptr[buf->size] = '\0';
112             }
113             return 0;
114             }
115              
116 0           int gh_buf_sets(gh_buf *buf, const char *string)
117             {
118 0 0         return gh_buf_set(buf, string, string ? strlen(string) : 0);
119             }
120              
121 23           int gh_buf_putc(gh_buf *buf, char c)
122             {
123 23           ENSURE_SIZE(buf, buf->size + 2);
124 23           buf->ptr[buf->size++] = c;
125 23           buf->ptr[buf->size] = '\0';
126 23           return 0;
127             }
128              
129 117           int gh_buf_put(gh_buf *buf, const void *data, size_t len)
130             {
131 153           ENSURE_SIZE(buf, buf->size + len + 1);
132 117           memmove(buf->ptr + buf->size, data, len);
133 117           buf->size += len;
134 117           buf->ptr[buf->size] = '\0';
135 117           return 0;
136             }
137              
138 22           int gh_buf_puts(gh_buf *buf, const char *string)
139             {
140 22 50         assert(string);
141 22           return gh_buf_put(buf, string, strlen(string));
142             }
143              
144 0           int gh_buf_vprintf(gh_buf *buf, const char *format, va_list ap)
145             {
146             int len;
147 0           const size_t expected_size = buf->size + (strlen(format) * 2);
148              
149 0 0         ENSURE_SIZE(buf, expected_size);
    0          
150              
151             while (1) {
152             va_list args;
153 0           va_copy(args, ap);
154              
155 0           len = vsnprintf(
156 0           buf->ptr + buf->size,
157 0           buf->asize - buf->size,
158             format, args
159             );
160              
161 0 0         if (len < 0) {
162 0           free(buf->ptr);
163 0           buf->ptr = gh_buf__oom;
164 0           return -1;
165             }
166              
167 0 0         if ((size_t)len + 1 <= buf->asize - buf->size) {
168 0           buf->size += len;
169 0           break;
170             }
171              
172 0           ENSURE_SIZE(buf, buf->size + len + 1);
173 0           }
174              
175 0           return 0;
176             }
177              
178 0           int gh_buf_printf(gh_buf *buf, const char *format, ...)
179             {
180             int r;
181             va_list ap;
182              
183 0           va_start(ap, format);
184 0           r = gh_buf_vprintf(buf, format, ap);
185 0           va_end(ap);
186              
187 0           return r;
188             }
189              
190 0           void gh_buf_copy_cstr(char *data, size_t datasize, const gh_buf *buf)
191             {
192             size_t copylen;
193              
194 0 0         assert(data && datasize && buf);
    0          
195              
196 0           data[0] = '\0';
197              
198 0 0         if (buf->size == 0 || buf->asize <= 0)
    0          
199             return;
200              
201             copylen = buf->size;
202 0 0         if (copylen > datasize - 1)
203             copylen = datasize - 1;
204 0           memmove(data, buf->ptr, copylen);
205 0           data[copylen] = '\0';
206             }
207              
208 0           void gh_buf_swap(gh_buf *buf_a, gh_buf *buf_b)
209             {
210 0           gh_buf t = *buf_a;
211 0           *buf_a = *buf_b;
212 0           *buf_b = t;
213 0           }
214              
215 0           char *gh_buf_detach(gh_buf *buf)
216             {
217 0           char *data = buf->ptr;
218              
219 0 0         if (buf->asize == 0 || buf->ptr == gh_buf__oom)
    0          
220             return NULL;
221              
222 0           gh_buf_init(buf, 0);
223              
224 0           return data;
225             }
226              
227 0           void gh_buf_attach(gh_buf *buf, char *ptr, size_t asize)
228             {
229 0           gh_buf_free(buf);
230              
231 0 0         if (ptr) {
232 0           buf->ptr = ptr;
233 0           buf->size = strlen(ptr);
234 0 0         if (asize)
235 0 0         buf->asize = (asize < buf->size) ? buf->size + 1 : asize;
236             else /* pass 0 to fall back on strlen + 1 */
237 0           buf->asize = buf->size + 1;
238             } else {
239             gh_buf_grow(buf, asize);
240             }
241 0           }
242              
243 0           int gh_buf_cmp(const gh_buf *a, const gh_buf *b)
244             {
245 0           int result = memcmp(a->ptr, b->ptr, a->size < b->size ? a->size : b-> size);
246 0 0         return (result != 0) ? result :
247 0 0         (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
248             }
249