#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++]; }