mod_s2s: Remove warning about hostname mismatch
[prosody.git] / util-src / ringbuffer.c
blob8f9013f7a88a5bbfdd13fca6c89a2f68803cf16d
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <stdio.h>
7 #include <lua.h>
8 #include <lauxlib.h>
10 typedef struct {
11 size_t rpos; /* read position */
12 size_t wpos; /* write position */
13 size_t alen; /* allocated size */
14 size_t blen; /* current content size */
15 char buffer[];
16 } ringbuffer;
18 char readchar(ringbuffer *b) {
19 b->blen--;
20 return b->buffer[(b->rpos++) % b->alen];
23 void writechar(ringbuffer *b, char c) {
24 b->blen++;
25 b->buffer[(b->wpos++) % b->alen] = c;
28 /* make sure position counters stay within the allocation */
29 void modpos(ringbuffer *b) {
30 b->rpos = b->rpos % b->alen;
31 b->wpos = b->wpos % b->alen;
34 int find(ringbuffer *b, const char *s, size_t l) {
35 size_t i, j;
36 int m;
38 if(b->rpos == b->wpos) { /* empty */
39 return 0;
42 /* look for a matching first byte */
43 for(i = 0; i <= b->blen - l; i++) {
44 if(b->buffer[(b->rpos + i) % b->alen] == *s) {
45 m = 1;
47 /* check if the following byte also match */
48 for(j = 1; j < l; j++)
49 if(b->buffer[(b->rpos + i + j) % b->alen] != s[j]) {
50 m = 0;
51 break;
54 if(m) {
55 return i + l;
60 return 0;
64 * Find first position of a substring in buffer
65 * (buffer, string) -> number
67 int rb_find(lua_State *L) {
68 size_t l, m;
69 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
70 const char *s = luaL_checklstring(L, 2, &l);
71 m = find(b, s, l);
73 if(m > 0) {
74 lua_pushinteger(L, m);
75 return 1;
78 return 0;
82 * Move read position forward without returning the data
83 * (buffer, number) -> boolean
85 int rb_discard(lua_State *L) {
86 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
87 size_t r = luaL_checkinteger(L, 2);
89 if(r > b->blen) {
90 lua_pushboolean(L, 0);
91 return 1;
94 b->blen -= r;
95 b->rpos += r;
96 modpos(b);
98 lua_pushboolean(L, 1);
99 return 1;
103 * Read bytes from buffer
104 * (buffer, number, boolean?) -> string
106 int rb_read(lua_State *L) {
107 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
108 size_t r = luaL_checkinteger(L, 2);
109 int peek = lua_toboolean(L, 3);
111 if(r > b->blen) {
112 lua_pushnil(L);
113 return 1;
116 if((b->rpos + r) > b->alen) {
117 /* Substring wraps around to the beginning of the buffer */
118 lua_pushlstring(L, &b->buffer[b->rpos], b->alen - b->rpos);
119 lua_pushlstring(L, b->buffer, r - (b->alen - b->rpos));
120 lua_concat(L, 2);
121 } else {
122 lua_pushlstring(L, &b->buffer[b->rpos], r);
125 if(!peek) {
126 b->blen -= r;
127 b->rpos += r;
128 modpos(b);
131 return 1;
135 * Read buffer until first occurrence of a substring
136 * (buffer, string) -> string
138 int rb_readuntil(lua_State *L) {
139 size_t l, m;
140 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
141 const char *s = luaL_checklstring(L, 2, &l);
142 m = find(b, s, l);
144 if(m > 0) {
145 lua_settop(L, 1);
146 lua_pushinteger(L, m);
147 return rb_read(L);
150 return 0;
154 * Write bytes into the buffer
155 * (buffer, string) -> integer
157 int rb_write(lua_State *L) {
158 size_t l, w = 0;
159 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
160 const char *s = luaL_checklstring(L, 2, &l);
162 /* Does `l` bytes fit? */
163 if((l + b->blen) > b->alen) {
164 lua_pushnil(L);
165 return 1;
168 while(l-- > 0) {
169 writechar(b, *s++);
170 w++;
173 modpos(b);
175 lua_pushinteger(L, w);
177 return 1;
180 int rb_tostring(lua_State *L) {
181 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
182 lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen);
183 return 1;
186 int rb_length(lua_State *L) {
187 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
188 lua_pushinteger(L, b->blen);
189 return 1;
192 int rb_size(lua_State *L) {
193 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
194 lua_pushinteger(L, b->alen);
195 return 1;
198 int rb_free(lua_State *L) {
199 ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt");
200 lua_pushinteger(L, b->alen - b->blen);
201 return 1;
204 int rb_new(lua_State *L) {
205 size_t size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE));
206 ringbuffer *b = lua_newuserdata(L, sizeof(ringbuffer) + size);
208 b->rpos = 0;
209 b->wpos = 0;
210 b->alen = size;
211 b->blen = 0;
213 luaL_getmetatable(L, "ringbuffer_mt");
214 lua_setmetatable(L, -2);
216 return 1;
219 int luaopen_util_ringbuffer(lua_State *L) {
220 #if (LUA_VERSION_NUM > 501)
221 luaL_checkversion(L);
222 #endif
224 if(luaL_newmetatable(L, "ringbuffer_mt")) {
225 lua_pushcfunction(L, rb_tostring);
226 lua_setfield(L, -2, "__tostring");
227 lua_pushcfunction(L, rb_length);
228 lua_setfield(L, -2, "__len");
230 lua_createtable(L, 0, 7); /* __index */
232 lua_pushcfunction(L, rb_find);
233 lua_setfield(L, -2, "find");
234 lua_pushcfunction(L, rb_discard);
235 lua_setfield(L, -2, "discard");
236 lua_pushcfunction(L, rb_read);
237 lua_setfield(L, -2, "read");
238 lua_pushcfunction(L, rb_readuntil);
239 lua_setfield(L, -2, "readuntil");
240 lua_pushcfunction(L, rb_write);
241 lua_setfield(L, -2, "write");
242 lua_pushcfunction(L, rb_size);
243 lua_setfield(L, -2, "size");
244 lua_pushcfunction(L, rb_length);
245 lua_setfield(L, -2, "length");
246 lua_pushcfunction(L, rb_free);
247 lua_setfield(L, -2, "free");
249 lua_setfield(L, -2, "__index");
252 lua_createtable(L, 0, 1);
253 lua_pushcfunction(L, rb_new);
254 lua_setfield(L, -2, "new");
255 return 1;