xref: /freebsd/usr.bin/wc/wc.c (revision 8e05c2373efd43632b1ec410528552fa01b40a3f)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1987, 1991, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329e4c5144SMariusz Zaborski #include <sys/capsicum.h>
339b50d902SRodney W. Grimes #include <sys/param.h>
349b50d902SRodney W. Grimes #include <sys/stat.h>
352c51e5edSBruce Evans 
369e4c5144SMariusz Zaborski #include <capsicum_helpers.h>
372c51e5edSBruce Evans #include <ctype.h>
38ebb42aeeSTim J. Robbins #include <errno.h>
399b50d902SRodney W. Grimes #include <fcntl.h>
40ae6fa8aeSAndrey A. Chernov #include <locale.h>
41dad64f0eSDag-Erling Smørgrav #include <stdbool.h>
42a821e36eSMike Barcroft #include <stdint.h>
439b50d902SRodney W. Grimes #include <stdio.h>
449b50d902SRodney W. Grimes #include <stdlib.h>
459b50d902SRodney W. Grimes #include <string.h>
462c51e5edSBruce Evans #include <unistd.h>
47149a123bSTim J. Robbins #include <wchar.h>
48e58245f7STim J. Robbins #include <wctype.h>
496711c482SMarcel Moolenaar #include <libxo/xo.h>
509b50d902SRodney W. Grimes 
519e4c5144SMariusz Zaborski #include <libcasper.h>
529e4c5144SMariusz Zaborski #include <casper/cap_fileargs.h>
539e4c5144SMariusz Zaborski 
54dad64f0eSDag-Erling Smørgrav static const char *stdin_filename = "stdin";
55dad64f0eSDag-Erling Smørgrav 
569e4c5144SMariusz Zaborski static fileargs_t *fa;
578df975a2SEd Schouten static uintmax_t tlinect, twordct, tcharct, tlongline;
58dad64f0eSDag-Erling Smørgrav static bool doline, doword, dochar, domulti, dolongline;
59c9a96406SPawel Jakub Dawidek static volatile sig_atomic_t siginfo;
606711c482SMarcel Moolenaar static xo_handle_t *stderr_handle;
619b50d902SRodney W. Grimes 
62f09bc093SPawel Jakub Dawidek static void	show_cnt(const char *file, uintmax_t linect, uintmax_t wordct,
63f09bc093SPawel Jakub Dawidek 		    uintmax_t charct, uintmax_t llct);
643f330d7dSWarner Losh static int	cnt(const char *);
653f330d7dSWarner Losh static void	usage(void);
669b50d902SRodney W. Grimes 
67f09bc093SPawel Jakub Dawidek static void
68f09bc093SPawel Jakub Dawidek siginfo_handler(int sig __unused)
69f09bc093SPawel Jakub Dawidek {
70f09bc093SPawel Jakub Dawidek 
71f09bc093SPawel Jakub Dawidek 	siginfo = 1;
72f09bc093SPawel Jakub Dawidek }
73f09bc093SPawel Jakub Dawidek 
748ded906dSBryan Drewery static void
758ded906dSBryan Drewery reset_siginfo(void)
768ded906dSBryan Drewery {
778ded906dSBryan Drewery 
788ded906dSBryan Drewery 	signal(SIGINFO, SIG_DFL);
798ded906dSBryan Drewery 	siginfo = 0;
808ded906dSBryan Drewery }
818ded906dSBryan Drewery 
829b50d902SRodney W. Grimes int
83806abfccSJosef El-Rayes main(int argc, char *argv[])
849b50d902SRodney W. Grimes {
85a0cf59e6SSheldon Hearn 	int ch, errors, total;
869e4c5144SMariusz Zaborski 	cap_rights_t rights;
879b50d902SRodney W. Grimes 
88ae6fa8aeSAndrey A. Chernov 	(void) setlocale(LC_CTYPE, "");
89ae6fa8aeSAndrey A. Chernov 
906711c482SMarcel Moolenaar 	argc = xo_parse_args(argc, argv);
916711c482SMarcel Moolenaar 	if (argc < 0)
92dad64f0eSDag-Erling Smørgrav 		exit(EXIT_FAILURE);
936711c482SMarcel Moolenaar 
94f45dd010SGiorgos Keramidas 	while ((ch = getopt(argc, argv, "clmwL")) != -1)
959b50d902SRodney W. Grimes 		switch((char)ch) {
969b50d902SRodney W. Grimes 		case 'l':
97dad64f0eSDag-Erling Smørgrav 			doline = true;
989b50d902SRodney W. Grimes 			break;
999b50d902SRodney W. Grimes 		case 'w':
100dad64f0eSDag-Erling Smørgrav 			doword = true;
1019b50d902SRodney W. Grimes 			break;
1029b50d902SRodney W. Grimes 		case 'c':
103dad64f0eSDag-Erling Smørgrav 			dochar = true;
104dad64f0eSDag-Erling Smørgrav 			domulti = false;
105ebb42aeeSTim J. Robbins 			break;
106f45dd010SGiorgos Keramidas 		case 'L':
107dad64f0eSDag-Erling Smørgrav 			dolongline = true;
108f45dd010SGiorgos Keramidas 			break;
109ebb42aeeSTim J. Robbins 		case 'm':
110dad64f0eSDag-Erling Smørgrav 			domulti = true;
111dad64f0eSDag-Erling Smørgrav 			dochar = false;
1129b50d902SRodney W. Grimes 			break;
1139b50d902SRodney W. Grimes 		case '?':
1149b50d902SRodney W. Grimes 		default:
1159b50d902SRodney W. Grimes 			usage();
1169b50d902SRodney W. Grimes 		}
1179b50d902SRodney W. Grimes 	argv += optind;
1189b50d902SRodney W. Grimes 	argc -= optind;
1199b50d902SRodney W. Grimes 
120f09bc093SPawel Jakub Dawidek 	(void)signal(SIGINFO, siginfo_handler);
121f09bc093SPawel Jakub Dawidek 
1229e4c5144SMariusz Zaborski 	fa = fileargs_init(argc, argv, O_RDONLY, 0,
123d76eef34SEd Maste 	    cap_rights_init(&rights, CAP_READ, CAP_FSTAT), FA_OPEN);
124dad64f0eSDag-Erling Smørgrav 	if (fa == NULL)
125dad64f0eSDag-Erling Smørgrav 		xo_err(EXIT_FAILURE, "Unable to initialize casper");
1269e4c5144SMariusz Zaborski 	caph_cache_catpages();
127dad64f0eSDag-Erling Smørgrav 	if (caph_limit_stdio() < 0)
128dad64f0eSDag-Erling Smørgrav 		xo_err(EXIT_FAILURE, "Unable to limit stdio");
129dad64f0eSDag-Erling Smørgrav 	if (caph_enter_casper() < 0)
130dad64f0eSDag-Erling Smørgrav 		xo_err(EXIT_FAILURE, "Unable to enter capability mode");
1319e4c5144SMariusz Zaborski 
1329b50d902SRodney W. Grimes 	/* Wc's flags are on by default. */
133dad64f0eSDag-Erling Smørgrav 	if (!(doline || doword || dochar || domulti || dolongline))
134dad64f0eSDag-Erling Smørgrav 		doline = doword = dochar = true;
1359b50d902SRodney W. Grimes 
1366711c482SMarcel Moolenaar 	stderr_handle = xo_create_to_file(stderr, XO_STYLE_TEXT, 0);
1376711c482SMarcel Moolenaar 	xo_open_container("wc");
1386711c482SMarcel Moolenaar 	xo_open_list("file");
1396711c482SMarcel Moolenaar 
1402c51e5edSBruce Evans 	errors = 0;
1419b50d902SRodney W. Grimes 	total = 0;
142dad64f0eSDag-Erling Smørgrav 	if (argc == 0) {
1436711c482SMarcel Moolenaar 		xo_open_instance("file");
144dad64f0eSDag-Erling Smørgrav 		if (cnt(NULL) != 0)
1452c51e5edSBruce Evans 			++errors;
1466711c482SMarcel Moolenaar 		xo_close_instance("file");
147f09bc093SPawel Jakub Dawidek 	} else {
148dad64f0eSDag-Erling Smørgrav 		while (argc--) {
1496711c482SMarcel Moolenaar 			xo_open_instance("file");
150dad64f0eSDag-Erling Smørgrav 			if (cnt(*argv++) != 0)
1512c51e5edSBruce Evans 				++errors;
1526711c482SMarcel Moolenaar 			xo_close_instance("file");
1539b50d902SRodney W. Grimes 			++total;
154dad64f0eSDag-Erling Smørgrav 		}
1559b50d902SRodney W. Grimes 	}
156f09bc093SPawel Jakub Dawidek 
157399d3485SMarcel Moolenaar 	xo_close_list("file");
158399d3485SMarcel Moolenaar 
1596711c482SMarcel Moolenaar 	if (total > 1) {
1606711c482SMarcel Moolenaar 		xo_open_container("total");
161f09bc093SPawel Jakub Dawidek 		show_cnt("total", tlinect, twordct, tcharct, tlongline);
1626711c482SMarcel Moolenaar 		xo_close_container("total");
1636711c482SMarcel Moolenaar 	}
164399d3485SMarcel Moolenaar 
1659e4c5144SMariusz Zaborski 	fileargs_free(fa);
1666711c482SMarcel Moolenaar 	xo_close_container("wc");
167dad64f0eSDag-Erling Smørgrav 	if (xo_finish() < 0)
168dad64f0eSDag-Erling Smørgrav 		xo_err(EXIT_FAILURE, "stdout");
169dad64f0eSDag-Erling Smørgrav 	exit(errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1709b50d902SRodney W. Grimes }
1719b50d902SRodney W. Grimes 
172f09bc093SPawel Jakub Dawidek static void
173f09bc093SPawel Jakub Dawidek show_cnt(const char *file, uintmax_t linect, uintmax_t wordct,
174f09bc093SPawel Jakub Dawidek     uintmax_t charct, uintmax_t llct)
175f09bc093SPawel Jakub Dawidek {
1766711c482SMarcel Moolenaar 	xo_handle_t *xop;
177f09bc093SPawel Jakub Dawidek 
178f09bc093SPawel Jakub Dawidek 	if (!siginfo)
1796711c482SMarcel Moolenaar 		xop = NULL;
180f09bc093SPawel Jakub Dawidek 	else {
1816711c482SMarcel Moolenaar 		xop = stderr_handle;
182f09bc093SPawel Jakub Dawidek 		siginfo = 0;
183f09bc093SPawel Jakub Dawidek 	}
184f09bc093SPawel Jakub Dawidek 
185f09bc093SPawel Jakub Dawidek 	if (doline)
1866711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:lines/%7ju/%ju}", linect);
187f09bc093SPawel Jakub Dawidek 	if (doword)
1886711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:words/%7ju/%ju}", wordct);
189f09bc093SPawel Jakub Dawidek 	if (dochar || domulti)
1906711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:characters/%7ju/%ju}", charct);
191f09bc093SPawel Jakub Dawidek 	if (dolongline)
1926711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:long-lines/%7ju/%ju}", llct);
193dad64f0eSDag-Erling Smørgrav 	if (file != stdin_filename)
194985c93f0SMarcel Moolenaar 		xo_emit_h(xop, " {:filename/%s}\n", file);
195f09bc093SPawel Jakub Dawidek 	else
1966711c482SMarcel Moolenaar 		xo_emit_h(xop, "\n");
197f09bc093SPawel Jakub Dawidek }
198f09bc093SPawel Jakub Dawidek 
199a821e36eSMike Barcroft static int
200806abfccSJosef El-Rayes cnt(const char *file)
2019b50d902SRodney W. Grimes {
2025016d112SDag-Erling Smørgrav 	static char buf[MAXBSIZE];
2039b50d902SRodney W. Grimes 	struct stat sb;
204149a123bSTim J. Robbins 	mbstate_t mbs;
2055016d112SDag-Erling Smørgrav 	const char *p;
206dad64f0eSDag-Erling Smørgrav 	uintmax_t linect, wordct, charct, llct, tmpll;
207dad64f0eSDag-Erling Smørgrav 	ssize_t len;
208dad64f0eSDag-Erling Smørgrav 	size_t clen;
209dad64f0eSDag-Erling Smørgrav 	int fd;
210dad64f0eSDag-Erling Smørgrav 	wchar_t wch;
211dad64f0eSDag-Erling Smørgrav 	bool gotsp, warned;
2129b50d902SRodney W. Grimes 
213f45dd010SGiorgos Keramidas 	linect = wordct = charct = llct = tmpll = 0;
214dad64f0eSDag-Erling Smørgrav 	if (file == NULL) {
2152c51e5edSBruce Evans 		fd = STDIN_FILENO;
216dad64f0eSDag-Erling Smørgrav 		file = stdin_filename;
217dad64f0eSDag-Erling Smørgrav 	} else if ((fd = fileargs_open(fa, file)) < 0) {
2186711c482SMarcel Moolenaar 		xo_warn("%s: open", file);
2192c51e5edSBruce Evans 		return (1);
220a0d038a4SWolfram Schneider 	}
221ebb42aeeSTim J. Robbins 	if (doword || (domulti && MB_CUR_MAX != 1))
2229b50d902SRodney W. Grimes 		goto word;
2239b50d902SRodney W. Grimes 	/*
2240dc7c9e6SConrad Meyer 	 * If all we need is the number of characters and it's a regular file,
2250dc7c9e6SConrad Meyer 	 * just stat it.
2269b50d902SRodney W. Grimes 	 */
22784b851c2SConrad Meyer 	if (doline == 0 && dolongline == 0) {
2280dc7c9e6SConrad Meyer 		if (fstat(fd, &sb)) {
229dad64f0eSDag-Erling Smørgrav 			xo_warn("%s: fstat", file);
2300dc7c9e6SConrad Meyer 			(void)close(fd);
2310dc7c9e6SConrad Meyer 			return (1);
2320dc7c9e6SConrad Meyer 		}
233*8e05c237SRicardo Branco 		/* pseudo-filesystems advertize a zero size */
234*8e05c237SRicardo Branco 		if (S_ISREG(sb.st_mode) && sb.st_size > 0) {
2350dc7c9e6SConrad Meyer 			reset_siginfo();
2360dc7c9e6SConrad Meyer 			charct = sb.st_size;
2370dc7c9e6SConrad Meyer 			show_cnt(file, linect, wordct, charct, llct);
2380dc7c9e6SConrad Meyer 			tcharct += charct;
2390dc7c9e6SConrad Meyer 			(void)close(fd);
2400dc7c9e6SConrad Meyer 			return (0);
2410dc7c9e6SConrad Meyer 		}
2420dc7c9e6SConrad Meyer 	}
2430dc7c9e6SConrad Meyer 	/*
2440dc7c9e6SConrad Meyer 	 * For files we can't stat, or if we need line counting, slurp the
2450dc7c9e6SConrad Meyer 	 * file.  Line counting is split out because it's a lot faster to get
2460dc7c9e6SConrad Meyer 	 * lines than to get words, since the word count requires locale
2470dc7c9e6SConrad Meyer 	 * handling.
2480dc7c9e6SConrad Meyer 	 */
2495016d112SDag-Erling Smørgrav 	while ((len = read(fd, buf, sizeof(buf))) != 0) {
250dad64f0eSDag-Erling Smørgrav 		if (len < 0) {
251dad64f0eSDag-Erling Smørgrav 			xo_warn("%s: read", file);
2522c51e5edSBruce Evans 			(void)close(fd);
2532c51e5edSBruce Evans 			return (1);
2542c51e5edSBruce Evans 		}
2550dc7c9e6SConrad Meyer 		if (siginfo)
2560dc7c9e6SConrad Meyer 			show_cnt(file, linect, wordct, charct, llct);
2579b50d902SRodney W. Grimes 		charct += len;
25884b851c2SConrad Meyer 		if (doline || dolongline) {
259dad64f0eSDag-Erling Smørgrav 			for (p = buf; len > 0; --len, ++p) {
260f45dd010SGiorgos Keramidas 				if (*p == '\n') {
261f45dd010SGiorgos Keramidas 					if (tmpll > llct)
262f45dd010SGiorgos Keramidas 						llct = tmpll;
263f45dd010SGiorgos Keramidas 					tmpll = 0;
2649b50d902SRodney W. Grimes 					++linect;
265dad64f0eSDag-Erling Smørgrav 				} else {
266f45dd010SGiorgos Keramidas 					tmpll++;
2679b50d902SRodney W. Grimes 				}
268de143041SConrad Meyer 			}
269dad64f0eSDag-Erling Smørgrav 		}
270dad64f0eSDag-Erling Smørgrav 	}
2718ded906dSBryan Drewery 	reset_siginfo();
272de143041SConrad Meyer 	if (doline)
2739b50d902SRodney W. Grimes 		tlinect += linect;
274f09bc093SPawel Jakub Dawidek 	if (dochar)
2759b50d902SRodney W. Grimes 		tcharct += charct;
27684b851c2SConrad Meyer 	if (dolongline && llct > tlongline)
277f45dd010SGiorgos Keramidas 		tlongline = llct;
278f09bc093SPawel Jakub Dawidek 	show_cnt(file, linect, wordct, charct, llct);
2799b50d902SRodney W. Grimes 	(void)close(fd);
2802c51e5edSBruce Evans 	return (0);
2819b50d902SRodney W. Grimes 
2829b50d902SRodney W. Grimes 	/* Do it the hard way... */
283dad64f0eSDag-Erling Smørgrav word:	gotsp = true;
284dad64f0eSDag-Erling Smørgrav 	warned = false;
285149a123bSTim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
286dad64f0eSDag-Erling Smørgrav 	while ((len = read(fd, buf, sizeof(buf))) != 0) {
287dad64f0eSDag-Erling Smørgrav 		if (len < 0) {
288dad64f0eSDag-Erling Smørgrav 			xo_warn("%s: read", file);
2892c51e5edSBruce Evans 			(void)close(fd);
2902c51e5edSBruce Evans 			return (1);
2912c51e5edSBruce Evans 		}
292ebb42aeeSTim J. Robbins 		p = buf;
293ebb42aeeSTim J. Robbins 		while (len > 0) {
294f09bc093SPawel Jakub Dawidek 			if (siginfo)
295f09bc093SPawel Jakub Dawidek 				show_cnt(file, linect, wordct, charct, llct);
296ebb42aeeSTim J. Robbins 			if (!domulti || MB_CUR_MAX == 1) {
297ebb42aeeSTim J. Robbins 				clen = 1;
298ebb42aeeSTim J. Robbins 				wch = (unsigned char)*p;
299dad64f0eSDag-Erling Smørgrav 			} else if ((clen = mbrtowc(&wch, p, len, &mbs)) == 0) {
300dad64f0eSDag-Erling Smørgrav 				clen = 1;
301dad64f0eSDag-Erling Smørgrav 			} else if (clen == (size_t)-1) {
302ebb42aeeSTim J. Robbins 				if (!warned) {
303ebb42aeeSTim J. Robbins 					errno = EILSEQ;
304dad64f0eSDag-Erling Smørgrav 					xo_warn("%s", file);
305dad64f0eSDag-Erling Smørgrav 					warned = true;
306ebb42aeeSTim J. Robbins 				}
307149a123bSTim J. Robbins 				memset(&mbs, 0, sizeof(mbs));
308149a123bSTim J. Robbins 				clen = 1;
309149a123bSTim J. Robbins 				wch = (unsigned char)*p;
310dad64f0eSDag-Erling Smørgrav 			} else if (clen == (size_t)-2) {
311ebb42aeeSTim J. Robbins 				break;
312dad64f0eSDag-Erling Smørgrav 			}
313ebb42aeeSTim J. Robbins 			charct++;
314f45dd010SGiorgos Keramidas 			if (wch != L'\n')
315f45dd010SGiorgos Keramidas 				tmpll++;
316ebb42aeeSTim J. Robbins 			len -= clen;
317ebb42aeeSTim J. Robbins 			p += clen;
318f45dd010SGiorgos Keramidas 			if (wch == L'\n') {
319f45dd010SGiorgos Keramidas 				if (tmpll > llct)
320f45dd010SGiorgos Keramidas 					llct = tmpll;
321f45dd010SGiorgos Keramidas 				tmpll = 0;
3229b50d902SRodney W. Grimes 				++linect;
323f45dd010SGiorgos Keramidas 			}
324dad64f0eSDag-Erling Smørgrav 			if (iswspace(wch)) {
325dad64f0eSDag-Erling Smørgrav 				gotsp = true;
326dad64f0eSDag-Erling Smørgrav 			} else if (gotsp) {
327dad64f0eSDag-Erling Smørgrav 				gotsp = false;
3289b50d902SRodney W. Grimes 				++wordct;
3299b50d902SRodney W. Grimes 			}
3309b50d902SRodney W. Grimes 		}
3319b50d902SRodney W. Grimes 	}
3328ded906dSBryan Drewery 	reset_siginfo();
333dad64f0eSDag-Erling Smørgrav 	if (domulti && MB_CUR_MAX > 1) {
334149a123bSTim J. Robbins 		if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
335dad64f0eSDag-Erling Smørgrav 			xo_warn("%s", file);
336dad64f0eSDag-Erling Smørgrav 	}
337f09bc093SPawel Jakub Dawidek 	if (doline)
3389b50d902SRodney W. Grimes 		tlinect += linect;
339f09bc093SPawel Jakub Dawidek 	if (doword)
3409b50d902SRodney W. Grimes 		twordct += wordct;
341f09bc093SPawel Jakub Dawidek 	if (dochar || domulti)
3429b50d902SRodney W. Grimes 		tcharct += charct;
34384b851c2SConrad Meyer 	if (dolongline && llct > tlongline)
344f45dd010SGiorgos Keramidas 		tlongline = llct;
345f09bc093SPawel Jakub Dawidek 	show_cnt(file, linect, wordct, charct, llct);
3469b50d902SRodney W. Grimes 	(void)close(fd);
3472c51e5edSBruce Evans 	return (0);
3489b50d902SRodney W. Grimes }
3499b50d902SRodney W. Grimes 
350a821e36eSMike Barcroft static void
3510970727fSEd Schouten usage(void)
3529b50d902SRodney W. Grimes {
3536711c482SMarcel Moolenaar 	xo_error("usage: wc [-Lclmw] [file ...]\n");
354dad64f0eSDag-Erling Smørgrav 	exit(EXIT_FAILURE);
3559b50d902SRodney W. Grimes }
356