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