summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2009-10-25 00:49:29 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2009-10-25 00:49:29 +0800
commit68f10cab65ef8a4943fbff2471080bfb318512ff (patch)
tree22a2d99311c5c744b3d1dd0df487a0da73f27509
parentd011a6ef1b489578051fc4943d1d96a2a71fc330 (diff)
downloadpttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.tar
pttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.tar.gz
pttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.tar.bz2
pttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.tar.lz
pttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.tar.xz
pttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.tar.zst
pttbbs-68f10cab65ef8a4943fbff2471080bfb318512ff.zip
* add virtual (ring) buffer implementation
git-svn-id: http://opensvn.csie.org/pttbbs/trunk@4982 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--pttbbs/common/sys/Makefile2
-rw-r--r--pttbbs/common/sys/vbuf.c411
-rw-r--r--pttbbs/include/cmsys.h46
3 files changed, 457 insertions, 2 deletions
diff --git a/pttbbs/common/sys/Makefile b/pttbbs/common/sys/Makefile
index 4de3a4cf..bc07bbdd 100644
--- a/pttbbs/common/sys/Makefile
+++ b/pttbbs/common/sys/Makefile
@@ -4,7 +4,7 @@ SRCROOT= ../..
.include "$(SRCROOT)/pttbbs.mk"
SRCS:= daemon.c file.c lock.c log.c net.c sort.c string.c time.c \
- crypt.c record.c vector.c telnet.c vtkbd.c
+ crypt.c record.c vector.c telnet.c vbuf.c vtkbd.c
LIB:= cmsys
all: .depend
diff --git a/pttbbs/common/sys/vbuf.c b/pttbbs/common/sys/vbuf.c
new file mode 100644
index 00000000..4dda19ed
--- /dev/null
+++ b/pttbbs/common/sys/vbuf.c
@@ -0,0 +1,411 @@
+// $Id$
+//
+// vbuf.c
+// piaip's simple virtual (ring) buffer
+//
+// Author: Hung-Te Lin (piaip)
+// Create: Sat Oct 24 22:44:00 CST 2009
+// An implementation from scratch, with the API names inspired by vrb
+// ---------------------------------------------------------------------------
+// Copyright (c) 2009 Hung-Te Lin <piaip@csie.org>
+// All rights reserved.
+// Distributed under BSD license (GPL compatible).
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// ---------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+// for read/write/send/recv
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+// #include "vbuf.h"
+#include "cmsys.h"
+
+// #define VBUFPROTO inline
+#define VBUFPROTO
+
+// These APIs are defined as macro in vbuf.h(cmsys.h) for faster access
+#if 0
+
+VBUFPROTO int
+vbuf_is_empty(VBUF *v)
+{
+ return v->head == v->tail;
+}
+
+VBUFPROTO size_t
+vbuf_capacity(VBUF *v)
+{
+ return v->capacity;
+}
+
+VBUFPROTO size_t
+vbuf_size(VBUF *v)
+{
+ return (v->head >= v->tail) ? (v->head - v->tail) :
+ (v->buf_end - v->tail + v->head - v->buf);
+}
+
+VBUFPROTO size_t
+vbuf_space(VBUF *v)
+{
+ return v->capacity - vbuf_size(v);
+}
+
+#endif
+
+VBUFPROTO void
+vbuf_new(VBUF *v, size_t szbuf)
+{
+ assert(szbuf > 1);
+ memset(v, 0, sizeof(*v));
+ v->buf = (char*)malloc(szbuf);
+ assert(v->buf);
+ v->buf_end = v->buf + szbuf;
+ v->capacity = szbuf-1; // ring buffer needs one extra space
+ v->head = v->tail = v->buf;
+}
+
+VBUFPROTO void
+vbuf_delete(VBUF *v)
+{
+ free(v->buf);
+ memset(v, 0, sizeof(*v));
+}
+
+VBUFPROTO void
+vbuf_attach(VBUF *v, char *buf, size_t szbuf)
+{
+ assert(szbuf > 1);
+ v->head = v->tail = v->buf = buf;
+ v->buf_end = v->buf + v->capacity;
+ v->capacity = szbuf-1;
+}
+
+VBUFPROTO void
+vbuf_detach(VBUF *v)
+{
+ memset(v, 0, sizeof(VBUF));
+}
+
+VBUFPROTO void
+vbuf_clear(VBUF *v)
+{
+ v->head = v->tail = v->buf;
+}
+
+VBUFPROTO int
+vbuf_peek(VBUF *v)
+{
+ if (vbuf_is_empty(v))
+ return -1;
+ return (unsigned char)(*v->tail);
+}
+
+VBUFPROTO int
+vbuf_pop(VBUF *v)
+{
+ int c = vbuf_peek(v);
+ if (c >= 0 && ++v->tail == v->buf_end)
+ v->tail = v->buf;
+ return c;
+}
+
+VBUFPROTO int
+vbuf_push(VBUF *v, char c)
+{
+ if (vbuf_is_full(v))
+ return 0;
+ *v->head++ = c;
+ if (v->head == v->buf_end)
+ v->head = v->buf;
+ return 1;
+}
+
+VBUFPROTO int
+vbuf_strchr(VBUF *v, char c)
+{
+ const char *s = v->tail, *d = v->head;
+
+ if (vbuf_is_empty(v))
+ return 0;
+
+ if (d < s)
+ d = v->buf_end;
+
+ while (s < d)
+ if (*s++ == c)
+ return s - v->tail -1;
+
+ if (v->head > v->tail)
+ return -1;
+
+ s = v->buf; d = v->head;
+
+ while (s < d)
+ if (*s++ == c)
+ return s - v->tail -1;
+
+ return -1;
+}
+
+#define VBUF_TAIL_SZ(v) ((v->head >= v->tail) ? v->head - v->tail : v->buf_end - v->tail)
+#define VBUF_HEAD_SZ(v) ((v->head >= v->tail) ? v->buf_end - v->head : v->tail - v->head)
+
+// get data from vbuf
+VBUFPROTO int
+vbuf_get(VBUF *v, char *s, size_t sz)
+{
+ size_t rw, i;
+ if (!sz || vbuf_size(v) < sz)
+ return 0;
+
+ // two phase
+ for (i = 0; sz && i < 2; i++)
+ {
+ rw = VBUF_TAIL_SZ(v);
+ if (rw > sz) rw = sz;
+ memcpy(s, v->tail, rw);
+ v->tail += rw; s += rw; sz -= rw;
+ if (v->tail == v->buf_end)
+ v->tail = v->buf;
+ }
+ return 1;
+}
+
+// put data into vbuf
+VBUFPROTO int
+vbuf_put(VBUF *v, const char *s, size_t sz)
+{
+ size_t rw, i;
+ if (!sz || vbuf_space(v) < sz)
+ return 0;
+
+ // two phase
+ for (i = 0; sz && i < 2; i++)
+ {
+ rw = VBUF_HEAD_SZ(v);
+ if (rw > sz) rw = sz;
+ memcpy(v->head, s, rw);
+ v->head += rw; s += rw; sz -= rw;
+ if (v->head == v->buf_end)
+ v->head = v->buf;
+ }
+ return 1;
+}
+
+/* read/write callbacks */
+
+static ssize_t
+vbuf_rw_write(const void *p, size_t len, void *ctx)
+{
+ int fd = *(int*)ctx;
+ ssize_t ret;
+ while ( (ret = write(fd, p, len)) < 0 &&
+ (errno == EAGAIN || errno == EINTR));
+ return ret;
+}
+
+static ssize_t
+vbuf_rw_read(void *p, size_t len, void *ctx)
+{
+ int fd = *(int*)ctx;
+ ssize_t ret;
+ while ( (ret = read(fd, p, len)) < 0 &&
+ (errno == EAGAIN || errno == EINTR));
+ return ret;
+}
+
+static ssize_t
+vbuf_rw_send(const void *p, size_t len, void *ctx)
+{
+ int *fdflag = (int*)ctx;
+ ssize_t ret;
+ while ( (ret = send(fdflag[0], p, len, fdflag[1])) < 0 &&
+ (errno == EAGAIN || errno == EINTR));
+ return ret;
+}
+
+static ssize_t
+vbuf_rw_recv(void *p, size_t len, void *ctx)
+{
+ int *fdflag = (int*)ctx;
+ ssize_t ret;
+ while ( (ret = recv(fdflag[0], p, len, fdflag[1])) < 0 &&
+ (errno == EAGAIN || errno == EINTR));
+ return ret;
+}
+
+/* read/write herlpers */
+
+ssize_t
+vbuf_read (VBUF *v, int fd, ssize_t sz)
+{
+ return vbuf_general_read(v, sz, &fd, vbuf_rw_read);
+}
+
+ssize_t
+vbuf_write(VBUF *v, int fd, ssize_t sz)
+{
+ return vbuf_general_write(v, sz, &fd, vbuf_rw_write);
+}
+
+ssize_t
+vbuf_recv (VBUF *v, int fd, ssize_t sz, int flags)
+{
+ int ctx[2] = {fd, flags};
+ return vbuf_general_read(v, sz, &ctx, vbuf_rw_recv);
+}
+
+ssize_t
+vbuf_send (VBUF *v, int fd, ssize_t sz, int flags)
+{
+ int ctx[2] = {fd, flags};
+ return vbuf_general_write(v, sz, &ctx, vbuf_rw_send);
+}
+
+/* read/write primitives */
+
+// write from vbuf to writer
+ssize_t
+vbuf_general_write(VBUF *v, ssize_t sz, void *ctx,
+ ssize_t (writer)(const void *p, size_t len, void *ctx))
+{
+ ssize_t rw, copied = 0;
+ int is_min = 0;
+
+ if (sz == VBUF_RWSZ_ALL)
+ {
+ sz = vbuf_size(v);
+ }
+ else if (sz == VBUF_RWSZ_MIN)
+ {
+ sz = vbuf_size(v);
+ is_min = 1;
+ }
+
+ if (sz < 1 || vbuf_size(v) < sz)
+ return 0;
+
+ do {
+ rw = VBUF_TAIL_SZ(v);
+ if ((size_t)rw > sz) rw = sz;
+
+ rw = writer(v->tail, rw, ctx);
+ if (rw < 0)
+ return copied > 0 ? copied : -1;
+
+ v->tail += rw; sz -= rw;
+ if (v->tail == v->buf_end)
+ v->tail = v->buf;
+
+ } while (sz > 0 && !is_min);
+
+ return copied;
+}
+
+// read from reader to vbuf
+ssize_t
+vbuf_general_read(VBUF *v, ssize_t sz, void *ctx,
+ ssize_t (reader)(void *p, size_t len, void *ctx))
+{
+ ssize_t rw, copied = 0;
+ int is_min = 0;
+
+ if (sz == VBUF_RWSZ_ALL)
+ {
+ sz = vbuf_space(v);
+ }
+ else if (sz == VBUF_RWSZ_MIN)
+ {
+ sz = vbuf_space(v);
+ is_min = 1;
+ }
+
+ if (sz < 1 || vbuf_space(v) < sz)
+ return 0;
+
+ do {
+ rw = VBUF_HEAD_SZ(v);
+ if ((size_t)rw > sz) rw = sz;
+
+ rw = reader(v->head, rw, ctx);
+ if (rw < 0)
+ return copied > 0 ? copied : -1;
+
+ v->head += rw; sz -= rw;
+ if (v->head == v->buf_end)
+ v->head = v->buf;
+
+ } while (sz > 0 && !is_min);
+
+ return copied;
+}
+
+// testing sample
+
+#ifdef _VBUF_TEST_MAIN
+int main()
+{
+ int i;
+ VBUF vbuf, *v = &vbuf;
+
+ printf("start!\n");
+
+ vbuf_new(v, 50);
+ for (i = 0; i < 10; i++)
+ {
+ vbuf_put(v, "blah", sizeof("blah"));
+ printf("now capacity: %d, size: %d, empty: %s\n",
+ vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO");
+ }
+ for (i = 0; i < 10; i++)
+ {
+ char buf[64] = "";
+ vbuf_get(v, buf, 5);
+ printf("[%s] now capacity: %d, size: %d, empty: %s\n", buf,
+ vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO");
+ }
+
+ for (i = 0; i < 10; i++)
+ {
+ char buf[64] = "";
+ vbuf_put(v, "blah", sizeof("blah"));
+ vbuf_get(v, buf, 5);
+ printf("[%s] now capacity: %d, size: %d, empty: %s\n", buf,
+ vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO");
+ }
+
+ vbuf_clear(v);
+ printf("now capacity: %d, size: %d, empty: %s\n",
+ vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO");
+ printf("give me some input: "); fflush(stdout);
+ vbuf_read(v, 0, VBUF_RWSZ_MIN);
+ printf("index of 't' = %d\n", vbuf_strchr(v, 't'));
+ printf("now capacity: %d, size: %d, empty: %s\n",
+ vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO");
+ printf("give me 4 chars: "); fflush(stdout);
+ vbuf_read(v, 0, 5);
+ printf("now capacity: %d, size: %d, empty: %s\n",
+ vbuf_capacity(v), vbuf_size(v), vbuf_is_empty(v) ? "YES" : "NO");
+ printf("\n flushing vbuf: ["); fflush(stdout);
+ vbuf_write(v, 1, VBUF_RWSZ_ALL);
+ printf("]\n");
+ getchar();
+ return 0;
+}
+#endif
diff --git a/pttbbs/include/cmsys.h b/pttbbs/include/cmsys.h
index a4add657..4dee67c5 100644
--- a/pttbbs/include/cmsys.h
+++ b/pttbbs/include/cmsys.h
@@ -15,7 +15,6 @@
#define GCC_CHECK_FORMAT(a,b)
#endif
-
// flags used by strip_ansi
enum STRIP_FLAG {
STRIP_ALL = 0,
@@ -180,6 +179,51 @@ extern void Vector_sublist(const struct Vector *src, struct Vector *dst, const c
extern int Vector_remove(struct Vector *self, const char *name);
extern int Vector_search(const struct Vector *self, const char *name);
+/* vbuf.c */
+typedef struct VBUF {
+ char *buf;
+ char *buf_end; // (buf+capacity+1)
+ char *head; // pointer to write
+ char *tail; // pointer to read
+ size_t capacity;
+} VBUF;
+
+#define vbuf_is_empty(v) ((v)->head == (v)->tail)
+#define vbuf_is_full(v) (!vbuf_space(v))
+#define vbuf_capacity(v) ((v)->capacity)
+#define vbuf_size(v) ((size_t)((v)->head >= (v)->tail ? (v)->head - (v)->tail : (v)->buf_end - (v)->tail + (v)->head - (v)->buf))
+#define vbuf_space(v) ((size_t)((v)->capacity - vbuf_size(v)))
+// buffer management
+extern void vbuf_new (VBUF *v, size_t szbuf);
+extern void vbuf_delete(VBUF *v);
+extern void vbuf_attach(VBUF *v, char *buf, size_t szbuf);
+extern void vbuf_detach(VBUF *v);
+extern void vbuf_clear (VBUF *v);
+// data accessing
+extern int vbuf_get (VBUF *v, char *s, size_t sz); // get data from vbuf, return true/false
+extern int vbuf_put (VBUF *v, const char *s, size_t sz); // put data into vbuf, return true/false
+extern int vbuf_peek (VBUF *v); // peek one byte from vbuf, -1 if buffer empty
+extern int vbuf_pop (VBUF *v); // pop one byte from vbuf, -1 if buffer empty
+extern int vbuf_push (VBUF *v, char c); // push one byte into vbuf, return true/false
+// search and test
+extern int vbuf_strchr(VBUF *v, char c); // index of first location of c, otherwise -1
+
+#define VBUF_RWSZ_ALL (0) // r/w until buffer full
+#define VBUF_RWSZ_MIN (-1) // r/w for minimal try (do not block for more)
+
+// following APIs take VBUF_RWSZ_* in their sz parameter.
+extern ssize_t vbuf_read (VBUF *v, int fd, ssize_t sz); // read from fd to vbuf
+extern ssize_t vbuf_write(VBUF *v, int fd, ssize_t sz); // write from vbuf to fd
+extern ssize_t vbuf_send (VBUF *v, int fd, ssize_t sz, int flags);
+extern ssize_t vbuf_recv (VBUF *v, int fd, ssize_t sz, int flags);
+
+// write from vbuf to writer
+extern ssize_t vbuf_general_write(VBUF *v, ssize_t sz, void *ctx,
+ ssize_t (writer)(const void *p, size_t len, void *ctx));
+// read from reader to vbuf
+extern ssize_t vbuf_general_read (VBUF *v, ssize_t sz, void *ctx,
+ ssize_t (reader)(void *p, size_t len, void *ctx));
+
/* telnet.c */
struct TelnetCallback {
void (*write_data) (void *write_arg, int fd, const void *buf, size_t nbytes);