X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fstdio%2Fgetdelim.c;h=df114441c72562a8bfd39e6e1fb3f4687d6715e9;hb=1d5750b95c06913a1f18a995481276d698d20fae;hp=26093a6cfa02a358c1a50e6e59ac618d8920d86e;hpb=c6d441e3a246370d9c459396ec22b096db93850e;p=musl diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c index 26093a6c..df114441 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; @@ -13,33 +12,54 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric 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; - FLOCK(f); - for (;;) { - z = memchr(f->rpos, delim, f->rend - f->rpos); - k = z ? z - f->rpos + 1 : f->rend - f->rpos; + 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) { - if (k >= SIZE_MAX/2-i) goto oom; - *n = i+k+2; - if (*n < SIZE_MAX/4) *n *= 2; - tmp = realloc(*s, *n); + size_t m = i+k+2; + if (!z && m < SIZE_MAX/4) m += m/2; + tmp = realloc(*s, m); if (!tmp) { - *n = i+k+2; - tmp = realloc(*s, *n); - if (!tmp) goto oom; + 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; } - memcpy(*s+i, f->rpos, k); - f->rpos += k; - i += k; if (z) break; if ((c = getc_unlocked(f)) == EOF) { if (!i || !feof(f)) { @@ -48,17 +68,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: - FUNLOCK(f); - errno = ENOMEM; - return -1; } weak_alias(getdelim, __getdelim);