xref: /original-bsd/bin/cat/cat.c (revision ba762ddc)
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.13 (Berkeley) 05/02/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 	exit(rval);
80 }
81 
82 void
83 cook_args(argv)
84 	char **argv;
85 {
86 	register FILE *fp;
87 
88 	fp = stdin;
89 	filename = "-";
90 	do {
91 		if (*argv) {
92 			if (!strcmp(*argv, "-"))
93 				fp = stdin;
94 			else if (!(fp = fopen(*argv, "r"))) {
95 				err(0, "%s: %s", *argv, strerror(errno));
96 				++argv;
97 				continue;
98 			}
99 			filename = *argv++;
100 		}
101 		cook_buf(fp);
102 		if (fp != stdin)
103 			(void)fclose(fp);
104 	} while (*argv);
105 }
106 
107 void
108 cook_buf(fp)
109 	register FILE *fp;
110 {
111 	register int ch, gobble, line, prev;
112 
113 	line = gobble = 0;
114 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
115 		if (prev == '\n') {
116 			if (ch == '\n') {
117 				if (sflag) {
118 					if (!gobble && putchar(ch) == EOF)
119 						break;
120 					gobble = 1;
121 					continue;
122 				}
123 				if (nflag && !bflag) {
124 					(void)fprintf(stdout, "%6d\t", ++line);
125 					if (ferror(stdout))
126 						break;
127 				}
128 			} else if (nflag) {
129 				(void)fprintf(stdout, "%6d\t", ++line);
130 				if (ferror(stdout))
131 					break;
132 			}
133 		}
134 		gobble = 0;
135 		if (ch == '\n') {
136 			if (eflag)
137 				if (putchar('$') == EOF)
138 					break;
139 		} else if (ch == '\t') {
140 			if (tflag) {
141 				if (putchar('^') == EOF || putchar('I') == EOF)
142 					break;
143 				continue;
144 			}
145 		} else if (vflag) {
146 			if (!isascii(ch)) {
147 				if (putchar('M') == EOF || putchar('-') == EOF)
148 					break;
149 				ch = toascii(ch);
150 			}
151 			if (iscntrl(ch)) {
152 				if (putchar('^') == EOF ||
153 				    putchar(ch == '\177' ? '?' :
154 				    ch | 0100) == EOF)
155 					break;
156 				continue;
157 			}
158 		}
159 		if (putchar(ch) == EOF)
160 			break;
161 	}
162 	if (ferror(fp)) {
163 		err(0, "%s: %s", strerror(errno));
164 		clearerr(fp);
165 	}
166 	if (ferror(stdout))
167 		err(1, "stdout: %s", strerror(errno));
168 }
169 
170 void
171 raw_args(argv)
172 	char **argv;
173 {
174 	register int fd;
175 
176 	fd = fileno(stdin);
177 	filename = "-";
178 	do {
179 		if (*argv) {
180 			if (!strcmp(*argv, "-"))
181 				fd = fileno(stdin);
182 			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
183 				err(0, "%s: %s", *argv, strerror(errno));
184 				++argv;
185 				continue;
186 			}
187 			filename = *argv++;
188 		}
189 		raw_cat(fd);
190 		if (fd != fileno(stdin))
191 			(void)close(fd);
192 	} while (*argv);
193 }
194 
195 void
196 raw_cat(rfd)
197 	register int rfd;
198 {
199 	register int nr, nw, off, wfd;
200 	static int bsize;
201 	static char *buf;
202 	struct stat sbuf;
203 
204 	wfd = fileno(stdout);
205 	if (!buf) {
206 		if (fstat(wfd, &sbuf))
207 			err(1, "%s: %s", filename, strerror(errno));
208 		bsize = MAX(sbuf.st_blksize, 1024);
209 		if (!(buf = malloc((u_int)bsize)))
210 			err(1, "%s", strerror(errno));
211 	}
212 	while ((nr = read(rfd, buf, bsize)) > 0)
213 		for (off = 0; off < nr; nr -= nw, off += nw)
214 			if ((nw = write(wfd, buf + off, nr)) < 0)
215 				err(1, "stdout");
216 	if (nr < 0)
217 		err(0, "%s: %s", filename, strerror(errno));
218 }
219 
220 #if __STDC__
221 #include <stdarg.h>
222 #else
223 #include <varargs.h>
224 #endif
225 
226 void
227 #if __STDC__
228 err(int ex, const char *fmt, ...)
229 #else
230 err(ex, fmt, va_alist)
231 	int ex;
232 	char *fmt;
233         va_dcl
234 #endif
235 {
236 	va_list ap;
237 #if __STDC__
238 	va_start(ap, fmt);
239 #else
240 	va_start(ap);
241 #endif
242 	(void)fprintf(stderr, "cat: ");
243 	(void)vfprintf(stderr, fmt, ap);
244 	va_end(ap);
245 	(void)fprintf(stderr, "\n");
246 	if (ex)
247 		exit(1);
248 	rval = 1;
249 }
250