1
0

can't work any less than before

This commit is contained in:
dtb 2023-08-14 20:24:57 -04:00
parent 4393dcac21
commit 54f69b21ed

186
cat/cat.c
View File

@ -1,104 +1,106 @@
#include <errno.h> #include <errno.h> /* errno, EBADF, EFAULT, EINVAL, ELOOP, ENAMETOOLONG,
#include <fcntl.h> * ENOENT, ENOMEM, ENOTDIR, EOVERFLOW */
#include <sysexits.h> #include <stdio.h> /* fprintf(3), getc(3), putc(3), setvbuf(3), stderr, stdin,
#include <unistd.h> * stdout */
#include <sysexits.h> /* EX_DATAERR, EX_NOINPUT, EX_OK, EX_OSERR,
* EX_UNAVAILABLE, EX_USAGE */
#include <unistd.h> /* getopt(3) */
#include <sys/stat.h> /* stat(2), struct stat, S_ISDIR */
/* NetBSD's default according to an strace */ /* NetBSD's default size according to an strace */
#define BUFFER 4096 static unsigned char buf[4096];
static unsigned char buf[BUFFER]; static char **default_argv = {
(char [])"cat",
static char *program_name = "cat"; (char [])"-",
NULL
}
static char *program_name = *default_argv;
static char *stdout_name = "/dev/stdout";
int main(int argc, char *argv[]){ int main(int argc, char *argv[]){
char *argv0; int arguing;
int argv0_s;
extern int errno;
char *f;
int b; /* how many meaningful bytes are in the buffer */
int c; int c;
int fd; extern int errno;
int multiple_files; extern int opterr;
extern int optind;
struct stat fi; /* info */
char *fn; /* name */
FILE *fo; /* object */
if(argv[0] == NULL) setvbuf(stdout, buf, _IOFBF, (sizeof buf)/(sizeof *buf));
goto dumb; if(argc < 2){
argc = 2;
argv0 = argv[0]; if(argc > 0)
for(argv0_s = 0; argv0_s != '\0'; ++argv0_s); default_argv[0] = argv[0];
argv = default_argv;
while((c = getopt(argc, argv, "hu")) != -1) }
switch(c){ arguing = 1;
case 'u': opterr = 0;
/* cat(1p) says the following: while(optind < argc){
* "Write bytes from the input file to the standard if(arguing && (c = getopt(argc, argv, "hu")) != -1)
* output without delay as each is read." switch(c){
* Then in Application Usage: case 'u':
* "It is unspecified whether standard output is or is setvbuf(stdout, NULL, _IONBF, 0);
* not buffered in the default case." continue;
* POSIX defines "buffering" to be a not-strictly case '-':
* -necessary delay in processing input, so there still arguing = 0;
* needs to be a place in memory to put data, which for continue;
* the purposes of this implementation is buf[]. case 'h': default: usage:
* fprintf(stderr, "Usage: %s (-h) (file...)\n",
* Using the standard library would make it more argv[0]);
* difficult to manage this flow manually. */ return EX_USAGE;
break; }
case 'h': default: usage: if(arguing && *argv[optind] == '-'){ /* "--" */
write(2, "Usage: ", 7); arguing = 0;
write(2, argv[0], argv0_s); continue;
write(2, "(-hu) (file...)\n", 16); if(*argv[optind] == '-' && argv[optind][1] == '\0'){ /* "-" */
return EX_USAGE; fn = stdout_name;
} fo = stdout;
}else{
argc -= optind; fn = argv[optind];
argv += optind - 1; if(stat(fn, &fi) == -1){
multiple_files = argc > 1; fclose(fo);
switch(errno){
do{ case EFAULT: case ENOENT: case ENOTDIR:
++argv; fprintf(stderr,
if(argc == 0) /* `cat` */ "%s: %s: Unable to open file."
dumb: fd = 1; " Does it exist?\n",
else if((fd = open(*argv, O_RDONLY)) == -1){ argv[0], fn);
ferr: /* `cat bad_file` */ return EX_NOINPUT;
case EBADF: case EINVAL: case ENOMEM:
/* `cat: file: ` */ case EOVERFLOW:
write(2, argv0, argv0_s); fprintf(stderr,
write(2, ": ", 2); "%s: %s: System error"
for(i = 0; argv[0][i] != '\0'; ++i); " (errno=%d),\n",
write(2, *argv, i); argv[0], fn, errno);
write(2, ": ", 2); return EX_OSERR;
case ELOOP: case ENAMETOOLONG:
switch(errno){ fprintf(stderr,
case EISDIR: "%s: %s: Unable to open file.",
write(2, "Is directory.\n", 14); argv[0], fn);
return EX_NOINPUT; return EX_DATAERR;
case EACCES: case EFAULT: case EPERM: }
write(2, "Unable to open file.\n", 21); }
return EX_NOINPUT; if(S_ISDIR(fi.st_mode)){
case ENAMETOOLONG: case ENFILE: case EBADF: fclose(fo);
write(2, "Operating system error.\n", 24); fprintf(stderr, "%s: %s: Is a directory.\n",
return EX_OSERR; argv[0], fn);
case EMFILE: return EX_DATAERR;
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;
} }
}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;
}
} ++optind;
}
if(fd < 0 && fd > 2)
close(fd);
}while(--argc > 0);
return EX_OK; return EX_OK;
} }