I need some help with Exercise 8-3 in The C Programming Language. Basically these first exercises in chapter 8 are dealing with making our own i/o header so we can learn about system calls. Everything is going ok except for my function _flushbuf.

It seems to only be printing from the buffer once and then fails to reuse it after it's been flushed. At least I think that's whats happening. I wrote a small test program to test my header and it should print more than 1024 bytes which is the size of my buffer. I manually counted the output and it stops at 1021. I just can't figure it out.

I'd appreciate any help you guys can give me.

Header:
Code:
/* Exercise 8-3. Design and write _flushbuf, fflush, and fclose. */


#define NULL      0
#define EOF       (-1)
#define BUFSIZ    1024
#define OPEN_MAX  20    /* max #files open at once */

typedef struct _iobuf
{
    int cnt;        /* characters left */
    char *ptr;      /* next character position */
    char *base;     /* location of buffer */
    int flag;       /* mode of file access */
    int fd;         /* file descriptor */
} FILE_;

FILE_ _iob[OPEN_MAX];

#define stdin   (&_iob[0])
#define stdout  (&_iob[1])
#define stderr  (&_iob[2])

enum _flags
{
    _READ   = 01,   /* file open for reading */
    _WRITE  = 02,   /* file open for writing */
    _UNBUF  = 04,   /* file is unbuffered */
    _EOF    = 010,  /* EOF has occurred on this file */
    _ERR    = 020   /* error occurred on this file */
};

FILE_ *_fopen(char *, char *);
int _fillbuf(FILE_ *);
int _flushbuf(int, FILE_ *);
int _fflush(FILE_ *);
int _fclose(FILE_ *);

#define feof(p)     ((p)->flag & _EOF) != 0)
#define ferror(p)   ((p)->flag & _ERR) != 0)
#define fileno(p)   ((p)->fd)

#define getc(p)   (--(p)->cnt >= 0                             \
                     ? (unsigned char) *(p)->ptr++ : _fillbuf(p))
#define putc(x,p) (--(p)->cnt >= 0                         \
                     ? *(p)->ptr++ = (x) : _flushbuf((x),p))

#define getchar()   getc(stdin)
#define putcher(x) putc((x), stdout)

#include <fcntl.h>

#define PERMS 0666    /* RW for owner, group, others */

FILE_ *_fopen(char *name, char *mode)
{
    int fd;
    FILE_ *fp;

    if (*mode != 'r' && *mode != 'w' && *mode != 'a')
        return NULL;

    for (fp = _iob; fp < _iob + OPEN_MAX; fp++)
        if ((fp->flag & (_READ | _WRITE)) == 0)
            break;        /* found free slot */

    if (fp >= _iob + OPEN_MAX)   /* no free slots */
        return NULL;
    if (*mode == 'w')
        fd = creat(name, PERMS);
    else if (*mode == 'a')
    {
        if ((fd = open(name, O_WRONLY, 0)) == -1)
            fd = creat(name, PERMS);
        lseek(fd, 0L, 2);
    }
    else
        fd = open(name, O_RDONLY, 0);
    if (fd == -1)         /* couldn't access name */
        return NULL;
    fp->fd = fd;
    fp->cnt = 0;
    fp->base = NULL;
    fp->flag = (*mode == 'r') ? _READ : _WRITE;
    return fp;
}

#include <stdlib.h>

/* _fillbuf: allocate and fill input buffer */
int _fillbuf(FILE_ *fp)
{
    int bufsize;

    if ((fp->flag&(_READ|_EOF|_ERR)) != _READ)
        return EOF;
    bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ;
    if (fp->base == NULL)     /* no buffer yet */
        if ((fp->base = (char *) malloc(bufsize)) == NULL)
            return EOF;       /* can't get buffer */
    fp->ptr = fp->base;
    fp->cnt = read(fp->fd, fp->ptr, bufsize);
    if (--fp->cnt < 0)
    {
        if (fp->cnt == -1)
            fp->flag |= _EOF;
        else
            fp->flag |= _ERR;
        fp->cnt = 0;
        return EOF;
    }

    return (unsigned char) *fp->ptr++;
}

int _flushbuf(int c, FILE_ *fp)
{
    int bufsize;

    unsigned char uc = c;

    if (fp->flag & (_WRITE | _EOF | _ERR) != _WRITE)
        return EOF;
    bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ;
    if (fp->base == NULL)
        if ((fp->base = (char *) malloc(bufsize)) == NULL)
            return EOF;
    if (bufsize == BUFSIZ && fp->ptr != 0)
    {
        if (write(fp->fd, fp->base, BUFSIZ) != BUFSIZ)
            return EOF;
    }
    else if (fp->ptr != 0)
        if (write(fp->fd, fp->base, 1) != 1)
            return EOF;
    fp->ptr = fp->base;
    *fp->ptr++ = uc;
    fp->cnt = BUFSIZ-1;
    return uc;
}

int _fflush(FILE_ *fp)
{
    int strm;

    if (fp->flag & (_WRITE | _EOF | _ERR) != _WRITE)
        return EOF;
    if (fp == NULL)
        for (strm = 0; _iob[strm].flag != 0; ++strm)
            if (write(fp->fd, fp->ptr, (fp->ptr-fp->base)) != fp->cnt)
                return EOF;
    else
        if (write(fp->fd, fp->ptr, (fp->ptr-fp->base)) != fp->cnt)
            return EOF;
    return 0;
}

int _fclose(FILE_ *fp)
{

    if (fp->flag & _ERR)
        return EOF;
    if (fp->flag & _WRITE)
        fflush(fp);
    free(fp->base);
    close(fp->fd);
    return 0;
}

FILE_ _iob[OPEN_MAX] =    {    /* stdin, stdout, stderr */
                            { 0, (char *) 0, (char *) 0, _READ, 0 },
                            { 0, (char *) 0, (char *) 0, _WRITE, 1 },
                            { 0, (char *) 0, (char *) 0, _WRITE | _UNBUF, 2 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 },
                            { 0, (char *) 0, (char *) 0, 0, 0 }
                        };
Test program:
Code:
/* Exercise 8-3. Design and write _flushbuf, fflush, and fclose. */

#include "exercise.8-3.h"

/* cat:  concatenate files, version 1 */
main(int argc, char *argv[])
{
    FILE_ *fp;
    void filecopy(FILE_ *, FILE_ *);

    if (argc == 1) /* no args; copy standard input */
        filecopy(stdin, stdout);
    else
       while(--argc > 0)
           if ((fp = _fopen(*++argv, "r")) == NULL)
           {
               putc('X', stderr);
               return 1;
           }
           else
           {
              filecopy(fp, stdout);
              _fclose(fp);
           }
    return 0;
}

/* filecopy: copy file ifp to file ofp */
void filecopy(FILE_ *ifp, FILE_ *ofp)
{
    int c;

    while ((c = getc(ifp)) != EOF)
        putc(c, ofp);
}