X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fstdio%2Fgetdelim.c;h=d2f5b15ab1d7da3d693bcf5d9d4652ec89d4e858;hb=54316a52b2119edf73e274c8b4f25d7757f7b4d3;hp=813b09fcfbc2b91b991158b3721160464b5e411f;hpb=d87f0a9a95f0a1228ee5579e5822a8c93bc96823;p=musl diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c index 813b09fc..d2f5b15a 100644 --- a/src/stdio/getdelim.c +++ b/src/stdio/getdelim.c @@ -1,10 +1,9 @@ #include "stdio_impl.h" #include +#include #include #include -#define MIN(a,b) ((a)<(b) ? (a) : (b)) - ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f) { char *tmp; @@ -16,6 +15,7 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric FLOCK(f); if (!n || !s) { + f->mode |= f->mode-1; f->flags |= F_ERR; FUNLOCK(f); errno = EINVAL; @@ -25,17 +25,32 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric if (!*s) *n=0; for (;;) { - z = memchr(f->rpos, delim, f->rend - f->rpos); - k = z ? z - f->rpos + 1 : f->rend - f->rpos; - if (i+k+1 >= *n) { - if (k >= SIZE_MAX/2-i) goto oom; + 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 (m < SIZE_MAX/4) m *= 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) goto oom; + 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; @@ -51,18 +66,16 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric } break; } - if (((*s)[i++] = c) == delim) 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; -oom: - f->flags |= F_ERR; - FUNLOCK(f); - errno = ENOMEM; - return -1; } weak_alias(getdelim, __getdelim);