From 2b68c3d06fb2961ae3797d1ef461cff655f328b2 Mon Sep 17 00:00:00 2001 From: zlg Date: Sun, 9 Jan 2022 16:41:26 -0800 Subject: Refactor syscalls.h for ch8 exercises The refactor includes implementations for fflush and fclose as well, needed in 8-03. --- ch8/syscalls.h | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 ch8/syscalls.h (limited to 'ch8/syscalls.h') diff --git a/ch8/syscalls.h b/ch8/syscalls.h new file mode 100644 index 0000000..ff58db5 --- /dev/null +++ b/ch8/syscalls.h @@ -0,0 +1,222 @@ +/* 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') { + 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; + } + 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) { + return NULL; + } + fp->fd = fd; + fp->cnt = 0; + if (*mode == 'r') { + fp->flags._READ = 1; + } else { + 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; +} -- cgit v1.2.3-54-g00ecf