summaryrefslogtreecommitdiff
path: root/src/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer.c')
-rw-r--r--src/buffer.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..06e3857
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,226 @@
+#include <unistd.h>
+#include "buffer.h"
+#include "str.h"
+#include "byte.h"
+#include "error.h"
+
+/**
+ * @file buffer.c
+ * @author djb
+ * @brief input/output routines
+ */
+
+void buffer_init(buffer *s,ssize_t (*op)(),int fd,char *buf,size_t len)
+{
+ s->x = buf;
+ s->fd = fd;
+ s->op = op;
+ s->p = 0;
+ s->n = len;
+}
+
+static ssize_t buffer_0_read(int fd,char *buf,size_t len)
+{
+ if (buffer_flush(buffer_1) == -1) return -1;
+ return read(fd,buf,len);
+}
+
+ssize_t buffer_unixread(int fd,char *buf,size_t len)
+{
+ return (ssize_t) read(fd,buf,len);
+}
+
+ssize_t buffer_unixwrite(int fd,char *buf,size_t len)
+{
+ return (ssize_t) write(fd,buf,len);
+}
+
+char buffer_0_space[BUFFER_INSIZE];
+static buffer it0 = BUFFER_INIT(buffer_0_read,0,buffer_0_space,sizeof(buffer_0_space));
+buffer *buffer_0 = &it0;
+
+char buffer_1_space[BUFFER_OUTSIZE];
+static buffer it1 = BUFFER_INIT(buffer_unixwrite,1,buffer_1_space,sizeof(buffer_1_space));
+buffer *buffer_1 = &it1;
+
+char buffer_2_space[BUFFER_OUTSIZE];
+static buffer it2 = BUFFER_INIT(buffer_unixwrite,2,buffer_2_space,sizeof(buffer_2_space));
+buffer *buffer_2 = &it2;
+
+char buffer_0_small[BUFFER_SMALL];
+static buffer is0 = BUFFER_INIT(buffer_0_read,0,buffer_0_small,sizeof(buffer_0_small));
+buffer *buffer_0small = &is0;
+
+char buffer_1_small[BUFFER_SMALL];
+static buffer is1 = BUFFER_INIT(buffer_unixwrite,1,buffer_1_small,sizeof(buffer_1_small));
+buffer *buffer_1small = &is1;
+
+char buffer_2_small[BUFFER_SMALL];
+static buffer is2 = BUFFER_INIT(buffer_unixwrite,2,buffer_2_small,sizeof(buffer_2_small));
+buffer *buffer_2small = &is2;
+
+int buffer_copy(buffer *bout,buffer *bin)
+{
+ int n;
+ char *x;
+
+ for (;;) {
+ n = buffer_feed(bin);
+ if (n < 0) return -2;
+ if (!n) return 0;
+ x = buffer_PEEK(bin);
+ if (buffer_put(bout,x,n) == -1) return -3;
+ buffer_SEEK(bin,n);
+ }
+}
+
+static int oneread(ssize_t (*op)(),int fd,char *buf,size_t len)
+{
+ int r;
+
+ for (;;) {
+ r = op(fd,buf,len);
+ if (r == -1) if (errno == EINTR) continue;
+ return r;
+ }
+}
+
+static int getthis(buffer *s,char *buf,size_t len)
+{
+ if (len > s->p) len = s->p;
+ s->p -= len;
+ byte_copy(buf,len,s->x + s->n);
+ s->n += len;
+ return len;
+}
+
+int buffer_feed(buffer *s)
+{
+ int r;
+
+ if (s->p) return s->p;
+ r = oneread(s->op,s->fd,s->x,s->n);
+ if (r <= 0) return r;
+ s->p = r;
+ s->n -= r;
+ if (s->n > 0) byte_copyr(s->x + s->n,r,s->x);
+ return r;
+}
+
+int buffer_bget(buffer *s,char *buf,size_t len)
+{
+ int r;
+
+ if (s->p > 0) return getthis(s,buf,len);
+ if (s->n <= len) return oneread(s->op,s->fd,buf,s->n);
+ r = buffer_feed(s);
+ if (r <= 0) return r;
+ return getthis(s,buf,len);
+}
+
+int buffer_get(buffer *s,char *buf,size_t len)
+{
+ int r;
+
+ if (s->p > 0) return getthis(s,buf,len);
+ if (s->n <= len) return oneread(s->op,s->fd,buf,len);
+ r = buffer_feed(s);
+ if (r <= 0) return r;
+ return getthis(s,buf,len);
+}
+
+char *buffer_peek(buffer *s)
+{
+ return s->x + s->n;
+}
+
+void buffer_seek(buffer *s,size_t len)
+{
+ s->n += len;
+ s->p -= len;
+}
+
+static int allwrite(ssize_t (*op)(),int fd,const char *buf,size_t len)
+{
+ int w;
+
+ while (len) {
+ w = op(fd,buf,len);
+ if (w == -1) {
+ if (errno == EINTR) continue;
+ return -1; /* note that some data may have been written */
+ }
+ if (w == 0) /* luser's fault */
+ ;
+ buf += w;
+ len -= w;
+ }
+ return 0;
+}
+
+int buffer_flush(buffer *s)
+{
+ int p;
+
+ p = s->p;
+ if (!p) return 0;
+ s->p = 0;
+ return allwrite(s->op,s->fd,s->x,p);
+}
+
+int buffer_putalign(buffer *s,const char *buf,size_t len)
+{
+ unsigned int n;
+
+ while (len > (n = s->n - s->p)) {
+ byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n;
+ if (buffer_flush(s) == -1) return -1;
+ }
+ /* now len <= s->n - s->p */
+ byte_copy(s->x + s->p,len,buf);
+ s->p += len;
+ return 0;
+}
+
+int buffer_put(buffer *s,const char *buf,size_t len)
+{
+ unsigned int n;
+
+ n = s->n;
+ if (len > n - s->p) {
+ if (buffer_flush(s) == -1) return -1;
+ /* now s->p == 0 */
+ if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE;
+ while (len > s->n) {
+ if (n > len) n = len;
+ if (allwrite(s->op,s->fd,buf,n) == -1) return -1;
+ buf += n;
+ len -= n;
+ }
+ }
+ /* now len <= s->n - s->p */
+ byte_copy(s->x + s->p,len,buf);
+ s->p += len;
+ return 0;
+}
+
+int buffer_putflush(buffer *s,const char *buf,size_t len)
+{
+ if (buffer_flush(s) == -1) return -1;
+ return allwrite(s->op,s->fd,buf,len);
+}
+
+int buffer_putsalign(buffer *s,const char *buf)
+{
+ return buffer_putalign(s,buf,str_len(buf));
+}
+
+int buffer_puts(buffer *s,const char *buf)
+{
+ return buffer_put(s,buf,str_len(buf));
+}
+
+int buffer_putsflush(buffer *s,const char *buf)
+{
+ return buffer_putflush(s,buf,str_len(buf));
+}