From 593a95de0133deeb66b4073e57c018622d6495a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20-rsm-=20Marek?= <rsm@disroot.org> Date: Tue, 6 Aug 2024 02:40:01 +0200 Subject: [PATCH] Exerc 8_3. --- .../8_3.flush_cat/Makefile | 3 + .../8_3.flush_cat/knr_io.c | 139 ++++++++++++++++++ .../8_3.flush_cat/knr_io.h | 44 ++++++ chapter_8.unix_interface/8_3.flush_cat/main.c | 26 ++++ .../8_3.flush_cat/tests/0_usage_info.tin | 0 .../8_3.flush_cat/tests/0_usage_info.tout | 1 + .../8_3.flush_cat/tests/1_err_file_open.targs | 1 + .../8_3.flush_cat/tests/1_err_file_open.terr | 1 + .../8_3.flush_cat/tests/1_err_file_open.tin | 0 .../8_3.flush_cat/tests/1_err_file_open.tout | 0 .../8_3.flush_cat/tests/2_file.c | 24 +++ .../8_3.flush_cat/tests/2_one.targs | 1 + .../8_3.flush_cat/tests/2_one.tin | 0 .../8_3.flush_cat/tests/2_one.tout | 24 +++ .../8_3.flush_cat/tests/3_file0.c | 24 +++ .../8_3.flush_cat/tests/3_file1.c | 86 +++++++++++ .../8_3.flush_cat/tests/3_file2.mk | 3 + .../8_3.flush_cat/tests/3_many.targs | 1 + .../8_3.flush_cat/tests/3_many.tin | 0 .../8_3.flush_cat/tests/3_many.tout | 113 ++++++++++++++ 20 files changed, 491 insertions(+) create mode 100644 chapter_8.unix_interface/8_3.flush_cat/Makefile create mode 100644 chapter_8.unix_interface/8_3.flush_cat/knr_io.c create mode 100644 chapter_8.unix_interface/8_3.flush_cat/knr_io.h create mode 100644 chapter_8.unix_interface/8_3.flush_cat/main.c create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tin create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tout create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.targs create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.terr create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.tin create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.tout create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/2_file.c create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/2_one.targs create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tin create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tout create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/3_file0.c create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/3_file1.c create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/3_file2.mk create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/3_many.targs create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tin create mode 100644 chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tout diff --git a/chapter_8.unix_interface/8_3.flush_cat/Makefile b/chapter_8.unix_interface/8_3.flush_cat/Makefile new file mode 100644 index 0000000..c61f224 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/Makefile @@ -0,0 +1,3 @@ +BINARY=flush_cat + +include ../../Exercise.mk diff --git a/chapter_8.unix_interface/8_3.flush_cat/knr_io.c b/chapter_8.unix_interface/8_3.flush_cat/knr_io.c new file mode 100644 index 0000000..3d68a71 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/knr_io.c @@ -0,0 +1,139 @@ +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <fcntl.h> +# include "knr_io.h" + +enum knr_flags { + KNR_FREAD = 01, /* file open for reading */ + KNR_FWRITE = 02, /* file open for writing */ + KNR_FUNBUF = 04, /* file is unbuffered */ + KNR_FEOF = 010, /* EOF has occurred on this file */ + KNR_FERR = 020, /* error occurred on this file */ + KNR_FWL = 030 /* wrote less then buffer size */ +}; + +KNR_FILE knr_iob[KNR_OPEN_MAX] = { /* stdin, stdout, stderr */ + { 0, (char *) 0, (char *) 0, KNR_FREAD, 0 }, + { 0, (char *) 0, (char *) 0, KNR_FWRITE, 1 }, + { 0, (char *) 0, (char *) 0, KNR_FWRITE | KNR_FUNBUF, 2 } +}; + +/* knr_fopen: open file, return KNR_FILE* on success, KNR_NULL on error */ +KNR_FILE *knr_fopen (char *name, char *mode) +{ + int fd; + KNR_FILE *fp; + + if (*mode != 'r' && *mode != 'w' && *mode != 'a') + return KNR_NULL; + for (fp = knr_iob; fp < knr_iob + KNR_OPEN_MAX; fp++) + if ((fp->flag & (KNR_FREAD | KNR_FWRITE)) == 0) + break; /* found free slot */ + if (fp >= knr_iob + KNR_OPEN_MAX) /* no free slots */ + return KNR_NULL; + + if (*mode == 'w') + fd = creat(name, KNR_PERMS); + else if (*mode == 'a') { + if ((fd = open(name, O_WRONLY, 0)) == -1) + fd = creat(name, KNR_PERMS); + lseek(fd, 0L, 2); + } else + fd = open(name, O_RDONLY, 0); + if (fd == -1) /* couldn't access name */ + return KNR_NULL; + fp->fd = fd; + fp->cnt = 0; + fp->base = KNR_NULL; + fp->flag = (*mode == 'r') ? KNR_FREAD : KNR_FWRITE; + return fp; +} + +/* knr_fillbuf: allocate and fill input buffer */ +int knr_fillbuf (KNR_FILE *fp) +{ + int bufsize; + + if ((fp->flag & (KNR_FREAD | KNR_FEOF | KNR_FERR)) != KNR_FREAD) + return KNR_EOF; + bufsize = (fp->flag & KNR_FUNBUF) ? 1 : KNR_BUFSIZ; + if (fp->base == KNR_NULL) /* no buffer yet */ + if ((fp->base = (char*) malloc(bufsize)) == NULL) + return KNR_EOF; /* can't get buffer */ + fp->ptr = fp->base; + fp->cnt = read(fp->fd, fp->ptr, bufsize); + if (--fp->cnt < 0) { + if (fp->cnt == -1) + fp->flag |= KNR_FEOF; + else + fp->flag |= KNR_FERR; + fp->cnt = 0; + return KNR_EOF; + } + return (unsigned char) *fp->ptr++; +} + +/* knr_flushbuf: flush output buffer, store c, return c on success, KNR_FWL on error */ +int knr_flushbuf (int c, KNR_FILE *fp) +{ + int bufsize; + + if ((fp->flag & (KNR_FWRITE | KNR_FEOF | KNR_FERR)) != KNR_FWRITE) + return KNR_FWL; + bufsize = (fp->flag & KNR_FUNBUF) ? 1 : KNR_BUFSIZ; + if (fp->base == KNR_NULL) { /* no buffer yet */ + if ((fp->base = (char*) malloc(bufsize)) == NULL) + return KNR_FWL; + } + else { + fp->cnt = write(fp->fd, fp->base, fp->ptr - fp->base); + if (fp->cnt < fp->ptr - fp->base) { + if (fp->cnt == -1) + fp->flag |= KNR_FWL; + fp->flag |= KNR_FERR; + return KNR_FWL; + } + } + fp->cnt = bufsize; + fp->ptr = fp->base; + fp->cnt -= 1; + return *fp->ptr++ = c; +} + +/* knr_fflush: flush output buffer, return 0 on success, KNR_FWL on error */ +int knr_fflush (KNR_FILE *fp) +{ + int bufsize; + + if ((fp->flag & (KNR_FWRITE | KNR_FEOF | KNR_FERR)) != KNR_FWRITE) + return KNR_FWL; + bufsize = (fp->flag & KNR_FUNBUF) ? 1 : KNR_BUFSIZ; + if (fp->base == KNR_NULL) /* no buffer yet */ + return KNR_FWL; + else { + fp->cnt = write(fp->fd, fp->base, fp->ptr - fp->base); + if (fp->cnt < fp->ptr - fp->base) { + if (fp->cnt == -1) + fp->flag |= KNR_FWL; + fp->flag |= KNR_FERR; + return KNR_FWL; + } + } + fp->cnt = bufsize; + fp->ptr = fp->base; + return 0; +} + +/* knr_fclose: close a stream, return 0 on success, KNR_EOF on error */ +int knr_fclose (KNR_FILE *fp) +{ + if ((fp->flag & (KNR_FWRITE | KNR_FEOF | KNR_FERR)) == KNR_FWRITE) + if (knr_fflush(fp) != 0) + return KNR_EOF; + if (close(fp->fd) == -1) + return KNR_EOF; + free(fp->base); + fp->flag = 0; + return 0; +} diff --git a/chapter_8.unix_interface/8_3.flush_cat/knr_io.h b/chapter_8.unix_interface/8_3.flush_cat/knr_io.h new file mode 100644 index 0000000..3f83bbe --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/knr_io.h @@ -0,0 +1,44 @@ +# ifndef KNR_IO_H +# define KNR_IO_H + +# define KNR_PERMS 0666 /* RW for owner, group, others */ + +# define KNR_NULL 0 +# define KNR_EOF (-1) +# define KNR_BUFSIZ 128 +# define KNR_OPEN_MAX 20 /* max #files open at once */ + +typedef struct knr_iobuf { + int cnt; /* characters left */ + char *ptr; /* next character position */ + char *base; /* location of buffer */ + int flag; /* mode of file access */ + int fd; /* file descriptor */ +} KNR_FILE; +extern KNR_FILE knr_iob[KNR_OPEN_MAX]; + +# define knr_stdin (&knr_iob[0]) +# define knr_stdout (&knr_iob[1]) +# define knr_stderr (&knr_iob[2]) + +/* knr_fopen: open file, return KNR_FILE* on success, KNR_NULL on error */ +KNR_FILE *knr_fopen (char *name, char *mode); +/* knr_fillbuf: allocate and fill input buffer */ +int knr_fillbuf (KNR_FILE *fp); +/* knr_flushbuf: flush output buffer, store c, return c on success, KNR_FWL on error */ +int knr_flushbuf (int c, KNR_FILE *fp); +/* knr_fflush: flush output buffer, return 0 on success, KNR_FWL on error */ +int knr_fflush (KNR_FILE *fp); +/* knr_fclose: close a stream, return 0 on success, KNR_EOF on error */ +int knr_fclose (KNR_FILE *fp); + +# define knr_feof(p) ((p)->flag & KNR_EOF) != 0) +# define knr_ferror(p) ((p)->flag & KNR_ERR) != 0) +# define knr_fileno(p) ((p)->fd) + +# define knr_getc(p) (--(p)->cnt >= 0 ? (unsigned char) *(p)->ptr++ : knr_fillbuf(p)) +# define knr_putc(x,p) (--(p)->cnt >= 0 ? *(p)->ptr++ = (x) : knr_flushbuf((x),p)) +# define knr_getchar() knr_getc(knr_stdin) +# define knr_putchar(x) knr_putc((x), knr_stdout) + +# endif diff --git a/chapter_8.unix_interface/8_3.flush_cat/main.c b/chapter_8.unix_interface/8_3.flush_cat/main.c new file mode 100644 index 0000000..0d53c53 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/main.c @@ -0,0 +1,26 @@ +# include <stdio.h> +# include <error.h> +# include "knr_io.h" + + +int main (int argc, char *argv[]) +{ + KNR_FILE *fp; + int c; + + if (argc == 1) + printf("Usage: %s <file1> <...fileN>\n", argv[0]); + else + while (--argc > 0) { + if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL) + error(1, 0, "Can't open file %s.", *argv); + while ((c = knr_getc(fp)) != KNR_EOF) + knr_putchar(c); + if (knr_fclose(fp) != 0) + error(2, 0, "Can't close file %s.", *argv); + } + knr_fflush(knr_stdout); + knr_fflush(knr_stderr); + + return 0; +} diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tin b/chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tin new file mode 100644 index 0000000..e69de29 diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tout b/chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tout new file mode 100644 index 0000000..10675e1 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/0_usage_info.tout @@ -0,0 +1 @@ +Usage: ./flush_cat <file1> <...fileN> diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.targs b/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.targs new file mode 100644 index 0000000..c4414a8 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.targs @@ -0,0 +1 @@ +no_such_file.txt diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.terr b/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.terr new file mode 100644 index 0000000..05393a6 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.terr @@ -0,0 +1 @@ +./flush_cat: Can't open file no_such_file.txt. diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.tin b/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.tin new file mode 100644 index 0000000..e69de29 diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.tout b/chapter_8.unix_interface/8_3.flush_cat/tests/1_err_file_open.tout new file mode 100644 index 0000000..e69de29 diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/2_file.c b/chapter_8.unix_interface/8_3.flush_cat/tests/2_file.c new file mode 100644 index 0000000..0eb05c7 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/2_file.c @@ -0,0 +1,24 @@ +# include <stdio.h> +# include <error.h> +# include "knr_io.h" + + +int main (int argc, char *argv[]) +{ + KNR_FILE *fp; + int c; + + if (argc == 1) + printf("Usage: %s <file1> <...fileN>\n", argv[0]); + else + while (--argc > 0) { + if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL) + error(1, 0, "Can't open file %s.", *argv); + while ((c = knr_getc(fp)) != KNR_EOF) + putchar(c); + if (knr_fclose(fp) != 0) + error(2, 0, "Can't close file %s.", *argv); + } + + return 0; +} diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.targs b/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.targs new file mode 100644 index 0000000..edff2ec --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.targs @@ -0,0 +1 @@ +tests/2_file.c \ No newline at end of file diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tin b/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tin new file mode 100644 index 0000000..e69de29 diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tout b/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tout new file mode 100644 index 0000000..0eb05c7 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tout @@ -0,0 +1,24 @@ +# include <stdio.h> +# include <error.h> +# include "knr_io.h" + + +int main (int argc, char *argv[]) +{ + KNR_FILE *fp; + int c; + + if (argc == 1) + printf("Usage: %s <file1> <...fileN>\n", argv[0]); + else + while (--argc > 0) { + if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL) + error(1, 0, "Can't open file %s.", *argv); + while ((c = knr_getc(fp)) != KNR_EOF) + putchar(c); + if (knr_fclose(fp) != 0) + error(2, 0, "Can't close file %s.", *argv); + } + + return 0; +} diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/3_file0.c b/chapter_8.unix_interface/8_3.flush_cat/tests/3_file0.c new file mode 100644 index 0000000..0eb05c7 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/3_file0.c @@ -0,0 +1,24 @@ +# include <stdio.h> +# include <error.h> +# include "knr_io.h" + + +int main (int argc, char *argv[]) +{ + KNR_FILE *fp; + int c; + + if (argc == 1) + printf("Usage: %s <file1> <...fileN>\n", argv[0]); + else + while (--argc > 0) { + if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL) + error(1, 0, "Can't open file %s.", *argv); + while ((c = knr_getc(fp)) != KNR_EOF) + putchar(c); + if (knr_fclose(fp) != 0) + error(2, 0, "Can't close file %s.", *argv); + } + + return 0; +} diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/3_file1.c b/chapter_8.unix_interface/8_3.flush_cat/tests/3_file1.c new file mode 100644 index 0000000..b0f63e5 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/3_file1.c @@ -0,0 +1,86 @@ +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <fcntl.h> +# include "knr_io.h" + +KNR_FILE knr_iob[KNR_OPEN_MAX] = { /* stdin, stdout, stderr */ + { 0, (char *) 0, (char *) 0, 0, 1, 0, 0, 0, 0 }, + { 0, (char *) 0, (char *) 0, 1, 0, 1, 0, 0, 0 }, + { 0, (char *) 0, (char *) 0, 2, 0, 1, 1, 0, 0 } +}; + +/* knr_fopen: open file, return KNR_FILE* on success, KNR_NULL on error */ +KNR_FILE *knr_fopen (char *name, char *mode) +{ + int fd; + KNR_FILE *fp; + + if (*mode != 'r' && *mode != 'w' && *mode != 'a') + return KNR_NULL; + for (fp = knr_iob; fp < knr_iob + KNR_OPEN_MAX; fp++) + if (fp->f_read == 0 && fp->f_write == 0) + break; /* found free slot */ + if (fp >= knr_iob + KNR_OPEN_MAX) /* no free slots */ + return KNR_NULL; + + if (*mode == 'w') + fd = creat(name, KNR_PERMS); + else if (*mode == 'a') { + if ((fd = open(name, O_WRONLY, 0)) == -1) + fd = creat(name, KNR_PERMS); + lseek(fd, 0L, 2); + } else + fd = open(name, O_RDONLY, 0); + if (fd == -1) /* couldn't access name */ + return KNR_NULL; + fp->fd = fd; + fp->cnt = 0; + fp->base = KNR_NULL; + if (*mode == 'r') + fp->f_read = 1; + else + fp->f_write = 1; + return fp; +} + +/* knr_fillbuf: allocate and fill input buffer */ +int knr_fillbuf (KNR_FILE *fp) +{ + int bufsize; + + if (fp->f_read == 0 || fp->f_eof == 1 || fp->f_err == 1) + return KNR_EOF; + bufsize = fp->f_unbuf==1 ? 1 : KNR_BUFSIZ; + if (fp->base == KNR_NULL) /* no buffer yet */ + if ((fp->base = (char*) malloc(bufsize)) == NULL) + return KNR_EOF; /* can't get buffer */ + fp->ptr = fp->base; + fp->cnt = read(fp->fd, fp->ptr, bufsize); + if (--fp->cnt < 0) { + if (fp->cnt == -1) + fp->f_eof = 1; + else + fp->f_err = 1; + fp->cnt = 0; + return KNR_EOF; + } + return (unsigned char) *fp->ptr++; +} + +/* knr_flushbuf: flush buffer (TODO LATER) */ +int knr_flushbuf (int, KNR_FILE *) +{ + return 0; +} + +/* knr_fclose: close a stream, return 0 on success, KNR_EOF on error */ +int knr_fclose (KNR_FILE *fp) +{ + int r; + + if ((r = close(fp->fd)) == -1) + return KNR_EOF; + fp->f_read = fp->f_write = fp->f_unbuf = fp->f_eof = fp->f_err = 0; + return 0; +} diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/3_file2.mk b/chapter_8.unix_interface/8_3.flush_cat/tests/3_file2.mk new file mode 100644 index 0000000..e407b12 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/3_file2.mk @@ -0,0 +1,3 @@ +BINARY=fopen_fields + +include ../../Exercise.mk diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.targs b/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.targs new file mode 100644 index 0000000..a97ba8f --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.targs @@ -0,0 +1 @@ +tests/3_file0.c tests/3_file1.c tests/3_file2.mk \ No newline at end of file diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tin b/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tin new file mode 100644 index 0000000..e69de29 diff --git a/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tout b/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tout new file mode 100644 index 0000000..c7158b5 --- /dev/null +++ b/chapter_8.unix_interface/8_3.flush_cat/tests/3_many.tout @@ -0,0 +1,113 @@ +# include <stdio.h> +# include <error.h> +# include "knr_io.h" + + +int main (int argc, char *argv[]) +{ + KNR_FILE *fp; + int c; + + if (argc == 1) + printf("Usage: %s <file1> <...fileN>\n", argv[0]); + else + while (--argc > 0) { + if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL) + error(1, 0, "Can't open file %s.", *argv); + while ((c = knr_getc(fp)) != KNR_EOF) + putchar(c); + if (knr_fclose(fp) != 0) + error(2, 0, "Can't close file %s.", *argv); + } + + return 0; +} +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <fcntl.h> +# include "knr_io.h" + +KNR_FILE knr_iob[KNR_OPEN_MAX] = { /* stdin, stdout, stderr */ + { 0, (char *) 0, (char *) 0, 0, 1, 0, 0, 0, 0 }, + { 0, (char *) 0, (char *) 0, 1, 0, 1, 0, 0, 0 }, + { 0, (char *) 0, (char *) 0, 2, 0, 1, 1, 0, 0 } +}; + +/* knr_fopen: open file, return KNR_FILE* on success, KNR_NULL on error */ +KNR_FILE *knr_fopen (char *name, char *mode) +{ + int fd; + KNR_FILE *fp; + + if (*mode != 'r' && *mode != 'w' && *mode != 'a') + return KNR_NULL; + for (fp = knr_iob; fp < knr_iob + KNR_OPEN_MAX; fp++) + if (fp->f_read == 0 && fp->f_write == 0) + break; /* found free slot */ + if (fp >= knr_iob + KNR_OPEN_MAX) /* no free slots */ + return KNR_NULL; + + if (*mode == 'w') + fd = creat(name, KNR_PERMS); + else if (*mode == 'a') { + if ((fd = open(name, O_WRONLY, 0)) == -1) + fd = creat(name, KNR_PERMS); + lseek(fd, 0L, 2); + } else + fd = open(name, O_RDONLY, 0); + if (fd == -1) /* couldn't access name */ + return KNR_NULL; + fp->fd = fd; + fp->cnt = 0; + fp->base = KNR_NULL; + if (*mode == 'r') + fp->f_read = 1; + else + fp->f_write = 1; + return fp; +} + +/* knr_fillbuf: allocate and fill input buffer */ +int knr_fillbuf (KNR_FILE *fp) +{ + int bufsize; + + if (fp->f_read == 0 || fp->f_eof == 1 || fp->f_err == 1) + return KNR_EOF; + bufsize = fp->f_unbuf==1 ? 1 : KNR_BUFSIZ; + if (fp->base == KNR_NULL) /* no buffer yet */ + if ((fp->base = (char*) malloc(bufsize)) == NULL) + return KNR_EOF; /* can't get buffer */ + fp->ptr = fp->base; + fp->cnt = read(fp->fd, fp->ptr, bufsize); + if (--fp->cnt < 0) { + if (fp->cnt == -1) + fp->f_eof = 1; + else + fp->f_err = 1; + fp->cnt = 0; + return KNR_EOF; + } + return (unsigned char) *fp->ptr++; +} + +/* knr_flushbuf: flush buffer (TODO LATER) */ +int knr_flushbuf (int, KNR_FILE *) +{ + return 0; +} + +/* knr_fclose: close a stream, return 0 on success, KNR_EOF on error */ +int knr_fclose (KNR_FILE *fp) +{ + int r; + + if ((r = close(fp->fd)) == -1) + return KNR_EOF; + fp->f_read = fp->f_write = fp->f_unbuf = fp->f_eof = fp->f_err = 0; + return 0; +} +BINARY=fopen_fields + +include ../../Exercise.mk