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

168
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) }
arguing = 1;
opterr = 0;
while(optind < argc){
if(arguing && (c = getopt(argc, argv, "hu")) != -1)
switch(c){ switch(c){
case 'u': case 'u':
/* cat(1p) says the following: setvbuf(stdout, NULL, _IONBF, 0);
* "Write bytes from the input file to the standard continue;
* output without delay as each is read." case '-':
* Then in Application Usage: arguing = 0;
* "It is unspecified whether standard output is or is continue;
* 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: case 'h': default: usage:
write(2, "Usage: ", 7); fprintf(stderr, "Usage: %s (-h) (file...)\n",
write(2, argv[0], argv0_s); argv[0]);
write(2, "(-hu) (file...)\n", 16);
return EX_USAGE; return EX_USAGE;
} }
if(arguing && *argv[optind] == '-'){ /* "--" */
argc -= optind; arguing = 0;
argv += optind - 1; continue;
multiple_files = argc > 1; if(*argv[optind] == '-' && argv[optind][1] == '\0'){ /* "-" */
fn = stdout_name;
do{ fo = stdout;
++argv; }else{
if(argc == 0) /* `cat` */ fn = argv[optind];
dumb: fd = 1; if(stat(fn, &fi) == -1){
else if((fd = open(*argv, O_RDONLY)) == -1){ fclose(fo);
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){ switch(errno){
case EISDIR: case EFAULT: case ENOENT: case ENOTDIR:
write(2, "Is directory.\n", 14); fprintf(stderr,
"%s: %s: Unable to open file."
" Does it exist?\n",
argv[0], fn);
return EX_NOINPUT; return EX_NOINPUT;
case EACCES: case EFAULT: case EPERM: case EBADF: case EINVAL: case ENOMEM:
write(2, "Unable to open file.\n", 21); case EOVERFLOW:
return EX_NOINPUT; fprintf(stderr,
case ENAMETOOLONG: case ENFILE: case EBADF: "%s: %s: System error"
write(2, "Operating system error.\n", 24); " (errno=%d),\n",
argv[0], fn, errno);
return EX_OSERR; return EX_OSERR;
case EMFILE: case ELOOP: case ENAMETOOLONG:
write(2, "Internal error.\n", 16); fprintf(stderr,
return EX_SOFTWARE; "%s: %s: Unable to open file.",
case ENOENT: case ENOTDIR: case ENXIO: argv[0], fn);
write(2, "File does not exist.\n", 21); return EX_DATAERR;
return EX_NOINPUT; }
default: }
write(2, "Unknown error.", 14); if(S_ISDIR(fi.st_mode)){
return 1; 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) ++optind;
close(fd); }
}while(--argc > 0);
return EX_OK; return EX_OK;
} }