xref: /csrg-svn/usr.bin/wc/wc.c (revision 42785)
121588Sdist /*
233163Sbostic  * Copyright (c) 1980, 1987 Regents of the University of California.
333163Sbostic  * All rights reserved.
433163Sbostic  *
5*42785Sbostic  * %sccs.include.redist.c%
621588Sdist  */
721588Sdist 
821588Sdist #ifndef lint
921588Sdist char copyright[] =
1033163Sbostic "@(#) Copyright (c) 1980, 1987 Regents of the University of California.\n\
1121588Sdist  All rights reserved.\n";
1233163Sbostic #endif /* not lint */
1321588Sdist 
1421588Sdist #ifndef lint
15*42785Sbostic static char sccsid[] = "@(#)wc.c	5.6 (Berkeley) 06/01/90";
1633163Sbostic #endif /* not lint */
1721588Sdist 
1830103Sbostic /* wc line, word and char count */
191161Sbill 
2030103Sbostic #include <sys/param.h>
2130103Sbostic #include <sys/stat.h>
2230103Sbostic #include <sys/file.h>
231161Sbill #include <stdio.h>
241161Sbill 
2530103Sbostic #define DEL	0177			/* del char */
2630103Sbostic #define NL	012			/* newline char */
2730103Sbostic #define SPACE	040			/* space char */
2830103Sbostic #define TAB	011			/* tab char */
2930103Sbostic 
3033163Sbostic static long	tlinect, twordct, tcharct;
3135284Sbostic static int	doline, doword, dochar;
3230103Sbostic 
3335284Sbostic main(argc, argv)
3433163Sbostic 	int argc;
3533163Sbostic 	char **argv;
361161Sbill {
3733163Sbostic 	extern int optind;
3833163Sbostic 	register int ch;
3935284Sbostic 	int total;
401161Sbill 
4130103Sbostic 	/*
4230103Sbostic 	 * wc is unusual in that its flags are on by default, so,
4330103Sbostic 	 * if you don't get any arguments, you have to turn them
4430103Sbostic 	 * all on.
4530103Sbostic 	 */
4630103Sbostic 	if (argc > 1 && argv[1][0] == '-' && argv[1][1]) {
4735284Sbostic 		while ((ch = getopt(argc, argv, "lwc")) != EOF)
4830103Sbostic 			switch((char)ch) {
4933163Sbostic 			case 'l':
5033163Sbostic 				doline = 1;
5133163Sbostic 				break;
5233163Sbostic 			case 'w':
5333163Sbostic 				doword = 1;
5433163Sbostic 				break;
5533163Sbostic 			case 'c':
5633163Sbostic 				dochar = 1;
5733163Sbostic 				break;
5833163Sbostic 			case '?':
5933163Sbostic 			default:
6035284Sbostic 				fputs("usage: wc [-lwc] [files]\n", stderr);
6133163Sbostic 				exit(1);
6230103Sbostic 			}
6330103Sbostic 		argv += optind;
6430103Sbostic 		argc -= optind;
6530103Sbostic 	}
6630103Sbostic 	else {
6730103Sbostic 		++argv;
6830103Sbostic 		--argc;
6933163Sbostic 		doline = doword = dochar = 1;
7030103Sbostic 	}
7130103Sbostic 
7235284Sbostic 	total = 0;
7335284Sbostic 	if (!*argv) {
7435284Sbostic 		cnt((char *)NULL);
7535284Sbostic 		putchar('\n');
761161Sbill 	}
7735284Sbostic 	else do {
7835284Sbostic 		cnt(*argv);
7935284Sbostic 		printf(" %s\n", *argv);
8035284Sbostic 		++total;
8130103Sbostic 	} while(*++argv);
8230103Sbostic 
8335284Sbostic 	if (total > 1) {
8435284Sbostic 		if (doline)
8535284Sbostic 			printf(" %7ld", tlinect);
8635284Sbostic 		if (doword)
8735284Sbostic 			printf(" %7ld", twordct);
8835284Sbostic 		if (dochar)
8935284Sbostic 			printf(" %7ld", tcharct);
9035284Sbostic 		puts(" total");
9135284Sbostic 	}
9233163Sbostic 	exit(0);
9330103Sbostic }
9430103Sbostic 
9530103Sbostic static
9630103Sbostic cnt(file)
9733163Sbostic 	char *file;
9830103Sbostic {
9933163Sbostic 	register u_char *C;
10033163Sbostic 	register short gotsp;
10133163Sbostic 	register int len;
10235284Sbostic 	register long linect, wordct, charct;
10333163Sbostic 	struct stat sbuf;
10433163Sbostic 	int fd;
10533163Sbostic 	u_char buf[MAXBSIZE];
10630103Sbostic 
10730103Sbostic 	linect = wordct = charct = 0;
10830103Sbostic 	if (file) {
10933163Sbostic 		if ((fd = open(file, O_RDONLY, 0)) < 0) {
11030103Sbostic 			perror(file);
11133163Sbostic 			exit(1);
11230103Sbostic 		}
11330103Sbostic 		if (!doword) {
11430103Sbostic 			/*
11530103Sbostic 			 * line counting is split out because it's a lot
11630103Sbostic 			 * faster to get lines than to get words, since
11730103Sbostic 			 * the word count requires some logic.
11830103Sbostic 			 */
11930103Sbostic 			if (doline) {
12033163Sbostic 				while(len = read(fd, buf, MAXBSIZE)) {
12130103Sbostic 					if (len == -1) {
12230103Sbostic 						perror(file);
12333163Sbostic 						exit(1);
12430103Sbostic 					}
12530103Sbostic 					charct += len;
12633163Sbostic 					for (C = buf; len--; ++C)
12730103Sbostic 						if (*C == '\n')
12830103Sbostic 							++linect;
1291161Sbill 				}
13030103Sbostic 				tlinect += linect;
13133163Sbostic 				printf(" %7ld", linect);
13230103Sbostic 				if (dochar) {
13330103Sbostic 					tcharct += charct;
13435284Sbostic 					printf(" %7ld", charct);
13530103Sbostic 				}
13630103Sbostic 				close(fd);
13730103Sbostic 				return;
1381161Sbill 			}
13930103Sbostic 			/*
14030103Sbostic 			 * if all we need is the number of characters and
14130103Sbostic 			 * it's a directory or a regular or linked file, just
14230103Sbostic 			 * stat the puppy.  We avoid testing for it not being
14330103Sbostic 			 * a special device in case someone adds a new type
14430103Sbostic 			 * of inode.
14530103Sbostic 			 */
14630103Sbostic 			if (dochar) {
14733163Sbostic 				if (fstat(fd, &sbuf)) {
14830103Sbostic 					perror(file);
14933163Sbostic 					exit(1);
15030103Sbostic 				}
15130103Sbostic 				if (sbuf.st_mode & (S_IFREG | S_IFLNK | S_IFDIR)) {
15233163Sbostic 					printf(" %7ld", sbuf.st_size);
15330103Sbostic 					tcharct += sbuf.st_size;
15430103Sbostic 					close(fd);
15530103Sbostic 					return;
15630103Sbostic 				}
1571161Sbill 			}
1581161Sbill 		}
15930103Sbostic 	}
16030103Sbostic 	else
16130103Sbostic 		fd = 0;
16230103Sbostic 	/* do it the hard way... */
16333163Sbostic 	for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
16430103Sbostic 		if (len == -1) {
16530103Sbostic 			perror(file);
16633163Sbostic 			exit(1);
16730103Sbostic 		}
16830103Sbostic 		charct += len;
16933163Sbostic 		for (C = buf; len--; ++C)
17030103Sbostic 			switch(*C) {
17130103Sbostic 				case NL:
17230103Sbostic 					++linect;
17330103Sbostic 				case TAB:
17430103Sbostic 				case SPACE:
17533163Sbostic 					gotsp = 1;
17630103Sbostic 					continue;
17730103Sbostic 				default:
17833163Sbostic #ifdef notdef
17930103Sbostic 					/*
18030103Sbostic 					 * This line of code implements the
18130103Sbostic 					 * original V7 wc algorithm, i.e.
18230103Sbostic 					 * a non-printing character doesn't
18330103Sbostic 					 * toggle the "word" count, so that
18430103Sbostic 					 * "  ^D^F  " counts as 6 spaces,
18530103Sbostic 					 * while "foo^D^Fbar" counts as 8
18630103Sbostic 					 * characters.
18730103Sbostic 					 *
18830103Sbostic 					 * test order is important -- gotsp
18930103Sbostic 					 * will normally be NO, so test it
19030103Sbostic 					 * first
19130103Sbostic 					 */
19230103Sbostic 					if (gotsp && *C > SPACE && *C < DEL) {
19333163Sbostic #endif
19430103Sbostic 					/*
19530103Sbostic 					 * This line implements the manual
19630103Sbostic 					 * page, i.e. a word is a "maximal
19730103Sbostic 					 * string of characters delimited by
19830103Sbostic 					 * spaces, tabs or newlines."  Notice
19930103Sbostic 					 * nothing was said about a character
20030103Sbostic 					 * being printing or non-printing.
20130103Sbostic 					 */
20230103Sbostic 					if (gotsp) {
20333163Sbostic 						gotsp = 0;
20430103Sbostic 						++wordct;
20530103Sbostic 					}
20630103Sbostic 			}
20730103Sbostic 	}
20830103Sbostic 	if (doline) {
2091161Sbill 		tlinect += linect;
21033163Sbostic 		printf(" %7ld", linect);
21130103Sbostic 	}
21230103Sbostic 	if (doword) {
2131161Sbill 		twordct += wordct;
21433163Sbostic 		printf(" %7ld", wordct);
21530103Sbostic 	}
21630103Sbostic 	if (dochar) {
2171161Sbill 		tcharct += charct;
21833163Sbostic 		printf(" %7ld", charct);
2191161Sbill 	}
22030103Sbostic 	close(fd);
2211161Sbill }
222