master xplshn/aruu / cmd / posix / wc.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <string.h>
  5
  6#include "utf.h"
  7#include "util.h"
  8
  9static int    lflag = 0;
 10static int    wflag = 0;
 11static char   cmode = 0;
 12static size_t tc = 0, tl = 0, tw = 0;
 13
 14static void
 15output(const char *str, size_t nc, size_t nl, size_t nw)
 16{
 17	int first = 1;
 18
 19	if (lflag) {
 20		first = 0;
 21		printf("%zu", nl);
 22	}
 23	if (wflag) {
 24		if (!first)
 25			putchar(' ');
 26		first = 0;
 27		printf("%zu", nw);
 28	}
 29	if (cmode) {
 30		if (!first)
 31			putchar(' ');
 32		printf("%zu", nc);
 33	}
 34	if (str)
 35		printf(" %s", str);
 36	putchar('\n');
 37}
 38
 39static void
 40wc(FILE *fp, const char *str)
 41{
 42	int word = 0, rlen;
 43	Rune c;
 44	size_t nc = 0, nl = 0, nw = 0;
 45
 46	while ((rlen = efgetrune(&c, fp, str))) {
 47		nc += (cmode == 'c') ? rlen : (c != Runeerror);
 48		if (c == '\n')
 49			nl++;
 50		if (!isspacerune(c))
 51			word = 1;
 52		else if (word) {
 53			word = 0;
 54			nw++;
 55		}
 56	}
 57	if (word)
 58		nw++;
 59	tc += nc;
 60	tl += nl;
 61	tw += nw;
 62	output(str, nc, nl, nw);
 63}
 64
 65static void
 66usage(void)
 67{
 68	eprintf("usage: %s [-c | -m] [-lw] [file ...]\n", argv0);
 69}
 70
 71// ?man wc: count lines, words, and bytes
 72// ?man arguments: file ...
 73// ?man display the number of lines, words, and bytes in files
 74int
 75main(int argc, char *argv[])
 76{
 77	FILE *fp;
 78	int many;
 79	int ret = 0;
 80
 81	ARGBEGIN {
 82	// ?man -c: print count or perform stdout action
 83	case 'c':
 84		cmode = 'c';
 85		break;
 86	// ?man -m: specify mode or limit
 87	case 'm':
 88		cmode = 'm';
 89		break;
 90	// ?man -l: list in long format
 91	case 'l':
 92		lflag = 1;
 93		break;
 94	// ?man -w: wait for completion
 95	case 'w':
 96		wflag = 1;
 97		break;
 98	default:
 99		usage();
100	} ARGEND
101
102	if (!lflag && !wflag && !cmode) {
103		cmode = 'c';
104		lflag = 1;
105		wflag = 1;
106	}
107
108	if (!argc) {
109		wc(stdin, NULL);
110	} else {
111		for (many = (argc > 1); *argv; argc--, argv++) {
112			if (!strcmp(*argv, "-")) {
113				*argv = "<stdin>";
114				fp = stdin;
115			} else if (!(fp = fopen(*argv, "r"))) {
116				weprintf("fopen %s:", *argv);
117				ret = 1;
118				continue;
119			}
120			wc(fp, *argv);
121			if (fp != stdin && fshut(fp, *argv))
122				ret = 1;
123		}
124		if (many)
125			output("total", tc, tl, tw);
126	}
127
128	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
129
130	return ret;
131}