libpolluxd/px_msg_buf.c

134 lines
3.2 KiB
C

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <px_common.h>
#include <px_msg_buf.h>
#include <px_log.h>
px_msg_buf_t* px_msg_buf_new(size_t sz) {
px_msg_buf_t* rbuf = PX_NEW_UNINITIALIZED(px_msg_buf_t);
if (!rbuf) {
int e = errno;
px_log_error("could not allocate response buffer: %s", strerror(e));
errno = e;
return NULL;
}
px_msg_buf_init(rbuf);
if (px_msg_buf_resize(rbuf, sz) != 0) {
free(rbuf);
return NULL;
}
memset((char*)rbuf->buf, 0, sz);
return rbuf;
}
void px_msg_buf_init(px_msg_buf_t* mbuf) {
if (!mbuf)
return;
memset(mbuf, 0, sizeof(*mbuf));
}
void px_msg_buf_use_external_buf(px_msg_buf_t* mbuf, char const* buf, size_t bufsz) {
if (mbuf->buf && !(mbuf->flags & PX_MSG_BUF_EXTERNAL))
free((void*)mbuf->buf);
mbuf->flags |= PX_MSG_BUF_EXTERNAL;
mbuf->buf = buf;
mbuf->buf_sz = bufsz;
}
int px_msg_buf_has_external_buf(px_msg_buf_t* mbuf) {
return mbuf->flags & PX_MSG_BUF_EXTERNAL;
}
void px_msg_buf_release_external_buf(px_msg_buf_t* mbuf) {
if (mbuf->flags & PX_MSG_BUF_EXTERNAL) {
mbuf->buf = NULL;
mbuf->buf_sz = 0;
mbuf->flags &= ~PX_MSG_BUF_EXTERNAL;
}
}
size_t px_msg_buf_resize(px_msg_buf_t* mbuf, size_t newsz) {
if (mbuf->flags & PX_MSG_BUF_EXTERNAL)
return mbuf->buf_sz;
char const* newbuf = (char const*)realloc((void*)mbuf->buf, newsz);
if (!newbuf)
return mbuf->buf_sz;
mbuf->buf = newbuf;
mbuf->buf_sz = newsz;
return newsz;
}
size_t px_msg_buf_grow(px_msg_buf_t* mbuf, size_t add) {
if (mbuf->flags & PX_MSG_BUF_EXTERNAL)
return mbuf->buf_sz;
size_t total = add + mbuf->buf_sz;
if (total < add) // overflow
return mbuf->buf_sz;
return px_msg_buf_resize(mbuf, total);
}
char const* px_msg_buf_get_buffer(px_msg_buf_t* mbuf) {
return mbuf->buf;
}
int px_msg_buf_is_writable(px_msg_buf_t* mbuf) {
return !(mbuf->flags & PX_MSG_BUF_EXTERNAL);
}
char* px_msg_buf_get_buffer_writable(px_msg_buf_t* mbuf) {
if (mbuf->flags & PX_MSG_BUF_EXTERNAL)
return NULL;
return (char*)mbuf->buf;
}
char const* px_msg_buf_pend_buffer(px_msg_buf_t* msg) {
msg->pending = msg->buf;
msg->pending_sz = msg->buf_sz;
return msg->pending;
}
char const* px_msg_buf_advance_pending(px_msg_buf_t* msg, size_t count) {
if (count > msg->pending_sz)
count = msg->pending_sz;
msg->pending += count;
msg->pending_sz -= count;
return msg->pending;
}
char const* px_msg_buf_update_pending(px_msg_buf_t* msg, size_t buf_offt, size_t pend_sz) {
// allow size_t(-1) to get whole remainder of buffer
if (pend_sz > msg->buf_sz)
pend_sz = msg->buf_sz;
if (buf_offt > msg->buf_sz
|| buf_offt + pend_sz < buf_offt) // overflow
return NULL;
if (buf_offt + pend_sz > msg->buf_sz) // don't go past the end of the buffer
pend_sz = msg->buf_sz - buf_offt;
msg->pending = msg->buf + buf_offt;
msg->pending_sz = pend_sz;
return msg->pending;
}
void px_msg_buf_destroy(px_msg_buf_t* mbuf) {
if (!mbuf)
return;
if (mbuf->flags & PX_MSG_BUF_EXTERNAL)
px_msg_buf_release_external_buf(mbuf);
else
free((void*)mbuf->buf);
px_msg_buf_init(mbuf);
}
void px_msg_buf_delete(px_msg_buf_t* mbuf) {
px_msg_buf_destroy(mbuf);
free(mbuf);
}