|
// Written by retoor@molodetz.nl
|
|
|
|
// A ring buffer implementation in C that provides functionalities such as
|
|
// creating a new buffer, freeing, resetting, writing data, pushing data,
|
|
// popping data, matching options and more. It efficiently manages dynamic
|
|
// memory to handle data of varying sizes and applies basic buffer manipulation techniques.
|
|
|
|
// This code includes the utility "rmalloc.h". It is assumed that this file
|
|
// contains custom memory management functions which are not specified here.
|
|
|
|
// MIT License
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
#ifndef RBUFFER_H
|
|
#define RBUFFER_H
|
|
#include "rmalloc.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <assert.h>
|
|
|
|
typedef struct rbuffer_t {
|
|
unsigned char *data;
|
|
unsigned char *_data;
|
|
size_t size;
|
|
size_t pos;
|
|
bool eof;
|
|
} rbuffer_t;
|
|
|
|
rbuffer_t *rbuffer_new(unsigned char *data, size_t size);
|
|
void rbuffer_free(rbuffer_t *rfb);
|
|
void rbuffer_reset(rbuffer_t *rfb);
|
|
void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size);
|
|
size_t rbuffer_push(rbuffer_t *rfb, unsigned char data);
|
|
unsigned char rbuffer_pop(rbuffer_t *rfb);
|
|
unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore);
|
|
void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size);
|
|
|
|
void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size) {
|
|
if (rfb->_data) {
|
|
free(rfb->_data);
|
|
rfb->_data = NULL;
|
|
rfb->data = NULL;
|
|
rfb->eof = true;
|
|
}
|
|
if (size) {
|
|
rfb->_data = (unsigned char *)malloc(size);
|
|
memcpy(rfb->_data, data, size);
|
|
rfb->data = rfb->_data;
|
|
rfb->eof = false;
|
|
}
|
|
rfb->size = size;
|
|
rfb->pos = 0;
|
|
}
|
|
|
|
rbuffer_t *rbuffer_new(unsigned char *data, size_t size) {
|
|
rbuffer_t *rfb = (rbuffer_t *)malloc(sizeof(rbuffer_t));
|
|
if (size) {
|
|
rfb->_data = (unsigned char *)malloc(size);
|
|
memcpy(rfb->_data, data, size);
|
|
rfb->eof = false;
|
|
} else {
|
|
rfb->_data = NULL;
|
|
rfb->eof = true;
|
|
}
|
|
rfb->size = size;
|
|
rfb->pos = 0;
|
|
rfb->data = rfb->_data;
|
|
return rfb;
|
|
}
|
|
|
|
void rbuffer_free(rbuffer_t *rfb) {
|
|
if (rfb->_data) {
|
|
free(rfb->_data);
|
|
}
|
|
free(rfb);
|
|
}
|
|
|
|
size_t rbuffer_push(rbuffer_t *rfb, unsigned char data) {
|
|
if (rfb->pos < rfb->size) {
|
|
rfb->_data[rfb->pos++] = data;
|
|
return 1;
|
|
}
|
|
rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2);
|
|
rfb->_data[rfb->pos++] = data;
|
|
rfb->size++;
|
|
return rfb->pos;
|
|
}
|
|
|
|
void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) {
|
|
for (size_t i = 0; i < size; i++) {
|
|
rbuffer_push(rfb, data[i]);
|
|
}
|
|
}
|
|
|
|
unsigned char rbuffer_peek(rbuffer_t *rfb) {
|
|
if (rfb->pos != rfb->size) {
|
|
return rfb->_data[rfb->pos];
|
|
}
|
|
rfb->eof = true;
|
|
return EOF;
|
|
}
|
|
|
|
unsigned char rbuffer_pop(rbuffer_t *rfb) {
|
|
if (rfb->pos < rfb->size) {
|
|
unsigned char result = rfb->_data[rfb->pos];
|
|
rfb->pos++;
|
|
rfb->data++;
|
|
if (rfb->pos == rfb->size) {
|
|
rfb->eof = true;
|
|
}
|
|
return result;
|
|
}
|
|
rfb->eof = true;
|
|
return EOF;
|
|
}
|
|
|
|
void rbuffer_reset(rbuffer_t *rfb) {
|
|
rfb->data = rfb->_data;
|
|
rfb->pos = 0;
|
|
}
|
|
|
|
unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) {
|
|
return strncmp((const char *)s1, (const char *)s2, n);
|
|
}
|
|
|
|
size_t ustrlen(const unsigned char *s) { return strlen((const char *)s); }
|
|
|
|
unsigned char *rbuffer_to_string(rbuffer_t *rfb) {
|
|
unsigned char *result = rfb->_data;
|
|
rfb->_data = NULL;
|
|
rfb->data = NULL;
|
|
rbuffer_free(rfb);
|
|
return result;
|
|
}
|
|
|
|
unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) {
|
|
char *option = NULL;
|
|
char options_cpy[1024] = {0};
|
|
strcpy(options_cpy, options);
|
|
char *memory = options_cpy;
|
|
while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) {
|
|
size_t option_length = strlen(option);
|
|
if (option_length > rfb->size - rfb->pos) {
|
|
continue;
|
|
}
|
|
if (!strcmp(option, "\\d") && *rfb->data >= '0' && *rfb->data <= '9') {
|
|
return rfb->data;
|
|
}
|
|
if (rfb->size - rfb->pos >= 5 && !strcmp(option, "\\b") &&
|
|
((!ustrncmp(rfb->data, (unsigned char *)"true", 4) || !ustrncmp(rfb->data, (unsigned char *)"false", 5)))) {
|
|
return rfb->data;
|
|
}
|
|
if (!ustrncmp(rfb->data, (unsigned char *)option, option_length)) {
|
|
return rfb->data;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) {
|
|
while (rfb->pos < rfb->size) {
|
|
if (rbuffer_match_option(rfb, options) != NULL) {
|
|
return rfb->data;
|
|
}
|
|
if (rbuffer_match_option(rfb, ignore)) {
|
|
printf("SKIP:%s\n", rfb->data);
|
|
rbuffer_pop(rfb);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) {
|
|
unsigned char *result = NULL;
|
|
if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) {
|
|
rbuffer_pop(rfb);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endif |