180 lines
4.4 KiB
C
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++];
|
|
}
|