diff options
author | zlg <zlg@zlg.space> | 2022-01-09 16:41:26 -0800 |
---|---|---|
committer | zlg <zlg@zlg.space> | 2022-01-09 16:41:26 -0800 |
commit | 2b68c3d06fb2961ae3797d1ef461cff655f328b2 (patch) | |
tree | 8731595b523ec3dcad0e9a70992de5f0a4a95a01 /ch8 | |
parent | Solve Exercise 8-2: fopen and fillbuf (diff) | |
download | knr-2b68c3d06fb2961ae3797d1ef461cff655f328b2.tar.gz knr-2b68c3d06fb2961ae3797d1ef461cff655f328b2.tar.bz2 knr-2b68c3d06fb2961ae3797d1ef461cff655f328b2.tar.xz knr-2b68c3d06fb2961ae3797d1ef461cff655f328b2.zip |
Refactor syscalls.h for ch8 exercises
The refactor includes implementations for fflush and fclose as well,
needed in 8-03.
Diffstat (limited to 'ch8')
-rw-r--r-- | ch8/8-02_fopen-and-fillbuf.c | 82 | ||||
-rw-r--r-- | ch8/8-02_syscalls.h | 47 | ||||
-rw-r--r-- | ch8/syscalls.h | 222 |
3 files changed, 234 insertions, 117 deletions
diff --git a/ch8/8-02_fopen-and-fillbuf.c b/ch8/8-02_fopen-and-fillbuf.c index e533da8..66d7336 100644 --- a/ch8/8-02_fopen-and-fillbuf.c +++ b/ch8/8-02_fopen-and-fillbuf.c @@ -1,8 +1,9 @@ +#include <errno.h> +#include <string.h> #include <fcntl.h> -#include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include "8-02_syscalls.h" +#include "syscalls.h" /* The C Programming Language: 2nd Edition * @@ -14,76 +15,14 @@ * * The resulting binary of this file (plus the custom header) runs through this * source file in about 0.001s. However, the binary is 1KB larger. + * + * Some subsequent exercises use the same syscalls.h file created for this + * exercise. For this reason, the file only refers to its chapter and not + * specific exercises. */ -#define PERMS 0666 - -int getc(FILE *); - -int my__fillbuf(my_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++; -} - -my_FILE * my_fopen(char *name, char *mode) { - int fd; - my_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 main() { - my_FILE *fp = my_fopen("8-02_fopen-and-fillbuf.c", "r"); + FILE *fp = fopen("8-02_fopen-and-fillbuf.c", "r"); if (fp != NULL) { puts("We could read the file.\n"); /* pro tip: don't declare this as 'unsigned' or you'll create an @@ -91,9 +30,12 @@ int main() { * half an hour on a newbie mistake like I did. :) */ char c; - while ((c = my_getc(fp)) != EOF) { + while ((c = getc(fp)) != EOF) { putchar(c); } + /* fclose calls fflush */ + fclose(fp); + fclose(stdout); } else { puts("Could not open file for reading."); } diff --git a/ch8/8-02_syscalls.h b/ch8/8-02_syscalls.h deleted file mode 100644 index 728c5af..0000000 --- a/ch8/8-02_syscalls.h +++ /dev/null @@ -1,47 +0,0 @@ -/* 8-02_syscalls.h - * - * A simpler stdio.h to aid in exercises 8-2 - */ - -long lseek(int fd, long offset, int origin); - -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; -} my_FILE; - -my_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 feof(p) (((p)->flags._EOF) != 0) -#define ferror(p) (((p)->flags._ERR) != 0) -#define fileno(p) ((p)->fd) -#define my_getc(p) (--(p)->cnt >= 0 ? (unsigned char) *(p)->ptr++ : my__fillbuf(p)) -#define getchar() getc(stdin) - -int my_fempty(struct _flags flags) { - if (!flags._READ && !flags._WRITE && !flags._UNBUF && !flags._EOF && !flags._ERR) { - return 1; - } else { - return 0; - } -} - -int my_fclose(my_FILE*); 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; +} |