1 /* $NetBSD: cat.c,v 1.14 1997/06/26 23:07:19 kleink Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kevin Fall. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #ifndef lint 40 static char copyright[] = 41 "@(#) Copyright (c) 1989, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n"; 43 #endif /* not lint */ 44 45 #ifndef lint 46 #if 0 47 static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; 48 #else 49 static char rcsid[] = "$NetBSD: cat.c,v 1.14 1997/06/26 23:07:19 kleink Exp $"; 50 #endif 51 #endif /* not lint */ 52 53 #include <sys/param.h> 54 #include <sys/stat.h> 55 56 #include <locale.h> 57 #include <ctype.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <fcntl.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <unistd.h> 65 66 int bflag, eflag, nflag, sflag, tflag, vflag; 67 int rval; 68 char *filename; 69 70 void cook_args __P((char *argv[])); 71 void cook_buf __P((FILE *)); 72 void raw_args __P((char *argv[])); 73 void raw_cat __P((int)); 74 75 int 76 main(argc, argv) 77 int argc; 78 char *argv[]; 79 { 80 extern int optind; 81 int ch; 82 83 setlocale(LC_ALL, ""); 84 85 while ((ch = getopt(argc, argv, "benstuv")) != -1) 86 switch (ch) { 87 case 'b': 88 bflag = nflag = 1; /* -b implies -n */ 89 break; 90 case 'e': 91 eflag = vflag = 1; /* -e implies -v */ 92 break; 93 case 'n': 94 nflag = 1; 95 break; 96 case 's': 97 sflag = 1; 98 break; 99 case 't': 100 tflag = vflag = 1; /* -t implies -v */ 101 break; 102 case 'u': 103 setbuf(stdout, (char *)NULL); 104 break; 105 case 'v': 106 vflag = 1; 107 break; 108 default: 109 case '?': 110 (void)fprintf(stderr, 111 "usage: cat [-benstuv] [-] [file ...]\n"); 112 exit(1); 113 } 114 argv += optind; 115 116 if (bflag || eflag || nflag || sflag || tflag || vflag) 117 cook_args(argv); 118 else 119 raw_args(argv); 120 if (fclose(stdout)) 121 err(1, "stdout"); 122 exit(rval); 123 } 124 125 void 126 cook_args(argv) 127 char **argv; 128 { 129 FILE *fp; 130 131 fp = stdin; 132 filename = "stdin"; 133 do { 134 if (*argv) { 135 if (!strcmp(*argv, "-")) 136 fp = stdin; 137 else if ((fp = fopen(*argv, "r")) == NULL) { 138 warn("%s", *argv); 139 rval = 1; 140 ++argv; 141 continue; 142 } 143 filename = *argv++; 144 } 145 cook_buf(fp); 146 if (fp != stdin) 147 (void)fclose(fp); 148 } while (*argv); 149 } 150 151 void 152 cook_buf(fp) 153 FILE *fp; 154 { 155 int ch, gobble, line, prev; 156 157 line = gobble = 0; 158 for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 159 if (prev == '\n') { 160 if (ch == '\n') { 161 if (sflag) { 162 if (!gobble && putchar(ch) == EOF) 163 break; 164 gobble = 1; 165 continue; 166 } 167 if (nflag && !bflag) { 168 (void)fprintf(stdout, "%6d\t", ++line); 169 if (ferror(stdout)) 170 break; 171 } 172 } else if (nflag) { 173 (void)fprintf(stdout, "%6d\t", ++line); 174 if (ferror(stdout)) 175 break; 176 } 177 } 178 gobble = 0; 179 if (ch == '\n') { 180 if (eflag) 181 if (putchar('$') == EOF) 182 break; 183 } else if (ch == '\t') { 184 if (tflag) { 185 if (putchar('^') == EOF || putchar('I') == EOF) 186 break; 187 continue; 188 } 189 } else if (vflag) { 190 if (!isascii(ch)) { 191 if (putchar('M') == EOF || putchar('-') == EOF) 192 break; 193 ch = toascii(ch); 194 } 195 if (iscntrl(ch)) { 196 if (putchar('^') == EOF || 197 putchar(ch == '\177' ? '?' : 198 ch | 0100) == EOF) 199 break; 200 continue; 201 } 202 } 203 if (putchar(ch) == EOF) 204 break; 205 } 206 if (ferror(fp)) { 207 warn("%s", filename); 208 rval = 1; 209 clearerr(fp); 210 } 211 if (ferror(stdout)) 212 err(1, "stdout"); 213 } 214 215 void 216 raw_args(argv) 217 char **argv; 218 { 219 int fd; 220 221 fd = fileno(stdin); 222 filename = "stdin"; 223 do { 224 if (*argv) { 225 if (!strcmp(*argv, "-")) 226 fd = fileno(stdin); 227 else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 228 warn("%s", *argv); 229 rval = 1; 230 ++argv; 231 continue; 232 } 233 filename = *argv++; 234 } 235 raw_cat(fd); 236 if (fd != fileno(stdin)) 237 (void)close(fd); 238 } while (*argv); 239 } 240 241 void 242 raw_cat(rfd) 243 int rfd; 244 { 245 int nr, nw, off, wfd; 246 static int bsize; 247 static char *buf; 248 struct stat sbuf; 249 250 wfd = fileno(stdout); 251 if (buf == NULL) { 252 if (fstat(wfd, &sbuf)) 253 err(1, "%s", filename); 254 bsize = MAX(sbuf.st_blksize, 1024); 255 if ((buf = malloc((u_int)bsize)) == NULL) 256 err(1, "cannot allocate buffer"); 257 } 258 while ((nr = read(rfd, buf, bsize)) > 0) 259 for (off = 0; nr; nr -= nw, off += nw) 260 if ((nw = write(wfd, buf + off, nr)) < 0) 261 err(1, "stdout"); 262 if (nr < 0) { 263 warn("%s", filename); 264 rval = 1; 265 } 266 } 267