Thread: The UNIX System Interface

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    36

    The UNIX System Interface

    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);
    }

  2. #2
    Registered User
    Join Date
    Feb 2009
    Posts
    36
    Here's the macro and suspect function by themselves:
    Code:
    #define putc(x,p) (--(p)->cnt >= 0 						\
                   	  ? *(p)->ptr++ = (x) : _flushbuf((x),p))
    
    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;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Calling IRichEditOle interface methods
    By Niara in forum C Programming
    Replies: 2
    Last Post: 01-16-2009, 01:23 PM
  2. How to get the user ID and group ID from UNIX system
    By dragonfly1801 in forum Linux Programming
    Replies: 6
    Last Post: 11-16-2006, 04:45 AM
  3. Linux Media Player
    By joshdick in forum A Brief History of Cprogramming.com
    Replies: 43
    Last Post: 09-07-2003, 08:08 AM
  4. problem with lseek system call on unix
    By kheinz in forum C Programming
    Replies: 2
    Last Post: 06-03-2003, 12:50 PM
  5. question about open file in unix system
    By wu7up in forum C Programming
    Replies: 6
    Last Post: 03-13-2003, 06:20 AM

Tags for this Thread