wc.c revision 13380
1174604Sscottl/* 2174604Sscottl * Copyright (c) 1980, 1987, 1991, 1993 3174604Sscottl * The Regents of the University of California. All rights reserved. 4174604Sscottl * 5174604Sscottl * Redistribution and use in source and binary forms, with or without 6174604Sscottl * modification, are permitted provided that the following conditions 7174604Sscottl * are met: 8174604Sscottl * 1. Redistributions of source code must retain the above copyright 9174604Sscottl * notice, this list of conditions and the following disclaimer. 10174604Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11174604Sscottl * notice, this list of conditions and the following disclaimer in the 12174604Sscottl * documentation and/or other materials provided with the distribution. 13174604Sscottl * 3. All advertising materials mentioning features or use of this software 14174604Sscottl * must display the following acknowledgement: 15174604Sscottl * This product includes software developed by the University of 16174604Sscottl * California, Berkeley and its contributors. 17174604Sscottl * 4. Neither the name of the University nor the names of its contributors 18174604Sscottl * may be used to endorse or promote products derived from this software 19174604Sscottl * without specific prior written permission. 20174604Sscottl * 21174604Sscottl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22174604Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23174604Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24174604Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25174604Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26174604Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27174604Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28174604Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29176018Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30174604Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31174604Sscottl * SUCH DAMAGE. 32174604Sscottl */ 33174604Sscottl 34174604Sscottl#ifndef lint 35174604Sscottlstatic char copyright[] = 36174604Sscottl"@(#) Copyright (c) 1980, 1987, 1991, 1993\n\ 37199043Smav The Regents of the University of California. All rights reserved.\n"; 38199043Smav#endif /* not lint */ 39199043Smav 40174604Sscottl#ifndef lint 41174604Sscottlstatic char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93"; 42174604Sscottl#endif /* not lint */ 43174604Sscottl 44174604Sscottl#include <sys/param.h> 45174604Sscottl#include <sys/stat.h> 46174604Sscottl#include <fcntl.h> 47199043Smav#include <locale.h> 48199043Smav#include <unistd.h> 49199043Smav#include <errno.h> 50174604Sscottl#include <stdio.h> 51174604Sscottl#include <stdlib.h> 52174604Sscottl#include <string.h> 53174604Sscottl#include <ctype.h> 54174604Sscottl 55174604Sscottlu_long tlinect, twordct, tcharct; 56174604Sscottlint doline, doword, dochar; 57174604Sscottl 58174604Sscottlvoid cnt __P((char *)); 59174604Sscottlvoid err __P((const char *, ...)); 60174604Sscottlvoid usage __P((void)); 61174604Sscottl 62174604Sscottlint 63174604Sscottlmain(argc, argv) 64174604Sscottl int argc; 65174604Sscottl char *argv[]; 66174604Sscottl{ 67174604Sscottl register int ch; 68174604Sscottl int total; 69174604Sscottl 70174604Sscottl (void) setlocale(LC_CTYPE, ""); 71174604Sscottl 72174604Sscottl while ((ch = getopt(argc, argv, "lwc")) != EOF) 73174604Sscottl switch((char)ch) { 74174604Sscottl case 'l': 75174604Sscottl doline = 1; 76174604Sscottl break; 77174604Sscottl case 'w': 78174604Sscottl doword = 1; 79174604Sscottl break; 80174604Sscottl case 'c': 81174604Sscottl dochar = 1; 82174604Sscottl break; 83174604Sscottl case '?': 84174604Sscottl default: 85174604Sscottl usage(); 86174604Sscottl } 87174604Sscottl argv += optind; 88174604Sscottl argc -= optind; 89174604Sscottl 90174604Sscottl /* Wc's flags are on by default. */ 91174604Sscottl if (doline + doword + dochar == 0) 92174604Sscottl doline = doword = dochar = 1; 93174604Sscottl 94174604Sscottl total = 0; 95174604Sscottl if (!*argv) { 96174604Sscottl cnt(NULL); 97174604Sscottl (void)printf("\n"); 98174604Sscottl } 99174604Sscottl else do { 100174604Sscottl cnt(*argv); 101174604Sscottl (void)printf(" %s\n", *argv); 102174604Sscottl ++total; 103174604Sscottl } while(*++argv); 104174604Sscottl 105174604Sscottl if (total > 1) { 106174604Sscottl if (doline) 107174604Sscottl (void)printf(" %7ld", tlinect); 108174604Sscottl if (doword) 109174604Sscottl (void)printf(" %7ld", twordct); 110174604Sscottl if (dochar) 111174604Sscottl (void)printf(" %7ld", tcharct); 112174604Sscottl (void)printf(" total\n"); 113174604Sscottl } 114174604Sscottl exit(0); 115174604Sscottl} 116174604Sscottl 117174604Sscottlvoid 118174604Sscottlcnt(file) 119174604Sscottl char *file; 120174604Sscottl{ 121174604Sscottl register u_char *p, ch; 122174604Sscottl register short gotsp; 123174604Sscottl register int len; 124174604Sscottl register u_long linect, wordct, charct; 125174604Sscottl struct stat sb; 126174604Sscottl int fd; 127174604Sscottl u_char buf[MAXBSIZE]; 128174604Sscottl 129174604Sscottl fd = STDIN_FILENO; 130174604Sscottl linect = wordct = charct = 0; 131174604Sscottl if (file) { 132174604Sscottl if ((fd = open(file, O_RDONLY, 0)) < 0) 133174604Sscottl err("%s: %s", file, strerror(errno)); 134174604Sscottl if (doword) 135174604Sscottl goto word; 136174604Sscottl /* 137174604Sscottl * Line counting is split out because it's a lot faster to get 138174604Sscottl * lines than to get words, since the word count requires some 139174604Sscottl * logic. 140174604Sscottl */ 141174604Sscottl if (doline) { 142174604Sscottl while (len = read(fd, buf, MAXBSIZE)) { 143174604Sscottl if (len == -1) 144174604Sscottl err("%s: %s", file, strerror(errno)); 145174604Sscottl charct += len; 146174604Sscottl for (p = buf; len--; ++p) 147174604Sscottl if (*p == '\n') 148174604Sscottl ++linect; 149174604Sscottl } 150174604Sscottl tlinect += linect; 151174604Sscottl (void)printf(" %7lu", linect); 152174604Sscottl if (dochar) { 153174604Sscottl tcharct += charct; 154174604Sscottl (void)printf(" %7lu", charct); 155174604Sscottl } 156174604Sscottl (void)close(fd); 157174604Sscottl return; 158174604Sscottl } 159174604Sscottl /* 160174604Sscottl * If all we need is the number of characters and it's a 161174604Sscottl * regular or linked file, just stat the puppy. 162174604Sscottl */ 163174604Sscottl if (dochar) { 164174604Sscottl if (fstat(fd, &sb)) 165174604Sscottl err("%s: %s", file, strerror(errno)); 166174604Sscottl if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) { 167174604Sscottl (void)printf(" %7qu", sb.st_size); 168174604Sscottl tcharct += sb.st_size; 169174604Sscottl (void)close(fd); 170174604Sscottl return; 171174604Sscottl } 172174604Sscottl } 173174604Sscottl } 174174604Sscottl 175174604Sscottl /* Do it the hard way... */ 176174604Sscottlword: for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) { 177174604Sscottl if (len == -1) 178174604Sscottl err("%s: %s", file, strerror(errno)); 179174604Sscottl /* 180174604Sscottl * This loses in the presence of multi-byte characters. 181174604Sscottl * To do it right would require a function to return a 182174604Sscottl * character while knowing how many bytes it consumed. 183174604Sscottl */ 184174604Sscottl charct += len; 185174604Sscottl for (p = buf; len--;) { 186174604Sscottl ch = *p++; 187174604Sscottl if (ch == '\n') 188174604Sscottl ++linect; 189174604Sscottl if (isspace(ch)) 190174604Sscottl gotsp = 1; 191174604Sscottl else if (gotsp) { 192174604Sscottl gotsp = 0; 193174604Sscottl ++wordct; 194174604Sscottl } 195174604Sscottl } 196174604Sscottl } 197174604Sscottl if (doline) { 198174604Sscottl tlinect += linect; 199174604Sscottl (void)printf(" %7lu", linect); 200174604Sscottl } 201174604Sscottl if (doword) { 202174604Sscottl twordct += wordct; 203174604Sscottl (void)printf(" %7lu", wordct); 204174604Sscottl } 205174604Sscottl if (dochar) { 206174604Sscottl tcharct += charct; 207174604Sscottl (void)printf(" %7lu", charct); 208174604Sscottl } 209174604Sscottl (void)close(fd); 210174604Sscottl} 211174604Sscottl 212174604Sscottlvoid 213174604Sscottlusage() 214176939Sscottl{ 215174604Sscottl (void)fprintf(stderr, "usage: wc [-clw] [files]\n"); 216174604Sscottl exit(1); 217174604Sscottl} 218174604Sscottl 219174604Sscottl#if __STDC__ 220174604Sscottl#include <stdarg.h> 221174604Sscottl#else 222174604Sscottl#include <varargs.h> 223174604Sscottl#endif 224174604Sscottl 225174604Sscottlvoid 226174604Sscottl#if __STDC__ 227174604Sscottlerr(const char *fmt, ...) 228174604Sscottl#else 229174604Sscottlerr(fmt, va_alist) 230174604Sscottl char *fmt; 231176939Sscottl va_dcl 232174604Sscottl#endif 233174604Sscottl{ 234174604Sscottl va_list ap; 235174604Sscottl#if __STDC__ 236174604Sscottl va_start(ap, fmt); 237174604Sscottl#else 238174604Sscottl va_start(ap); 239174604Sscottl#endif 240174604Sscottl (void)fprintf(stderr, "wc: "); 241174604Sscottl (void)vfprintf(stderr, fmt, ap); 242174604Sscottl va_end(ap); 243174604Sscottl (void)fprintf(stderr, "\n"); 244174604Sscottl exit(1); 245174604Sscottl /* NOTREACHED */ 246174604Sscottl} 247174604Sscottl