cat.c revision 39138
11592Srgrimes/*
21592Srgrimes * Copyright (c) 1989, 1993
31592Srgrimes *	The Regents of the University of California.  All rights reserved.
41592Srgrimes *
51592Srgrimes * This code is derived from software contributed to Berkeley by
61592Srgrimes * Kevin Fall.
71592Srgrimes *
81592Srgrimes * Redistribution and use in source and binary forms, with or without
91592Srgrimes * modification, are permitted provided that the following conditions
101592Srgrimes * are met:
111592Srgrimes * 1. Redistributions of source code must retain the above copyright
121592Srgrimes *    notice, this list of conditions and the following disclaimer.
131592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141592Srgrimes *    notice, this list of conditions and the following disclaimer in the
151592Srgrimes *    documentation and/or other materials provided with the distribution.
161592Srgrimes * 3. All advertising materials mentioning features or use of this software
171592Srgrimes *    must display the following acknowledgement:
181592Srgrimes *	This product includes software developed by the University of
191592Srgrimes *	California, Berkeley and its contributors.
201592Srgrimes * 4. Neither the name of the University nor the names of its contributors
211592Srgrimes *    may be used to endorse or promote products derived from this software
221592Srgrimes *    without specific prior written permission.
231592Srgrimes *
241592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341592Srgrimes * SUCH DAMAGE.
3529916Smarkm */
361592Srgrimes
371592Srgrimes#ifndef lint
381592Srgrimesstatic char const copyright[] =
391592Srgrimes"@(#) Copyright (c) 1989, 1993\n\
401592Srgrimes	The Regents of the University of California.  All rights reserved.\n";
4131405Scharnier#endif /* not lint */
4229916Smarkm
4331405Scharnier#ifndef lint
4431405Scharnier#if 0
4550476Speterstatic char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
461592Srgrimes#endif
471592Srgrimesstatic const char rcsid[] =
481592Srgrimes	"$Id: cat.c,v 1.12 1998/09/11 05:48:06 imp Exp $";
491592Srgrimes#endif /* not lint */
501592Srgrimes
511592Srgrimes#include <sys/param.h>
521592Srgrimes#include <sys/stat.h>
531592Srgrimes
541592Srgrimes#include <ctype.h>
551592Srgrimes#include <err.h>
561592Srgrimes#include <fcntl.h>
571592Srgrimes#include <locale.h>
5829916Smarkm#include <stdio.h>
591592Srgrimes#include <stdlib.h>
601592Srgrimes#include <unistd.h>
611592Srgrimes
621592Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag;
631592Srgrimesint rval;
641592Srgrimesconst char *filename;
651592Srgrimes
661592Srgrimesvoid cook_args __P((char *argv[]));
671592Srgrimesvoid cook_buf __P((FILE *));
681592Srgrimesint main __P((int argc, char *argv[]));
6911486Sdgvoid raw_args __P((char *argv[]));
701592Srgrimesvoid raw_cat __P((int));
711592Srgrimes
721592Srgrimesint
7331405Scharniermain(argc, argv)
7431405Scharnier	int argc;
751592Srgrimes	char *argv[];
761592Srgrimes{
771592Srgrimes	int ch;
781592Srgrimes
791592Srgrimes	setlocale(LC_CTYPE, "");
8031405Scharnier
811592Srgrimes	while ((ch = getopt(argc, argv, "benstuv")) != -1)
821592Srgrimes		switch (ch) {
8351433Smarkm		case 'b':
8451433Smarkm			bflag = nflag = 1;	/* -b implies -n */
8551433Smarkm			break;
8651433Smarkm		case 'e':
8751433Smarkm			eflag = vflag = 1;	/* -e implies -v */
881592Srgrimes			break;
891592Srgrimes		case 'n':
901592Srgrimes			nflag = 1;
911592Srgrimes			break;
9251433Smarkm		case 's':
931592Srgrimes			sflag = 1;
9456590Sshin			break;
9556590Sshin		case 't':
9656590Sshin			tflag = vflag = 1;	/* -t implies -v */
9756590Sshin			break;
9856590Sshin		case 'u':
991592Srgrimes			setbuf(stdout, (char *)NULL);
1001592Srgrimes			break;
1011592Srgrimes		case 'v':
1021592Srgrimes			vflag = 1;
1031592Srgrimes			break;
1041592Srgrimes		default:
1051592Srgrimes			(void)fprintf(stderr,
10611486Sdg			    "usage: cat [-benstuv] [-] [file ...]\n");
1071592Srgrimes			exit(1);
1081592Srgrimes		}
1091592Srgrimes	argv += optind;
11056590Sshin
11156590Sshin	if (bflag || eflag || nflag || sflag || tflag || vflag)
11256590Sshin		cook_args(argv);
11356590Sshin	else
11456590Sshin		raw_args(argv);
11556590Sshin	if (fclose(stdout))
11656590Sshin		err(1, "stdout");
11756590Sshin	exit(rval);
11856590Sshin}
11956590Sshin
12056590Sshinvoid
12156590Sshincook_args(argv)
12256590Sshin	char **argv;
12356590Sshin{
1241592Srgrimes	register FILE *fp;
1251592Srgrimes
1261592Srgrimes	fp = stdin;
1271592Srgrimes	filename = "stdin";
12856590Sshin	do {
1291592Srgrimes		if (*argv) {
1301592Srgrimes			if (!strcmp(*argv, "-"))
1311592Srgrimes				fp = stdin;
1321592Srgrimes			else if ((fp = fopen(*argv, "r")) == NULL) {
1331592Srgrimes				warn("%s", *argv);
13451433Smarkm				rval = 1;
13551433Smarkm				++argv;
13651433Smarkm				continue;
13751433Smarkm			}
1381592Srgrimes			filename = *argv++;
1391592Srgrimes		}
1401592Srgrimes		cook_buf(fp);
1411592Srgrimes		if (fp != stdin)
1421592Srgrimes			(void)fclose(fp);
1431592Srgrimes	} while (*argv);
14456590Sshin}
1451592Srgrimes
1461592Srgrimesvoid
1471592Srgrimescook_buf(fp)
1481592Srgrimes	register FILE *fp;
1491592Srgrimes{
15024349Simp	register int ch, gobble, line, prev;
1511592Srgrimes
15211486Sdg	line = gobble = 0;
15311486Sdg	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
15411486Sdg		if (prev == '\n') {
1551592Srgrimes			if (ch == '\n') {
1561592Srgrimes				if (sflag) {
1571592Srgrimes					if (!gobble && putchar(ch) == EOF)
1581592Srgrimes						break;
1591592Srgrimes					gobble = 1;
1601592Srgrimes					continue;
1611592Srgrimes				}
1621592Srgrimes				if (nflag && !bflag) {
1631592Srgrimes					(void)fprintf(stdout, "%6d\t", ++line);
1641592Srgrimes					if (ferror(stdout))
1651592Srgrimes						break;
1661592Srgrimes				}
1671592Srgrimes			} else if (nflag) {
1681592Srgrimes				(void)fprintf(stdout, "%6d\t", ++line);
1691592Srgrimes				if (ferror(stdout))
1701592Srgrimes					break;
1711592Srgrimes			}
1721592Srgrimes		}
1731592Srgrimes		gobble = 0;
1741592Srgrimes		if (ch == '\n') {
1751592Srgrimes			if (eflag)
1761592Srgrimes				if (putchar('$') == EOF)
1771592Srgrimes					break;
1781592Srgrimes		} else if (ch == '\t') {
1791592Srgrimes			if (tflag) {
1801592Srgrimes				if (putchar('^') == EOF || putchar('I') == EOF)
1811592Srgrimes					break;
1821592Srgrimes				continue;
1831592Srgrimes			}
1841592Srgrimes		} else if (vflag) {
1851592Srgrimes			if (!isascii(ch) && !isprint(ch)) {
18611486Sdg				if (putchar('M') == EOF || putchar('-') == EOF)
18711486Sdg					break;
18811486Sdg				ch = toascii(ch);
18956590Sshin			}
19056590Sshin			if (iscntrl(ch)) {
1911592Srgrimes				if (putchar('^') == EOF ||
1921592Srgrimes				    putchar(ch == '\177' ? '?' :
1931592Srgrimes				    ch | 0100) == EOF)
19456590Sshin					break;
19511486Sdg				continue;
1961592Srgrimes			}
19729916Smarkm		}
1981592Srgrimes		if (putchar(ch) == EOF)
1991592Srgrimes			break;
2001592Srgrimes	}
2011592Srgrimes	if (ferror(fp)) {
2021592Srgrimes		warn("%s", filename);
2031592Srgrimes		rval = 1;
2041592Srgrimes		clearerr(fp);
2051592Srgrimes	}
2061592Srgrimes	if (ferror(stdout))
2071592Srgrimes		err(1, "stdout");
2081592Srgrimes}
2091592Srgrimes
2101592Srgrimesvoid
21156590Sshinraw_args(argv)
2121592Srgrimes	char **argv;
2131592Srgrimes{
2141592Srgrimes	register int fd;
21556590Sshin
21656590Sshin	fd = fileno(stdin);
2171592Srgrimes	filename = "stdin";
2181592Srgrimes	do {
2191592Srgrimes		if (*argv) {
2201592Srgrimes			if (!strcmp(*argv, "-"))
2211592Srgrimes				fd = fileno(stdin);
2221592Srgrimes			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
2231592Srgrimes				warn("%s", *argv);
2241592Srgrimes				rval = 1;
2251592Srgrimes				++argv;
22656590Sshin				continue;
22756590Sshin			}
22856590Sshin			filename = *argv++;
22956590Sshin		}
23056590Sshin		raw_cat(fd);
23124191Simp		if (fd != fileno(stdin))
2321592Srgrimes			(void)close(fd);
2331592Srgrimes	} while (*argv);
23463959Sume}
23556590Sshin
23663959Sumevoid
23756590Sshinraw_cat(rfd)
23856590Sshin	register int rfd;
23956590Sshin{
24056590Sshin	register int off, wfd;
24156590Sshin	ssize_t nr, nw;
24256590Sshin	static size_t bsize;
24356590Sshin	static char *buf;
24456590Sshin	struct stat sbuf;
24556590Sshin
2461592Srgrimes	wfd = fileno(stdout);
24756590Sshin	if (buf == NULL) {
2481592Srgrimes		if (fstat(wfd, &sbuf))
2491592Srgrimes			err(1, "%s", filename);
2501592Srgrimes		bsize = MAX(sbuf.st_blksize, 1024);
25156590Sshin		if ((buf = malloc(bsize)) == NULL)
25256590Sshin			err(1, NULL);
25322455Simp	}
25422455Simp	while ((nr = read(rfd, buf, bsize)) > 0)
2551592Srgrimes		for (off = 0; nr; nr -= nw, off += nw)
2561592Srgrimes			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
2571592Srgrimes				err(1, "stdout");
2581592Srgrimes	if (nr < 0) {
2591592Srgrimes		warn("%s", filename);
2601592Srgrimes		rval = 1;
2611592Srgrimes	}
2621592Srgrimes}
26322455Simp