cat.c revision 1556
11556Srgrimes/*
21556Srgrimes * Copyright (c) 1989, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kevin Fall.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
381556Srgrimesstatic char copyright[] =
391556Srgrimes"@(#) Copyright (c) 1989, 1993\n\
401556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
411556Srgrimes#endif /* not lint */
421556Srgrimes
431556Srgrimes#ifndef lint
441556Srgrimesstatic char sccsid[] = "@(#)cat.c	8.1 (Berkeley) 7/19/93";
451556Srgrimes#endif /* not lint */
461556Srgrimes
471556Srgrimes#include <sys/param.h>
481556Srgrimes#include <sys/stat.h>
491556Srgrimes
501556Srgrimes#include <ctype.h>
511556Srgrimes#include <err.h>
521556Srgrimes#include <errno.h>
531556Srgrimes#include <fcntl.h>
541556Srgrimes#include <stdio.h>
551556Srgrimes#include <stdlib.h>
561556Srgrimes#include <string.h>
571556Srgrimes#include <unistd.h>
581556Srgrimes
591556Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag;
601556Srgrimesint rval;
611556Srgrimeschar *filename;
621556Srgrimes
631556Srgrimesvoid cook_args __P((char *argv[]));
641556Srgrimesvoid cook_buf __P((FILE *));
651556Srgrimesvoid raw_args __P((char *argv[]));
661556Srgrimesvoid raw_cat __P((int));
671556Srgrimes
681556Srgrimesint
691556Srgrimesmain(argc, argv)
701556Srgrimes	int argc;
711556Srgrimes	char *argv[];
721556Srgrimes{
731556Srgrimes	extern int optind;
741556Srgrimes	int ch;
751556Srgrimes
761556Srgrimes	while ((ch = getopt(argc, argv, "benstuv")) != EOF)
771556Srgrimes		switch (ch) {
781556Srgrimes		case 'b':
791556Srgrimes			bflag = nflag = 1;	/* -b implies -n */
801556Srgrimes			break;
811556Srgrimes		case 'e':
821556Srgrimes			eflag = vflag = 1;	/* -e implies -v */
831556Srgrimes			break;
841556Srgrimes		case 'n':
851556Srgrimes			nflag = 1;
861556Srgrimes			break;
871556Srgrimes		case 's':
881556Srgrimes			sflag = 1;
891556Srgrimes			break;
901556Srgrimes		case 't':
911556Srgrimes			tflag = vflag = 1;	/* -t implies -v */
921556Srgrimes			break;
931556Srgrimes		case 'u':
941556Srgrimes			setbuf(stdout, (char *)NULL);
951556Srgrimes			break;
961556Srgrimes		case 'v':
971556Srgrimes			vflag = 1;
981556Srgrimes			break;
991556Srgrimes		case '?':
1001556Srgrimes			(void)fprintf(stderr,
1011556Srgrimes			    "usage: cat [-benstuv] [-] [file ...]\n");
1021556Srgrimes			exit(1);
1031556Srgrimes		}
1041556Srgrimes	argv += optind;
1051556Srgrimes
1061556Srgrimes	if (bflag || eflag || nflag || sflag || tflag || vflag)
1071556Srgrimes		cook_args(argv);
1081556Srgrimes	else
1091556Srgrimes		raw_args(argv);
1101556Srgrimes	if (fclose(stdout))
1111556Srgrimes		err(1, "stdout");
1121556Srgrimes	exit(rval);
1131556Srgrimes}
1141556Srgrimes
1151556Srgrimesvoid
1161556Srgrimescook_args(argv)
1171556Srgrimes	char **argv;
1181556Srgrimes{
1191556Srgrimes	register FILE *fp;
1201556Srgrimes
1211556Srgrimes	fp = stdin;
1221556Srgrimes	filename = "stdin";
1231556Srgrimes	do {
1241556Srgrimes		if (*argv) {
1251556Srgrimes			if (!strcmp(*argv, "-"))
1261556Srgrimes				fp = stdin;
1271556Srgrimes			else if ((fp = fopen(*argv, "r")) == NULL) {
1281556Srgrimes				warn("%s", *argv);
1291556Srgrimes				++argv;
1301556Srgrimes				continue;
1311556Srgrimes			}
1321556Srgrimes			filename = *argv++;
1331556Srgrimes		}
1341556Srgrimes		cook_buf(fp);
1351556Srgrimes		if (fp != stdin)
1361556Srgrimes			(void)fclose(fp);
1371556Srgrimes	} while (*argv);
1381556Srgrimes}
1391556Srgrimes
1401556Srgrimesvoid
1411556Srgrimescook_buf(fp)
1421556Srgrimes	register FILE *fp;
1431556Srgrimes{
1441556Srgrimes	register int ch, gobble, line, prev;
1451556Srgrimes
1461556Srgrimes	line = gobble = 0;
1471556Srgrimes	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
1481556Srgrimes		if (prev == '\n') {
1491556Srgrimes			if (ch == '\n') {
1501556Srgrimes				if (sflag) {
1511556Srgrimes					if (!gobble && putchar(ch) == EOF)
1521556Srgrimes						break;
1531556Srgrimes					gobble = 1;
1541556Srgrimes					continue;
1551556Srgrimes				}
1561556Srgrimes				if (nflag && !bflag) {
1571556Srgrimes					(void)fprintf(stdout, "%6d\t", ++line);
1581556Srgrimes					if (ferror(stdout))
1591556Srgrimes						break;
1601556Srgrimes				}
1611556Srgrimes			} else if (nflag) {
1621556Srgrimes				(void)fprintf(stdout, "%6d\t", ++line);
1631556Srgrimes				if (ferror(stdout))
1641556Srgrimes					break;
1651556Srgrimes			}
1661556Srgrimes		}
1671556Srgrimes		gobble = 0;
1681556Srgrimes		if (ch == '\n') {
1691556Srgrimes			if (eflag)
1701556Srgrimes				if (putchar('$') == EOF)
1711556Srgrimes					break;
1721556Srgrimes		} else if (ch == '\t') {
1731556Srgrimes			if (tflag) {
1741556Srgrimes				if (putchar('^') == EOF || putchar('I') == EOF)
1751556Srgrimes					break;
1761556Srgrimes				continue;
1771556Srgrimes			}
1781556Srgrimes		} else if (vflag) {
1791556Srgrimes			if (!isascii(ch)) {
1801556Srgrimes				if (putchar('M') == EOF || putchar('-') == EOF)
1811556Srgrimes					break;
1821556Srgrimes				ch = toascii(ch);
1831556Srgrimes			}
1841556Srgrimes			if (iscntrl(ch)) {
1851556Srgrimes				if (putchar('^') == EOF ||
1861556Srgrimes				    putchar(ch == '\177' ? '?' :
1871556Srgrimes				    ch | 0100) == EOF)
1881556Srgrimes					break;
1891556Srgrimes				continue;
1901556Srgrimes			}
1911556Srgrimes		}
1921556Srgrimes		if (putchar(ch) == EOF)
1931556Srgrimes			break;
1941556Srgrimes	}
1951556Srgrimes	if (ferror(fp)) {
1961556Srgrimes		warn("%s", filename);
1971556Srgrimes		clearerr(fp);
1981556Srgrimes	}
1991556Srgrimes	if (ferror(stdout))
2001556Srgrimes		err(1, "stdout");
2011556Srgrimes}
2021556Srgrimes
2031556Srgrimesvoid
2041556Srgrimesraw_args(argv)
2051556Srgrimes	char **argv;
2061556Srgrimes{
2071556Srgrimes	register int fd;
2081556Srgrimes
2091556Srgrimes	fd = fileno(stdin);
2101556Srgrimes	filename = "stdin";
2111556Srgrimes	do {
2121556Srgrimes		if (*argv) {
2131556Srgrimes			if (!strcmp(*argv, "-"))
2141556Srgrimes				fd = fileno(stdin);
2151556Srgrimes			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
2161556Srgrimes				warn("%s", *argv);
2171556Srgrimes				++argv;
2181556Srgrimes				continue;
2191556Srgrimes			}
2201556Srgrimes			filename = *argv++;
2211556Srgrimes		}
2221556Srgrimes		raw_cat(fd);
2231556Srgrimes		if (fd != fileno(stdin))
2241556Srgrimes			(void)close(fd);
2251556Srgrimes	} while (*argv);
2261556Srgrimes}
2271556Srgrimes
2281556Srgrimesvoid
2291556Srgrimesraw_cat(rfd)
2301556Srgrimes	register int rfd;
2311556Srgrimes{
2321556Srgrimes	register int nr, nw, off, wfd;
2331556Srgrimes	static int bsize;
2341556Srgrimes	static char *buf;
2351556Srgrimes	struct stat sbuf;
2361556Srgrimes
2371556Srgrimes	wfd = fileno(stdout);
2381556Srgrimes	if (buf == NULL) {
2391556Srgrimes		if (fstat(wfd, &sbuf))
2401556Srgrimes			err(1, "%s", filename);
2411556Srgrimes		bsize = MAX(sbuf.st_blksize, 1024);
2421556Srgrimes		if ((buf = malloc((u_int)bsize)) == NULL)
2431556Srgrimes			err(1, "");
2441556Srgrimes	}
2451556Srgrimes	while ((nr = read(rfd, buf, bsize)) > 0)
2461556Srgrimes		for (off = 0; nr; nr -= nw, off += nw)
2471556Srgrimes			if ((nw = write(wfd, buf + off, nr)) < 0)
2481556Srgrimes				err(1, "stdout");
2491556Srgrimes	if (nr < 0)
2501556Srgrimes		warn("%s", filename);
2511556Srgrimes}
252