filetype: Set "groovy" for Jenkinsfile
[vis.git] / buffer.c
blobffda00fc0390294473177e7ccb381a6398157cfb
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdarg.h>
4 #include <stdio.h>
6 #include "buffer.h"
7 #include "util.h"
9 #ifndef BUFFER_SIZE
10 #define BUFFER_SIZE 1024
11 #endif
13 void buffer_init(Buffer *buf) {
14 memset(buf, 0, sizeof *buf);
17 bool buffer_reserve(Buffer *buf, size_t size) {
18 /* ensure minimal buffer size, to avoid repeated realloc(3) calls */
19 if (size < BUFFER_SIZE)
20 size = BUFFER_SIZE;
21 if (buf->size < size) {
22 size = MAX(size, buf->size*2);
23 char *data = realloc(buf->data, size);
24 if (!data)
25 return false;
26 buf->size = size;
27 buf->data = data;
29 return true;
32 bool buffer_grow(Buffer *buf, size_t len) {
33 size_t size;
34 if (!addu(buf->len, len, &size))
35 return false;
36 return buffer_reserve(buf, size);
39 bool buffer_terminate(Buffer *buf) {
40 return !buf->data || buf->len == 0 || buf->data[buf->len-1] == '\0' ||
41 buffer_append(buf, "\0", 1);
44 void buffer_release(Buffer *buf) {
45 if (!buf)
46 return;
47 free(buf->data);
48 buffer_init(buf);
51 void buffer_clear(Buffer *buf) {
52 buf->len = 0;
55 bool buffer_put(Buffer *buf, const void *data, size_t len) {
56 if (!buffer_reserve(buf, len))
57 return false;
58 memmove(buf->data, data, len);
59 buf->len = len;
60 return true;
63 bool buffer_put0(Buffer *buf, const char *data) {
64 return buffer_put(buf, data, strlen(data)+1);
67 bool buffer_remove(Buffer *buf, size_t pos, size_t len) {
68 size_t end;
69 if (len == 0)
70 return true;
71 if (!addu(pos, len, &end) || end > buf->len)
72 return false;
73 memmove(buf->data + pos, buf->data + pos + len, buf->len - pos - len);
74 buf->len -= len;
75 return true;
78 bool buffer_insert(Buffer *buf, size_t pos, const void *data, size_t len) {
79 if (pos > buf->len)
80 return false;
81 if (len == 0)
82 return true;
83 if (!buffer_grow(buf, len))
84 return false;
85 size_t move = buf->len - pos;
86 if (move > 0)
87 memmove(buf->data + pos + len, buf->data + pos, move);
88 memcpy(buf->data + pos, data, len);
89 buf->len += len;
90 return true;
93 bool buffer_insert0(Buffer *buf, size_t pos, const char *data) {
94 if (pos == 0)
95 return buffer_prepend0(buf, data);
96 if (pos == buf->len)
97 return buffer_append0(buf, data);
98 return buffer_insert(buf, pos, data, strlen(data));
101 bool buffer_append(Buffer *buf, const void *data, size_t len) {
102 return buffer_insert(buf, buf->len, data, len);
105 bool buffer_append0(Buffer *buf, const char *data) {
106 size_t nul = (buf->len > 0 && buf->data[buf->len-1] == '\0') ? 1 : 0;
107 buf->len -= nul;
108 bool ret = buffer_append(buf, data, strlen(data)+1);
109 if (!ret)
110 buf->len += nul;
111 return ret;
114 bool buffer_prepend(Buffer *buf, const void *data, size_t len) {
115 return buffer_insert(buf, 0, data, len);
118 bool buffer_prepend0(Buffer *buf, const char *data) {
119 return buffer_prepend(buf, data, strlen(data) + (buf->len == 0));
122 static bool buffer_vappendf(Buffer *buf, const char *fmt, va_list ap) {
123 va_list ap_save;
124 va_copy(ap_save, ap);
125 int len = vsnprintf(NULL, 0, fmt, ap);
126 if (len == -1 || !buffer_grow(buf, len+1)) {
127 va_end(ap_save);
128 return false;
130 size_t nul = (buf->len > 0 && buf->data[buf->len-1] == '\0') ? 1 : 0;
131 buf->len -= nul;
132 bool ret = vsnprintf(buf->data+buf->len, len+1, fmt, ap_save) == len;
133 buf->len += ret ? (size_t)len+1 : nul;
134 va_end(ap_save);
135 return ret;
138 bool buffer_appendf(Buffer *buf, const char *fmt, ...) {
139 va_list ap;
140 va_start(ap, fmt);
141 bool ret = buffer_vappendf(buf, fmt, ap);
142 va_end(ap);
143 return ret;
146 bool buffer_printf(Buffer *buf, const char *fmt, ...) {
147 buffer_clear(buf);
148 va_list ap;
149 va_start(ap, fmt);
150 bool ret = buffer_vappendf(buf, fmt, ap);
151 va_end(ap);
152 return ret;
155 size_t buffer_length0(Buffer *buf) {
156 size_t len = buf->len;
157 if (len > 0 && buf->data[len-1] == '\0')
158 len--;
159 return len;
162 size_t buffer_length(Buffer *buf) {
163 return buf->len;
166 size_t buffer_capacity(Buffer *buf) {
167 return buf->size;
170 const char *buffer_content(Buffer *buf) {
171 return buf->data;
174 const char *buffer_content0(Buffer *buf) {
175 if (buf->len == 0 || !buffer_terminate(buf))
176 return "";
177 return buf->data;
180 char *buffer_move(Buffer *buf) {
181 char *data = buf->data;
182 buffer_init(buf);
183 return data;