temporary-satori-hole/src/buffer.c
2023-12-27 01:35:22 +01:00

180 lines
4.4 KiB
C

#include "buffer.h"
inline sat_buffer_piece_ptr sat_buffer_piece_alloc(void) {
sat_buffer_piece_ptr piece = malloc(sizeof(sat_buffer_piece));
piece->next = NULL;
return piece;
}
inline void sat_buffer_piece_free(sat_buffer_piece_ptr piece) {
if(piece != NULL)
free(piece);
}
sat_buffer_ptr sat_buffer_alloc(void) {
sat_buffer_ptr buffer = malloc(sizeof(sat_buffer));
buffer->available = buffer->rPos = buffer->wPos = 0;
buffer->wCurrent = buffer->rCurrent = buffer->start = sat_buffer_piece_alloc();
return buffer;
}
void sat_buffer_free(sat_buffer_ptr buffer) {
if(buffer == NULL) return;
sat_buffer_piece_ptr curr = buffer->start;
while(curr != NULL) {
buffer->start = curr->next;
free(curr);
curr = buffer->start;
}
free(buffer);
}
bool sat_buffer_pending(sat_buffer_ptr buffer) {
return buffer->available > 0;
}
size_t sat_buffer_available(sat_buffer_ptr buffer) {
return buffer->available;
}
void sat_buffer_tidy(sat_buffer_ptr buffer) {
// wCurrent should always be the same or ahead of rCurrent
sat_buffer_piece_ptr curr = buffer->start;
while(curr != NULL && curr != buffer->rCurrent) {
buffer->start = curr->next;
free(curr);
curr = buffer->start;
}
}
int sat_buffer_write(sat_buffer_ptr buffer, char *source, size_t count) {
if(buffer == NULL) return -1;
if(source == NULL) return -2;
if(count == 0)
return 0;
if(buffer->wCurrent == NULL) {
buffer->wCurrent = buffer->start;
buffer->wPos = 0;
}
int offset = buffer->wPos;
sat_buffer_piece_ptr piece = buffer->wCurrent;
int written = 0;
int shove;
while(count > 0) {
if(count + offset < SAT_BUFFER_PIECE_SIZE)
shove = count;
else if(offset < SAT_BUFFER_PIECE_SIZE)
shove = SAT_BUFFER_PIECE_SIZE - offset;
else {
offset = 0;
piece = (piece->next = sat_buffer_piece_alloc());
continue;
}
memcpy(&piece->data[offset], source, shove);
offset += shove;
written += shove;
count -= shove;
}
buffer->wPos = offset;
buffer->wCurrent = piece;
buffer->available += written;
return written;
}
void sat_buffer_putc(sat_buffer_ptr buffer, char value) {
if(buffer == NULL) return;
if(buffer->wCurrent == NULL) {
buffer->wCurrent = buffer->start;
buffer->wPos = 0;
} else if(buffer->wPos >= SAT_BUFFER_PIECE_MAX) {
buffer->wCurrent = (buffer->wCurrent->next = sat_buffer_piece_alloc());
buffer->wPos = 0;
}
buffer->wCurrent->data[buffer->wPos++] = value;
++buffer->available;
}
int sat_buffer_read(sat_buffer_ptr buffer, char *target, size_t length) {
if(buffer == NULL) return -1;
if(target == NULL) return -2;
if(buffer->rCurrent == NULL) return -3;
if(length == 0)
return 0;
if(buffer->rCurrent == NULL) {
buffer->rCurrent = buffer->start;
buffer->rPos = 0;
}
int remaining = length > buffer->available ? buffer->available : length;
if(remaining < 1)
return 0;
int offset = buffer->rPos;
sat_buffer_piece_ptr piece = buffer->rCurrent;
int read = 0;
int take;
while(remaining > 0) {
if(remaining + offset < SAT_BUFFER_PIECE_SIZE)
take = remaining;
else if(offset < SAT_BUFFER_PIECE_SIZE)
take = SAT_BUFFER_PIECE_SIZE - offset;
else {
offset = 0;
piece = piece->next;
// this shouldn't happen, maybe make this an assert?
if(piece == NULL)
break;
continue;
}
memcpy(target, &piece->data[offset], take);
offset += take;
read += take;
remaining -= take;
}
buffer->rPos = offset;
buffer->rCurrent = piece;
buffer->available -= read;
return read;
}
char sat_buffer_getc(sat_buffer_ptr buffer) {
if(buffer == NULL || buffer->rCurrent == NULL || buffer->available < 1)
return '\0';
if(buffer->rCurrent == NULL) {
buffer->rCurrent = buffer->start;
buffer->rPos = 0;
} else if(buffer->rPos >= SAT_BUFFER_PIECE_MAX) {
buffer->rCurrent = buffer->rCurrent->next;
buffer->rPos = 0;
}
if(buffer->rCurrent == NULL)
return '\0';
--buffer->available;
return buffer->rCurrent->data[buffer->rPos++];
}