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