cat.c revision 132433
1139743Simp/*
249267Snewton * Copyright (c) 1989, 1993
349267Snewton *	The Regents of the University of California.  All rights reserved.
449267Snewton *
549267Snewton * This code is derived from software contributed to Berkeley by
649267Snewton * Kevin Fall.
749267Snewton *
849267Snewton * Redistribution and use in source and binary forms, with or without
949267Snewton * modification, are permitted provided that the following conditions
1049267Snewton * are met:
1149267Snewton * 1. Redistributions of source code must retain the above copyright
1249267Snewton *    notice, this list of conditions and the following disclaimer.
1349267Snewton * 2. Redistributions in binary form must reproduce the above copyright
1449267Snewton *    notice, this list of conditions and the following disclaimer in the
1549267Snewton *    documentation and/or other materials provided with the distribution.
1649267Snewton * 4. Neither the name of the University nor the names of its contributors
1749267Snewton *    may be used to endorse or promote products derived from this software
1849267Snewton *    without specific prior written permission.
1949267Snewton *
2049267Snewton * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2149267Snewton * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2249267Snewton * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349267Snewton * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2449267Snewton * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2549267Snewton * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2649267Snewton * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2749267Snewton * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2849267Snewton * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2949267Snewton * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3049267Snewton * SUCH DAMAGE.
31116174Sobrien */
32116174Sobrien
33116174Sobrien#if 0
3443412Snewton#ifndef lint
3543412Snewtonstatic char const copyright[] =
3643412Snewton"@(#) Copyright (c) 1989, 1993\n\
3743412Snewton	The Regents of the University of California.  All rights reserved.\n";
3843412Snewton#endif /* not lint */
3943412Snewton#endif
4043412Snewton
4143412Snewton#ifndef lint
4248503Sgreen#if 0
4343412Snewtonstatic char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
4443412Snewton#endif
4543412Snewton#endif /* not lint */
4643412Snewton#include <sys/cdefs.h>
4794455Sjhb__FBSDID("$FreeBSD: head/bin/cat/cat.c 132433 2004-07-20 05:52:00Z tjr $");
4843412Snewton
49141486Sjhb#include <sys/param.h>
5094455Sjhb#include <sys/stat.h>
5143412Snewton#ifndef NO_UDOM_SUPPORT
52141486Sjhb#include <sys/socket.h>
53141486Sjhb#include <sys/un.h>
5443412Snewton#include <errno.h>
5543412Snewton#endif
5643412Snewton
5743412Snewton#include <ctype.h>
5843412Snewton#include <err.h>
5943412Snewton#include <fcntl.h>
6043412Snewton#include <locale.h>
6165302Sobrien#include <stdio.h>
6265302Sobrien#include <stdlib.h>
6365302Sobrien#include <string.h>
6465302Sobrien#include <unistd.h>
6565302Sobrien#include <stddef.h>
6665302Sobrien
6765302Sobrienint bflag, eflag, nflag, sflag, tflag, vflag;
6865302Sobrienint rval;
6965302Sobrienconst char *filename;
7043412Snewton
7143412Snewtonstatic void usage(void);
7243412Snewtonstatic void scanfiles(char *argv[], int cooked);
7343412Snewtonstatic void cook_cat(FILE *);
7443412Snewtonstatic void raw_cat(int);
7543412Snewton
7643412Snewton#ifndef NO_UDOM_SUPPORT
7743412Snewtonstatic int udom_open(const char *path, int flags);
7843412Snewton#endif
7943412Snewton
8043412Snewtonint
8143412Snewtonmain(int argc, char *argv[])
8243412Snewton{
8343412Snewton	int ch;
8443412Snewton
8543412Snewton	setlocale(LC_CTYPE, "");
8643412Snewton
8743412Snewton	while ((ch = getopt(argc, argv, "benstuv")) != -1)
8843412Snewton		switch (ch) {
8943412Snewton		case 'b':
9043412Snewton			bflag = nflag = 1;	/* -b implies -n */
9143412Snewton			break;
9243412Snewton		case 'e':
9343412Snewton			eflag = vflag = 1;	/* -e implies -v */
9443412Snewton			break;
9543412Snewton		case 'n':
9643412Snewton			nflag = 1;
9743412Snewton			break;
9843412Snewton		case 's':
9943412Snewton			sflag = 1;
10043412Snewton			break;
10143412Snewton		case 't':
10243412Snewton			tflag = vflag = 1;	/* -t implies -v */
10343412Snewton			break;
10443412Snewton		case 'u':
10543412Snewton			setbuf(stdout, NULL);
10643412Snewton			break;
10743412Snewton		case 'v':
10843412Snewton			vflag = 1;
10943412Snewton			break;
11043412Snewton		default:
11143412Snewton			usage();
11243412Snewton		}
11343412Snewton	argv += optind;
11443412Snewton
11543412Snewton	if (bflag || eflag || nflag || sflag || tflag || vflag)
11643412Snewton		scanfiles(argv, 1);
11743412Snewton	else
11843412Snewton		scanfiles(argv, 0);
11943412Snewton	if (fclose(stdout))
12043412Snewton		err(1, "stdout");
12143412Snewton	exit(rval);
12243412Snewton	/* NOTREACHED */
12343412Snewton}
12443412Snewton
12543412Snewtonstatic void
12643412Snewtonusage(void)
12743412Snewton{
12843412Snewton	fprintf(stderr, "usage: cat [-benstuv] [file ...]\n");
12943412Snewton	exit(1);
13043412Snewton	/* NOTREACHED */
13143412Snewton}
13243412Snewton
13343412Snewtonstatic void
13443412Snewtonscanfiles(char *argv[], int cooked)
13543412Snewton{
13643412Snewton	int i = 0;
13743412Snewton	char *path;
13843412Snewton	FILE *fp;
13943412Snewton
14043412Snewton	while ((path = argv[i]) != NULL || i == 0) {
14143412Snewton		int fd;
14243412Snewton
14343412Snewton		if (path == NULL || strcmp(path, "-") == 0) {
14443412Snewton			filename = "stdin";
14543412Snewton			fd = STDIN_FILENO;
14643412Snewton		} else {
14743412Snewton			filename = path;
14843412Snewton			fd = open(path, O_RDONLY);
14943412Snewton#ifndef NO_UDOM_SUPPORT
15043412Snewton			if (fd < 0 && errno == EOPNOTSUPP)
15143412Snewton				fd = udom_open(path, O_RDONLY);
15243412Snewton#endif
15343412Snewton		}
15443412Snewton		if (fd < 0) {
15543412Snewton			warn("%s", path);
15643412Snewton			rval = 1;
15743412Snewton		} else if (cooked) {
15843412Snewton			if (fd == STDIN_FILENO)
15959342Sobrien				cook_cat(stdin);
16043412Snewton			else {
16143412Snewton				fp = fdopen(fd, "r");
16243412Snewton				cook_cat(fp);
16343412Snewton				fclose(fp);
16443412Snewton			}
16543412Snewton		} else {
16643412Snewton			raw_cat(fd);
16743412Snewton			if (fd != STDIN_FILENO)
16843412Snewton				close(fd);
16943412Snewton		}
17043412Snewton		if (path == NULL)
17143412Snewton			break;
17251793Smarcel		++i;
17343412Snewton	}
17443412Snewton}
17543412Snewton
176102808Sjakestatic void
17743412Snewtoncook_cat(FILE *fp)
17843412Snewton{
17943412Snewton	int ch, gobble, line, prev;
18043412Snewton
18149267Snewton	/* Reset EOF condition on stdin. */
18249267Snewton	if (fp == stdin && feof(stdin))
183100384Speter		clearerr(stdin);
18468520Smarcel
185102808Sjake	line = gobble = 0;
186102808Sjake	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
187102808Sjake		if (prev == '\n') {
188102808Sjake			if (sflag) {
189102808Sjake				if (ch == '\n') {
190102808Sjake					if (gobble)
191102808Sjake						continue;
192102808Sjake					gobble = 1;
193120422Speter				} else
194120422Speter					gobble = 0;
19543412Snewton			}
19643412Snewton			if (nflag && (!bflag || ch != '\n')) {
197141486Sjhb				(void)fprintf(stdout, "%6d\t", ++line);
198141486Sjhb				if (ferror(stdout))
19943412Snewton					break;
20099669Srobert			}
201100384Speter		}
20272999Sobrien		if (ch == '\n') {
20359342Sobrien			if (eflag && putchar('$') == EOF)
20443412Snewton				break;
205123742Speter		} else if (ch == '\t') {
206123742Speter			if (tflag) {
20743412Snewton				if (putchar('^') == EOF || putchar('I') == EOF)
20843412Snewton					break;
20943412Snewton				continue;
21059342Sobrien			}
21143412Snewton		} else if (vflag) {
212112470Sjhb			if (!isascii(ch) && !isprint(ch)) {
21359342Sobrien				if (putchar('M') == EOF || putchar('-') == EOF)
21443412Snewton					break;
215112470Sjhb				ch = toascii(ch);
216116361Sdavidxu			}
217112470Sjhb			if (iscntrl(ch)) {
218112470Sjhb				if (putchar('^') == EOF ||
219140992Ssobomax				    putchar(ch == '\177' ? '?' :
22043412Snewton				    ch | 0100) == EOF)
221112470Sjhb					break;
22243412Snewton				continue;
223112470Sjhb			}
22443412Snewton		}
22543412Snewton		if (putchar(ch) == EOF)
22643412Snewton			break;
22743412Snewton	}
22843412Snewton	if (ferror(fp)) {
22943412Snewton		warn("%s", filename);
23043412Snewton		rval = 1;
23143412Snewton		clearerr(fp);
23277183Srwatson	}
23377183Srwatson	if (ferror(stdout))
23477183Srwatson		err(1, "stdout");
23577183Srwatson}
23643412Snewton
23743412Snewtonstatic void
23843412Snewtonraw_cat(int rfd)
23943412Snewton{
24043412Snewton	int off, wfd;
24143412Snewton	ssize_t nr, nw;
242140992Ssobomax	static size_t bsize;
24343412Snewton	static char *buf = NULL;
24443412Snewton	struct stat sbuf;
24543412Snewton
24643412Snewton	wfd = fileno(stdout);
24743412Snewton	if (buf == NULL) {
24872091Sasmodai		if (fstat(wfd, &sbuf))
24943412Snewton			err(1, "%s", filename);
25043412Snewton		bsize = MAX(sbuf.st_blksize, 1024);
25143412Snewton		if ((buf = malloc(bsize)) == NULL)
25243412Snewton			err(1, "buffer");
25343412Snewton	}
25443412Snewton	while ((nr = read(rfd, buf, bsize)) > 0)
255141486Sjhb		for (off = 0; nr; nr -= nw, off += nw)
256141486Sjhb			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
25743412Snewton				err(1, "stdout");
25843412Snewton	if (nr < 0) {
259141486Sjhb		warn("%s", filename);
260141486Sjhb		rval = 1;
26143412Snewton	}
26243412Snewton}
26343412Snewton
26443412Snewton#ifndef NO_UDOM_SUPPORT
26543412Snewton
26643412Snewtonstatic int
26743412Snewtonudom_open(const char *path, int flags)
26843412Snewton{
26943412Snewton	struct sockaddr_un sou;
27043412Snewton	int fd;
27143412Snewton	unsigned int len;
272100384Speter
27343412Snewton	bzero(&sou, sizeof(sou));
27443412Snewton
27543412Snewton	/*
27643412Snewton	 * Construct the unix domain socket address and attempt to connect
27743412Snewton	 */
27843412Snewton	fd = socket(AF_UNIX, SOCK_STREAM, 0);
27943412Snewton	if (fd >= 0) {
28043597Snewton		sou.sun_family = AF_UNIX;
281100384Speter		if ((len = strlcpy(sou.sun_path, path,
28243597Snewton		    sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) {
283100384Speter			errno = ENAMETOOLONG;
28443412Snewton			return (-1);
28543597Snewton		}
28643597Snewton		len = offsetof(struct sockaddr_un, sun_path[len+1]);
28743412Snewton
28843597Snewton		if (connect(fd, (void *)&sou, len) < 0) {
28943597Snewton			close(fd);
29043412Snewton			fd = -1;
29143412Snewton		}
29243412Snewton	}
29343412Snewton
294132199Sphk	/*
29543412Snewton	 * handle the open flags by shutting down appropriate directions
29643412Snewton	 */
29743412Snewton	if (fd >= 0) {
29843412Snewton		switch(flags & O_ACCMODE) {
29943412Snewton		case O_RDONLY:
30043412Snewton			if (shutdown(fd, SHUT_WR) == -1)
30143412Snewton				warn(NULL);
30243412Snewton			break;
30343412Snewton		case O_WRONLY:
30443412Snewton			if (shutdown(fd, SHUT_RD) == -1)
30543412Snewton				warn(NULL);
30660060Sgreen			break;
307		default:
308			break;
309		}
310	}
311	return(fd);
312}
313
314#endif
315