cat.c revision 39138
11592Srgrimes/* 21592Srgrimes * Copyright (c) 1989, 1993 31592Srgrimes * The Regents of the University of California. All rights reserved. 41592Srgrimes * 51592Srgrimes * This code is derived from software contributed to Berkeley by 61592Srgrimes * Kevin Fall. 71592Srgrimes * 81592Srgrimes * Redistribution and use in source and binary forms, with or without 91592Srgrimes * modification, are permitted provided that the following conditions 101592Srgrimes * are met: 111592Srgrimes * 1. Redistributions of source code must retain the above copyright 121592Srgrimes * notice, this list of conditions and the following disclaimer. 131592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141592Srgrimes * notice, this list of conditions and the following disclaimer in the 151592Srgrimes * documentation and/or other materials provided with the distribution. 161592Srgrimes * 3. All advertising materials mentioning features or use of this software 171592Srgrimes * must display the following acknowledgement: 181592Srgrimes * This product includes software developed by the University of 191592Srgrimes * California, Berkeley and its contributors. 201592Srgrimes * 4. Neither the name of the University nor the names of its contributors 211592Srgrimes * may be used to endorse or promote products derived from this software 221592Srgrimes * without specific prior written permission. 231592Srgrimes * 241592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341592Srgrimes * SUCH DAMAGE. 3529916Smarkm */ 361592Srgrimes 371592Srgrimes#ifndef lint 381592Srgrimesstatic char const copyright[] = 391592Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 401592Srgrimes The Regents of the University of California. All rights reserved.\n"; 4131405Scharnier#endif /* not lint */ 4229916Smarkm 4331405Scharnier#ifndef lint 4431405Scharnier#if 0 4550476Speterstatic char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; 461592Srgrimes#endif 471592Srgrimesstatic const char rcsid[] = 481592Srgrimes "$Id: cat.c,v 1.12 1998/09/11 05:48:06 imp Exp $"; 491592Srgrimes#endif /* not lint */ 501592Srgrimes 511592Srgrimes#include <sys/param.h> 521592Srgrimes#include <sys/stat.h> 531592Srgrimes 541592Srgrimes#include <ctype.h> 551592Srgrimes#include <err.h> 561592Srgrimes#include <fcntl.h> 571592Srgrimes#include <locale.h> 5829916Smarkm#include <stdio.h> 591592Srgrimes#include <stdlib.h> 601592Srgrimes#include <unistd.h> 611592Srgrimes 621592Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag; 631592Srgrimesint rval; 641592Srgrimesconst char *filename; 651592Srgrimes 661592Srgrimesvoid cook_args __P((char *argv[])); 671592Srgrimesvoid cook_buf __P((FILE *)); 681592Srgrimesint main __P((int argc, char *argv[])); 6911486Sdgvoid raw_args __P((char *argv[])); 701592Srgrimesvoid raw_cat __P((int)); 711592Srgrimes 721592Srgrimesint 7331405Scharniermain(argc, argv) 7431405Scharnier int argc; 751592Srgrimes char *argv[]; 761592Srgrimes{ 771592Srgrimes int ch; 781592Srgrimes 791592Srgrimes setlocale(LC_CTYPE, ""); 8031405Scharnier 811592Srgrimes while ((ch = getopt(argc, argv, "benstuv")) != -1) 821592Srgrimes switch (ch) { 8351433Smarkm case 'b': 8451433Smarkm bflag = nflag = 1; /* -b implies -n */ 8551433Smarkm break; 8651433Smarkm case 'e': 8751433Smarkm eflag = vflag = 1; /* -e implies -v */ 881592Srgrimes break; 891592Srgrimes case 'n': 901592Srgrimes nflag = 1; 911592Srgrimes break; 9251433Smarkm case 's': 931592Srgrimes sflag = 1; 9456590Sshin break; 9556590Sshin case 't': 9656590Sshin tflag = vflag = 1; /* -t implies -v */ 9756590Sshin break; 9856590Sshin case 'u': 991592Srgrimes setbuf(stdout, (char *)NULL); 1001592Srgrimes break; 1011592Srgrimes case 'v': 1021592Srgrimes vflag = 1; 1031592Srgrimes break; 1041592Srgrimes default: 1051592Srgrimes (void)fprintf(stderr, 10611486Sdg "usage: cat [-benstuv] [-] [file ...]\n"); 1071592Srgrimes exit(1); 1081592Srgrimes } 1091592Srgrimes argv += optind; 11056590Sshin 11156590Sshin if (bflag || eflag || nflag || sflag || tflag || vflag) 11256590Sshin cook_args(argv); 11356590Sshin else 11456590Sshin raw_args(argv); 11556590Sshin if (fclose(stdout)) 11656590Sshin err(1, "stdout"); 11756590Sshin exit(rval); 11856590Sshin} 11956590Sshin 12056590Sshinvoid 12156590Sshincook_args(argv) 12256590Sshin char **argv; 12356590Sshin{ 1241592Srgrimes register FILE *fp; 1251592Srgrimes 1261592Srgrimes fp = stdin; 1271592Srgrimes filename = "stdin"; 12856590Sshin do { 1291592Srgrimes if (*argv) { 1301592Srgrimes if (!strcmp(*argv, "-")) 1311592Srgrimes fp = stdin; 1321592Srgrimes else if ((fp = fopen(*argv, "r")) == NULL) { 1331592Srgrimes warn("%s", *argv); 13451433Smarkm rval = 1; 13551433Smarkm ++argv; 13651433Smarkm continue; 13751433Smarkm } 1381592Srgrimes filename = *argv++; 1391592Srgrimes } 1401592Srgrimes cook_buf(fp); 1411592Srgrimes if (fp != stdin) 1421592Srgrimes (void)fclose(fp); 1431592Srgrimes } while (*argv); 14456590Sshin} 1451592Srgrimes 1461592Srgrimesvoid 1471592Srgrimescook_buf(fp) 1481592Srgrimes register FILE *fp; 1491592Srgrimes{ 15024349Simp register int ch, gobble, line, prev; 1511592Srgrimes 15211486Sdg line = gobble = 0; 15311486Sdg for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 15411486Sdg if (prev == '\n') { 1551592Srgrimes if (ch == '\n') { 1561592Srgrimes if (sflag) { 1571592Srgrimes if (!gobble && putchar(ch) == EOF) 1581592Srgrimes break; 1591592Srgrimes gobble = 1; 1601592Srgrimes continue; 1611592Srgrimes } 1621592Srgrimes if (nflag && !bflag) { 1631592Srgrimes (void)fprintf(stdout, "%6d\t", ++line); 1641592Srgrimes if (ferror(stdout)) 1651592Srgrimes break; 1661592Srgrimes } 1671592Srgrimes } else if (nflag) { 1681592Srgrimes (void)fprintf(stdout, "%6d\t", ++line); 1691592Srgrimes if (ferror(stdout)) 1701592Srgrimes break; 1711592Srgrimes } 1721592Srgrimes } 1731592Srgrimes gobble = 0; 1741592Srgrimes if (ch == '\n') { 1751592Srgrimes if (eflag) 1761592Srgrimes if (putchar('$') == EOF) 1771592Srgrimes break; 1781592Srgrimes } else if (ch == '\t') { 1791592Srgrimes if (tflag) { 1801592Srgrimes if (putchar('^') == EOF || putchar('I') == EOF) 1811592Srgrimes break; 1821592Srgrimes continue; 1831592Srgrimes } 1841592Srgrimes } else if (vflag) { 1851592Srgrimes if (!isascii(ch) && !isprint(ch)) { 18611486Sdg if (putchar('M') == EOF || putchar('-') == EOF) 18711486Sdg break; 18811486Sdg ch = toascii(ch); 18956590Sshin } 19056590Sshin if (iscntrl(ch)) { 1911592Srgrimes if (putchar('^') == EOF || 1921592Srgrimes putchar(ch == '\177' ? '?' : 1931592Srgrimes ch | 0100) == EOF) 19456590Sshin break; 19511486Sdg continue; 1961592Srgrimes } 19729916Smarkm } 1981592Srgrimes if (putchar(ch) == EOF) 1991592Srgrimes break; 2001592Srgrimes } 2011592Srgrimes if (ferror(fp)) { 2021592Srgrimes warn("%s", filename); 2031592Srgrimes rval = 1; 2041592Srgrimes clearerr(fp); 2051592Srgrimes } 2061592Srgrimes if (ferror(stdout)) 2071592Srgrimes err(1, "stdout"); 2081592Srgrimes} 2091592Srgrimes 2101592Srgrimesvoid 21156590Sshinraw_args(argv) 2121592Srgrimes char **argv; 2131592Srgrimes{ 2141592Srgrimes register int fd; 21556590Sshin 21656590Sshin fd = fileno(stdin); 2171592Srgrimes filename = "stdin"; 2181592Srgrimes do { 2191592Srgrimes if (*argv) { 2201592Srgrimes if (!strcmp(*argv, "-")) 2211592Srgrimes fd = fileno(stdin); 2221592Srgrimes else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 2231592Srgrimes warn("%s", *argv); 2241592Srgrimes rval = 1; 2251592Srgrimes ++argv; 22656590Sshin continue; 22756590Sshin } 22856590Sshin filename = *argv++; 22956590Sshin } 23056590Sshin raw_cat(fd); 23124191Simp if (fd != fileno(stdin)) 2321592Srgrimes (void)close(fd); 2331592Srgrimes } while (*argv); 23463959Sume} 23556590Sshin 23663959Sumevoid 23756590Sshinraw_cat(rfd) 23856590Sshin register int rfd; 23956590Sshin{ 24056590Sshin register int off, wfd; 24156590Sshin ssize_t nr, nw; 24256590Sshin static size_t bsize; 24356590Sshin static char *buf; 24456590Sshin struct stat sbuf; 24556590Sshin 2461592Srgrimes wfd = fileno(stdout); 24756590Sshin if (buf == NULL) { 2481592Srgrimes if (fstat(wfd, &sbuf)) 2491592Srgrimes err(1, "%s", filename); 2501592Srgrimes bsize = MAX(sbuf.st_blksize, 1024); 25156590Sshin if ((buf = malloc(bsize)) == NULL) 25256590Sshin err(1, NULL); 25322455Simp } 25422455Simp while ((nr = read(rfd, buf, bsize)) > 0) 2551592Srgrimes for (off = 0; nr; nr -= nw, off += nw) 2561592Srgrimes if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2571592Srgrimes err(1, "stdout"); 2581592Srgrimes if (nr < 0) { 2591592Srgrimes warn("%s", filename); 2601592Srgrimes rval = 1; 2611592Srgrimes } 2621592Srgrimes} 26322455Simp