cat.c revision 83961
177696Sbrian/* 236321Samurai * Copyright (c) 1989, 1993 377696Sbrian * The Regents of the University of California. All rights reserved. 477696Sbrian * 536321Samurai * This code is derived from software contributed to Berkeley by 677696Sbrian * Kevin Fall. 777696Sbrian * 877696Sbrian * Redistribution and use in source and binary forms, with or without 977696Sbrian * modification, are permitted provided that the following conditions 1077696Sbrian * are met: 1177696Sbrian * 1. Redistributions of source code must retain the above copyright 1277696Sbrian * notice, this list of conditions and the following disclaimer. 1377696Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1436321Samurai * notice, this list of conditions and the following disclaimer in the 1577696Sbrian * documentation and/or other materials provided with the distribution. 1677696Sbrian * 3. All advertising materials mentioning features or use of this software 1777696Sbrian * must display the following acknowledgement: 1877696Sbrian * This product includes software developed by the University of 1977696Sbrian * California, Berkeley and its contributors. 2077696Sbrian * 4. Neither the name of the University nor the names of its contributors 2177696Sbrian * may be used to endorse or promote products derived from this software 2277696Sbrian * without specific prior written permission. 2377696Sbrian * 2477696Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2577696Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2636321Samurai * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2799207Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2836321Samurai * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2936321Samurai * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3084195Sdillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3184195Sdillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3284195Sdillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3384195Sdillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3436321Samurai * SUCH DAMAGE. 3536321Samurai */ 3636321Samurai 3736321Samurai#ifndef lint 3836321Samuraistatic char const copyright[] = 3936321Samurai"@(#) Copyright (c) 1989, 1993\n\ 4036321Samurai The Regents of the University of California. All rights reserved.\n"; 4136321Samurai#endif /* not lint */ 4236321Samurai 4336321Samurai#ifndef lint 4436321Samurai#if 0 4599207Sbrianstatic char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; 4636321Samurai#endif 4736321Samuraistatic const char rcsid[] = 4836321Samurai "$FreeBSD: head/bin/cat/cat.c 83961 2001-09-26 11:32:23Z ru $"; 4936321Samurai#endif /* not lint */ 5036321Samurai 5136321Samurai#include <sys/param.h> 5236321Samurai#include <sys/stat.h> 5336321Samurai#ifndef NO_UDOM_SUPPORT 5436321Samurai#include <sys/socket.h> 5536321Samurai#include <sys/un.h> 5636321Samurai#include <errno.h> 5736321Samurai#endif 5836321Samurai 5936321Samurai#include <ctype.h> 6036321Samurai#include <err.h> 6136321Samurai#include <fcntl.h> 6236321Samurai#include <locale.h> 6336321Samurai#include <stdio.h> 6436321Samurai#include <stdlib.h> 6536321Samurai#include <string.h> 6636321Samurai#include <unistd.h> 6736321Samurai#include <stddef.h> 6836321Samurai 6936321Samuraiint bflag, eflag, nflag, sflag, tflag, vflag; 7036321Samuraiint rval; 7136321Samuraiconst char *filename; 7236321Samurai 7336321Samuraiint main __P((int argc, char *argv[])); 7436321Samurai 7536321Samuraistatic void scanfiles __P((char **argv, int cooked)); 7636321Samuraistatic void cook_cat __P((FILE *)); 7736321Samuraistatic void raw_cat __P((int)); 7836321Samurai 7936321Samurai#ifndef NO_UDOM_SUPPORT 8036321Samuraistatic int udom_open __P((const char *path, int flags, int modes)); 8136321Samurai#endif 8236321Samurai 8336321Samuraiint 8436321Samuraimain(argc, argv) 8536321Samurai int argc; 8636321Samurai char *argv[]; 8736321Samurai{ 8836321Samurai int ch; 8936321Samurai 9036321Samurai setlocale(LC_CTYPE, ""); 9136321Samurai 9236321Samurai while ((ch = getopt(argc, argv, "benstuv")) != -1) 9336321Samurai switch (ch) { 9436321Samurai case 'b': 9536321Samurai bflag = nflag = 1; /* -b implies -n */ 9636321Samurai break; 9736321Samurai case 'e': 9844616Sbrian eflag = vflag = 1; /* -e implies -v */ 9944616Sbrian break; 10036321Samurai case 'n': 10136321Samurai nflag = 1; 10236321Samurai break; 10336321Samurai case 's': 10436321Samurai sflag = 1; 10536321Samurai break; 10636321Samurai case 't': 10736321Samurai tflag = vflag = 1; /* -t implies -v */ 10836321Samurai break; 10936321Samurai case 'u': 11036321Samurai setbuf(stdout, NULL); 11136321Samurai break; 11236321Samurai case 'v': 11336321Samurai vflag = 1; 11436321Samurai break; 11597627Swollman default: 11636321Samurai (void)fprintf(stderr, 11799207Sbrian "usage: cat [-benstuv] [-] [file ...]\n"); 11836321Samurai exit(1); 11944616Sbrian } 12036321Samurai argv += optind; 12136321Samurai 12236321Samurai if (bflag || eflag || nflag || sflag || tflag || vflag) 12344616Sbrian scanfiles(argv, 1); 12436321Samurai else 12536321Samurai scanfiles(argv, 0); 12636321Samurai if (fclose(stdout)) 12736321Samurai err(1, "stdout"); 12836321Samurai exit(rval); 12936321Samurai} 13041759Sdillon 13141759Sdillonvoid 13241759Sdillonscanfiles(argv, cooked) 13341759Sdillon char **argv; 13436321Samurai int cooked; 13536321Samurai{ 13641759Sdillon int i = 0; 13741759Sdillon char *path; 13836321Samurai FILE *fp; 13936321Samurai 14036321Samurai while ((path = argv[i]) != NULL || i == 0) { 14136321Samurai int fd; 14236321Samurai 14336321Samurai if (path == NULL || strcmp(path, "-") == 0) { 14436321Samurai filename = "stdin"; 14536321Samurai fd = STDIN_FILENO; 14699207Sbrian } else { 14736321Samurai filename = path; 14836321Samurai fd = open(path, O_RDONLY); 14941759Sdillon#ifndef NO_UDOM_SUPPORT 15041759Sdillon if (fd < 0 && errno == EOPNOTSUPP) 15141759Sdillon fd = udom_open(path, O_RDONLY, 0); 15241759Sdillon#endif 15336321Samurai } 15436321Samurai if (fd < 0) { 15536321Samurai warn("%s", path); 15636321Samurai rval = 1; 15736321Samurai } else if (cooked) { 15836321Samurai if (fd == STDIN_FILENO) 15936321Samurai cook_cat(stdin); 16036321Samurai else { 16136321Samurai fp = fdopen(fd, "r"); 16236321Samurai cook_cat(fp); 16336321Samurai fclose(fp); 16436321Samurai } 16536321Samurai } else { 16636321Samurai raw_cat(fd); 16736321Samurai if (fd != STDIN_FILENO) 16836321Samurai close(fd); 16936321Samurai } 17036321Samurai if (path == NULL) 17136321Samurai break; 17236321Samurai ++i; 17336321Samurai } 17436321Samurai} 17536321Samurai 17636321Samuraistatic void 17736321Samuraicook_cat(fp) 17836321Samurai register FILE *fp; 17936321Samurai{ 18041759Sdillon register int ch, gobble, line, prev; 18141759Sdillon 18241759Sdillon /* Reset EOF condition on stdin. */ 18341759Sdillon if (fp == stdin && feof(stdin)) 18436321Samurai clearerr(stdin); 18536321Samurai 18636321Samurai line = gobble = 0; 18799207Sbrian for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 18836321Samurai if (prev == '\n') { 18936321Samurai if (ch == '\n') { 19036321Samurai if (sflag) { 19136321Samurai if (!gobble && putchar(ch) == EOF) 19236321Samurai break; 19336321Samurai gobble = 1; 19436321Samurai continue; 19536321Samurai } 19636321Samurai if (nflag && !bflag) { 19736321Samurai (void)fprintf(stdout, "%6d\t", ++line); 19841759Sdillon if (ferror(stdout)) 19936321Samurai break; 20036321Samurai } 20136321Samurai } else if (nflag) { 20241759Sdillon (void)fprintf(stdout, "%6d\t", ++line); 20341759Sdillon if (ferror(stdout)) 20436321Samurai break; 20536321Samurai } 20641759Sdillon } 20741759Sdillon gobble = 0; 20899207Sbrian if (ch == '\n') { 20936321Samurai if (eflag) 21036321Samurai if (putchar('$') == EOF) 21141759Sdillon break; 21241759Sdillon } else if (ch == '\t') { 21336321Samurai if (tflag) { 21441759Sdillon if (putchar('^') == EOF || putchar('I') == EOF) 21541759Sdillon break; 21636321Samurai continue; 21736321Samurai } 21836321Samurai } else if (vflag) { 21936321Samurai if (!isascii(ch) && !isprint(ch)) { 22036321Samurai if (putchar('M') == EOF || putchar('-') == EOF) 22136321Samurai break; 22236321Samurai ch = toascii(ch); 22336321Samurai } 22441759Sdillon if (iscntrl(ch)) { 22541759Sdillon if (putchar('^') == EOF || 22636321Samurai putchar(ch == '\177' ? '?' : 22736321Samurai ch | 0100) == EOF) 22836321Samurai break; 22936321Samurai continue; 23036321Samurai } 23136321Samurai } 23236321Samurai if (putchar(ch) == EOF) 23336321Samurai break; 23441759Sdillon } 23536321Samurai if (ferror(fp)) { 23636321Samurai warn("%s", filename); 23741759Sdillon rval = 1; 23841759Sdillon clearerr(fp); 23936321Samurai } 24036321Samurai if (ferror(stdout)) 24136321Samurai err(1, "stdout"); 24236321Samurai} 24336321Samurai 24436321Samuraistatic void 24536321Samurairaw_cat(rfd) 24636321Samurai register int rfd; 24736321Samurai{ 24836321Samurai register int off, wfd; 24936321Samurai ssize_t nr, nw; 25036321Samurai static size_t bsize; 25136321Samurai static char *buf; 25236321Samurai struct stat sbuf; 25336321Samurai 25474778Sbrian wfd = fileno(stdout); 25536321Samurai if (buf == NULL) { 25636321Samurai if (fstat(wfd, &sbuf)) 25736321Samurai err(1, "%s", filename); 25836321Samurai bsize = MAX(sbuf.st_blksize, 1024); 25936321Samurai if ((buf = malloc(bsize)) == NULL) 26036321Samurai err(1, "buffer"); 26136321Samurai } 26241759Sdillon while ((nr = read(rfd, buf, bsize)) > 0) 26336321Samurai for (off = 0; nr; nr -= nw, off += nw) 26436321Samurai if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 26536321Samurai err(1, "stdout"); 26636321Samurai if (nr < 0) { 26736321Samurai warn("%s", filename); 26836321Samurai rval = 1; 26936321Samurai } 27036321Samurai} 27136321Samurai 27236321Samurai#ifndef NO_UDOM_SUPPORT 27344616Sbrian 27441759Sdillonstatic int 27541759Sdillonudom_open(path, flags, modes) 27636321Samurai const char *path; 27741759Sdillon int flags; 27836321Samurai int modes; 27936321Samurai{ 28036321Samurai struct sockaddr_un sou; 28136321Samurai int fd; 28236321Samurai int len; 28341759Sdillon 28436321Samurai bzero(&sou, sizeof(sou)); 28541759Sdillon 28641759Sdillon /* 28741759Sdillon * Construct the unix domain socket address and attempt to connect 28841759Sdillon */ 28941759Sdillon if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { 29036321Samurai sou.sun_family = AF_UNIX; 29136321Samurai snprintf(sou.sun_path, sizeof(sou.sun_path), "%s", path); 29236321Samurai len = strlen(sou.sun_path); 29336321Samurai len = offsetof(struct sockaddr_un, sun_path[len+1]); 29436321Samurai 29536321Samurai if (connect(fd, (void *)&sou, len) < 0) { 29636321Samurai close(fd); 29744616Sbrian fd = -1; 29836321Samurai } 29944616Sbrian } 30036321Samurai 30136321Samurai /* 30236321Samurai * handle the open flags by shutting down appropriate directions 30336321Samurai */ 30436321Samurai if (fd >= 0) { 30536321Samurai switch(flags & O_ACCMODE) { 30636321Samurai case O_RDONLY: 30736321Samurai shutdown(fd, SHUT_WR); 30836321Samurai break; 30936321Samurai case O_WRONLY: 31036321Samurai shutdown(fd, SHUT_RD); 31136321Samurai break; 31236321Samurai default: 31336321Samurai break; 31436321Samurai } 31536321Samurai } 31636321Samurai return(fd); 31736321Samurai} 31836321Samurai 31936321Samurai#endif 32036321Samurai 32136321Samurai