vis
a vi-like editor based on Plan 9's structural regular expressions
git clone https://9o.is/git/vis.git
buffer.c
(3459B)
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5
6 #include "buffer.h"
7 #include "util.h"
8
9 #ifndef BUFFER_SIZE
10 #define BUFFER_SIZE 1024
11 #endif
12
13 bool buffer_reserve(Buffer *buf, size_t size) {
14 /* ensure minimal buffer size, to avoid repeated realloc(3) calls */
15 if (size < BUFFER_SIZE)
16 size = BUFFER_SIZE;
17 if (buf->size < size) {
18 size = MAX(size, buf->size*2);
19 char *data = realloc(buf->data, size);
20 if (!data)
21 return false;
22 buf->size = size;
23 buf->data = data;
24 }
25 return true;
26 }
27
28 bool buffer_grow(Buffer *buf, size_t len) {
29 size_t size;
30 if (!addu(buf->len, len, &size))
31 return false;
32 return buffer_reserve(buf, size);
33 }
34
35 bool buffer_terminate(Buffer *buf) {
36 return !buf->data || buf->len == 0 || buf->data[buf->len-1] == '\0' ||
37 buffer_append(buf, "\0", 1);
38 }
39
40 void buffer_release(Buffer *buf) {
41 if (!buf)
42 return;
43 free(buf->data);
44 *buf = (Buffer){0};
45 }
46
47 bool buffer_put(Buffer *buf, const void *data, size_t len) {
48 if (!buffer_reserve(buf, len))
49 return false;
50 memmove(buf->data, data, len);
51 buf->len = len;
52 return true;
53 }
54
55 bool buffer_put0(Buffer *buf, const char *data) {
56 return buffer_put(buf, data, strlen(data)+1);
57 }
58
59 bool buffer_remove(Buffer *buf, size_t pos, size_t len) {
60 size_t end;
61 if (len == 0)
62 return true;
63 if (!addu(pos, len, &end) || end > buf->len)
64 return false;
65 memmove(buf->data + pos, buf->data + pos + len, buf->len - pos - len);
66 buf->len -= len;
67 return true;
68 }
69
70 static bool buffer_insert(Buffer *buf, size_t pos, const void *data, size_t len) {
71 if (pos > buf->len)
72 return false;
73 if (len == 0)
74 return true;
75 if (!buffer_grow(buf, len))
76 return false;
77 size_t move = buf->len - pos;
78 if (move > 0)
79 memmove(buf->data + pos + len, buf->data + pos, move);
80 memcpy(buf->data + pos, data, len);
81 buf->len += len;
82 return true;
83 }
84
85 bool buffer_insert0(Buffer *buf, size_t pos, const char *data) {
86 if (pos == 0)
87 return buffer_insert(buf, 0, data, strlen(data) + (buf->len == 0));
88 if (pos == buf->len)
89 return buffer_append0(buf, data);
90 return buffer_insert(buf, pos, data, strlen(data));
91 }
92
93 bool buffer_append(Buffer *buf, const void *data, size_t len) {
94 return buffer_insert(buf, buf->len, data, len);
95 }
96
97 bool buffer_append0(Buffer *buf, const char *data) {
98 size_t nul = (buf->len > 0 && buf->data[buf->len-1] == '\0') ? 1 : 0;
99 buf->len -= nul;
100 bool ret = buffer_append(buf, data, strlen(data)+1);
101 if (!ret)
102 buf->len += nul;
103 return ret;
104 }
105
106 static bool buffer_vappendf(Buffer *buf, const char *fmt, va_list ap) {
107 va_list ap_save;
108 va_copy(ap_save, ap);
109 int len = vsnprintf(NULL, 0, fmt, ap);
110 if (len == -1 || !buffer_grow(buf, len+1)) {
111 va_end(ap_save);
112 return false;
113 }
114 size_t nul = (buf->len > 0 && buf->data[buf->len-1] == '\0') ? 1 : 0;
115 buf->len -= nul;
116 bool ret = vsnprintf(buf->data+buf->len, len+1, fmt, ap_save) == len;
117 buf->len += ret ? (size_t)len+1 : nul;
118 va_end(ap_save);
119 return ret;
120 }
121
122 bool buffer_appendf(Buffer *buf, const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 bool ret = buffer_vappendf(buf, fmt, ap);
126 va_end(ap);
127 return ret;
128 }
129
130 size_t buffer_length0(Buffer *buf) {
131 size_t len = buf->len;
132 if (len > 0 && buf->data[len-1] == '\0')
133 len--;
134 return len;
135 }
136
137 const char *buffer_content0(Buffer *buf) {
138 if (buf->len == 0 || !buffer_terminate(buf))
139 return "";
140 return buf->data;
141 }
142
143 ssize_t read_into_buffer(void *context, char *data, size_t len) {
144 buffer_append(context, data, len);
145 return len;
146 }