Skip to content

Instantly share code, notes, and snippets.

@Druid-of-Luhn
Last active December 18, 2018 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Druid-of-Luhn/d1a85f366ceecfc3c2dc5491e3d25cb4 to your computer and use it in GitHub Desktop.
Save Druid-of-Luhn/d1a85f366ceecfc3c2dc5491e3d25cb4 to your computer and use it in GitHub Desktop.
Portable C function to read a line from a file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 512
size_t next_buffer(const size_t buffer, const size_t count)
{
return (buffer + 1) % count;
}
size_t read_line(FILE *file, char **line)
{
if (file == NULL) {
return 0;
}
size_t buffer_size = BUF_SIZE;
size_t start = 0;
char *buffers[2];
size_t buffer = 0;
size_t next = next_buffer(buffer, sizeof(buffers));
buffers[buffer] = calloc(buffer_size, sizeof(char));
buffers[next_buffer(buffer, sizeof(buffers))] = NULL;
while (1) {
char *result = fgets(buffers[buffer] + start, buffer_size - start, file);
if (result == NULL) {
break;
}
// The line is longer than the buffer
if (buffers[buffer][buffer_size - 2] != 0 && buffers[buffer][buffer_size - 2] != '\n') {
if (buffers[next] != NULL) {
free(buffers[next]);
}
// Allocate the next buffer and copy this buffer's contents into it
buffers[next] = calloc(buffer_size * 2, sizeof(char));
if (!memcpy(buffers[next], buffers[buffer], buffer_size)) {
break;
}
// Swap the buffers around
start = buffer_size - 1;
buffer_size *= 2;
buffer = next;
next = next_buffer(next, sizeof(buffers));
} else {
// The whole line was read
size_t length = strlen(buffers[buffer]) + 1;
// The final \n is replaced by 0, so the length (including 0)
// is decreased by 1
if (buffers[buffer][length - 1] == '\n') {
buffers[buffer][length - 1] = 0;
--length;
}
*line = calloc(length, sizeof(char));
if (memcpy(*line, buffers[buffer], length) == NULL) {
break;
}
// Free the buffers used for reading in the line
if (buffers[buffer] != NULL) {
free(buffers[buffer]);
}
if (buffers[next] != NULL) {
free(buffers[next]);
}
return length - 1;
}
}
// Free the buffers used for reading in the line
if (buffers[buffer] != NULL) {
free(buffers[buffer]);
}
if (buffers[next] != NULL) {
free(buffers[next]);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment