xref: /csrg-svn/usr.bin/wc/wc.c (revision 69172)
121588Sdist /*
262437Sbostic  * Copyright (c) 1980, 1987, 1991, 1993
362437Sbostic  *	The Regents of the University of California.  All rights reserved.
433163Sbostic  *
542785Sbostic  * %sccs.include.redist.c%
621588Sdist  */
721588Sdist 
821588Sdist #ifndef lint
962437Sbostic static char copyright[] =
1062437Sbostic "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
1162437Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1233163Sbostic #endif /* not lint */
1321588Sdist 
1421588Sdist #ifndef lint
15*69172Smckusick static char sccsid[] = "@(#)wc.c	8.2 (Berkeley) 05/02/95";
1633163Sbostic #endif /* not lint */
1721588Sdist 
1830103Sbostic #include <sys/param.h>
1930103Sbostic #include <sys/stat.h>
2051587Sbostic #include <fcntl.h>
2151587Sbostic #include <unistd.h>
2251587Sbostic #include <errno.h>
231161Sbill #include <stdio.h>
2451587Sbostic #include <stdlib.h>
2551587Sbostic #include <string.h>
2651587Sbostic #include <ctype.h>
271161Sbill 
2851587Sbostic u_long tlinect, twordct, tcharct;
2951587Sbostic int doline, doword, dochar;
3030103Sbostic 
3151587Sbostic void cnt __P((char *));
3251587Sbostic void err __P((const char *, ...));
3351587Sbostic void usage __P((void));
3430103Sbostic 
3551587Sbostic int
main(argc,argv)3635284Sbostic main(argc, argv)
3733163Sbostic 	int argc;
3851587Sbostic 	char *argv[];
391161Sbill {
4033163Sbostic 	register int ch;
4135284Sbostic 	int total;
421161Sbill 
4351587Sbostic 	while ((ch = getopt(argc, argv, "lwc")) != EOF)
4451587Sbostic 		switch((char)ch) {
4551587Sbostic 		case 'l':
4651587Sbostic 			doline = 1;
4751587Sbostic 			break;
4851587Sbostic 		case 'w':
4951587Sbostic 			doword = 1;
5051587Sbostic 			break;
5151587Sbostic 		case 'c':
5251587Sbostic 			dochar = 1;
5351587Sbostic 			break;
5451587Sbostic 		case '?':
5551587Sbostic 		default:
5651587Sbostic 			usage();
5751587Sbostic 		}
5851587Sbostic 	argv += optind;
5951587Sbostic 	argc -= optind;
6051587Sbostic 
6151587Sbostic 	/* Wc's flags are on by default. */
6251587Sbostic 	if (doline + doword + dochar == 0)
6333163Sbostic 		doline = doword = dochar = 1;
6430103Sbostic 
6535284Sbostic 	total = 0;
6635284Sbostic 	if (!*argv) {
6751587Sbostic 		cnt(NULL);
6851587Sbostic 		(void)printf("\n");
691161Sbill 	}
7035284Sbostic 	else do {
7135284Sbostic 		cnt(*argv);
7251587Sbostic 		(void)printf(" %s\n", *argv);
7335284Sbostic 		++total;
7430103Sbostic 	} while(*++argv);
7530103Sbostic 
7635284Sbostic 	if (total > 1) {
7735284Sbostic 		if (doline)
7851587Sbostic 			(void)printf(" %7ld", tlinect);
7935284Sbostic 		if (doword)
8051587Sbostic 			(void)printf(" %7ld", twordct);
8135284Sbostic 		if (dochar)
8251587Sbostic 			(void)printf(" %7ld", tcharct);
8351587Sbostic 		(void)printf(" total\n");
8435284Sbostic 	}
8533163Sbostic 	exit(0);
8630103Sbostic }
8730103Sbostic 
8851587Sbostic void
cnt(file)8930103Sbostic cnt(file)
9033163Sbostic 	char *file;
9130103Sbostic {
9251587Sbostic 	register u_char *p;
9333163Sbostic 	register short gotsp;
9451587Sbostic 	register int ch, len;
9551587Sbostic 	register u_long linect, wordct, charct;
9651587Sbostic 	struct stat sb;
9733163Sbostic 	int fd;
9833163Sbostic 	u_char buf[MAXBSIZE];
9930103Sbostic 
10051587Sbostic 	fd = STDIN_FILENO;
10130103Sbostic 	linect = wordct = charct = 0;
10230103Sbostic 	if (file) {
10351587Sbostic 		if ((fd = open(file, O_RDONLY, 0)) < 0)
10451587Sbostic 			err("%s: %s", file, strerror(errno));
10551587Sbostic 		if (doword)
10651587Sbostic 			goto word;
10751587Sbostic 		/*
10851587Sbostic 		 * Line counting is split out because it's a lot faster to get
10951587Sbostic 		 * lines than to get words, since the word count requires some
11051587Sbostic 		 * logic.
11151587Sbostic 		 */
11251587Sbostic 		if (doline) {
11351587Sbostic 			while (len = read(fd, buf, MAXBSIZE)) {
11451587Sbostic 				if (len == -1)
11551587Sbostic 					err("%s: %s", file, strerror(errno));
11651587Sbostic 				charct += len;
11751587Sbostic 				for (p = buf; len--; ++p)
11851587Sbostic 					if (*p == '\n')
11951587Sbostic 						++linect;
1201161Sbill 			}
12151587Sbostic 			tlinect += linect;
12251587Sbostic 			(void)printf(" %7lu", linect);
12330103Sbostic 			if (dochar) {
12451587Sbostic 				tcharct += charct;
12551587Sbostic 				(void)printf(" %7lu", charct);
1261161Sbill 			}
12751587Sbostic 			(void)close(fd);
12851587Sbostic 			return;
1291161Sbill 		}
13051587Sbostic 		/*
13151587Sbostic 		 * If all we need is the number of characters and it's a
13251587Sbostic 		 * regular or linked file, just stat the puppy.
13351587Sbostic 		 */
13451587Sbostic 		if (dochar) {
13551587Sbostic 			if (fstat(fd, &sb))
13651587Sbostic 				err("%s: %s", file, strerror(errno));
137*69172Smckusick 			if (S_ISREG(sb.st_mode)) {
13859588Sbostic 				(void)printf(" %7qu", sb.st_size);
13951587Sbostic 				tcharct += sb.st_size;
14051587Sbostic 				(void)close(fd);
14151587Sbostic 				return;
14251587Sbostic 			}
14351587Sbostic 		}
14430103Sbostic 	}
14551587Sbostic 
14651587Sbostic 	/* Do it the hard way... */
14751587Sbostic word:	for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
14851587Sbostic 		if (len == -1)
14951587Sbostic 			err("%s: %s", file, strerror(errno));
15051587Sbostic 		/*
15151587Sbostic 		 * This loses in the presence of multi-byte characters.
15251587Sbostic 		 * To do it right would require a function to return a
15351587Sbostic 		 * character while knowing how many bytes it consumed.
15451587Sbostic 		 */
15530103Sbostic 		charct += len;
15651587Sbostic 		for (p = buf; len--;) {
15751587Sbostic 			ch = *p++;
15851587Sbostic 			if (ch == '\n')
15951587Sbostic 				++linect;
16051587Sbostic 			if (isspace(ch))
16151587Sbostic 				gotsp = 1;
16251587Sbostic 			else if (gotsp) {
16351587Sbostic 				gotsp = 0;
16451587Sbostic 				++wordct;
16530103Sbostic 			}
16651587Sbostic 		}
16730103Sbostic 	}
16830103Sbostic 	if (doline) {
1691161Sbill 		tlinect += linect;
17051587Sbostic 		(void)printf(" %7lu", linect);
17130103Sbostic 	}
17230103Sbostic 	if (doword) {
1731161Sbill 		twordct += wordct;
17451587Sbostic 		(void)printf(" %7lu", wordct);
17530103Sbostic 	}
17630103Sbostic 	if (dochar) {
1771161Sbill 		tcharct += charct;
17851587Sbostic 		(void)printf(" %7lu", charct);
1791161Sbill 	}
18051587Sbostic 	(void)close(fd);
1811161Sbill }
18251587Sbostic 
18351587Sbostic void
usage()18451587Sbostic usage()
18551587Sbostic {
18651587Sbostic 	(void)fprintf(stderr, "usage: wc [-clw] [files]\n");
18751587Sbostic 	exit(1);
18851587Sbostic }
18951587Sbostic 
19051587Sbostic #if __STDC__
19151587Sbostic #include <stdarg.h>
19251587Sbostic #else
19351587Sbostic #include <varargs.h>
19451587Sbostic #endif
19551587Sbostic 
19651587Sbostic void
19751587Sbostic #if __STDC__
err(const char * fmt,...)19851587Sbostic err(const char *fmt, ...)
19951587Sbostic #else
20051587Sbostic err(fmt, va_alist)
20151587Sbostic 	char *fmt;
20251587Sbostic         va_dcl
20351587Sbostic #endif
20451587Sbostic {
20551587Sbostic 	va_list ap;
20651587Sbostic #if __STDC__
20751587Sbostic 	va_start(ap, fmt);
20851587Sbostic #else
20951587Sbostic 	va_start(ap);
21051587Sbostic #endif
21151587Sbostic 	(void)fprintf(stderr, "wc: ");
21251587Sbostic 	(void)vfprintf(stderr, fmt, ap);
21351587Sbostic 	va_end(ap);
21451587Sbostic 	(void)fprintf(stderr, "\n");
21551587Sbostic 	exit(1);
21651587Sbostic 	/* NOTREACHED */
21751587Sbostic }
218