cat.c revision 11145
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.
353044Sdg *
3611145Sbde *	$Id: cat.c,v 1.2 1994/09/24 02:53:26 davidg Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
401556Srgrimesstatic char copyright[] =
411556Srgrimes"@(#) Copyright (c) 1989, 1993\n\
421556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
431556Srgrimes#endif /* not lint */
441556Srgrimes
451556Srgrimes#ifndef lint
461556Srgrimesstatic char sccsid[] = "@(#)cat.c	8.1 (Berkeley) 7/19/93";
471556Srgrimes#endif /* not lint */
481556Srgrimes
491556Srgrimes#include <sys/param.h>
501556Srgrimes#include <sys/stat.h>
511556Srgrimes
521556Srgrimes#include <ctype.h>
531556Srgrimes#include <err.h>
541556Srgrimes#include <errno.h>
551556Srgrimes#include <fcntl.h>
561556Srgrimes#include <stdio.h>
571556Srgrimes#include <stdlib.h>
581556Srgrimes#include <string.h>
591556Srgrimes#include <unistd.h>
601556Srgrimes
611556Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag;
621556Srgrimesint rval;
631556Srgrimeschar *filename;
641556Srgrimes
651556Srgrimesvoid cook_args __P((char *argv[]));
661556Srgrimesvoid cook_buf __P((FILE *));
671556Srgrimesvoid raw_args __P((char *argv[]));
681556Srgrimesvoid raw_cat __P((int));
691556Srgrimes
701556Srgrimesint
711556Srgrimesmain(argc, argv)
721556Srgrimes	int argc;
731556Srgrimes	char *argv[];
741556Srgrimes{
751556Srgrimes	extern int optind;
761556Srgrimes	int ch;
771556Srgrimes
781556Srgrimes	while ((ch = getopt(argc, argv, "benstuv")) != EOF)
791556Srgrimes		switch (ch) {
801556Srgrimes		case 'b':
811556Srgrimes			bflag = nflag = 1;	/* -b implies -n */
821556Srgrimes			break;
831556Srgrimes		case 'e':
841556Srgrimes			eflag = vflag = 1;	/* -e implies -v */
851556Srgrimes			break;
861556Srgrimes		case 'n':
871556Srgrimes			nflag = 1;
881556Srgrimes			break;
891556Srgrimes		case 's':
901556Srgrimes			sflag = 1;
911556Srgrimes			break;
921556Srgrimes		case 't':
931556Srgrimes			tflag = vflag = 1;	/* -t implies -v */
941556Srgrimes			break;
951556Srgrimes		case 'u':
961556Srgrimes			setbuf(stdout, (char *)NULL);
971556Srgrimes			break;
981556Srgrimes		case 'v':
991556Srgrimes			vflag = 1;
1001556Srgrimes			break;
1011556Srgrimes		case '?':
1021556Srgrimes			(void)fprintf(stderr,
1031556Srgrimes			    "usage: cat [-benstuv] [-] [file ...]\n");
1041556Srgrimes			exit(1);
1051556Srgrimes		}
1061556Srgrimes	argv += optind;
1071556Srgrimes
1081556Srgrimes	if (bflag || eflag || nflag || sflag || tflag || vflag)
1091556Srgrimes		cook_args(argv);
1101556Srgrimes	else
1111556Srgrimes		raw_args(argv);
1121556Srgrimes	if (fclose(stdout))
1131556Srgrimes		err(1, "stdout");
1141556Srgrimes	exit(rval);
1151556Srgrimes}
1161556Srgrimes
1171556Srgrimesvoid
1181556Srgrimescook_args(argv)
1191556Srgrimes	char **argv;
1201556Srgrimes{
1211556Srgrimes	register FILE *fp;
1221556Srgrimes
1231556Srgrimes	fp = stdin;
1241556Srgrimes	filename = "stdin";
1251556Srgrimes	do {
1261556Srgrimes		if (*argv) {
1271556Srgrimes			if (!strcmp(*argv, "-"))
1281556Srgrimes				fp = stdin;
1291556Srgrimes			else if ((fp = fopen(*argv, "r")) == NULL) {
1301556Srgrimes				warn("%s", *argv);
13111145Sbde				rval = 1;
1321556Srgrimes				++argv;
1331556Srgrimes				continue;
1341556Srgrimes			}
1351556Srgrimes			filename = *argv++;
1361556Srgrimes		}
1371556Srgrimes		cook_buf(fp);
1381556Srgrimes		if (fp != stdin)
1391556Srgrimes			(void)fclose(fp);
1401556Srgrimes	} while (*argv);
1411556Srgrimes}
1421556Srgrimes
1431556Srgrimesvoid
1441556Srgrimescook_buf(fp)
1451556Srgrimes	register FILE *fp;
1461556Srgrimes{
1471556Srgrimes	register int ch, gobble, line, prev;
1481556Srgrimes
1491556Srgrimes	line = gobble = 0;
1501556Srgrimes	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
1511556Srgrimes		if (prev == '\n') {
1521556Srgrimes			if (ch == '\n') {
1531556Srgrimes				if (sflag) {
1541556Srgrimes					if (!gobble && putchar(ch) == EOF)
1551556Srgrimes						break;
1561556Srgrimes					gobble = 1;
1571556Srgrimes					continue;
1581556Srgrimes				}
1591556Srgrimes				if (nflag && !bflag) {
1601556Srgrimes					(void)fprintf(stdout, "%6d\t", ++line);
1611556Srgrimes					if (ferror(stdout))
1621556Srgrimes						break;
1631556Srgrimes				}
1641556Srgrimes			} else if (nflag) {
1651556Srgrimes				(void)fprintf(stdout, "%6d\t", ++line);
1661556Srgrimes				if (ferror(stdout))
1671556Srgrimes					break;
1681556Srgrimes			}
1691556Srgrimes		}
1701556Srgrimes		gobble = 0;
1711556Srgrimes		if (ch == '\n') {
1721556Srgrimes			if (eflag)
1731556Srgrimes				if (putchar('$') == EOF)
1741556Srgrimes					break;
1751556Srgrimes		} else if (ch == '\t') {
1761556Srgrimes			if (tflag) {
1771556Srgrimes				if (putchar('^') == EOF || putchar('I') == EOF)
1781556Srgrimes					break;
1791556Srgrimes				continue;
1801556Srgrimes			}
1811556Srgrimes		} else if (vflag) {
1821556Srgrimes			if (!isascii(ch)) {
1831556Srgrimes				if (putchar('M') == EOF || putchar('-') == EOF)
1841556Srgrimes					break;
1851556Srgrimes				ch = toascii(ch);
1861556Srgrimes			}
1871556Srgrimes			if (iscntrl(ch)) {
1881556Srgrimes				if (putchar('^') == EOF ||
1891556Srgrimes				    putchar(ch == '\177' ? '?' :
1901556Srgrimes				    ch | 0100) == EOF)
1911556Srgrimes					break;
1921556Srgrimes				continue;
1931556Srgrimes			}
1941556Srgrimes		}
1951556Srgrimes		if (putchar(ch) == EOF)
1961556Srgrimes			break;
1971556Srgrimes	}
1981556Srgrimes	if (ferror(fp)) {
1991556Srgrimes		warn("%s", filename);
20011145Sbde		rval = 1;
2011556Srgrimes		clearerr(fp);
2021556Srgrimes	}
2031556Srgrimes	if (ferror(stdout))
2041556Srgrimes		err(1, "stdout");
2051556Srgrimes}
2061556Srgrimes
2071556Srgrimesvoid
2081556Srgrimesraw_args(argv)
2091556Srgrimes	char **argv;
2101556Srgrimes{
2111556Srgrimes	register int fd;
2121556Srgrimes
2131556Srgrimes	fd = fileno(stdin);
2141556Srgrimes	filename = "stdin";
2151556Srgrimes	do {
2161556Srgrimes		if (*argv) {
2171556Srgrimes			if (!strcmp(*argv, "-"))
2181556Srgrimes				fd = fileno(stdin);
2191556Srgrimes			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
2201556Srgrimes				warn("%s", *argv);
22111145Sbde				rval = 1;
2221556Srgrimes				++argv;
2231556Srgrimes				continue;
2241556Srgrimes			}
2251556Srgrimes			filename = *argv++;
2261556Srgrimes		}
2271556Srgrimes		raw_cat(fd);
2281556Srgrimes		if (fd != fileno(stdin))
2291556Srgrimes			(void)close(fd);
2301556Srgrimes	} while (*argv);
2311556Srgrimes}
2321556Srgrimes
2331556Srgrimesvoid
2341556Srgrimesraw_cat(rfd)
2351556Srgrimes	register int rfd;
2361556Srgrimes{
2371556Srgrimes	register int nr, nw, off, wfd;
2381556Srgrimes	static int bsize;
2391556Srgrimes	static char *buf;
2401556Srgrimes	struct stat sbuf;
2411556Srgrimes
2421556Srgrimes	wfd = fileno(stdout);
2431556Srgrimes	if (buf == NULL) {
2441556Srgrimes		if (fstat(wfd, &sbuf))
2451556Srgrimes			err(1, "%s", filename);
2461556Srgrimes		bsize = MAX(sbuf.st_blksize, 1024);
2471556Srgrimes		if ((buf = malloc((u_int)bsize)) == NULL)
2481556Srgrimes			err(1, "");
2491556Srgrimes	}
2501556Srgrimes	while ((nr = read(rfd, buf, bsize)) > 0)
2511556Srgrimes		for (off = 0; nr; nr -= nw, off += nw)
2521556Srgrimes			if ((nw = write(wfd, buf + off, nr)) < 0)
2531556Srgrimes				err(1, "stdout");
25411145Sbde	if (nr < 0) {
2551556Srgrimes		warn("%s", filename);
25611145Sbde		rval = 1;
25711145Sbde	}
2581556Srgrimes}
259