/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> * * GNU Library General Public License (LGPL) version 2 or later. * * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. */ #include "_stdio.h" libc_hidden_proto(getdelim) libc_hidden_proto(__fgetc_unlocked) /* Note: There is a defect in this function. (size_t vs ssize_t). */ /* glibc function -- * Return -1 if error or EOF prior to any chars read. * Return number of chars read (including possible delimiter but not * the terminating nul) otherwise. * * NOTE: If we need to allocate a buffer, we do so prior to attempting * a reading. So space may be allocated even if initially at EOF. */ #define GETDELIM_GROWBY 64 ssize_t getdelim(char **__restrict lineptr, size_t *__restrict n, int delimiter, register FILE *__restrict stream) { register char *buf; ssize_t pos = -1; int c; __STDIO_AUTO_THREADLOCK_VAR; if (!lineptr || !n || !stream) { /* Be compatable with glibc... even */ __set_errno(EINVAL); /* though I think we should assert here */ } else { __STDIO_AUTO_THREADLOCK(stream); if (!(buf = *lineptr)) { /* If passed NULL for buffer, */ *n = 0; /* ignore value passed and treat size as 0. */ } /* Within the loop, pos is actually the current buffer index + 2, * because we want to make sure we have enough space to store * an additional char plus a nul terminator. */ pos = 1; do { if (pos >= *n) { if (!(buf = realloc(buf, *n + GETDELIM_GROWBY))) { pos = -1; break; } *n += GETDELIM_GROWBY; *lineptr = buf; } if ((c = __GETC_UNLOCKED(stream)) != EOF) { buf[++pos - 2] = c; if (c != delimiter) { continue; } } /* We're done, so correct pos back to being the current index. */ if ((pos -= 2) >= 0) { buf[++pos] = 0; } break; } while (1); __STDIO_AUTO_THREADUNLOCK(stream); } return pos; } libc_hidden_def(getdelim)