%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% header /** @file dk4membuf.h Memory buffer. */ #ifndef DK4ERROR_H_INCLUDED #include "dk4error.h" #endif /** One cell of a memory buffer. */ typedef struct _dk4_membuf_cell_t_ { struct _dk4_membuf_cell_t_ *next; /**< Next element in linked list. */ char *buf; /**< Buffer for data storage. */ size_t max; /**< Number of bytes available. */ size_t used; /**< Number of bytes used. */ } dk4_membuf_cell_t; /** Memory buffer object. */ typedef struct { dk4_membuf_cell_t *first; /**< First cell (head of list). */ dk4_membuf_cell_t *last; /**< Last cell (end of list). */ int he; /**< Flag: Had allocation error. */ } dk4_membuf_t; #ifdef __cplusplus extern "C" { #endif /** Create new buffer, allocate initial memory. @param erp Error report, may be NULL. @return Pointer on success, NULL on error. */ dk4_membuf_t * dk4membuf_open(dk4_er_t *erp); /** Destroy buffer, release memory. @param mbptr Buffer to destroy. */ void dk4membuf_close(dk4_membuf_t *mbptr); /** Store data in buffer. @param mbptr Buffer object. @param src Address of data to store. @param sz Number of bytes to store. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error code: - DK4_E_INVALID_ARGUMENTS
if mbptr or src is NULL or sz is 0, - DK4_E_MATH_OVERFLOW
if a mathematical overflow occured in size calculation, - DK4_E_MEMORY_ALLOCATION_FAILED
with mem.elsize and mem.nelem set if there is not enough memory available. */ int dk4membuf_store(dk4_membuf_t *mbptr, const void *src, size_t sz, dk4_er_t *erp); /** Retrieve size of data stored in memory buffer. @param szptr Address of result variable. @param mbptr Buffer to find size for. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error code: - DK4_E_INVALID_ARGUMENTS
if szptr or mbptr is NULL. - DK4_E_MATH_OVERFLOW
if a mathematical overflow occured in size calculation. */ int dk4membuf_size(size_t *szptr, dk4_membuf_t *mbptr, dk4_er_t *erp); #ifdef __cplusplus } #endif /** Default chunk size. */ #define DK4MEMBUF_CHUNK_SIZE 4096U %% module #include "dk4membuf.h" #include "dk4mem.h" #include "dk4maasz.h" $!trace-include static void dk4membuf_cell_close(dk4_membuf_cell_t *mcptr) { if (NULL != mcptr) { dk4mem_release(mcptr->buf); mcptr->next = NULL; mcptr->max = mcptr->used = 0; dk4mem_free(mcptr); } } static dk4_membuf_cell_t * dk4membuf_cell_open(size_t sz, dk4_er_t *erp) { dk4_er_t er; dk4_membuf_cell_t *back = NULL; size_t nb; /* Ensure number of bytes is a multiple of the chunk size. */ nb = sz / DK4MEMBUF_CHUNK_SIZE; if (0 != (sz % DK4MEMBUF_CHUNK_SIZE)) { nb++; } dk4error_init(&er); nb = dk4ma_size_t_mul(nb, (size_t)(DK4MEMBUF_CHUNK_SIZE), &er); if (0 != er.ec) { nb = sz; } /* Allocate */ back = dk4mem_new(dk4_membuf_cell_t,1,erp); if (NULL != back) { back->next = NULL; back->max = nb; back->used = 0; back->buf = dk4mem_new(char,nb,erp); if (NULL == back->buf) { dk4mem_free(back); back = NULL; } } return back; } dk4_membuf_t * dk4membuf_open(dk4_er_t *erp) { dk4_membuf_t *back = NULL; back = dk4mem_new(dk4_membuf_t,1,erp); if (NULL != back) { back->he = 0; back->last = NULL; back->first = dk4membuf_cell_open(DK4MEMBUF_CHUNK_SIZE, erp); if (NULL != back->first) { back->last = back->first; } else { dk4mem_free(back); back = NULL; } } return back; } void dk4membuf_close(dk4_membuf_t *mbptr) { dk4_membuf_cell_t *pc; dk4_membuf_cell_t *pn; if (NULL != mbptr) { pc = mbptr->first; while (NULL != pc) { pn = pc->next; dk4membuf_cell_close(pc); pc = pn; } dk4mem_free(mbptr); } } int dk4membuf_store(dk4_membuf_t *mbptr, const void *src, size_t sz, dk4_er_t *erp) { dk4_membuf_cell_t *pc = NULL; dk4_membuf_cell_t *pn = NULL; const char *psrc = NULL; size_t bl = 0; int back = 0; if ((NULL != mbptr) && (NULL != src) && (0 < sz)) { /* Initialize variables. */ back = 1; pc = mbptr->last; psrc = (const char *)src; /* Attempt to fill current cell. */ if (pc->max > pc->used) { bl = pc->max - pc->used; if (sz < bl) { bl = sz; } DK4_MEMCPY(&((pc->buf)[pc->used]), psrc, bl); pc->used += bl; sz -= bl; psrc = &(psrc[bl]); } /* Use new cell if necessary. */ if (0 < sz) { back = 0; pn = dk4membuf_cell_open(sz, erp); if (NULL != pn) { pc->next = pn; mbptr->last = pn; DK4_MEMCPY(pn->buf, psrc, sz); back = 1; pn->used = sz; } else { mbptr->he = 1; } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4membuf_size(size_t *szptr, dk4_membuf_t *mbptr, dk4_er_t *erp) { dk4_er_t er; dk4_membuf_cell_t *cp = NULL; size_t result = (size_t)0U; int back = 0; if ((NULL != szptr) && (NULL != mbptr)) { back = 1; cp = mbptr->first; dk4error_init(&er); while (NULL != cp) { result = dk4ma_size_t_add(result, cp->used, &er); cp = cp->next; } if (DK4_E_NONE == er.ec) { back = 1; *szptr = result; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; }