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
main(argc,argv)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
cook_args(argv)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
cook_buf(fp)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
raw_args(argv)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
raw_cat(rfd)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