From bfd18a52e1baa4da7040b8df04a3f29e83b0d6b6 Mon Sep 17 00:00:00 2001 From: zlg Date: Sun, 9 Jan 2022 20:18:52 -0800 Subject: Solve Exercise 8-4: fseek() implementation --- ch8/8-04_fseek.c | 34 ++++++++++++++++++++++++++++++++++ ch8/syscalls.h | 45 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 ch8/8-04_fseek.c diff --git a/ch8/8-04_fseek.c b/ch8/8-04_fseek.c new file mode 100644 index 0000000..b968ca2 --- /dev/null +++ b/ch8/8-04_fseek.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include "syscalls.h" +/* The C Programming Language: 2nd Edition + * + * Exercise 8-4: The standard library function + * + * int fseek(FILE *fp, long offset, int origin) + * + * is identical to `lseek` except that `fp` is a file pointer instead of a file + * descriptor and the return value is an `int` status, not a position. Write + * `fseek`. Make sure that your `fseek` coordinates properly with the buffering + * done for the other functions of the library. + * + * Notes: Page 174 covers lseek, where it describes fseek's return value as 0 + * for success and non-zero for errors. + */ + +int main() { + FILE *fp = fopen("8-04_fseek.c", "r"); + if (fp == NULL) { + exit(1); + } + fseek(fp, -34L, 2); + puts(fp->base); + fflush(stdout); + fclose(fp); + return 0; +} + +/* If you see this, 8-4 works! */ diff --git a/ch8/syscalls.h b/ch8/syscalls.h index ff58db5..cda913f 100644 --- a/ch8/syscalls.h +++ b/ch8/syscalls.h @@ -66,7 +66,7 @@ int fempty(struct _flags flags) { FILE * fopen(char *name, char *mode) { int fd; FILE *fp; - if (*mode != 'r' && *mode != 'w' && *mode != 'a') { + if (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != '+') { return NULL; } for (fp = _iob; fp < _iob + FOPEN_MAX; fp++) { @@ -77,24 +77,34 @@ FILE * fopen(char *name, char *mode) { 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) { + switch (*mode) { + case '+': + if ((fd = open(name, O_RDWR, 0)) == -1) { + fd = creat(name, PERMS); + } + break; + case 'w': fd = creat(name, PERMS); - } - lseek(fd, 0L, 2); - } else { - fd = open(name, O_RDONLY, 0); + 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; - if (*mode == 'r') { + fp->flags._EOF = 0; + if (*mode == 'r' || *mode == '+') { fp->flags._READ = 1; - } else { + } + if (*mode == 'w' || *mode == '+' || *mode == 'a') { fp->flags._WRITE = 1; } return fp; @@ -220,3 +230,16 @@ int puts(char *s) { 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; +} -- cgit v1.2.3-54-g00ecf