This is meant to be a drop in replacement for getline as it's not crossplatform. I am trying to do as minimal work as possible in here including only calling strlen once at the very end to calculate the size of the final block.
returns -1 for error, 0 for EOF, 1 for success
The way it works it by setting the last two bytes in the array as [0, 1]
and if the buffer is filled it will look like [X,0]
, X
being either LF
where we are done, or something else meaning we need to realloc and loop again unless we are at eof.
int
fgets_line(char **line, size_t *capacity, size_t *length, FILE *stream) {
if (!*line && !(*line = malloc(*capacity = 64)))
return *capacity = 0, -1;
(*line)[0] = 0;
if (length)
*length = 0;
char *position = *line;
while (1) {
(*line)[*capacity - 1] = 1;
(*line)[*capacity - 2] = 0;
if (fgets(position, *line + *capacity - position, stream)) {
if ((*line)[*capacity - 1] == 0
&& (*line)[*capacity - 2] != '\n') {
size_t new_capacity = *capacity * 2;
char *tmp = realloc(*line, new_capacity);
if (tmp) {
position = tmp + *capacity - 1;
*line = tmp;
*capacity = new_capacity;
} else return -1;
} else goto success;
} else if (position != *line) {
if (feof(stream))
goto success;
return -1;
} else return 0;
}
success:
if (length)
*length = position - *line + strlen(position);
return 1;
}
usage is similar to getline
int main() {
char *line = NULL;
size_t capacity = 0, length = 0;
int result = 0;
while ((result = fgets_line(&line, &capacity, &length, stdin)))
printf("---Capacity: %-8zuLength: %-8zu---\n%s------\n", capacity, length, line);
}