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