can't work any less than before
This commit is contained in:
parent
4393dcac21
commit
54f69b21ed
186
cat/cat.c
186
cat/cat.c
@ -1,104 +1,106 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h> /* errno, EBADF, EFAULT, EINVAL, ELOOP, ENAMETOOLONG,
|
||||
* ENOENT, ENOMEM, ENOTDIR, EOVERFLOW */
|
||||
#include <stdio.h> /* fprintf(3), getc(3), putc(3), setvbuf(3), stderr, stdin,
|
||||
* 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 */
|
||||
#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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user