#include "stdio_impl.h" | |
#include <string.h> | |
#include <stdlib.h> | |
#include <inttypes.h> | |
#include <errno.h> | |
ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f) | |
{ | |
char *tmp; | |
unsigned char *z; | |
size_t k; | |
size_t i=0; | |
int c; | |
FLOCK(f); | |
if (!n || !s) { | |
f->mode |= f->mode-1; | |
f->flags |= F_ERR; | |
FUNLOCK(f); | |
errno = EINVAL; | |
return -1; | |
} | |
if (!*s) *n=0; | |
for (;;) { | |
if (f->rpos != f->rend) { | |
z = memchr(f->rpos, delim, f->rend - f->rpos); | |
k = z ? z - f->rpos + 1 : f->rend - f->rpos; | |
} else { | |
z = 0; | |
k = 0; | |
} | |
if (i+k >= *n) { | |
size_t m = i+k+2; | |
if (!z && m < SIZE_MAX/4) m += m/2; | |
tmp = realloc(*s, m); | |
if (!tmp) { | |
m = i+k+2; | |
tmp = realloc(*s, m); | |
if (!tmp) { | |
/* Copy as much as fits and ensure no | |
* pushback remains in the FILE buf. */ | |
k = *n-i; | |
memcpy(*s+i, f->rpos, k); | |
f->rpos += k; | |
f->mode |= f->mode-1; | |
f->flags |= F_ERR; | |
FUNLOCK(f); | |
errno = ENOMEM; | |
return -1; | |
} | |
} | |
*s = tmp; | |
*n = m; | |
} | |
if (k) { | |
memcpy(*s+i, f->rpos, k); | |
f->rpos += k; | |
i += k; | |
} | |
if (z) break; | |
if ((c = getc_unlocked(f)) == EOF) { | |
if (!i || !feof(f)) { | |
FUNLOCK(f); | |
return -1; | |
} | |
break; | |
} | |
/* If the byte read by getc won't fit without growing the | |
* output buffer, push it back for next iteration. */ | |
if (i+1 >= *n) *--f->rpos = c; | |
else if (((*s)[i++] = c) == delim) break; | |
} | |
(*s)[i] = 0; | |
FUNLOCK(f); | |
return i; | |
} | |
weak_alias(getdelim, __getdelim); |