Last active
December 18, 2018 09:12
-
-
Save Druid-of-Luhn/d1a85f366ceecfc3c2dc5491e3d25cb4 to your computer and use it in GitHub Desktop.
Portable C function to read a line from a file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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