cat.c revision 35772
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
3820412Sstevestatic char const 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
4435772Scharnier#if 0
4520412Sstevestatic char const sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
4635772Scharnier#endif
4735772Scharnierstatic const char rcsid[] =
4835772Scharnier	"$Id$";
491556Srgrimes#endif /* not lint */
501556Srgrimes
511556Srgrimes#include <sys/param.h>
521556Srgrimes#include <sys/stat.h>
531556Srgrimes
541556Srgrimes#include <ctype.h>
551556Srgrimes#include <err.h>
561556Srgrimes#include <fcntl.h>
5718578Sache#include <locale.h>
581556Srgrimes#include <stdio.h>
591556Srgrimes#include <stdlib.h>
601556Srgrimes#include <unistd.h>
611556Srgrimes
621556Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag;
631556Srgrimesint rval;
641556Srgrimeschar *filename;
651556Srgrimes
661556Srgrimesvoid cook_args __P((char *argv[]));
671556Srgrimesvoid cook_buf __P((FILE *));
681556Srgrimesvoid raw_args __P((char *argv[]));
691556Srgrimesvoid raw_cat __P((int));
701556Srgrimes
711556Srgrimesint
721556Srgrimesmain(argc, argv)
731556Srgrimes	int argc;
741556Srgrimes	char *argv[];
751556Srgrimes{
761556Srgrimes	extern int optind;
771556Srgrimes	int ch;
781556Srgrimes
7918578Sache	setlocale(LC_CTYPE, "");
8018578Sache
8124348Simp	while ((ch = getopt(argc, argv, "benstuv")) != -1)
821556Srgrimes		switch (ch) {
831556Srgrimes		case 'b':
841556Srgrimes			bflag = nflag = 1;	/* -b implies -n */
851556Srgrimes			break;
861556Srgrimes		case 'e':
871556Srgrimes			eflag = vflag = 1;	/* -e implies -v */
881556Srgrimes			break;
891556Srgrimes		case 'n':
901556Srgrimes			nflag = 1;
911556Srgrimes			break;
921556Srgrimes		case 's':
931556Srgrimes			sflag = 1;
941556Srgrimes			break;
951556Srgrimes		case 't':
961556Srgrimes			tflag = vflag = 1;	/* -t implies -v */
971556Srgrimes			break;
981556Srgrimes		case 'u':
991556Srgrimes			setbuf(stdout, (char *)NULL);
1001556Srgrimes			break;
1011556Srgrimes		case 'v':
1021556Srgrimes			vflag = 1;
1031556Srgrimes			break;
10418546Simp		default:
1051556Srgrimes			(void)fprintf(stderr,
1061556Srgrimes			    "usage: cat [-benstuv] [-] [file ...]\n");
1071556Srgrimes			exit(1);
1081556Srgrimes		}
1091556Srgrimes	argv += optind;
1101556Srgrimes
1111556Srgrimes	if (bflag || eflag || nflag || sflag || tflag || vflag)
1121556Srgrimes		cook_args(argv);
1131556Srgrimes	else
1141556Srgrimes		raw_args(argv);
1151556Srgrimes	if (fclose(stdout))
1161556Srgrimes		err(1, "stdout");
1171556Srgrimes	exit(rval);
1181556Srgrimes}
1191556Srgrimes
1201556Srgrimesvoid
1211556Srgrimescook_args(argv)
1221556Srgrimes	char **argv;
1231556Srgrimes{
1241556Srgrimes	register FILE *fp;
1251556Srgrimes
1261556Srgrimes	fp = stdin;
1271556Srgrimes	filename = "stdin";
1281556Srgrimes	do {
1291556Srgrimes		if (*argv) {
1301556Srgrimes			if (!strcmp(*argv, "-"))
1311556Srgrimes				fp = stdin;
1321556Srgrimes			else if ((fp = fopen(*argv, "r")) == NULL) {
1331556Srgrimes				warn("%s", *argv);
13411145Sbde				rval = 1;
1351556Srgrimes				++argv;
1361556Srgrimes				continue;
1371556Srgrimes			}
1381556Srgrimes			filename = *argv++;
1391556Srgrimes		}
1401556Srgrimes		cook_buf(fp);
1411556Srgrimes		if (fp != stdin)
1421556Srgrimes			(void)fclose(fp);
1431556Srgrimes	} while (*argv);
1441556Srgrimes}
1451556Srgrimes
1461556Srgrimesvoid
1471556Srgrimescook_buf(fp)
1481556Srgrimes	register FILE *fp;
1491556Srgrimes{
1501556Srgrimes	register int ch, gobble, line, prev;
1511556Srgrimes
1521556Srgrimes	line = gobble = 0;
1531556Srgrimes	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
1541556Srgrimes		if (prev == '\n') {
1551556Srgrimes			if (ch == '\n') {
1561556Srgrimes				if (sflag) {
1571556Srgrimes					if (!gobble && putchar(ch) == EOF)
1581556Srgrimes						break;
1591556Srgrimes					gobble = 1;
1601556Srgrimes					continue;
1611556Srgrimes				}
1621556Srgrimes				if (nflag && !bflag) {
1631556Srgrimes					(void)fprintf(stdout, "%6d\t", ++line);
1641556Srgrimes					if (ferror(stdout))
1651556Srgrimes						break;
1661556Srgrimes				}
1671556Srgrimes			} else if (nflag) {
1681556Srgrimes				(void)fprintf(stdout, "%6d\t", ++line);
1691556Srgrimes				if (ferror(stdout))
1701556Srgrimes					break;
1711556Srgrimes			}
1721556Srgrimes		}
1731556Srgrimes		gobble = 0;
1741556Srgrimes		if (ch == '\n') {
1751556Srgrimes			if (eflag)
1761556Srgrimes				if (putchar('$') == EOF)
1771556Srgrimes					break;
1781556Srgrimes		} else if (ch == '\t') {
1791556Srgrimes			if (tflag) {
1801556Srgrimes				if (putchar('^') == EOF || putchar('I') == EOF)
1811556Srgrimes					break;
1821556Srgrimes				continue;
1831556Srgrimes			}
1841556Srgrimes		} else if (vflag) {
18518578Sache			if (!isascii(ch) && !isprint(ch)) {
1861556Srgrimes				if (putchar('M') == EOF || putchar('-') == EOF)
1871556Srgrimes					break;
1881556Srgrimes				ch = toascii(ch);
1891556Srgrimes			}
1901556Srgrimes			if (iscntrl(ch)) {
1911556Srgrimes				if (putchar('^') == EOF ||
1921556Srgrimes				    putchar(ch == '\177' ? '?' :
1931556Srgrimes				    ch | 0100) == EOF)
1941556Srgrimes					break;
1951556Srgrimes				continue;
1961556Srgrimes			}
1971556Srgrimes		}
1981556Srgrimes		if (putchar(ch) == EOF)
1991556Srgrimes			break;
2001556Srgrimes	}
2011556Srgrimes	if (ferror(fp)) {
2021556Srgrimes		warn("%s", filename);
20311145Sbde		rval = 1;
2041556Srgrimes		clearerr(fp);
2051556Srgrimes	}
2061556Srgrimes	if (ferror(stdout))
2071556Srgrimes		err(1, "stdout");
2081556Srgrimes}
2091556Srgrimes
2101556Srgrimesvoid
2111556Srgrimesraw_args(argv)
2121556Srgrimes	char **argv;
2131556Srgrimes{
2141556Srgrimes	register int fd;
2151556Srgrimes
2161556Srgrimes	fd = fileno(stdin);
2171556Srgrimes	filename = "stdin";
2181556Srgrimes	do {
2191556Srgrimes		if (*argv) {
2201556Srgrimes			if (!strcmp(*argv, "-"))
2211556Srgrimes				fd = fileno(stdin);
2221556Srgrimes			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
2231556Srgrimes				warn("%s", *argv);
22411145Sbde				rval = 1;
2251556Srgrimes				++argv;
2261556Srgrimes				continue;
2271556Srgrimes			}
2281556Srgrimes			filename = *argv++;
2291556Srgrimes		}
2301556Srgrimes		raw_cat(fd);
2311556Srgrimes		if (fd != fileno(stdin))
2321556Srgrimes			(void)close(fd);
2331556Srgrimes	} while (*argv);
2341556Srgrimes}
2351556Srgrimes
2361556Srgrimesvoid
2371556Srgrimesraw_cat(rfd)
2381556Srgrimes	register int rfd;
2391556Srgrimes{
2401556Srgrimes	register int nr, nw, off, wfd;
2411556Srgrimes	static int bsize;
2421556Srgrimes	static char *buf;
2431556Srgrimes	struct stat sbuf;
2441556Srgrimes
2451556Srgrimes	wfd = fileno(stdout);
2461556Srgrimes	if (buf == NULL) {
2471556Srgrimes		if (fstat(wfd, &sbuf))
2481556Srgrimes			err(1, "%s", filename);
2491556Srgrimes		bsize = MAX(sbuf.st_blksize, 1024);
2501556Srgrimes		if ((buf = malloc((u_int)bsize)) == NULL)
25118546Simp			err(1, NULL);
2521556Srgrimes	}
2531556Srgrimes	while ((nr = read(rfd, buf, bsize)) > 0)
2541556Srgrimes		for (off = 0; nr; nr -= nw, off += nw)
2551556Srgrimes			if ((nw = write(wfd, buf + off, nr)) < 0)
2561556Srgrimes				err(1, "stdout");
25711145Sbde	if (nr < 0) {
2581556Srgrimes		warn("%s", filename);
25911145Sbde		rval = 1;
26011145Sbde	}
2611556Srgrimes}
262