cat.c revision 83961
177696Sbrian/*
236321Samurai * Copyright (c) 1989, 1993
377696Sbrian *	The Regents of the University of California.  All rights reserved.
477696Sbrian *
536321Samurai * This code is derived from software contributed to Berkeley by
677696Sbrian * Kevin Fall.
777696Sbrian *
877696Sbrian * Redistribution and use in source and binary forms, with or without
977696Sbrian * modification, are permitted provided that the following conditions
1077696Sbrian * are met:
1177696Sbrian * 1. Redistributions of source code must retain the above copyright
1277696Sbrian *    notice, this list of conditions and the following disclaimer.
1377696Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1436321Samurai *    notice, this list of conditions and the following disclaimer in the
1577696Sbrian *    documentation and/or other materials provided with the distribution.
1677696Sbrian * 3. All advertising materials mentioning features or use of this software
1777696Sbrian *    must display the following acknowledgement:
1877696Sbrian *	This product includes software developed by the University of
1977696Sbrian *	California, Berkeley and its contributors.
2077696Sbrian * 4. Neither the name of the University nor the names of its contributors
2177696Sbrian *    may be used to endorse or promote products derived from this software
2277696Sbrian *    without specific prior written permission.
2377696Sbrian *
2477696Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2577696Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2636321Samurai * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2799207Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2836321Samurai * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2936321Samurai * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3084195Sdillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3184195Sdillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3284195Sdillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3384195Sdillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3436321Samurai * SUCH DAMAGE.
3536321Samurai */
3636321Samurai
3736321Samurai#ifndef lint
3836321Samuraistatic char const copyright[] =
3936321Samurai"@(#) Copyright (c) 1989, 1993\n\
4036321Samurai	The Regents of the University of California.  All rights reserved.\n";
4136321Samurai#endif /* not lint */
4236321Samurai
4336321Samurai#ifndef lint
4436321Samurai#if 0
4599207Sbrianstatic char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
4636321Samurai#endif
4736321Samuraistatic const char rcsid[] =
4836321Samurai  "$FreeBSD: head/bin/cat/cat.c 83961 2001-09-26 11:32:23Z ru $";
4936321Samurai#endif /* not lint */
5036321Samurai
5136321Samurai#include <sys/param.h>
5236321Samurai#include <sys/stat.h>
5336321Samurai#ifndef NO_UDOM_SUPPORT
5436321Samurai#include <sys/socket.h>
5536321Samurai#include <sys/un.h>
5636321Samurai#include <errno.h>
5736321Samurai#endif
5836321Samurai
5936321Samurai#include <ctype.h>
6036321Samurai#include <err.h>
6136321Samurai#include <fcntl.h>
6236321Samurai#include <locale.h>
6336321Samurai#include <stdio.h>
6436321Samurai#include <stdlib.h>
6536321Samurai#include <string.h>
6636321Samurai#include <unistd.h>
6736321Samurai#include <stddef.h>
6836321Samurai
6936321Samuraiint bflag, eflag, nflag, sflag, tflag, vflag;
7036321Samuraiint rval;
7136321Samuraiconst char *filename;
7236321Samurai
7336321Samuraiint main __P((int argc, char *argv[]));
7436321Samurai
7536321Samuraistatic void scanfiles __P((char **argv, int cooked));
7636321Samuraistatic void cook_cat __P((FILE *));
7736321Samuraistatic void raw_cat __P((int));
7836321Samurai
7936321Samurai#ifndef NO_UDOM_SUPPORT
8036321Samuraistatic int udom_open __P((const char *path, int flags, int modes));
8136321Samurai#endif
8236321Samurai
8336321Samuraiint
8436321Samuraimain(argc, argv)
8536321Samurai	int argc;
8636321Samurai	char *argv[];
8736321Samurai{
8836321Samurai	int ch;
8936321Samurai
9036321Samurai	setlocale(LC_CTYPE, "");
9136321Samurai
9236321Samurai	while ((ch = getopt(argc, argv, "benstuv")) != -1)
9336321Samurai		switch (ch) {
9436321Samurai		case 'b':
9536321Samurai			bflag = nflag = 1;	/* -b implies -n */
9636321Samurai			break;
9736321Samurai		case 'e':
9844616Sbrian			eflag = vflag = 1;	/* -e implies -v */
9944616Sbrian			break;
10036321Samurai		case 'n':
10136321Samurai			nflag = 1;
10236321Samurai			break;
10336321Samurai		case 's':
10436321Samurai			sflag = 1;
10536321Samurai			break;
10636321Samurai		case 't':
10736321Samurai			tflag = vflag = 1;	/* -t implies -v */
10836321Samurai			break;
10936321Samurai		case 'u':
11036321Samurai			setbuf(stdout, NULL);
11136321Samurai			break;
11236321Samurai		case 'v':
11336321Samurai			vflag = 1;
11436321Samurai			break;
11597627Swollman		default:
11636321Samurai			(void)fprintf(stderr,
11799207Sbrian			    "usage: cat [-benstuv] [-] [file ...]\n");
11836321Samurai			exit(1);
11944616Sbrian		}
12036321Samurai	argv += optind;
12136321Samurai
12236321Samurai	if (bflag || eflag || nflag || sflag || tflag || vflag)
12344616Sbrian		scanfiles(argv, 1);
12436321Samurai	else
12536321Samurai		scanfiles(argv, 0);
12636321Samurai	if (fclose(stdout))
12736321Samurai		err(1, "stdout");
12836321Samurai	exit(rval);
12936321Samurai}
13041759Sdillon
13141759Sdillonvoid
13241759Sdillonscanfiles(argv, cooked)
13341759Sdillon    char **argv;
13436321Samurai    int cooked;
13536321Samurai{
13641759Sdillon	int i = 0;
13741759Sdillon	char *path;
13836321Samurai	FILE *fp;
13936321Samurai
14036321Samurai	while ((path = argv[i]) != NULL || i == 0) {
14136321Samurai		int fd;
14236321Samurai
14336321Samurai		if (path == NULL || strcmp(path, "-") == 0) {
14436321Samurai			filename = "stdin";
14536321Samurai			fd = STDIN_FILENO;
14699207Sbrian		} else {
14736321Samurai			filename = path;
14836321Samurai			fd = open(path, O_RDONLY);
14941759Sdillon#ifndef NO_UDOM_SUPPORT
15041759Sdillon			if (fd < 0 && errno == EOPNOTSUPP)
15141759Sdillon				fd = udom_open(path, O_RDONLY, 0);
15241759Sdillon#endif
15336321Samurai		}
15436321Samurai		if (fd < 0) {
15536321Samurai			warn("%s", path);
15636321Samurai			rval = 1;
15736321Samurai		} else if (cooked) {
15836321Samurai			if (fd == STDIN_FILENO)
15936321Samurai				cook_cat(stdin);
16036321Samurai			else {
16136321Samurai				fp = fdopen(fd, "r");
16236321Samurai				cook_cat(fp);
16336321Samurai				fclose(fp);
16436321Samurai			}
16536321Samurai		} else {
16636321Samurai			raw_cat(fd);
16736321Samurai			if (fd != STDIN_FILENO)
16836321Samurai				close(fd);
16936321Samurai		}
17036321Samurai		if (path == NULL)
17136321Samurai			break;
17236321Samurai		++i;
17336321Samurai	}
17436321Samurai}
17536321Samurai
17636321Samuraistatic void
17736321Samuraicook_cat(fp)
17836321Samurai	register FILE *fp;
17936321Samurai{
18041759Sdillon	register int ch, gobble, line, prev;
18141759Sdillon
18241759Sdillon	/* Reset EOF condition on stdin. */
18341759Sdillon	if (fp == stdin && feof(stdin))
18436321Samurai		clearerr(stdin);
18536321Samurai
18636321Samurai	line = gobble = 0;
18799207Sbrian	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
18836321Samurai		if (prev == '\n') {
18936321Samurai			if (ch == '\n') {
19036321Samurai				if (sflag) {
19136321Samurai					if (!gobble && putchar(ch) == EOF)
19236321Samurai						break;
19336321Samurai					gobble = 1;
19436321Samurai					continue;
19536321Samurai				}
19636321Samurai				if (nflag && !bflag) {
19736321Samurai					(void)fprintf(stdout, "%6d\t", ++line);
19841759Sdillon					if (ferror(stdout))
19936321Samurai						break;
20036321Samurai				}
20136321Samurai			} else if (nflag) {
20241759Sdillon				(void)fprintf(stdout, "%6d\t", ++line);
20341759Sdillon				if (ferror(stdout))
20436321Samurai					break;
20536321Samurai			}
20641759Sdillon		}
20741759Sdillon		gobble = 0;
20899207Sbrian		if (ch == '\n') {
20936321Samurai			if (eflag)
21036321Samurai				if (putchar('$') == EOF)
21141759Sdillon					break;
21241759Sdillon		} else if (ch == '\t') {
21336321Samurai			if (tflag) {
21441759Sdillon				if (putchar('^') == EOF || putchar('I') == EOF)
21541759Sdillon					break;
21636321Samurai				continue;
21736321Samurai			}
21836321Samurai		} else if (vflag) {
21936321Samurai			if (!isascii(ch) && !isprint(ch)) {
22036321Samurai				if (putchar('M') == EOF || putchar('-') == EOF)
22136321Samurai					break;
22236321Samurai				ch = toascii(ch);
22336321Samurai			}
22441759Sdillon			if (iscntrl(ch)) {
22541759Sdillon				if (putchar('^') == EOF ||
22636321Samurai				    putchar(ch == '\177' ? '?' :
22736321Samurai				    ch | 0100) == EOF)
22836321Samurai					break;
22936321Samurai				continue;
23036321Samurai			}
23136321Samurai		}
23236321Samurai		if (putchar(ch) == EOF)
23336321Samurai			break;
23441759Sdillon	}
23536321Samurai	if (ferror(fp)) {
23636321Samurai		warn("%s", filename);
23741759Sdillon		rval = 1;
23841759Sdillon		clearerr(fp);
23936321Samurai	}
24036321Samurai	if (ferror(stdout))
24136321Samurai		err(1, "stdout");
24236321Samurai}
24336321Samurai
24436321Samuraistatic void
24536321Samurairaw_cat(rfd)
24636321Samurai	register int rfd;
24736321Samurai{
24836321Samurai	register int off, wfd;
24936321Samurai	ssize_t nr, nw;
25036321Samurai	static size_t bsize;
25136321Samurai	static char *buf;
25236321Samurai	struct stat sbuf;
25336321Samurai
25474778Sbrian	wfd = fileno(stdout);
25536321Samurai	if (buf == NULL) {
25636321Samurai		if (fstat(wfd, &sbuf))
25736321Samurai			err(1, "%s", filename);
25836321Samurai		bsize = MAX(sbuf.st_blksize, 1024);
25936321Samurai		if ((buf = malloc(bsize)) == NULL)
26036321Samurai			err(1, "buffer");
26136321Samurai	}
26241759Sdillon	while ((nr = read(rfd, buf, bsize)) > 0)
26336321Samurai		for (off = 0; nr; nr -= nw, off += nw)
26436321Samurai			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
26536321Samurai				err(1, "stdout");
26636321Samurai	if (nr < 0) {
26736321Samurai		warn("%s", filename);
26836321Samurai		rval = 1;
26936321Samurai	}
27036321Samurai}
27136321Samurai
27236321Samurai#ifndef NO_UDOM_SUPPORT
27344616Sbrian
27441759Sdillonstatic int
27541759Sdillonudom_open(path, flags, modes)
27636321Samurai    const char *path;
27741759Sdillon    int flags;
27836321Samurai    int modes;
27936321Samurai{
28036321Samurai	struct sockaddr_un sou;
28136321Samurai	int fd;
28236321Samurai	int len;
28341759Sdillon
28436321Samurai	bzero(&sou, sizeof(sou));
28541759Sdillon
28641759Sdillon	/*
28741759Sdillon	 * Construct the unix domain socket address and attempt to connect
28841759Sdillon	 */
28941759Sdillon	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
29036321Samurai		sou.sun_family = AF_UNIX;
29136321Samurai		snprintf(sou.sun_path, sizeof(sou.sun_path), "%s", path);
29236321Samurai		len = strlen(sou.sun_path);
29336321Samurai		len = offsetof(struct sockaddr_un, sun_path[len+1]);
29436321Samurai
29536321Samurai		if (connect(fd, (void *)&sou, len) < 0) {
29636321Samurai			close(fd);
29744616Sbrian			fd = -1;
29836321Samurai		}
29944616Sbrian	}
30036321Samurai
30136321Samurai	/*
30236321Samurai	 * handle the open flags by shutting down appropriate directions
30336321Samurai	 */
30436321Samurai	if (fd >= 0) {
30536321Samurai		switch(flags & O_ACCMODE) {
30636321Samurai		case O_RDONLY:
30736321Samurai			shutdown(fd, SHUT_WR);
30836321Samurai			break;
30936321Samurai		case O_WRONLY:
31036321Samurai			shutdown(fd, SHUT_RD);
31136321Samurai			break;
31236321Samurai		default:
31336321Samurai			break;
31436321Samurai		}
31536321Samurai	}
31636321Samurai	return(fd);
31736321Samurai}
31836321Samurai
31936321Samurai#endif
32036321Samurai
32136321Samurai