diff util-src/ringbuffer.c @ 11200:bf8f2da84007

Merge 0.11->trunk
author Kim Alvefur <zash@zash.se>
date Thu, 05 Nov 2020 22:31:25 +0100
parents c3b3ac63f4c3
children 1f6f05a98fcd
line wrap: on
line diff
--- a/util-src/ringbuffer.c	Thu Nov 05 22:27:17 2020 +0100
+++ b/util-src/ringbuffer.c	Thu Nov 05 22:31:25 2020 +0100
@@ -2,11 +2,14 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <stdio.h>
 
 #include <lua.h>
 #include <lauxlib.h>
 
+#if (LUA_VERSION_NUM < 504)
+#define luaL_pushfail lua_pushnil
+#endif
+
 typedef struct {
 	size_t rpos; /* read position */
 	size_t wpos; /* write position */
@@ -15,23 +18,67 @@
 	char buffer[];
 } ringbuffer;
 
-char readchar(ringbuffer *b) {
-	b->blen--;
-	return b->buffer[(b->rpos++) % b->alen];
+/* Translate absolute idx to a wrapped index within the buffer,
+   based on current read position */
+static int wrap_pos(const ringbuffer *b, const long idx, long *pos) {
+	if(idx > (long)b->blen) {
+		return 0;
+	}
+	if(idx + (long)b->rpos > (long)b->alen) {
+		*pos = idx - (b->alen - b->rpos);
+	} else {
+		*pos = b->rpos + idx;
+	}
+	return 1;
 }
 
-void writechar(ringbuffer *b, char c) {
+static int calc_splice_positions(const ringbuffer *b, long start, long end, long *out_start, long *out_end) {
+	if(start < 0) {
+		start = 1 + start + b->blen;
+	}
+	if(start <= 0) {
+		start = 1;
+	}
+
+	if(end < 0) {
+		end = 1 + end + b->blen;
+	}
+
+	if(end > (long)b->blen) {
+		end = b->blen;
+	}
+	if(start < 1) {
+		start = 1;
+	}
+
+	if(start > end) {
+		return 0;
+	}
+
+	start = start - 1;
+
+	if(!wrap_pos(b, start, out_start)) {
+		return 0;
+	}
+	if(!wrap_pos(b, end, out_end)) {
+		return 0;
+	}
+
+	return 1;
+}
+
+static void writechar(ringbuffer *b, char c) {
 	b->blen++;
 	b->buffer[(b->wpos++) % b->alen] = c;
 }
 
 /* make sure position counters stay within the allocation */
-void modpos(ringbuffer *b) {
+static void modpos(ringbuffer *b) {
 	b->rpos = b->rpos % b->alen;
 	b->wpos = b->wpos % b->alen;
 }
 
-int find(ringbuffer *b, const char *s, size_t l) {
+static int find(ringbuffer *b, const char *s, size_t l) {
 	size_t i, j;
 	int m;
 
@@ -64,7 +111,7 @@
  * Find first position of a substring in buffer
  * (buffer, string) -> number
  */
-int rb_find(lua_State *L) {
+static int rb_find(lua_State *L) {
 	size_t l, m;
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	const char *s = luaL_checklstring(L, 2, &l);
@@ -82,7 +129,7 @@
  * Move read position forward without returning the data
  * (buffer, number) -> boolean
  */
-int rb_discard(lua_State *L) {
+static int rb_discard(lua_State *L) {
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	size_t r = luaL_checkinteger(L, 2);
 
@@ -103,13 +150,13 @@
  * Read bytes from buffer
  * (buffer, number, boolean?) -> string
  */
-int rb_read(lua_State *L) {
+static int rb_read(lua_State *L) {
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	size_t r = luaL_checkinteger(L, 2);
 	int peek = lua_toboolean(L, 3);
 
 	if(r > b->blen) {
-		lua_pushnil(L);
+		luaL_pushfail(L);
 		return 1;
 	}
 
@@ -135,7 +182,7 @@
  * Read buffer until first occurrence of a substring
  * (buffer, string) -> string
  */
-int rb_readuntil(lua_State *L) {
+static int rb_readuntil(lua_State *L) {
 	size_t l, m;
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	const char *s = luaL_checklstring(L, 2, &l);
@@ -154,14 +201,14 @@
  * Write bytes into the buffer
  * (buffer, string) -> integer
  */
-int rb_write(lua_State *L) {
+static int rb_write(lua_State *L) {
 	size_t l, w = 0;
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	const char *s = luaL_checklstring(L, 2, &l);
 
 	/* Does `l` bytes fit? */
 	if((l + b->blen) > b->alen) {
-		lua_pushnil(L);
+		luaL_pushfail(L);
 		return 1;
 	}
 
@@ -177,32 +224,82 @@
 	return 1;
 }
 
-int rb_tostring(lua_State *L) {
+static int rb_tostring(lua_State *L) {
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen);
 	return 1;
 }
 
-int rb_length(lua_State *L) {
+static int rb_sub(lua_State *L) {
+	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
+
+	long start = luaL_checkinteger(L, 2);
+	long end = luaL_optinteger(L, 3, -1);
+
+	long wrapped_start, wrapped_end;
+	if(!calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) {
+		lua_pushstring(L, "");
+	} else if(wrapped_end <= wrapped_start) {
+		lua_pushlstring(L, &b->buffer[wrapped_start], b->alen - wrapped_start);
+		lua_pushlstring(L, b->buffer, wrapped_end);
+		lua_concat(L, 2);
+	} else {
+		lua_pushlstring(L, &b->buffer[wrapped_start], (wrapped_end - wrapped_start));
+	}
+
+	return 1;
+}
+
+static int rb_byte(lua_State *L) {
+	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
+
+	long start = luaL_optinteger(L, 2, 1);
+	long end = luaL_optinteger(L, 3, start);
+
+	long i;
+
+	long wrapped_start, wrapped_end;
+	if(calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) {
+		if(wrapped_end <= wrapped_start) {
+			for(i = wrapped_start; i < (long)b->alen; i++) {
+				lua_pushinteger(L, (unsigned char)b->buffer[i]);
+			}
+			for(i = 0; i < wrapped_end; i++) {
+				lua_pushinteger(L, (unsigned char)b->buffer[i]);
+			}
+			return wrapped_end + (b->alen - wrapped_start);
+		} else {
+			for(i = wrapped_start; i < wrapped_end; i++) {
+				lua_pushinteger(L, (unsigned char)b->buffer[i]);
+			}
+			return wrapped_end - wrapped_start;
+		}
+	}
+
+	return 0;
+}
+
+static int rb_length(lua_State *L) {
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	lua_pushinteger(L, b->blen);
 	return 1;
 }
 
-int rb_size(lua_State *L) {
+static int rb_size(lua_State *L) {
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	lua_pushinteger(L, b->alen);
 	return 1;
 }
 
-int rb_free(lua_State *L) {
+static int rb_free(lua_State *L) {
 	ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
 	lua_pushinteger(L, b->alen - b->blen);
 	return 1;
 }
 
-int rb_new(lua_State *L) {
-	size_t size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE));
+static int rb_new(lua_State *L) {
+	lua_Integer size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE));
+	luaL_argcheck(L, size > 0, 1, "positive integer expected");
 	ringbuffer *b = lua_newuserdata(L, sizeof(ringbuffer) + size);
 
 	b->rpos = 0;
@@ -243,6 +340,10 @@
 			lua_setfield(L, -2, "size");
 			lua_pushcfunction(L, rb_length);
 			lua_setfield(L, -2, "length");
+			lua_pushcfunction(L, rb_sub);
+			lua_setfield(L, -2, "sub");
+			lua_pushcfunction(L, rb_byte);
+			lua_setfield(L, -2, "byte");
 			lua_pushcfunction(L, rb_free);
 			lua_setfield(L, -2, "free");
 		}