1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
/*
* gensio - A library for abstracting stream I/O
* Copyright (C) 2018 Corey Minyard <minyard@acm.org>
*
* SPDX-License-Identifier: LGPL-2.1-only
*/
#include <string.h>
#include <assert.h>
#include <gensio/gensio_circbuf.h>
#include <gensio/gensio_os_funcs.h>
struct gensio_circbuf {
struct gensio_os_funcs *o;
gensiods pos;
gensiods size;
gensiods bufsize;
unsigned char *cbuf;
};
gensiods
gensio_circbuf_room_left(struct gensio_circbuf *c)
{
return c->bufsize - c->size;
}
void
gensio_circbuf_next_write_area(struct gensio_circbuf *c,
void **pos, gensiods *size)
{
gensiods end;
end = (c->pos + c->size) % c->bufsize;
if (c->size == c->bufsize)
*size = 0;
else if (end >= c->pos)
/* Unwrapped or empty buffer, write to the end. */
*size = c->bufsize - end;
else
/* Wrapped or full buffer, write between end and iopos. */
*size = c->pos - end;
*pos = c->cbuf + end;
}
void
gensio_circbuf_data_added(struct gensio_circbuf *c, gensiods len)
{
assert(len + c->size <= c->bufsize);
c->size += len;
}
void
gensio_circbuf_next_read_area(struct gensio_circbuf *c,
void **pos, gensiods *size)
{
gensiods end;
end = (c->pos + c->size) % c->bufsize;
if (c->size == 0)
*size = 0;
else if (end > c->pos)
/* Unwrapped buffer, read the whole thing. */
*size = c->size;
else
/* Wrapped buffer, read to end. */
*size = c->bufsize - c->pos;
*pos = c->cbuf + c->pos;
}
void
gensio_circbuf_data_removed(struct gensio_circbuf *c, gensiods len)
{
assert(len <= c->size);
c->size -= len;
c->pos = (c->pos + len) % c->bufsize;
}
gensiods
gensio_circbuf_datalen(struct gensio_circbuf *c)
{
return c->size;
}
void
gensio_circbuf_reset(struct gensio_circbuf *c)
{
c->pos = 0;
c->size = 0;
}
void
gensio_circbuf_sg_write(struct gensio_circbuf *c,
const struct gensio_sg *sg, gensiods sglen,
gensiods *rcount)
{
gensiods i, count = 0;
for (i = 0; i < sglen && gensio_circbuf_room_left(c) > 0; i++) {
gensiods buflen = sg[i].buflen;
const unsigned char *buf = sg[i].buf;
while (gensio_circbuf_room_left(c) && buflen > 0) {
gensiods size;
void *pos;
gensio_circbuf_next_write_area(c, &pos, &size);
if (size > buflen)
size = buflen;
memcpy(pos, buf, size);
gensio_circbuf_data_added(c, size);
buf += size;
buflen -= size;
count += size;
}
}
if (rcount)
*rcount = count;
}
void
gensio_circbuf_read(struct gensio_circbuf *c,
void *ibuf, gensiods buflen, gensiods *rcount)
{
gensiods count = 0;
unsigned char *buf = ibuf;
while (buflen > 0 && gensio_circbuf_datalen(c)) {
void *pos;
gensiods size;
gensio_circbuf_next_read_area(c, &pos, &size);
if (size > buflen)
size = buflen;
if (buf)
memcpy(buf, pos, size);
buflen -= size;
count += size;
if (buf)
buf += size;
gensio_circbuf_data_removed(c, size);
}
if (rcount)
*rcount = count;
}
struct gensio_circbuf *
gensio_circbuf_alloc(struct gensio_os_funcs *o, gensiods size)
{
struct gensio_circbuf *c;
c = o->zalloc(o, sizeof(*c));
if (!c)
return NULL;
c->o = o;
c->cbuf = o->zalloc(o, size);
if (!c->cbuf) {
o->free(o, c);
return NULL;
}
c->bufsize = size;
return c;
}
void
gensio_circbuf_free(struct gensio_circbuf *c)
{
c->o->free(c->o, c->cbuf);
c->o->free(c->o, c);
}
|