cat.c revision 78732
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
4536000Scharnierstatic char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
4635772Scharnier#endif
4735772Scharnierstatic const char rcsid[] =
4850471Speter  "$FreeBSD: head/bin/cat/cat.c 78732 2001-06-24 23:04:23Z dd $";
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>
6078732Sdd#include <string.h>
611556Srgrimes#include <unistd.h>
621556Srgrimes
631556Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag;
641556Srgrimesint rval;
6539065Simpconst char *filename;
661556Srgrimes
671556Srgrimesvoid cook_args __P((char *argv[]));
681556Srgrimesvoid cook_buf __P((FILE *));
6939138Simpint main __P((int argc, char *argv[]));
701556Srgrimesvoid raw_args __P((char *argv[]));
711556Srgrimesvoid raw_cat __P((int));
721556Srgrimes
731556Srgrimesint
7439138Simpmain(argc, argv)
7539138Simp	int argc;
7639138Simp	char *argv[];
771556Srgrimes{
781556Srgrimes	int ch;
791556Srgrimes
8018578Sache	setlocale(LC_CTYPE, "");
8118578Sache
8224348Simp	while ((ch = getopt(argc, argv, "benstuv")) != -1)
831556Srgrimes		switch (ch) {
841556Srgrimes		case 'b':
851556Srgrimes			bflag = nflag = 1;	/* -b implies -n */
861556Srgrimes			break;
871556Srgrimes		case 'e':
881556Srgrimes			eflag = vflag = 1;	/* -e implies -v */
891556Srgrimes			break;
901556Srgrimes		case 'n':
911556Srgrimes			nflag = 1;
921556Srgrimes			break;
931556Srgrimes		case 's':
941556Srgrimes			sflag = 1;
951556Srgrimes			break;
961556Srgrimes		case 't':
971556Srgrimes			tflag = vflag = 1;	/* -t implies -v */
981556Srgrimes			break;
991556Srgrimes		case 'u':
10059239Sasmodai			setbuf(stdout, NULL);
1011556Srgrimes			break;
1021556Srgrimes		case 'v':
1031556Srgrimes			vflag = 1;
1041556Srgrimes			break;
10518546Simp		default:
1061556Srgrimes			(void)fprintf(stderr,
1071556Srgrimes			    "usage: cat [-benstuv] [-] [file ...]\n");
1081556Srgrimes			exit(1);
1091556Srgrimes		}
1101556Srgrimes	argv += optind;
1111556Srgrimes
1121556Srgrimes	if (bflag || eflag || nflag || sflag || tflag || vflag)
1131556Srgrimes		cook_args(argv);
1141556Srgrimes	else
1151556Srgrimes		raw_args(argv);
1161556Srgrimes	if (fclose(stdout))
1171556Srgrimes		err(1, "stdout");
1181556Srgrimes	exit(rval);
1191556Srgrimes}
1201556Srgrimes
1211556Srgrimesvoid
1221556Srgrimescook_args(argv)
1231556Srgrimes	char **argv;
1241556Srgrimes{
1251556Srgrimes	register FILE *fp;
1261556Srgrimes
1271556Srgrimes	fp = stdin;
1281556Srgrimes	filename = "stdin";
1291556Srgrimes	do {
1301556Srgrimes		if (*argv) {
1311556Srgrimes			if (!strcmp(*argv, "-"))
1321556Srgrimes				fp = stdin;
1331556Srgrimes			else if ((fp = fopen(*argv, "r")) == NULL) {
1341556Srgrimes				warn("%s", *argv);
13511145Sbde				rval = 1;
1361556Srgrimes				++argv;
1371556Srgrimes				continue;
1381556Srgrimes			}
1391556Srgrimes			filename = *argv++;
1401556Srgrimes		}
1411556Srgrimes		cook_buf(fp);
1421556Srgrimes		if (fp != stdin)
1431556Srgrimes			(void)fclose(fp);
1441556Srgrimes	} while (*argv);
1451556Srgrimes}
1461556Srgrimes
1471556Srgrimesvoid
1481556Srgrimescook_buf(fp)
1491556Srgrimes	register FILE *fp;
1501556Srgrimes{
1511556Srgrimes	register int ch, gobble, line, prev;
1521556Srgrimes
1531556Srgrimes	line = gobble = 0;
1541556Srgrimes	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
1551556Srgrimes		if (prev == '\n') {
1561556Srgrimes			if (ch == '\n') {
1571556Srgrimes				if (sflag) {
1581556Srgrimes					if (!gobble && putchar(ch) == EOF)
1591556Srgrimes						break;
1601556Srgrimes					gobble = 1;
1611556Srgrimes					continue;
1621556Srgrimes				}
1631556Srgrimes				if (nflag && !bflag) {
1641556Srgrimes					(void)fprintf(stdout, "%6d\t", ++line);
1651556Srgrimes					if (ferror(stdout))
1661556Srgrimes						break;
1671556Srgrimes				}
1681556Srgrimes			} else if (nflag) {
1691556Srgrimes				(void)fprintf(stdout, "%6d\t", ++line);
1701556Srgrimes				if (ferror(stdout))
1711556Srgrimes					break;
1721556Srgrimes			}
1731556Srgrimes		}
1741556Srgrimes		gobble = 0;
1751556Srgrimes		if (ch == '\n') {
1761556Srgrimes			if (eflag)
1771556Srgrimes				if (putchar('$') == EOF)
1781556Srgrimes					break;
1791556Srgrimes		} else if (ch == '\t') {
1801556Srgrimes			if (tflag) {
1811556Srgrimes				if (putchar('^') == EOF || putchar('I') == EOF)
1821556Srgrimes					break;
1831556Srgrimes				continue;
1841556Srgrimes			}
1851556Srgrimes		} else if (vflag) {
18618578Sache			if (!isascii(ch) && !isprint(ch)) {
1871556Srgrimes				if (putchar('M') == EOF || putchar('-') == EOF)
1881556Srgrimes					break;
1891556Srgrimes				ch = toascii(ch);
1901556Srgrimes			}
1911556Srgrimes			if (iscntrl(ch)) {
1921556Srgrimes				if (putchar('^') == EOF ||
1931556Srgrimes				    putchar(ch == '\177' ? '?' :
1941556Srgrimes				    ch | 0100) == EOF)
1951556Srgrimes					break;
1961556Srgrimes				continue;
1971556Srgrimes			}
1981556Srgrimes		}
1991556Srgrimes		if (putchar(ch) == EOF)
2001556Srgrimes			break;
2011556Srgrimes	}
2021556Srgrimes	if (ferror(fp)) {
2031556Srgrimes		warn("%s", filename);
20411145Sbde		rval = 1;
2051556Srgrimes		clearerr(fp);
2061556Srgrimes	}
2071556Srgrimes	if (ferror(stdout))
2081556Srgrimes		err(1, "stdout");
2091556Srgrimes}
2101556Srgrimes
2111556Srgrimesvoid
2121556Srgrimesraw_args(argv)
2131556Srgrimes	char **argv;
2141556Srgrimes{
2151556Srgrimes	register int fd;
2161556Srgrimes
2171556Srgrimes	fd = fileno(stdin);
2181556Srgrimes	filename = "stdin";
2191556Srgrimes	do {
2201556Srgrimes		if (*argv) {
2211556Srgrimes			if (!strcmp(*argv, "-"))
2221556Srgrimes				fd = fileno(stdin);
2231556Srgrimes			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
2241556Srgrimes				warn("%s", *argv);
22511145Sbde				rval = 1;
2261556Srgrimes				++argv;
2271556Srgrimes				continue;
2281556Srgrimes			}
2291556Srgrimes			filename = *argv++;
2301556Srgrimes		}
2311556Srgrimes		raw_cat(fd);
2321556Srgrimes		if (fd != fileno(stdin))
2331556Srgrimes			(void)close(fd);
2341556Srgrimes	} while (*argv);
2351556Srgrimes}
2361556Srgrimes
2371556Srgrimesvoid
2381556Srgrimesraw_cat(rfd)
2391556Srgrimes	register int rfd;
2401556Srgrimes{
24139065Simp	register int off, wfd;
24239065Simp	ssize_t nr, nw;
24339065Simp	static size_t bsize;
2441556Srgrimes	static char *buf;
2451556Srgrimes	struct stat sbuf;
2461556Srgrimes
2471556Srgrimes	wfd = fileno(stdout);
2481556Srgrimes	if (buf == NULL) {
2491556Srgrimes		if (fstat(wfd, &sbuf))
2501556Srgrimes			err(1, "%s", filename);
2511556Srgrimes		bsize = MAX(sbuf.st_blksize, 1024);
25239138Simp		if ((buf = malloc(bsize)) == NULL)
25359239Sasmodai			err(1, "buffer");
2541556Srgrimes	}
2551556Srgrimes	while ((nr = read(rfd, buf, bsize)) > 0)
2561556Srgrimes		for (off = 0; nr; nr -= nw, off += nw)
25739138Simp			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
2581556Srgrimes				err(1, "stdout");
25911145Sbde	if (nr < 0) {
2601556Srgrimes		warn("%s", filename);
26111145Sbde		rval = 1;
26211145Sbde	}
2631556Srgrimes}
264