cat.c revision 1557
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kevin Fall.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1989, 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44static char sccsid[] = "@(#)cat.c	8.1 (Berkeley) 7/19/93";
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/stat.h>
49
50#include <ctype.h>
51#include <err.h>
52#include <errno.h>
53#include <fcntl.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <string.h>
57#include <unistd.h>
58
59int bflag, eflag, nflag, sflag, tflag, vflag;
60int rval;
61char *filename;
62
63void cook_args __P((char *argv[]));
64void cook_buf __P((FILE *));
65void raw_args __P((char *argv[]));
66void raw_cat __P((int));
67
68int
69main(argc, argv)
70	int argc;
71	char *argv[];
72{
73	extern int optind;
74	int ch;
75
76	while ((ch = getopt(argc, argv, "benstuv")) != EOF)
77		switch (ch) {
78		case 'b':
79			bflag = nflag = 1;	/* -b implies -n */
80			break;
81		case 'e':
82			eflag = vflag = 1;	/* -e implies -v */
83			break;
84		case 'n':
85			nflag = 1;
86			break;
87		case 's':
88			sflag = 1;
89			break;
90		case 't':
91			tflag = vflag = 1;	/* -t implies -v */
92			break;
93		case 'u':
94			setbuf(stdout, (char *)NULL);
95			break;
96		case 'v':
97			vflag = 1;
98			break;
99		case '?':
100			(void)fprintf(stderr,
101			    "usage: cat [-benstuv] [-] [file ...]\n");
102			exit(1);
103		}
104	argv += optind;
105
106	if (bflag || eflag || nflag || sflag || tflag || vflag)
107		cook_args(argv);
108	else
109		raw_args(argv);
110	if (fclose(stdout))
111		err(1, "stdout");
112	exit(rval);
113}
114
115void
116cook_args(argv)
117	char **argv;
118{
119	register FILE *fp;
120
121	fp = stdin;
122	filename = "stdin";
123	do {
124		if (*argv) {
125			if (!strcmp(*argv, "-"))
126				fp = stdin;
127			else if ((fp = fopen(*argv, "r")) == NULL) {
128				warn("%s", *argv);
129				++argv;
130				continue;
131			}
132			filename = *argv++;
133		}
134		cook_buf(fp);
135		if (fp != stdin)
136			(void)fclose(fp);
137	} while (*argv);
138}
139
140void
141cook_buf(fp)
142	register FILE *fp;
143{
144	register int ch, gobble, line, prev;
145
146	line = gobble = 0;
147	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
148		if (prev == '\n') {
149			if (ch == '\n') {
150				if (sflag) {
151					if (!gobble && putchar(ch) == EOF)
152						break;
153					gobble = 1;
154					continue;
155				}
156				if (nflag && !bflag) {
157					(void)fprintf(stdout, "%6d\t", ++line);
158					if (ferror(stdout))
159						break;
160				}
161			} else if (nflag) {
162				(void)fprintf(stdout, "%6d\t", ++line);
163				if (ferror(stdout))
164					break;
165			}
166		}
167		gobble = 0;
168		if (ch == '\n') {
169			if (eflag)
170				if (putchar('$') == EOF)
171					break;
172		} else if (ch == '\t') {
173			if (tflag) {
174				if (putchar('^') == EOF || putchar('I') == EOF)
175					break;
176				continue;
177			}
178		} else if (vflag) {
179			if (!isascii(ch)) {
180				if (putchar('M') == EOF || putchar('-') == EOF)
181					break;
182				ch = toascii(ch);
183			}
184			if (iscntrl(ch)) {
185				if (putchar('^') == EOF ||
186				    putchar(ch == '\177' ? '?' :
187				    ch | 0100) == EOF)
188					break;
189				continue;
190			}
191		}
192		if (putchar(ch) == EOF)
193			break;
194	}
195	if (ferror(fp)) {
196		warn("%s", filename);
197		clearerr(fp);
198	}
199	if (ferror(stdout))
200		err(1, "stdout");
201}
202
203void
204raw_args(argv)
205	char **argv;
206{
207	register int fd;
208
209	fd = fileno(stdin);
210	filename = "stdin";
211	do {
212		if (*argv) {
213			if (!strcmp(*argv, "-"))
214				fd = fileno(stdin);
215			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
216				warn("%s", *argv);
217				++argv;
218				continue;
219			}
220			filename = *argv++;
221		}
222		raw_cat(fd);
223		if (fd != fileno(stdin))
224			(void)close(fd);
225	} while (*argv);
226}
227
228void
229raw_cat(rfd)
230	register int rfd;
231{
232	register int nr, nw, off, wfd;
233	static int bsize;
234	static char *buf;
235	struct stat sbuf;
236
237	wfd = fileno(stdout);
238	if (buf == NULL) {
239		if (fstat(wfd, &sbuf))
240			err(1, "%s", filename);
241		bsize = MAX(sbuf.st_blksize, 1024);
242		if ((buf = malloc((u_int)bsize)) == NULL)
243			err(1, "");
244	}
245	while ((nr = read(rfd, buf, bsize)) > 0)
246		for (off = 0; nr; nr -= nw, off += nw)
247			if ((nw = write(wfd, buf + off, nr)) < 0)
248				err(1, "stdout");
249	if (nr < 0)
250		warn("%s", filename);
251}
252