asterisk-chan-dongle/ringbuffer.c

410 lines
6.7 KiB
C

/*
Copyright (C) 2009 - 2010
Artem Makhutov <artem@makhutov.org>
http://www.makhutov.org
Dmitry Vagin <dmitry2004@yandex.ru>
*/
#include "ast_config.h"
#include "memmem.h"
#include <string.h> /* memchr() */
#include "ringbuffer.h"
EXPORT_DEF int rb_memcmp (const struct ringbuffer* rb, const char* mem, size_t len)
{
size_t tmp;
if (rb->used > 0 && len > 0 && rb->used >= len)
{
if ((rb->read + len) > rb->size)
{
tmp = rb->size - rb->read;
if (memcmp (rb->buffer + rb->read, mem, tmp) == 0)
{
len -= tmp;
mem += tmp;
if (memcmp (rb->buffer, mem, len) == 0)
{
return 0;
}
}
}
else
{
if (memcmp (rb->buffer + rb->read, mem, len) == 0)
{
return 0;
}
}
return 1;
}
return -1;
}
/* ============================ READ ============================= */
EXPORT_DEF int rb_read_all_iov (const struct ringbuffer* rb, struct iovec iov[2])
{
if (rb->used > 0)
{
if ((rb->read + rb->used) > rb->size)
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->size - rb->read;
iov[1].iov_base = rb->buffer;
iov[1].iov_len = rb->used - iov[0].iov_len;
return 2;
}
else
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->used;
iov[1].iov_len = 0;
return 1;
}
}
return 0;
}
EXPORT_DEF int rb_read_n_iov (const struct ringbuffer* rb, struct iovec iov[2], size_t len)
{
if (rb->used < len)
{
return 0;
}
if (len > 0)
{
if ((rb->read + len) > rb->size)
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->size - rb->read;
iov[1].iov_base = rb->buffer;
iov[1].iov_len = len - iov[0].iov_len;
return 2;
}
else
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = len;
iov[1].iov_len = 0;
return 1;
}
}
return 0;
}
EXPORT_DEF int rb_read_until_char_iov (const struct ringbuffer* rb, struct iovec iov[2], char c)
{
void* p;
if (rb->used > 0)
{
if ((rb->read + rb->used) > rb->size)
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->size - rb->read;
if ((p = memchr (iov[0].iov_base, c, iov[0].iov_len)) != NULL)
{
iov[0].iov_len = p - iov[0].iov_base;
iov[1].iov_len = 0;
return 1;
}
if ((p = memchr (rb->buffer, c, rb->used - iov[0].iov_len)) != NULL)
{
iov[1].iov_base = rb->buffer;
iov[1].iov_len = p - rb->buffer;
return 2;
}
}
else
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->used;
if ((p = memchr (iov[0].iov_base, c, iov[0].iov_len)) != NULL)
{
iov[0].iov_len = p - iov[0].iov_base;
iov[1].iov_len = 0;
return 1;
}
}
}
return 0;
}
EXPORT_DEF int rb_read_until_mem_iov (const struct ringbuffer* rb, struct iovec iov[2], const void* mem, size_t len)
{
size_t i;
void* p;
if (len == 1)
{
return rb_read_until_char_iov (rb, iov, *((char*) mem));
}
if (rb->used > 0 && len > 0 && rb->used >= len)
{
if ((rb->read + rb->used) > rb->size)
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->size - rb->read;
if (iov[0].iov_len >= len)
{
if ((p = memmem (iov[0].iov_base, iov[0].iov_len, mem, len)) != NULL)
{
iov[0].iov_len = p - iov[0].iov_base;
iov[1].iov_len = 0;
return 1;
}
i = 1;
iov[1].iov_base = iov[0].iov_base + iov[0].iov_len - len + 1;
}
else
{
i = len - iov[0].iov_len;
iov[1].iov_base = iov[0].iov_base;
}
while (i < len)
{
if (memcmp (iov[1].iov_base, mem, len - i) == 0 && memcmp (rb->buffer, mem + i, i) == 0)
{
iov[0].iov_len = iov[1].iov_base - iov[0].iov_base;
iov[1].iov_len = 0;
return 1;
}
if (rb->used == iov[0].iov_len + i)
{
return 0;
}
iov[1].iov_base++;
i++;
}
if (rb->used >= iov[0].iov_len + len)
{
if ((p = memmem (rb->buffer, rb->used - iov[0].iov_len, mem, len)) != NULL)
{
if (p == rb->buffer)
{
iov[1].iov_len = 0;
return 1;
}
iov[1].iov_base = rb->buffer;
iov[1].iov_len = p - rb->buffer;
return 2;
}
}
}
else
{
iov[0].iov_base = rb->buffer + rb->read;
iov[0].iov_len = rb->used;
if ((p = memmem (iov[0].iov_base, iov[0].iov_len, mem, len)) != NULL)
{
iov[0].iov_len = p - iov[0].iov_base;
iov[1].iov_len = 0;
return 1;
}
}
}
return 0;
}
EXPORT_DEF size_t rb_read_upd (struct ringbuffer* rb, size_t len)
{
size_t s;
if (rb->used < len)
{
len = rb->used;
}
if (len > 0)
{
rb->used -= len;
if (rb->used == 0)
{
rb->read = 0;
rb->write = 0;
}
else
{
s = rb->read + len;
if (s >= rb->size)
{
rb->read = s - rb->size;
}
else
{
rb->read = s;
}
}
}
return len;
}
/* unused
static size_t rb_read (struct ringbuffer* rb, char* buf, size_t len)
{
size_t s;
if (rb->used < len)
{
len = rb->used;
}
if (len > 0)
{
s = rb->read + len;
if (s > rb->size)
{
memmove (buf, rb->buffer + rb->read, rb->size - rb->read);
memmove (buf + rb->size - rb->read, rb->buffer, s - rb->size);
rb->read = s - rb->size;
}
else
{
memmove (buf, rb->buffer + rb->read, len);
if (s == rb->size)
{
rb->read = 0;
}
else
{
rb->read = s;
}
}
rb->used -= len;
if (rb->used == 0)
{
rb->read = 0;
rb->write = 0;
}
}
return len;
}
*/
/* ============================ WRITE ============================ */
EXPORT_DEF int rb_write_iov (const struct ringbuffer* rb, struct iovec iov[2])
{
size_t free;
free = rb_free (rb);
if (free > 0)
{
if ((rb->write + free) > rb->size)
{
iov[0].iov_base = rb->buffer + rb->write;
iov[0].iov_len = rb->size - rb->write;
iov[1].iov_base = rb->buffer;
iov[1].iov_len = free - iov[0].iov_len;
return 2;
}
else
{
iov[0].iov_base = rb->buffer + rb->write;
iov[0].iov_len = free;
return 1;
}
}
return 0;
}
EXPORT_DEF size_t rb_write_upd (struct ringbuffer* rb, size_t len)
{
size_t free;
size_t s;
free = rb_free (rb);
if (free < len)
{
len = free;
}
if (len > 0)
{
s = rb->write + len;
if (s > rb->size)
{
rb->write = s - rb->size;
}
else
{
rb->write = s;
}
rb->used += len;
}
return len;
}
EXPORT_DEF size_t rb_write_core (struct ringbuffer* rb, const char* buf, size_t len, rb_write_f method)
{
size_t free;
size_t s;
free = rb_free (rb);
if (free < len)
{
len = free;
}
if (len > 0)
{
s = rb->write + len;
if (s > rb->size)
{
(*method) (rb->buffer + rb->write, buf, rb->size - rb->write);
(*method) (rb->buffer, buf + rb->size - rb->write, s - rb->size);
rb->write = s - rb->size;
}
else
{
(*method) (rb->buffer + rb->write, buf, len);
if (s == rb->size)
{
rb->write = 0;
}
else
{
rb->write = s;
}
}
rb->used += len;
}
return len;
}