Hi Ken,

> > I think that buf may only be len long on occasion when the NUL is
> > added.
>
> So could we get a Ralph-ified version?  I think the necessary
> configure glue should be straightforward, but someone else will have
> to test it.  I'd be glad to commit it, though.

I've written a getline(3) from scratch based on
https://manned.org/getdelim.3p and am happy for it to have whatever
licence nmh needs.  I've assumed POSIX, e.g. stdbool.h, SSIZE_MAX, etc.,
so it may need some conditional preprocessor bits for portability to
older systems.

It's quite a fun problem because it's a bit of a "loop and a half" where
you don't want more input, but need to produce a bit more output.  One
can spend ages re-arranging the deckchairs, but I finally went with the
attached.

-- 
Cheers, Ralph.
https://plus.google.com/+RalphCorderoy
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
#include <errno.h>

/* Largest possible size of buffer that allows SSIZE_MAX to be returned
 * to indicate SSIZE_MAX - 1 characters read before the '\n'.  The
 * additional 1 is for the terminating NUL. */
#define MAX_AVAIL ((size_t)SSIZE_MAX + 1)

/* Ideal increase in size of line buffer. */
#define GROWTH 128

ssize_t getline(char **lineptr, size_t *n, FILE *stream)
{
    char *l;
    size_t avail;
    size_t used;
    int c;
    bool last;

    if (!lineptr || !n) {
        errno = EINVAL;
        return -1;
    }

    l = *lineptr;
    if (l)
        avail = *n <= MAX_AVAIL ? *n : MAX_AVAIL;
    else
        avail = *n = 0; /* POSIX allows *lineptr = NULL, *n = 42. */
    used = 0;
    last = false;
    for (;;) {
        c = getc(stream);
        if (c == EOF) {
            if (ferror(stream) || /* errno set by stdlib. */
                !used)            /* EOF with nothing read. */
                return -1;
            /* Line will be returned without a \n terminator. */
append_nul:
            c = '\0';
            last = true;
        }

        if (used == avail) {
            size_t want;
            char *new;

            if (avail == MAX_AVAIL) {
                errno = EOVERFLOW;
                return -1;
            }
            want = avail + GROWTH;
            if (want > MAX_AVAIL)
                want = MAX_AVAIL;
            new = realloc(l, want);
            if (!new)
                return -1; /* errno set by stdlib. */
            l = *lineptr = new;
            avail = *n = want;
        }
        l[used++] = c;

        if (last)
            return used - 1; /* Don't include NUL. */

        if (c == '\n')
            goto append_nul; /* Final half loop. */
    }
}
_______________________________________________
Nmh-workers mailing list
Nmh-workers@nongnu.org
https://lists.nongnu.org/mailman/listinfo/nmh-workers

Reply via email to