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