#include "iovcursor.h"
#ifndef MINIMUM
#define MINIMUM(a, b) (a) < (b) ? a : b
#endif
typedef enum {
IOVCURSOR_STATUS_FRAGMENTED = -2,
IOVCURSOR_STATUS_CONTIGPTR_OK = 0,
IOVCURSOR_STATUS_BUFCOPY_OK
} iovcursor_STATUS;
static iovcursor_STATUS
iovcursor_peek_ex(const mc_IOVCURSOR *cursor,
char *copytgt, const char **contigref,
unsigned size, unsigned offset)
{
unsigned ii;
const nb_IOV *iov = cursor->iov;
offset += cursor->offset;
for (ii = 0; ii < cursor->niov && size > 0; ++ii) {
unsigned contiglen, tmpoff;
const char *srcbuf;
const nb_IOV *cur = iov + ii;
if (offset) {
if (offset >= cur->iov_len) {
offset -= cur->iov_len;
continue;
} else {
tmpoff = offset;
offset = 0;
}
} else {
tmpoff = 0;
}
contiglen = cur->iov_len - tmpoff;
srcbuf = (const char *)cur->iov_base + tmpoff;
if (size <= contiglen) {
if (contigref) {
*contigref = srcbuf;
return IOVCURSOR_STATUS_CONTIGPTR_OK;
} else {
memcpy(copytgt, srcbuf, size);
return IOVCURSOR_STATUS_BUFCOPY_OK;
}
} else if (copytgt == NULL) {
*contigref = NULL;
return IOVCURSOR_STATUS_FRAGMENTED;
} else {
unsigned to_copy = MINIMUM(size, cur->iov_len - tmpoff);
memcpy(copytgt, srcbuf, to_copy);
copytgt += to_copy;
if (contigref) {
*contigref = NULL;
contigref = NULL;
}
contigref = NULL;
if (!(size -= to_copy)) {
return IOVCURSOR_STATUS_BUFCOPY_OK;
}
}
}
assert(!size);
*contigref = NULL;
return IOVCURSOR_STATUS_FRAGMENTED;
}
static int
iovcursor_peek(const mc_IOVCURSOR *cursor, char *buf,
unsigned size, unsigned offset)
{
int rv = iovcursor_peek_ex(cursor, buf, NULL, size, offset);
return rv == IOVCURSOR_STATUS_BUFCOPY_OK;
}
static unsigned
iovcursor_adv_first(mc_IOVCURSOR *cursor, unsigned maxsize, nb_IOV *iov)
{
const char *srcbuf = (const char *)cursor->iov->iov_base + cursor->offset;
iov->iov_base = (void*)srcbuf;
iov->iov_len = MINIMUM(cursor->iov->iov_len - cursor->offset, maxsize);
if (iov->iov_len == (cursor->iov->iov_len - cursor->offset)) {
cursor->iov++;
cursor->niov--;
cursor->offset = 0;
} else {
cursor->offset += iov->iov_len;
}
return iov->iov_len;
}
static void
iovcursor_adv_copy(mc_IOVCURSOR *cursor, char *tgt, unsigned size)
{
nb_IOV tmpiov;
nb_IOV *iov;
unsigned niov;
size -= iovcursor_adv_first(cursor, size, &tmpiov);
memcpy(tgt, tmpiov.iov_base, tmpiov.iov_len);
tgt += tmpiov.iov_len;
iov = cursor->iov;
niov = cursor->niov;
while (size) {
unsigned to_copy = MINIMUM(iov->iov_len, size);
const char *srcbuf = (const char *)iov->iov_base;
memcpy(tgt, srcbuf, to_copy);
tgt += to_copy;
size -= to_copy;
if (to_copy != iov->iov_len) {
cursor->offset = to_copy;
assert(!size);
break;
}
iov++;
niov--;
}
cursor->iov = iov;
cursor->niov = niov;
}
#define IOVCURSOR_HAS_CONTIG(mincur, n) \
((mincur)->iov->iov_len - (mincur)->offset) >= n
static void
iovcursor_adv_iovalloc(mc_IOVCURSOR *cursor, unsigned size,
nb_IOV **p_arr, unsigned *p_narr)
{
unsigned ii, narr;
nb_IOV dummy, *arr;
size -= iovcursor_adv_first(cursor, size, &dummy);
narr = 1;
if (size) {
unsigned cursz = size;
for (ii = 0; cursz > 0; ++ii) {
cursz -= MINIMUM(cursz, cursor->iov[ii].iov_len);
}
narr += ii;
}
arr = (nb_IOV*) malloc(sizeof(*arr) * narr);
arr[0] = dummy;
for (ii = 1; size > 0; ++ii) {
unsigned to_adv = MINIMUM(size, cursor->iov->iov_len);
const char *srcbuf = (const char*)cursor->iov->iov_base;
arr[ii].iov_base = (void*)srcbuf;
arr[ii].iov_len = MINIMUM(size, cursor->iov->iov_len);
size -= to_adv;
if (size == 0 && to_adv < cursor->iov->iov_len) {
cursor->offset = to_adv;
} else {
cursor->iov++;
cursor->niov--;
}
}
*p_arr = arr;
*p_narr = narr;
}