aboutsummaryrefslogtreecommitdiff
path: root/ch8
diff options
context:
space:
mode:
authorzlg <zlg@zlg.space>2022-01-09 20:18:52 -0800
committerzlg <zlg@zlg.space>2022-01-09 20:18:52 -0800
commitbfd18a52e1baa4da7040b8df04a3f29e83b0d6b6 (patch)
tree37cd17530ef47fff106c0a30fb26fe70cca429d8 /ch8
parentSolve exercise 8-3: fflush and fclose (diff)
downloadknr-bfd18a52e1baa4da7040b8df04a3f29e83b0d6b6.tar.gz
knr-bfd18a52e1baa4da7040b8df04a3f29e83b0d6b6.tar.bz2
knr-bfd18a52e1baa4da7040b8df04a3f29e83b0d6b6.tar.xz
knr-bfd18a52e1baa4da7040b8df04a3f29e83b0d6b6.zip
Solve Exercise 8-4: fseek() implementation
Diffstat (limited to 'ch8')
-rw-r--r--ch8/8-04_fseek.c34
-rw-r--r--ch8/syscalls.h45
2 files changed, 68 insertions, 11 deletions
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 <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#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;
+}