#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#define MAXLINE 4096


/* The first two functions are helper functions for the third which is
 * the function to be exported 
 */


/* Wrap the read system call with the necessary error handling, and 
 * buffer management.
 */
static ssize_t
my_read(int fd, char *ptr)
{
    static int	read_cnt = 0;
    static char	*read_ptr;
    static char	read_buf[MAXLINE];
    
    if (read_cnt <= 0) {
    again:
	if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
	    if (errno == EINTR)
		goto again;
	    return(-1);
	} else if (read_cnt == 0)
	    return(0);
	read_ptr = read_buf;
    }
    
    read_cnt--;
    *ptr = *read_ptr++;
    return(1);
}

/* Read from file descriptor fd into the memory location referred to by vptr, 
 * until a newline character is seen, or we have read maxlen characters.
 * Returns 0 if there was nothing to read, the number of characters read if 
 * successfull, or -1 if an error was encountered.
 */
ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
    int		n, rc;
    char	c, *ptr;
    
    ptr = vptr;
    for (n = 1; n < maxlen; n++) {
	if ( (rc = my_read(fd, &c)) == 1) {
	    *ptr++ = c;
	    if (c == '\n')
		break;	/* newline is stored, like fgets() */
	} else if (rc == 0) {
	    if (n == 1)
		return(0);	/* EOF, no data read */
	    else
		break;		/* EOF, some data was read */
	} else
	    return(-1);		/* error, errno set by read() */
    }
    
    *ptr = 0;	/* null terminate like fgets() */
    return(n);
}


/* A public wrapper for readline which prints an error message if readline
 * fails.
 */
ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
    ssize_t n;
    
    if ( (n = readline(fd, ptr, maxlen)) < 0)
	perror("readline error");
    return(n);
}
