xref: /original-bsd/bin/cat/cat.c (revision 10020db5)
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  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 char copyright[] =
23 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
24  All rights reserved.\n";
25 #endif /* not lint */
26 
27 #ifndef lint
28 static char sccsid[] = "@(#)cat.c	5.10 (Berkeley) 03/05/90";
29 #endif /* not lint */
30 
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/file.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 
37 extern int errno;
38 int bflag, eflag, nflag, sflag, tflag, vflag;
39 int rval;
40 char *filename;
41 
42 main(argc, argv)
43 	int argc;
44 	char **argv;
45 {
46 	extern int optind;
47 	int ch;
48 	char *strerror();
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 	exit(rval);
85 }
86 
87 cook_args(argv)
88 	char **argv;
89 {
90 	register FILE *fp;
91 
92 	fp = stdin;
93 	filename = "-";
94 	do {
95 		if (*argv) {
96 			if (!strcmp(*argv, "-"))
97 				fp = stdin;
98 			else if (!(fp = fopen(*argv, "r"))) {
99 				(void)fprintf(stderr,
100 				    "cat: %s: %s\n", *argv, strerror(errno));
101 				rval = 1;
102 				++argv;
103 				continue;
104 			}
105 			filename = *argv++;
106 		}
107 		cook_buf(fp);
108 		if (fp != stdin)
109 			(void)fclose(fp);
110 	} while (*argv);
111 }
112 
113 cook_buf(fp)
114 	register FILE *fp;
115 {
116 	register int ch, gobble, line, prev;
117 
118 	line = gobble = 0;
119 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
120 		if (prev == '\n') {
121 			if (ch == '\n') {
122 				if (sflag) {
123 					if (!gobble && putchar(ch) == EOF)
124 						break;
125 					gobble = 1;
126 					continue;
127 				}
128 				if (nflag && !bflag) {
129 					(void)fprintf(stdout, "%6d\t", ++line);
130 					if (ferror(stdout))
131 						break;
132 				}
133 			} else if (nflag) {
134 				(void)fprintf(stdout, "%6d\t", ++line);
135 				if (ferror(stdout))
136 					break;
137 			}
138 		}
139 		gobble = 0;
140 		if (ch == '\n') {
141 			if (eflag)
142 				if (putchar('$') == EOF)
143 					break;
144 		} else if (ch == '\t') {
145 			if (tflag) {
146 				if (putchar('^') == EOF || putchar('I') == EOF)
147 					break;
148 				continue;
149 			}
150 		} else if (vflag) {
151 			if (!isascii(ch)) {
152 				if (putchar('M') == EOF || putchar('-') == EOF)
153 					break;
154 				ch = toascii(ch);
155 			}
156 			if (iscntrl(ch)) {
157 				if (putchar('^') == EOF ||
158 				    putchar(ch == '\177' ? '?' :
159 				    ch | 0100) == EOF)
160 					break;
161 				continue;
162 			}
163 		}
164 		if (putchar(ch) == EOF)
165 			break;
166 	}
167 	if (ferror(fp)) {
168 		(void)fprintf(stderr, "cat: %s: read error\n", filename);
169 		rval = 1;
170 	}
171 	if (ferror(stdout)) {
172 		clearerr(stdout);
173 		(void)fprintf(stderr, "cat: stdout: write error\n");
174 		rval = 1;
175 	}
176 }
177 
178 raw_args(argv)
179 	char **argv;
180 {
181 	register int fd;
182 
183 	fd = fileno(stdin);
184 	filename = "-";
185 	do {
186 		if (*argv) {
187 			if (!strcmp(*argv, "-"))
188 				fd = fileno(stdin);
189 			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
190 				(void)fprintf(stderr, "cat: %s: %s\n",
191 				    *argv, strerror(errno));
192 				rval = 1;
193 				++argv;
194 				continue;
195 			}
196 			filename = *argv++;
197 		}
198 		rval |= raw_cat(fd);
199 		if (fd != fileno(stdin))
200 			(void)close(fd);
201 	} while (*argv);
202 }
203 
204 raw_cat(fd)
205 	register int fd;
206 {
207 	register int nr, nw, off;
208 	static int bsize;
209 	static char *buf;
210 	struct stat sbuf;
211 	char *malloc(), *strerror();
212 
213 	if (!buf) {
214 		if (fstat(fileno(stdout), &sbuf)) {
215 			(void)fprintf(stderr, "cat: %s: %s\n", filename,
216 			    strerror(errno));
217 			return(1);
218 		}
219 		bsize = MAX(sbuf.st_blksize, 1024);
220 		if (!(buf = malloc((u_int)bsize))) {
221 			(void)fprintf(stderr, "cat: %s: no memory.\n",
222 			    filename);
223 			return(1);
224 		}
225 	}
226 	while ((nr = read(fd, buf, bsize)) > 0)
227 		for (off = 0; off < nr;) {
228 			if ((nw = write(fileno(stdout), buf + off, nr)) < 0) {
229 				perror("cat: stdout");
230 				return(1);
231 			}
232 			off += nw;
233 		}
234 	if (nr < 0) {
235 		(void)fprintf(stderr, "cat: %s: %s\n", filename,
236 		    strerror(errno));
237 		return(1);
238 	}
239 	return(0);
240 }
241