X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/d6d4c082764cbfffab1df173f68eae82f347ee6c..647d0ea2dedf292593f7d95d287d445c297ccca2:/usr/src/bin/cat/cat.c diff --git a/usr/src/bin/cat/cat.c b/usr/src/bin/cat/cat.c index d7f522a3a1..631f7c42e7 100644 --- a/usr/src/bin/cat/cat.c +++ b/usr/src/bin/cat/cat.c @@ -1,228 +1,277 @@ /* - * Copyright (c) 1980 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kevin Fall. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef lint char copyright[] = -"@(#) Copyright (c) 1980 Regents of the University of California.\n\ +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)cat.c 5.3 (Berkeley) %G%"; +static char sccsid[] = "@(#)cat.c 5.15 (Berkeley) 5/23/91"; #endif /* not lint */ -/* - * Concatenate files. - */ - -#include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include -/* #define OPTSIZE BUFSIZ /* define this only if not 4.2 BSD or beyond */ +int bflag, eflag, nflag, sflag, tflag, vflag; +int rval; +char *filename; -int bflg, eflg, nflg, sflg, tflg, uflg, vflg; -int spaced, col, lno, inaline, ibsize, obsize; +void cook_args(), cook_buf(), raw_args(), raw_cat(); +void err __P((int, const char *, ...)); main(argc, argv) -char **argv; + int argc; + char **argv; { - int fflg = 0; - register FILE *fi; - register c; - int dev, ino = -1; - struct stat statb; - int retval = 0; - - lno = 1; - for( ; argc>1 && argv[1][0]=='-'; argc--,argv++) { - switch(argv[1][1]) { - case 0: + extern int optind; + int ch; + + while ((ch = getopt(argc, argv, "benstuv")) != EOF) + switch (ch) { + case 'b': + bflag = nflag = 1; /* -b implies -n */ + break; + case 'e': + eflag = vflag = 1; /* -e implies -v */ break; - case 'u': - setbuf(stdout, (char *)NULL); - uflg++; - continue; case 'n': - nflg++; - continue; - case 'b': - bflg++; - nflg++; - continue; - case 'v': - vflg++; - continue; + nflag = 1; + break; case 's': - sflg++; - continue; - case 'e': - eflg++; - vflg++; - continue; + sflag = 1; + break; case 't': - tflg++; - vflg++; - continue; - } - break; - } - if (fstat(fileno(stdout), &statb) == 0) { - statb.st_mode &= S_IFMT; - if (statb.st_mode!=S_IFCHR && statb.st_mode!=S_IFBLK) { - dev = statb.st_dev; - ino = statb.st_ino; + tflag = vflag = 1; /* -t implies -v */ + break; + case 'u': + setbuf(stdout, (char *)NULL); + break; + case 'v': + vflag = 1; + break; + case '?': + (void)fprintf(stderr, + "usage: cat [-benstuv] [-] [file ...]\n"); + exit(1); } -#ifndef OPTSIZE - obsize = statb.st_blksize; -#endif - } + argv += optind; + + if (bflag || eflag || nflag || sflag || tflag || vflag) + cook_args(argv); else - obsize = 0; - if (argc < 2) { - argc = 2; - fflg++; - } - while (--argc > 0) { - if (fflg || (*++argv)[0]=='-' && (*argv)[1]=='\0') - fi = stdin; - else { - if ((fi = fopen(*argv, "r")) == NULL) { - perror(*argv); - retval = 1; + raw_args(argv); + if (fclose(stdout)) + err(1, "stdout: %s", strerror(errno)); + exit(rval); +} + +void +cook_args(argv) + char **argv; +{ + register FILE *fp; + + fp = stdin; + filename = "stdin"; + do { + if (*argv) { + if (!strcmp(*argv, "-")) + fp = stdin; + else if (!(fp = fopen(*argv, "r"))) { + err(0, "%s: %s", *argv, strerror(errno)); + ++argv; continue; } + filename = *argv++; + } + cook_buf(fp); + if (fp != stdin) + (void)fclose(fp); + } while (*argv); +} + +void +cook_buf(fp) + register FILE *fp; +{ + register int ch, gobble, line, prev; + + line = gobble = 0; + for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { + if (prev == '\n') { + if (ch == '\n') { + if (sflag) { + if (!gobble && putchar(ch) == EOF) + break; + gobble = 1; + continue; + } + if (nflag && !bflag) { + (void)fprintf(stdout, "%6d\t", ++line); + if (ferror(stdout)) + break; + } + } else if (nflag) { + (void)fprintf(stdout, "%6d\t", ++line); + if (ferror(stdout)) + break; + } } - if (fstat(fileno(fi), &statb) == 0) { - if ((statb.st_mode & S_IFMT) == S_IFREG && - statb.st_dev==dev && statb.st_ino==ino) { - fprintf(stderr, "cat: input %s is output\n", - fflg?"-": *argv); - fclose(fi); - retval = 1; + gobble = 0; + if (ch == '\n') { + if (eflag) + if (putchar('$') == EOF) + break; + } else if (ch == '\t') { + if (tflag) { + if (putchar('^') == EOF || putchar('I') == EOF) + break; + continue; + } + } else if (vflag) { + if (!isascii(ch)) { + if (putchar('M') == EOF || putchar('-') == EOF) + break; + ch = toascii(ch); + } + if (iscntrl(ch)) { + if (putchar('^') == EOF || + putchar(ch == '\177' ? '?' : + ch | 0100) == EOF) + break; continue; } -#ifndef OPTSIZE - ibsize = statb.st_blksize; -#endif } - else - ibsize = 0; - if (nflg||sflg||vflg) - copyopt(fi); - else if (uflg) { - while ((c = getc(fi)) != EOF) - putchar(c); - } else - retval |= fastcat(fileno(fi)); /* no flags specified */ - if (fi!=stdin) - fclose(fi); - else - clearerr(fi); /* reset sticky eof */ - if (ferror(stdout)) { - fprintf(stderr, "cat: output write error\n"); - retval = 1; + if (putchar(ch) == EOF) break; - } } - exit(retval); + if (ferror(fp)) { + err(0, "%s: %s", strerror(errno)); + clearerr(fp); + } + if (ferror(stdout)) + err(1, "stdout: %s", strerror(errno)); } -copyopt(f) - register FILE *f; +void +raw_args(argv) + char **argv; { - register int c; - -top: - c = getc(f); - if (c == EOF) - return; - if (c == '\n') { - if (inaline == 0) { - if (sflg && spaced) - goto top; - spaced = 1; - } - if (nflg && bflg==0 && inaline == 0) - printf("%6d\t", lno++); - if (eflg) - putchar('$'); - putchar('\n'); - inaline = 0; - goto top; - } - if (nflg && inaline == 0) - printf("%6d\t", lno++); - inaline = 1; - if (vflg) { - if (tflg==0 && c == '\t') - putchar(c); - else { - if (c > 0177) { - printf("M-"); - c &= 0177; + register int fd; + + fd = fileno(stdin); + filename = "stdin"; + do { + if (*argv) { + if (!strcmp(*argv, "-")) + fd = fileno(stdin); + else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { + err(0, "%s: %s", *argv, strerror(errno)); + ++argv; + continue; } - if (c < ' ') - printf("^%c", c+'@'); - else if (c == 0177) - printf("^?"); - else - putchar(c); + filename = *argv++; } - } else - putchar(c); - spaced = 0; - goto top; + raw_cat(fd); + if (fd != fileno(stdin)) + (void)close(fd); + } while (*argv); } -fastcat(fd) -register int fd; +void +raw_cat(rfd) + register int rfd; { - register int buffsize, n, nwritten, offset; - register char *buff; - struct stat statbuff; - char *malloc(); - -#ifndef OPTSIZE - if (obsize) - buffsize = obsize; /* common case, use output blksize */ - else if (ibsize) - buffsize = ibsize; - else - buffsize = BUFSIZ; -#else - buffsize = OPTSIZE; -#endif + register int nr, nw, off, wfd; + static int bsize; + static char *buf; + struct stat sbuf; - if ((buff = malloc(buffsize)) == NULL) { - perror("cat: no memory"); - return (1); + wfd = fileno(stdout); + if (!buf) { + if (fstat(wfd, &sbuf)) + err(1, "%s: %s", filename, strerror(errno)); + bsize = MAX(sbuf.st_blksize, 1024); + if (!(buf = malloc((u_int)bsize))) + err(1, "%s", strerror(errno)); } + while ((nr = read(rfd, buf, bsize)) > 0) + for (off = 0; off < nr; nr -= nw, off += nw) + if ((nw = write(wfd, buf + off, nr)) < 0) + err(1, "stdout"); + if (nr < 0) + err(0, "%s: %s", filename, strerror(errno)); +} - /* - * Note that on some systems (V7), very large writes to a pipe - * return less than the requested size of the write. - * In this case, multiple writes are required. - */ - while ((n = read(fd, buff, buffsize)) > 0) { - offset = 0; - do { - nwritten = write(fileno(stdout), &buff[offset], n); - if (nwritten <= 0) { - perror("cat: write error"); - exit(2); - } - offset += nwritten; - } while ((n -= nwritten) > 0); - } +#if __STDC__ +#include +#else +#include +#endif - free(buff); - if (n < 0) { - perror("cat: read error"); - return (1); - } - return (0); +void +#if __STDC__ +err(int ex, const char *fmt, ...) +#else +err(ex, fmt, va_alist) + int ex; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "cat: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (ex) + exit(1); + rval = 1; }