Skip to content

Commit

Permalink
Exerc 8_3.
Browse files Browse the repository at this point in the history
  • Loading branch information
rsm-lisper committed Aug 6, 2024
1 parent 04035b9 commit 593a95d
Show file tree
Hide file tree
Showing 20 changed files with 491 additions and 0 deletions.
3 changes: 3 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BINARY=flush_cat

include ../../Exercise.mk
139 changes: 139 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/knr_io.c
Original file line number Diff line number Diff line change
@@ -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;
}
44 changes: 44 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/knr_io.h
Original file line number Diff line number Diff line change
@@ -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
26 changes: 26 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/main.c
Original file line number Diff line number Diff line change
@@ -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;
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Usage: ./flush_cat <file1> <...fileN>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
no_such_file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./flush_cat: Can't open file no_such_file.txt.
Empty file.
Empty file.
24 changes: 24 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/2_file.c
Original file line number Diff line number Diff line change
@@ -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;
}
1 change: 1 addition & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/2_one.targs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/2_file.c
Empty file.
24 changes: 24 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/2_one.tout
Original file line number Diff line number Diff line change
@@ -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;
}
24 changes: 24 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/3_file0.c
Original file line number Diff line number Diff line change
@@ -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;
}
86 changes: 86 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/3_file1.c
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/3_file2.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BINARY=fopen_fields

include ../../Exercise.mk
1 change: 1 addition & 0 deletions chapter_8.unix_interface/8_3.flush_cat/tests/3_many.targs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/3_file0.c tests/3_file1.c tests/3_file2.mk
Empty file.
Loading

0 comments on commit 593a95d

Please sign in to comment.