From 54f69b21ed132d663922662d86d442b4f70381fa Mon Sep 17 00:00:00 2001 From: dtb Date: Mon, 14 Aug 2023 20:24:57 -0400 Subject: [PATCH] can't work any less than before --- cat/cat.c | 186 +++++++++++++++++++++++++++--------------------------- 1 file changed, 94 insertions(+), 92 deletions(-) diff --git a/cat/cat.c b/cat/cat.c index 4084dd8..c2261ff 100644 --- a/cat/cat.c +++ b/cat/cat.c @@ -1,104 +1,106 @@ -#include -#include -#include -#include +#include /* errno, EBADF, EFAULT, EINVAL, ELOOP, ENAMETOOLONG, + * ENOENT, ENOMEM, ENOTDIR, EOVERFLOW */ +#include /* fprintf(3), getc(3), putc(3), setvbuf(3), stderr, stdin, + * stdout */ +#include /* EX_DATAERR, EX_NOINPUT, EX_OK, EX_OSERR, + * EX_UNAVAILABLE, EX_USAGE */ +#include /* getopt(3) */ +#include /* stat(2), struct stat, S_ISDIR */ -/* NetBSD's default according to an strace */ -#define BUFFER 4096 -static unsigned char buf[BUFFER]; - -static char *program_name = "cat"; +/* NetBSD's default size according to an strace */ +static unsigned char buf[4096]; +static char **default_argv = { + (char [])"cat", + (char [])"-", + NULL +} +static char *program_name = *default_argv; +static char *stdout_name = "/dev/stdout"; int main(int argc, char *argv[]){ - char *argv0; - int argv0_s; - extern int errno; - char *f; - int b; /* how many meaningful bytes are in the buffer */ + int arguing; int c; - int fd; - int multiple_files; + extern int errno; + extern int opterr; + extern int optind; + struct stat fi; /* info */ + char *fn; /* name */ + FILE *fo; /* object */ - if(argv[0] == NULL) - goto dumb; - - argv0 = argv[0]; - for(argv0_s = 0; argv0_s != '\0'; ++argv0_s); - - while((c = getopt(argc, argv, "hu")) != -1) - switch(c){ - case 'u': - /* cat(1p) says the following: - * "Write bytes from the input file to the standard - * output without delay as each is read." - * Then in Application Usage: - * "It is unspecified whether standard output is or is - * not buffered in the default case." - * POSIX defines "buffering" to be a not-strictly - * -necessary delay in processing input, so there still - * needs to be a place in memory to put data, which for - * the purposes of this implementation is buf[]. - * - * Using the standard library would make it more - * difficult to manage this flow manually. */ - break; - case 'h': default: usage: - write(2, "Usage: ", 7); - write(2, argv[0], argv0_s); - write(2, "(-hu) (file...)\n", 16); - return EX_USAGE; - } - - argc -= optind; - argv += optind - 1; - multiple_files = argc > 1; - - do{ - ++argv; - if(argc == 0) /* `cat` */ -dumb: fd = 1; - else if((fd = open(*argv, O_RDONLY)) == -1){ -ferr: /* `cat bad_file` */ - - /* `cat: file: ` */ - write(2, argv0, argv0_s); - write(2, ": ", 2); - for(i = 0; argv[0][i] != '\0'; ++i); - write(2, *argv, i); - write(2, ": ", 2); - - switch(errno){ - case EISDIR: - write(2, "Is directory.\n", 14); - return EX_NOINPUT; - case EACCES: case EFAULT: case EPERM: - write(2, "Unable to open file.\n", 21); - return EX_NOINPUT; - case ENAMETOOLONG: case ENFILE: case EBADF: - write(2, "Operating system error.\n", 24); - return EX_OSERR; - case EMFILE: - write(2, "Internal error.\n", 16); - return EX_SOFTWARE; - case ENOENT: case ENOTDIR: case ENXIO: - write(2, "File does not exist.\n", 21); - return EX_NOINPUT; - default: - write(2, "Unknown error.", 14); - return 1; + setvbuf(stdout, buf, _IOFBF, (sizeof buf)/(sizeof *buf)); + if(argc < 2){ + argc = 2; + if(argc > 0) + default_argv[0] = argv[0]; + argv = default_argv; + } + arguing = 1; + opterr = 0; + while(optind < argc){ + if(arguing && (c = getopt(argc, argv, "hu")) != -1) + switch(c){ + case 'u': + setvbuf(stdout, NULL, _IONBF, 0); + continue; + case '-': + arguing = 0; + continue; + case 'h': default: usage: + fprintf(stderr, "Usage: %s (-h) (file...)\n", + argv[0]); + return EX_USAGE; + } + if(arguing && *argv[optind] == '-'){ /* "--" */ + arguing = 0; + continue; + if(*argv[optind] == '-' && argv[optind][1] == '\0'){ /* "-" */ + fn = stdout_name; + fo = stdout; + }else{ + fn = argv[optind]; + if(stat(fn, &fi) == -1){ + fclose(fo); + switch(errno){ + case EFAULT: case ENOENT: case ENOTDIR: + fprintf(stderr, + "%s: %s: Unable to open file." + " Does it exist?\n", + argv[0], fn); + return EX_NOINPUT; + case EBADF: case EINVAL: case ENOMEM: + case EOVERFLOW: + fprintf(stderr, + "%s: %s: System error" + " (errno=%d),\n", + argv[0], fn, errno); + return EX_OSERR; + case ELOOP: case ENAMETOOLONG: + fprintf(stderr, + "%s: %s: Unable to open file.", + argv[0], fn); + return EX_DATAERR; + } + } + if(S_ISDIR(fi.st_mode)){ + fclose(fo); + fprintf(stderr, "%s: %s: Is a directory.\n", + argv[0], fn); + return EX_DATAERR; } - }else if(multiple_files){ - /* `cat good_file good_file ...` */ - } - for(b = 0; b == -1;){ - - } + while((c = getc(fo)) != EOF) + if(putc(c, stdout) == EOF){ + fprintf(stderr, + "%s: Exiting due to error writing to" + " output...\n", + argv[0]); + fclose(fo); + return EX_UNAVAILABLE; + } - if(fd < 0 && fd > 2) - close(fd); - }while(--argc > 0); + ++optind; + } return EX_OK; }