/* syscalls.h * * A simpler stdio.h to aid in exercises within chapter 8 */ /* Declarations */ int puts(char *); long lseek(int fd, long offset, int origin); /* workarounds for GNU/Linux */ #undef NULL #define PERMS 0666 #define NULL 0 #define EOF (-1) #define BUFSIZ 100 #define FOPEN_MAX 20 struct _flags { unsigned int _READ : 1; unsigned int _WRITE : 1; unsigned int _UNBUF : 1; unsigned int _EOF : 1; unsigned int _ERR : 1; } flags; typedef struct _iobuf { int cnt; char *ptr; char *base; struct _flags flags; int fd; } FILE; FILE _iob[FOPEN_MAX] = { /* stdin is read-only */ { 0, (char *) 0, (char *) 0, {1, 0, 0, 0, 0}, 0 }, /* stdout is write only */ { 0, (char *) 0, (char *) 0, {0, 1, 0, 0, 0}, 1 }, /* stderr is written AND not buffered */ { 0, (char *) 0, (char *) 0, {0, 1, 1, 0, 0}, 2 } }; #define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2]) #define feof(p) (((p)->flags._EOF) != 0) #define ferror(p) (((p)->flags._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 putchar(x) putc((x), stdout) int fempty(struct _flags flags) { if (!flags._READ && !flags._WRITE && !flags._UNBUF && !flags._EOF && !flags._ERR) { return 1; } else { return 0; } } FILE * fopen(char *name, char *mode) { int fd; FILE *fp; if (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != '+') { return NULL; } for (fp = _iob; fp < _iob + FOPEN_MAX; fp++) { if (fp->flags._READ == 0 && fp->flags._WRITE == 0) { break; } } if (fp >= _iob + FOPEN_MAX) { return NULL; } switch (*mode) { case '+': if ((fd = open(name, O_RDWR, 0)) == -1) { fd = creat(name, PERMS); } break; case 'w': fd = creat(name, PERMS); break; case 'a': if ((fd = open(name, O_WRONLY, 0)) == -1) { fd = creat(name, PERMS); } lseek(fd, 0L, 2); break; default: fd = open(name, O_RDONLY, 0); } if (fd == -1) { return NULL; } fp->fd = fd; fp->cnt = 0; fp->flags._EOF = 0; if (*mode == 'r' || *mode == '+') { fp->flags._READ = 1; } if (*mode == 'w' || *mode == '+' || *mode == 'a') { fp->flags._WRITE = 1; } return fp; } /* int _fillbuf(FILE *); */ int _fillbuf(FILE *fp) { int bufsize; if (fp->flags._READ == 0) { return EOF; } bufsize = (fp->flags._UNBUF != 0) ? 1 : BUFSIZ; if (fp->base == NULL) { if ((fp->base = (char *) calloc(bufsize, sizeof (char))) == NULL) { return EOF; } } fp->ptr = fp->base; fp->cnt = read(fp->fd, fp->ptr, bufsize); if (--(fp)->cnt < 0) { if (fp->cnt == -1) { fp->flags._EOF = 1; } else { fp->flags._ERR = 1; } fp->cnt = 0; return EOF; } return (unsigned char) *fp->ptr++; } int _cleanbuf(FILE *fp) { int bufsize = (fp->flags._UNBUF != 0) ? 1 : BUFSIZ; if (fp->base != NULL) { free(fp->base); } fp->base = (char *) calloc(bufsize, sizeof (char)); if (fp->base == NULL) { return EOF; } return 0; } /* * write the buffer's contents to the file and reset the buffer * * Returns 0 on success, EOF on errors, with errno set. */ int _flushbuf(char c, FILE *fp) { int bufsize = (fp->flags._UNBUF != 0) ? 1 : BUFSIZ; if (fp->base == NULL) { if (_cleanbuf(fp) != 0) { errno = ENOMEM; return EOF; } } if (fp->flags._WRITE == 0) { errno = EBADF; return EOF; } int written = write(fp->fd, fp->base, bufsize); if (errno > 0) { fp->flags._ERR = 1; strerror(errno); return EOF; } if (_cleanbuf(fp) != 0) { errno = ENOMEM; return EOF; } fp->ptr = fp->base; fp->cnt = bufsize; if (c != NULL) { putc(c,fp); } return 0; } int fflush(FILE *fp) { if (fp == NULL) { int i; for (i=0; i < FOPEN_MAX; i++) { /* maybe check flags and buffers? */ if (fp->flags._WRITE == 1) { if (_flushbuf(NULL, &_iob[i]) == EOF) { strerror(errno); } } } return 0; } if (fp->flags._WRITE == 1) { if (_flushbuf(NULL, fp) == EOF) { strerror(errno); } } return 0; } int fclose(FILE *fp) { struct _flags f = {0,0,0,0,0}; if (fp->flags._WRITE == 1) { fflush(fp); } if (fp->base != NULL) { free(fp->base); fp->base = NULL; fp->ptr = NULL; } fp->cnt = 0; fp->flags = f; close(fp->fd); fp->fd = -1; return 0; } int puts(char *s) { int i; for (i=0; s[i] != '\0' && s[i] != EOF; i++) { putchar(s[i]); } putchar('\n'); return i; } /* Set the 'cursor' position within a file for read or write operations * Returns 0 on success, EOF on error, with errno set. */ int fseek(FILE *fp, long offset, int origin) { long pos; if ((pos = lseek(fp->fd, offset, origin)) == EOF) { return EOF; } _fillbuf(fp); lseek(fp->fd, offset, origin); return 0; }