cat.c revision 83962
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 83962 2001-09-26 11:34:14Z ru $";
491556Srgrimes#endif /* not lint */
501556Srgrimes
511556Srgrimes#include <sys/param.h>
521556Srgrimes#include <sys/stat.h>
5383482Sdillon#ifndef NO_UDOM_SUPPORT
5483482Sdillon#include <sys/socket.h>
5583482Sdillon#include <sys/un.h>
5683482Sdillon#include <errno.h>
5783482Sdillon#endif
581556Srgrimes
591556Srgrimes#include <ctype.h>
601556Srgrimes#include <err.h>
611556Srgrimes#include <fcntl.h>
6218578Sache#include <locale.h>
631556Srgrimes#include <stdio.h>
641556Srgrimes#include <stdlib.h>
6578732Sdd#include <string.h>
661556Srgrimes#include <unistd.h>
6783482Sdillon#include <stddef.h>
681556Srgrimes
691556Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag;
701556Srgrimesint rval;
7139065Simpconst char *filename;
721556Srgrimes
7339138Simpint main __P((int argc, char *argv[]));
741556Srgrimes
7583482Sdillonstatic void scanfiles __P((char **argv, int cooked));
7683482Sdillonstatic void cook_cat __P((FILE *));
7783482Sdillonstatic void raw_cat __P((int));
7883482Sdillon
7983482Sdillon#ifndef NO_UDOM_SUPPORT
8083962Srustatic int udom_open __P((const char *path, int flags));
8183482Sdillon#endif
8283482Sdillon
831556Srgrimesint
8439138Simpmain(argc, argv)
8539138Simp	int argc;
8639138Simp	char *argv[];
871556Srgrimes{
881556Srgrimes	int ch;
891556Srgrimes
9018578Sache	setlocale(LC_CTYPE, "");
9118578Sache
9224348Simp	while ((ch = getopt(argc, argv, "benstuv")) != -1)
931556Srgrimes		switch (ch) {
941556Srgrimes		case 'b':
951556Srgrimes			bflag = nflag = 1;	/* -b implies -n */
961556Srgrimes			break;
971556Srgrimes		case 'e':
981556Srgrimes			eflag = vflag = 1;	/* -e implies -v */
991556Srgrimes			break;
1001556Srgrimes		case 'n':
1011556Srgrimes			nflag = 1;
1021556Srgrimes			break;
1031556Srgrimes		case 's':
1041556Srgrimes			sflag = 1;
1051556Srgrimes			break;
1061556Srgrimes		case 't':
1071556Srgrimes			tflag = vflag = 1;	/* -t implies -v */
1081556Srgrimes			break;
1091556Srgrimes		case 'u':
11059239Sasmodai			setbuf(stdout, NULL);
1111556Srgrimes			break;
1121556Srgrimes		case 'v':
1131556Srgrimes			vflag = 1;
1141556Srgrimes			break;
11518546Simp		default:
1161556Srgrimes			(void)fprintf(stderr,
1171556Srgrimes			    "usage: cat [-benstuv] [-] [file ...]\n");
1181556Srgrimes			exit(1);
1191556Srgrimes		}
1201556Srgrimes	argv += optind;
1211556Srgrimes
1221556Srgrimes	if (bflag || eflag || nflag || sflag || tflag || vflag)
12383482Sdillon		scanfiles(argv, 1);
1241556Srgrimes	else
12583482Sdillon		scanfiles(argv, 0);
1261556Srgrimes	if (fclose(stdout))
1271556Srgrimes		err(1, "stdout");
1281556Srgrimes	exit(rval);
1291556Srgrimes}
1301556Srgrimes
1311556Srgrimesvoid
13283482Sdillonscanfiles(argv, cooked)
13383482Sdillon    char **argv;
13483482Sdillon    int cooked;
1351556Srgrimes{
13683482Sdillon	int i = 0;
13783482Sdillon	char *path;
13883961Sru	FILE *fp;
1391556Srgrimes
14083482Sdillon	while ((path = argv[i]) != NULL || i == 0) {
14183482Sdillon		int fd;
14283482Sdillon
14383482Sdillon		if (path == NULL || strcmp(path, "-") == 0) {
14483482Sdillon			filename = "stdin";
14583961Sru			fd = STDIN_FILENO;
14683482Sdillon		} else {
14783482Sdillon			filename = path;
14883482Sdillon			fd = open(path, O_RDONLY);
14983482Sdillon#ifndef NO_UDOM_SUPPORT
15083482Sdillon			if (fd < 0 && errno == EOPNOTSUPP)
15183962Sru				fd = udom_open(path, O_RDONLY);
15283482Sdillon#endif
1531556Srgrimes		}
15483482Sdillon		if (fd < 0) {
15583482Sdillon			warn("%s", path);
15683482Sdillon			rval = 1;
15783482Sdillon		} else if (cooked) {
15883961Sru			if (fd == STDIN_FILENO)
15983961Sru				cook_cat(stdin);
16083961Sru			else {
16183961Sru				fp = fdopen(fd, "r");
16283961Sru				cook_cat(fp);
16383961Sru				fclose(fp);
16483961Sru			}
16583482Sdillon		} else {
16683482Sdillon			raw_cat(fd);
16783961Sru			if (fd != STDIN_FILENO)
16883961Sru				close(fd);
16983482Sdillon		}
17083482Sdillon		if (path == NULL)
17183482Sdillon			break;
17283482Sdillon		++i;
17383482Sdillon	}
1741556Srgrimes}
1751556Srgrimes
17683482Sdillonstatic void
17783482Sdilloncook_cat(fp)
1781556Srgrimes	register FILE *fp;
1791556Srgrimes{
1801556Srgrimes	register int ch, gobble, line, prev;
1811556Srgrimes
18283961Sru	/* Reset EOF condition on stdin. */
18383961Sru	if (fp == stdin && feof(stdin))
18483961Sru		clearerr(stdin);
18583961Sru
1861556Srgrimes	line = gobble = 0;
1871556Srgrimes	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
1881556Srgrimes		if (prev == '\n') {
1891556Srgrimes			if (ch == '\n') {
1901556Srgrimes				if (sflag) {
1911556Srgrimes					if (!gobble && putchar(ch) == EOF)
1921556Srgrimes						break;
1931556Srgrimes					gobble = 1;
1941556Srgrimes					continue;
1951556Srgrimes				}
1961556Srgrimes				if (nflag && !bflag) {
1971556Srgrimes					(void)fprintf(stdout, "%6d\t", ++line);
1981556Srgrimes					if (ferror(stdout))
1991556Srgrimes						break;
2001556Srgrimes				}
2011556Srgrimes			} else if (nflag) {
2021556Srgrimes				(void)fprintf(stdout, "%6d\t", ++line);
2031556Srgrimes				if (ferror(stdout))
2041556Srgrimes					break;
2051556Srgrimes			}
2061556Srgrimes		}
2071556Srgrimes		gobble = 0;
2081556Srgrimes		if (ch == '\n') {
2091556Srgrimes			if (eflag)
2101556Srgrimes				if (putchar('$') == EOF)
2111556Srgrimes					break;
2121556Srgrimes		} else if (ch == '\t') {
2131556Srgrimes			if (tflag) {
2141556Srgrimes				if (putchar('^') == EOF || putchar('I') == EOF)
2151556Srgrimes					break;
2161556Srgrimes				continue;
2171556Srgrimes			}
2181556Srgrimes		} else if (vflag) {
21918578Sache			if (!isascii(ch) && !isprint(ch)) {
2201556Srgrimes				if (putchar('M') == EOF || putchar('-') == EOF)
2211556Srgrimes					break;
2221556Srgrimes				ch = toascii(ch);
2231556Srgrimes			}
2241556Srgrimes			if (iscntrl(ch)) {
2251556Srgrimes				if (putchar('^') == EOF ||
2261556Srgrimes				    putchar(ch == '\177' ? '?' :
2271556Srgrimes				    ch | 0100) == EOF)
2281556Srgrimes					break;
2291556Srgrimes				continue;
2301556Srgrimes			}
2311556Srgrimes		}
2321556Srgrimes		if (putchar(ch) == EOF)
2331556Srgrimes			break;
2341556Srgrimes	}
2351556Srgrimes	if (ferror(fp)) {
2361556Srgrimes		warn("%s", filename);
23711145Sbde		rval = 1;
2381556Srgrimes		clearerr(fp);
2391556Srgrimes	}
2401556Srgrimes	if (ferror(stdout))
2411556Srgrimes		err(1, "stdout");
2421556Srgrimes}
2431556Srgrimes
24483482Sdillonstatic void
2451556Srgrimesraw_cat(rfd)
2461556Srgrimes	register int rfd;
2471556Srgrimes{
24839065Simp	register int off, wfd;
24939065Simp	ssize_t nr, nw;
25039065Simp	static size_t bsize;
2511556Srgrimes	static char *buf;
2521556Srgrimes	struct stat sbuf;
2531556Srgrimes
2541556Srgrimes	wfd = fileno(stdout);
2551556Srgrimes	if (buf == NULL) {
2561556Srgrimes		if (fstat(wfd, &sbuf))
2571556Srgrimes			err(1, "%s", filename);
2581556Srgrimes		bsize = MAX(sbuf.st_blksize, 1024);
25939138Simp		if ((buf = malloc(bsize)) == NULL)
26059239Sasmodai			err(1, "buffer");
2611556Srgrimes	}
2621556Srgrimes	while ((nr = read(rfd, buf, bsize)) > 0)
2631556Srgrimes		for (off = 0; nr; nr -= nw, off += nw)
26439138Simp			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
2651556Srgrimes				err(1, "stdout");
26611145Sbde	if (nr < 0) {
2671556Srgrimes		warn("%s", filename);
26811145Sbde		rval = 1;
26911145Sbde	}
2701556Srgrimes}
27183482Sdillon
27283482Sdillon#ifndef NO_UDOM_SUPPORT
27383482Sdillon
27483482Sdillonstatic int
27583962Sruudom_open(path, flags)
27683482Sdillon    const char *path;
27783482Sdillon    int flags;
27883482Sdillon{
27983482Sdillon	struct sockaddr_un sou;
28083482Sdillon	int fd;
28183482Sdillon	int len;
28283482Sdillon
28383482Sdillon	bzero(&sou, sizeof(sou));
28483482Sdillon
28583482Sdillon	/*
28683482Sdillon	 * Construct the unix domain socket address and attempt to connect
28783482Sdillon	 */
28883482Sdillon	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
28983482Sdillon		sou.sun_family = AF_UNIX;
29083482Sdillon		snprintf(sou.sun_path, sizeof(sou.sun_path), "%s", path);
29183482Sdillon		len = strlen(sou.sun_path);
29283482Sdillon		len = offsetof(struct sockaddr_un, sun_path[len+1]);
29383482Sdillon
29483482Sdillon		if (connect(fd, (void *)&sou, len) < 0) {
29583482Sdillon			close(fd);
29683482Sdillon			fd = -1;
29783482Sdillon		}
29883482Sdillon	}
29983482Sdillon
30083482Sdillon	/*
30183482Sdillon	 * handle the open flags by shutting down appropriate directions
30283482Sdillon	 */
30383482Sdillon	if (fd >= 0) {
30483482Sdillon		switch(flags & O_ACCMODE) {
30583482Sdillon		case O_RDONLY:
30683482Sdillon			shutdown(fd, SHUT_WR);
30783482Sdillon			break;
30883482Sdillon		case O_WRONLY:
30983482Sdillon			shutdown(fd, SHUT_RD);
31083482Sdillon			break;
31183482Sdillon		default:
31283482Sdillon			break;
31383482Sdillon		}
31483482Sdillon	}
31583482Sdillon	return(fd);
31683482Sdillon}
31783482Sdillon
31883482Sdillon#endif
31983482Sdillon
320