/*
- * 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 <stdio.h>
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
-/* #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 <stdarg.h>
+#else
+#include <varargs.h>
+#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;
}