can't work any less than before
This commit is contained in:
parent
4393dcac21
commit
54f69b21ed
168
cat/cat.c
168
cat/cat.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user