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 }