xref: /original-bsd/bin/cat/cat.c (revision cba8738a)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kevin Fall.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)cat.c	5.14 (Berkeley) 05/06/91";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 
31 int bflag, eflag, nflag, sflag, tflag, vflag;
32 int rval;
33 char *filename;
34 
35 void cook_args(), cook_buf(), raw_args(), raw_cat();
36 void err __P((int, const char *, ...));
37 
38 main(argc, argv)
39 	int argc;
40 	char **argv;
41 {
42 	extern int optind;
43 	int ch;
44 
45 	while ((ch = getopt(argc, argv, "benstuv")) != EOF)
46 		switch (ch) {
47 		case 'b':
48 			bflag = nflag = 1;	/* -b implies -n */
49 			break;
50 		case 'e':
51 			eflag = vflag = 1;	/* -e implies -v */
52 			break;
53 		case 'n':
54 			nflag = 1;
55 			break;
56 		case 's':
57 			sflag = 1;
58 			break;
59 		case 't':
60 			tflag = vflag = 1;	/* -t implies -v */
61 			break;
62 		case 'u':
63 			setbuf(stdout, (char *)NULL);
64 			break;
65 		case 'v':
66 			vflag = 1;
67 			break;
68 		case '?':
69 			(void)fprintf(stderr,
70 			    "usage: cat [-benstuv] [-] [file ...]\n");
71 			exit(1);
72 		}
73 	argv += optind;
74 
75 	if (bflag || eflag || nflag || sflag || tflag || vflag)
76 		cook_args(argv);
77 	else
78 		raw_args(argv);
79 	if (fclose(stdout))
80 		err(1, "stdout: %s", strerror(errno));
81 	exit(rval);
82 }
83 
84 void
85 cook_args(argv)
86 	char **argv;
87 {
88 	register FILE *fp;
89 
90 	fp = stdin;
91 	filename = "-";
92 	do {
93 		if (*argv) {
94 			if (!strcmp(*argv, "-"))
95 				fp = stdin;
96 			else if (!(fp = fopen(*argv, "r"))) {
97 				err(0, "%s: %s", *argv, strerror(errno));
98 				++argv;
99 				continue;
100 			}
101 			filename = *argv++;
102 		}
103 		cook_buf(fp);
104 		if (fp != stdin)
105 			(void)fclose(fp);
106 	} while (*argv);
107 }
108 
109 void
110 cook_buf(fp)
111 	register FILE *fp;
112 {
113 	register int ch, gobble, line, prev;
114 
115 	line = gobble = 0;
116 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
117 		if (prev == '\n') {
118 			if (ch == '\n') {
119 				if (sflag) {
120 					if (!gobble && putchar(ch) == EOF)
121 						break;
122 					gobble = 1;
123 					continue;
124 				}
125 				if (nflag && !bflag) {
126 					(void)fprintf(stdout, "%6d\t", ++line);
127 					if (ferror(stdout))
128 						break;
129 				}
130 			} else if (nflag) {
131 				(void)fprintf(stdout, "%6d\t", ++line);
132 				if (ferror(stdout))
133 					break;
134 			}
135 		}
136 		gobble = 0;
137 		if (ch == '\n') {
138 			if (eflag)
139 				if (putchar('$') == EOF)
140 					break;
141 		} else if (ch == '\t') {
142 			if (tflag) {
143 				if (putchar('^') == EOF || putchar('I') == EOF)
144 					break;
145 				continue;
146 			}
147 		} else if (vflag) {
148 			if (!isascii(ch)) {
149 				if (putchar('M') == EOF || putchar('-') == EOF)
150 					break;
151 				ch = toascii(ch);
152 			}
153 			if (iscntrl(ch)) {
154 				if (putchar('^') == EOF ||
155 				    putchar(ch == '\177' ? '?' :
156 				    ch | 0100) == EOF)
157 					break;
158 				continue;
159 			}
160 		}
161 		if (putchar(ch) == EOF)
162 			break;
163 	}
164 	if (ferror(fp)) {
165 		err(0, "%s: %s", strerror(errno));
166 		clearerr(fp);
167 	}
168 	if (ferror(stdout))
169 		err(1, "stdout: %s", strerror(errno));
170 }
171 
172 void
173 raw_args(argv)
174 	char **argv;
175 {
176 	register int fd;
177 
178 	fd = fileno(stdin);
179 	filename = "-";
180 	do {
181 		if (*argv) {
182 			if (!strcmp(*argv, "-"))
183 				fd = fileno(stdin);
184 			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
185 				err(0, "%s: %s", *argv, strerror(errno));
186 				++argv;
187 				continue;
188 			}
189 			filename = *argv++;
190 		}
191 		raw_cat(fd);
192 		if (fd != fileno(stdin))
193 			(void)close(fd);
194 	} while (*argv);
195 }
196 
197 void
198 raw_cat(rfd)
199 	register int rfd;
200 {
201 	register int nr, nw, off, wfd;
202 	static int bsize;
203 	static char *buf;
204 	struct stat sbuf;
205 
206 	wfd = fileno(stdout);
207 	if (!buf) {
208 		if (fstat(wfd, &sbuf))
209 			err(1, "%s: %s", filename, strerror(errno));
210 		bsize = MAX(sbuf.st_blksize, 1024);
211 		if (!(buf = malloc((u_int)bsize)))
212 			err(1, "%s", strerror(errno));
213 	}
214 	while ((nr = read(rfd, buf, bsize)) > 0)
215 		for (off = 0; off < nr; nr -= nw, off += nw)
216 			if ((nw = write(wfd, buf + off, nr)) < 0)
217 				err(1, "stdout");
218 	if (nr < 0)
219 		err(0, "%s: %s", filename, strerror(errno));
220 }
221 
222 #if __STDC__
223 #include <stdarg.h>
224 #else
225 #include <varargs.h>
226 #endif
227 
228 void
229 #if __STDC__
230 err(int ex, const char *fmt, ...)
231 #else
232 err(ex, fmt, va_alist)
233 	int ex;
234 	char *fmt;
235         va_dcl
236 #endif
237 {
238 	va_list ap;
239 #if __STDC__
240 	va_start(ap, fmt);
241 #else
242 	va_start(ap);
243 #endif
244 	(void)fprintf(stderr, "cat: ");
245 	(void)vfprintf(stderr, fmt, ap);
246 	va_end(ap);
247 	(void)fprintf(stderr, "\n");
248 	if (ex)
249 		exit(1);
250 	rval = 1;
251 }
252