blob: a832f3f5fc3442c3b76fcd1e3fb701882a544240 [file] [log] [blame]
#include "text-utils.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
int
text_readline(
char **buffer_ptr,
size_t *capacity_ptr,
FILE *stream
)
{
int c;
size_t size = 0;
char *buffer;
size_t capacity;
int error;
/* Ensure the caller passed line and capacity pointers */
if (buffer_ptr == NULL || capacity_ptr == NULL)
return EINVAL;
buffer = *buffer_ptr;
capacity = *capacity_ptr;
do {
text_grow_buffer(&buffer, &capacity, size + 1);
/* Do the IO, read one byte at a time */
c = fgetc(stream);
if (c != EOF && c != '\n') {
buffer[size++] = (char)c;
} else {
buffer[size++] = 0;
break;
}
} while (1);
error = 0;
out:
/* Copy back the line and capacity */
*buffer_ptr = buffer;
*capacity_ptr = capacity;
return error;
}
int
text_copy(
char **buffer_ptr,
size_t *capacity_ptr,
const char *text
)
{
size_t text_len;
int error;
/* Ensure the caller passed line and capacity pointers */
if (buffer_ptr == NULL || capacity_ptr == NULL)
return EINVAL;
if (text == NULL)
return EINVAL;
text_len = strlen(text);
error = text_grow_buffer(buffer_ptr, capacity_ptr, text_len + 1);
if (error != 0)
return error;
strncpy(*buffer_ptr, text, *capacity_ptr);
return 0;
}
/**
* Find a good reallocation size for the current size
**/
static
size_t
next_best_capacity(size_t size) {
const size_t good_sizes[] = {128, 512, 4 * 1024, 16 * 1024};
size_t i;
/* Try to use one of the good sizes */
for (i=0; i<sizeof(good_sizes) / sizeof(*good_sizes); ++i)
if (size < good_sizes[i])
return good_sizes[i];
/* Or just double the current size */
return size * 2;
}
int
text_grow_buffer(
char **buffer_ptr,
size_t *capacity_ptr,
size_t min_capacity
)
{
char *buffer, *new_buffer;
size_t capacity, new_capacity;
/* Ensure the caller passed line and capacity pointers */
if (buffer_ptr == NULL || capacity_ptr == NULL)
return EINVAL;
/* Load current buffer pointer and size */
buffer = *buffer_ptr;
capacity = *capacity_ptr;
/* Keep growing the buffer as required */
while (capacity <= min_capacity) {
new_capacity = next_best_capacity(min_capacity);
debug_log("Resizing text buffer from %zd to %zd bytes\n",
capacity, new_capacity);
new_buffer = realloc(buffer, new_capacity);
if (new_buffer != NULL) {
debug_log("Resize complete, old buffer %p, new buffer %p\n",
buffer, new_buffer);
buffer = new_buffer;
capacity = new_capacity;
} else {
debug_log("Unable to resize line buffer!\n");
return ENOMEM;
}
}
/* Copy back the new buffer pointer and new capacity */
*buffer_ptr = buffer;
*capacity_ptr = capacity;
return 0;
}