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