xref: /freebsd/usr.bin/wc/wc.c (revision d76eef3430e27ec08548476dc1c1dbfe7f63b1f4)
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 
329b50d902SRodney W. Grimes #ifndef lint
3306469209SMike Barcroft static const char copyright[] =
349b50d902SRodney W. Grimes "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
359b50d902SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
36a821e36eSMike Barcroft #endif /* not lint */
379b50d902SRodney W. Grimes 
3806469209SMike Barcroft #if 0
399b50d902SRodney W. Grimes #ifndef lint
40a821e36eSMike Barcroft static char sccsid[] = "@(#)wc.c	8.1 (Berkeley) 6/6/93";
41a821e36eSMike Barcroft #endif /* not lint */
422c51e5edSBruce Evans #endif
439b50d902SRodney W. Grimes 
44a821e36eSMike Barcroft #include <sys/cdefs.h>
45a821e36eSMike Barcroft __FBSDID("$FreeBSD$");
46a821e36eSMike Barcroft 
479e4c5144SMariusz Zaborski #include <sys/capsicum.h>
489b50d902SRodney W. Grimes #include <sys/param.h>
499b50d902SRodney W. Grimes #include <sys/stat.h>
502c51e5edSBruce Evans 
519e4c5144SMariusz Zaborski #include <capsicum_helpers.h>
522c51e5edSBruce Evans #include <ctype.h>
532c51e5edSBruce Evans #include <err.h>
54ebb42aeeSTim J. Robbins #include <errno.h>
559b50d902SRodney W. Grimes #include <fcntl.h>
56ae6fa8aeSAndrey A. Chernov #include <locale.h>
57a821e36eSMike Barcroft #include <stdint.h>
589b50d902SRodney W. Grimes #include <stdio.h>
599b50d902SRodney W. Grimes #include <stdlib.h>
609b50d902SRodney W. Grimes #include <string.h>
612c51e5edSBruce Evans #include <unistd.h>
62149a123bSTim J. Robbins #include <wchar.h>
63e58245f7STim J. Robbins #include <wctype.h>
646711c482SMarcel Moolenaar #include <libxo/xo.h>
659b50d902SRodney W. Grimes 
669e4c5144SMariusz Zaborski #include <libcasper.h>
679e4c5144SMariusz Zaborski #include <casper/cap_fileargs.h>
689e4c5144SMariusz Zaborski 
699e4c5144SMariusz Zaborski static fileargs_t *fa;
708df975a2SEd Schouten static uintmax_t tlinect, twordct, tcharct, tlongline;
718df975a2SEd Schouten static int doline, doword, dochar, domulti, dolongline;
72c9a96406SPawel Jakub Dawidek static volatile sig_atomic_t siginfo;
736711c482SMarcel Moolenaar static xo_handle_t *stderr_handle;
749b50d902SRodney W. Grimes 
75f09bc093SPawel Jakub Dawidek static void	show_cnt(const char *file, uintmax_t linect, uintmax_t wordct,
76f09bc093SPawel Jakub Dawidek 		    uintmax_t charct, uintmax_t llct);
773f330d7dSWarner Losh static int	cnt(const char *);
783f330d7dSWarner Losh static void	usage(void);
799b50d902SRodney W. Grimes 
80f09bc093SPawel Jakub Dawidek static void
81f09bc093SPawel Jakub Dawidek siginfo_handler(int sig __unused)
82f09bc093SPawel Jakub Dawidek {
83f09bc093SPawel Jakub Dawidek 
84f09bc093SPawel Jakub Dawidek 	siginfo = 1;
85f09bc093SPawel Jakub Dawidek }
86f09bc093SPawel Jakub Dawidek 
878ded906dSBryan Drewery static void
888ded906dSBryan Drewery reset_siginfo(void)
898ded906dSBryan Drewery {
908ded906dSBryan Drewery 
918ded906dSBryan Drewery 	signal(SIGINFO, SIG_DFL);
928ded906dSBryan Drewery 	siginfo = 0;
938ded906dSBryan Drewery }
948ded906dSBryan Drewery 
959b50d902SRodney W. Grimes int
96806abfccSJosef El-Rayes main(int argc, char *argv[])
979b50d902SRodney W. Grimes {
98a0cf59e6SSheldon Hearn 	int ch, errors, total;
999e4c5144SMariusz Zaborski 	cap_rights_t rights;
1009b50d902SRodney W. Grimes 
101ae6fa8aeSAndrey A. Chernov 	(void) setlocale(LC_CTYPE, "");
102ae6fa8aeSAndrey A. Chernov 
1036711c482SMarcel Moolenaar 	argc = xo_parse_args(argc, argv);
1046711c482SMarcel Moolenaar 	if (argc < 0)
1056711c482SMarcel Moolenaar 		return (argc);
1066711c482SMarcel Moolenaar 
107f45dd010SGiorgos Keramidas 	while ((ch = getopt(argc, argv, "clmwL")) != -1)
1089b50d902SRodney W. Grimes 		switch((char)ch) {
1099b50d902SRodney W. Grimes 		case 'l':
1109b50d902SRodney W. Grimes 			doline = 1;
1119b50d902SRodney W. Grimes 			break;
1129b50d902SRodney W. Grimes 		case 'w':
1139b50d902SRodney W. Grimes 			doword = 1;
1149b50d902SRodney W. Grimes 			break;
1159b50d902SRodney W. Grimes 		case 'c':
1169b50d902SRodney W. Grimes 			dochar = 1;
117ebb42aeeSTim J. Robbins 			domulti = 0;
118ebb42aeeSTim J. Robbins 			break;
119f45dd010SGiorgos Keramidas 		case 'L':
120f45dd010SGiorgos Keramidas 			dolongline = 1;
121f45dd010SGiorgos Keramidas 			break;
122ebb42aeeSTim J. Robbins 		case 'm':
123ebb42aeeSTim J. Robbins 			domulti = 1;
124ebb42aeeSTim J. Robbins 			dochar = 0;
1259b50d902SRodney W. Grimes 			break;
1269b50d902SRodney W. Grimes 		case '?':
1279b50d902SRodney W. Grimes 		default:
1289b50d902SRodney W. Grimes 			usage();
1299b50d902SRodney W. Grimes 		}
1309b50d902SRodney W. Grimes 	argv += optind;
1319b50d902SRodney W. Grimes 	argc -= optind;
1329b50d902SRodney W. Grimes 
133f09bc093SPawel Jakub Dawidek 	(void)signal(SIGINFO, siginfo_handler);
134f09bc093SPawel Jakub Dawidek 
1359e4c5144SMariusz Zaborski 	fa = fileargs_init(argc, argv, O_RDONLY, 0,
136*d76eef34SEd Maste 	    cap_rights_init(&rights, CAP_READ, CAP_FSTAT), FA_OPEN);
1379e4c5144SMariusz Zaborski 	if (fa == NULL) {
1389e4c5144SMariusz Zaborski 		xo_warn("Unable to init casper");
1399e4c5144SMariusz Zaborski 		exit(1);
1409e4c5144SMariusz Zaborski 	}
1419e4c5144SMariusz Zaborski 
1429e4c5144SMariusz Zaborski 	caph_cache_catpages();
1439e4c5144SMariusz Zaborski 	if (caph_limit_stdio() < 0) {
1449e4c5144SMariusz Zaborski 		xo_warn("Unable to limit stdio");
1459e4c5144SMariusz Zaborski 		fileargs_free(fa);
1469e4c5144SMariusz Zaborski 		exit(1);
1479e4c5144SMariusz Zaborski 	}
1489e4c5144SMariusz Zaborski 
149509e73d4SMariusz Zaborski 	if (caph_enter_casper() < 0) {
1509e4c5144SMariusz Zaborski 		xo_warn("Unable to enter capability mode");
1519e4c5144SMariusz Zaborski 		fileargs_free(fa);
1529e4c5144SMariusz Zaborski 		exit(1);
1539e4c5144SMariusz Zaborski 	}
1549e4c5144SMariusz Zaborski 
1559b50d902SRodney W. Grimes 	/* Wc's flags are on by default. */
156f45dd010SGiorgos Keramidas 	if (doline + doword + dochar + domulti + dolongline == 0)
1579b50d902SRodney W. Grimes 		doline = doword = dochar = 1;
1589b50d902SRodney W. Grimes 
1596711c482SMarcel Moolenaar 	stderr_handle = xo_create_to_file(stderr, XO_STYLE_TEXT, 0);
1606711c482SMarcel Moolenaar 	xo_open_container("wc");
1616711c482SMarcel Moolenaar 	xo_open_list("file");
1626711c482SMarcel Moolenaar 
1632c51e5edSBruce Evans 	errors = 0;
1649b50d902SRodney W. Grimes 	total = 0;
1659b50d902SRodney W. Grimes 	if (!*argv) {
1666711c482SMarcel Moolenaar 	 	xo_open_instance("file");
1672c51e5edSBruce Evans 		if (cnt((char *)NULL) != 0)
1682c51e5edSBruce Evans 			++errors;
1696711c482SMarcel Moolenaar 	 	xo_close_instance("file");
170f09bc093SPawel Jakub Dawidek 	} else {
171f09bc093SPawel Jakub Dawidek 		do {
1726711c482SMarcel Moolenaar 	 		xo_open_instance("file");
1732c51e5edSBruce Evans 			if (cnt(*argv) != 0)
1742c51e5edSBruce Evans 				++errors;
1756711c482SMarcel Moolenaar 	 		xo_close_instance("file");
1769b50d902SRodney W. Grimes 			++total;
1779b50d902SRodney W. Grimes 		} while(*++argv);
1789b50d902SRodney W. Grimes 	}
179f09bc093SPawel Jakub Dawidek 
180399d3485SMarcel Moolenaar 	xo_close_list("file");
181399d3485SMarcel Moolenaar 
1826711c482SMarcel Moolenaar 	if (total > 1) {
1836711c482SMarcel Moolenaar 		xo_open_container("total");
184f09bc093SPawel Jakub Dawidek 		show_cnt("total", tlinect, twordct, tcharct, tlongline);
1856711c482SMarcel Moolenaar 		xo_close_container("total");
1866711c482SMarcel Moolenaar 	}
187399d3485SMarcel Moolenaar 
1889e4c5144SMariusz Zaborski 	fileargs_free(fa);
1896711c482SMarcel Moolenaar 	xo_close_container("wc");
1906711c482SMarcel Moolenaar 	xo_finish();
1912c51e5edSBruce Evans 	exit(errors == 0 ? 0 : 1);
1929b50d902SRodney W. Grimes }
1939b50d902SRodney W. Grimes 
194f09bc093SPawel Jakub Dawidek static void
195f09bc093SPawel Jakub Dawidek show_cnt(const char *file, uintmax_t linect, uintmax_t wordct,
196f09bc093SPawel Jakub Dawidek     uintmax_t charct, uintmax_t llct)
197f09bc093SPawel Jakub Dawidek {
1986711c482SMarcel Moolenaar 	xo_handle_t *xop;
199f09bc093SPawel Jakub Dawidek 
200f09bc093SPawel Jakub Dawidek 	if (!siginfo)
2016711c482SMarcel Moolenaar 		xop = NULL;
202f09bc093SPawel Jakub Dawidek 	else {
2036711c482SMarcel Moolenaar 		xop = stderr_handle;
204f09bc093SPawel Jakub Dawidek 		siginfo = 0;
205f09bc093SPawel Jakub Dawidek 	}
206f09bc093SPawel Jakub Dawidek 
207f09bc093SPawel Jakub Dawidek 	if (doline)
2086711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:lines/%7ju/%ju}", linect);
209f09bc093SPawel Jakub Dawidek 	if (doword)
2106711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:words/%7ju/%ju}", wordct);
211f09bc093SPawel Jakub Dawidek 	if (dochar || domulti)
2126711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:characters/%7ju/%ju}", charct);
213f09bc093SPawel Jakub Dawidek 	if (dolongline)
2146711c482SMarcel Moolenaar 		xo_emit_h(xop, " {:long-lines/%7ju/%ju}", llct);
215f09bc093SPawel Jakub Dawidek 	if (file != NULL)
216985c93f0SMarcel Moolenaar 		xo_emit_h(xop, " {:filename/%s}\n", file);
217f09bc093SPawel Jakub Dawidek 	else
2186711c482SMarcel Moolenaar 		xo_emit_h(xop, "\n");
219f09bc093SPawel Jakub Dawidek }
220f09bc093SPawel Jakub Dawidek 
221a821e36eSMike Barcroft static int
222806abfccSJosef El-Rayes cnt(const char *file)
2239b50d902SRodney W. Grimes {
2249b50d902SRodney W. Grimes 	struct stat sb;
225f45dd010SGiorgos Keramidas 	uintmax_t linect, wordct, charct, llct, tmpll;
226149a123bSTim J. Robbins 	int fd, len, warned;
227149a123bSTim J. Robbins 	size_t clen;
228a0cf59e6SSheldon Hearn 	short gotsp;
229a0cf59e6SSheldon Hearn 	u_char *p;
230abd0c85dSTim J. Robbins 	u_char buf[MAXBSIZE];
231ebb42aeeSTim J. Robbins 	wchar_t wch;
232149a123bSTim J. Robbins 	mbstate_t mbs;
2339b50d902SRodney W. Grimes 
234f45dd010SGiorgos Keramidas 	linect = wordct = charct = llct = tmpll = 0;
235f09bc093SPawel Jakub Dawidek 	if (file == NULL)
2362c51e5edSBruce Evans 		fd = STDIN_FILENO;
2379e4c5144SMariusz Zaborski 	else if ((fd = fileargs_open(fa, file)) < 0) {
2386711c482SMarcel Moolenaar 		xo_warn("%s: open", file);
2392c51e5edSBruce Evans 		return (1);
240a0d038a4SWolfram Schneider 	}
241ebb42aeeSTim J. Robbins 	if (doword || (domulti && MB_CUR_MAX != 1))
2429b50d902SRodney W. Grimes 		goto word;
2439b50d902SRodney W. Grimes 	/*
2440dc7c9e6SConrad Meyer 	 * If all we need is the number of characters and it's a regular file,
2450dc7c9e6SConrad Meyer 	 * just stat it.
2469b50d902SRodney W. Grimes 	 */
24784b851c2SConrad Meyer 	if (doline == 0 && dolongline == 0) {
2480dc7c9e6SConrad Meyer 		if (fstat(fd, &sb)) {
2490dc7c9e6SConrad Meyer 			xo_warn("%s: fstat", file);
2500dc7c9e6SConrad Meyer 			(void)close(fd);
2510dc7c9e6SConrad Meyer 			return (1);
2520dc7c9e6SConrad Meyer 		}
2530dc7c9e6SConrad Meyer 		if (S_ISREG(sb.st_mode)) {
2540dc7c9e6SConrad Meyer 			reset_siginfo();
2550dc7c9e6SConrad Meyer 			charct = sb.st_size;
2560dc7c9e6SConrad Meyer 			show_cnt(file, linect, wordct, charct, llct);
2570dc7c9e6SConrad Meyer 			tcharct += charct;
2580dc7c9e6SConrad Meyer 			(void)close(fd);
2590dc7c9e6SConrad Meyer 			return (0);
2600dc7c9e6SConrad Meyer 		}
2610dc7c9e6SConrad Meyer 	}
2620dc7c9e6SConrad Meyer 	/*
2630dc7c9e6SConrad Meyer 	 * For files we can't stat, or if we need line counting, slurp the
2640dc7c9e6SConrad Meyer 	 * file.  Line counting is split out because it's a lot faster to get
2650dc7c9e6SConrad Meyer 	 * lines than to get words, since the word count requires locale
2660dc7c9e6SConrad Meyer 	 * handling.
2670dc7c9e6SConrad Meyer 	 */
2688c85cce7SPhilippe Charnier 	while ((len = read(fd, buf, MAXBSIZE))) {
2692c51e5edSBruce Evans 		if (len == -1) {
2706711c482SMarcel Moolenaar 			xo_warn("%s: read", file);
2712c51e5edSBruce Evans 			(void)close(fd);
2722c51e5edSBruce Evans 			return (1);
2732c51e5edSBruce Evans 		}
2740dc7c9e6SConrad Meyer 		if (siginfo)
2750dc7c9e6SConrad Meyer 			show_cnt(file, linect, wordct, charct, llct);
2769b50d902SRodney W. Grimes 		charct += len;
27784b851c2SConrad Meyer 		if (doline || dolongline) {
2789b50d902SRodney W. Grimes 			for (p = buf; len--; ++p)
279f45dd010SGiorgos Keramidas 				if (*p == '\n') {
280f45dd010SGiorgos Keramidas 					if (tmpll > llct)
281f45dd010SGiorgos Keramidas 						llct = tmpll;
282f45dd010SGiorgos Keramidas 					tmpll = 0;
2839b50d902SRodney W. Grimes 					++linect;
284f45dd010SGiorgos Keramidas 				} else
285f45dd010SGiorgos Keramidas 					tmpll++;
2869b50d902SRodney W. Grimes 		}
287de143041SConrad Meyer 	}
2888ded906dSBryan Drewery 	reset_siginfo();
289de143041SConrad Meyer 	if (doline)
2909b50d902SRodney W. Grimes 		tlinect += linect;
291f09bc093SPawel Jakub Dawidek 	if (dochar)
2929b50d902SRodney W. Grimes 		tcharct += charct;
29384b851c2SConrad Meyer 	if (dolongline && llct > tlongline)
294f45dd010SGiorgos Keramidas 		tlongline = llct;
295f09bc093SPawel Jakub Dawidek 	show_cnt(file, linect, wordct, charct, llct);
2969b50d902SRodney W. Grimes 	(void)close(fd);
2972c51e5edSBruce Evans 	return (0);
2989b50d902SRodney W. Grimes 
2999b50d902SRodney W. Grimes 	/* Do it the hard way... */
300ebb42aeeSTim J. Robbins word:	gotsp = 1;
301ebb42aeeSTim J. Robbins 	warned = 0;
302149a123bSTim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
303149a123bSTim J. Robbins 	while ((len = read(fd, buf, MAXBSIZE)) != 0) {
304149a123bSTim J. Robbins 		if (len == -1) {
3056711c482SMarcel Moolenaar 			xo_warn("%s: read", file != NULL ? file : "stdin");
3062c51e5edSBruce Evans 			(void)close(fd);
3072c51e5edSBruce Evans 			return (1);
3082c51e5edSBruce Evans 		}
309ebb42aeeSTim J. Robbins 		p = buf;
310ebb42aeeSTim J. Robbins 		while (len > 0) {
311f09bc093SPawel Jakub Dawidek 			if (siginfo)
312f09bc093SPawel Jakub Dawidek 				show_cnt(file, linect, wordct, charct, llct);
313ebb42aeeSTim J. Robbins 			if (!domulti || MB_CUR_MAX == 1) {
314ebb42aeeSTim J. Robbins 				clen = 1;
315ebb42aeeSTim J. Robbins 				wch = (unsigned char)*p;
316149a123bSTim J. Robbins 			} else if ((clen = mbrtowc(&wch, p, len, &mbs)) ==
317149a123bSTim J. Robbins 			    (size_t)-1) {
318ebb42aeeSTim J. Robbins 				if (!warned) {
319ebb42aeeSTim J. Robbins 					errno = EILSEQ;
3206711c482SMarcel Moolenaar 					xo_warn("%s",
321f09bc093SPawel Jakub Dawidek 					    file != NULL ? file : "stdin");
322ebb42aeeSTim J. Robbins 					warned = 1;
323ebb42aeeSTim J. Robbins 				}
324149a123bSTim J. Robbins 				memset(&mbs, 0, sizeof(mbs));
325149a123bSTim J. Robbins 				clen = 1;
326149a123bSTim J. Robbins 				wch = (unsigned char)*p;
327149a123bSTim J. Robbins 			} else if (clen == (size_t)-2)
328ebb42aeeSTim J. Robbins 				break;
329149a123bSTim J. Robbins 			else if (clen == 0)
330149a123bSTim J. Robbins 				clen = 1;
331ebb42aeeSTim J. Robbins 			charct++;
332f45dd010SGiorgos Keramidas 			if (wch != L'\n')
333f45dd010SGiorgos Keramidas 				tmpll++;
334ebb42aeeSTim J. Robbins 			len -= clen;
335ebb42aeeSTim J. Robbins 			p += clen;
336f45dd010SGiorgos Keramidas 			if (wch == L'\n') {
337f45dd010SGiorgos Keramidas 				if (tmpll > llct)
338f45dd010SGiorgos Keramidas 					llct = tmpll;
339f45dd010SGiorgos Keramidas 				tmpll = 0;
3409b50d902SRodney W. Grimes 				++linect;
341f45dd010SGiorgos Keramidas 			}
342e58245f7STim J. Robbins 			if (iswspace(wch))
3439b50d902SRodney W. Grimes 				gotsp = 1;
3449b50d902SRodney W. Grimes 			else if (gotsp) {
3459b50d902SRodney W. Grimes 				gotsp = 0;
3469b50d902SRodney W. Grimes 				++wordct;
3479b50d902SRodney W. Grimes 			}
3489b50d902SRodney W. Grimes 		}
3499b50d902SRodney W. Grimes 	}
3508ded906dSBryan Drewery 	reset_siginfo();
351149a123bSTim J. Robbins 	if (domulti && MB_CUR_MAX > 1)
352149a123bSTim J. Robbins 		if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
3536711c482SMarcel Moolenaar 			xo_warn("%s", file != NULL ? file : "stdin");
354f09bc093SPawel Jakub Dawidek 	if (doline)
3559b50d902SRodney W. Grimes 		tlinect += linect;
356f09bc093SPawel Jakub Dawidek 	if (doword)
3579b50d902SRodney W. Grimes 		twordct += wordct;
358f09bc093SPawel Jakub Dawidek 	if (dochar || domulti)
3599b50d902SRodney W. Grimes 		tcharct += charct;
36084b851c2SConrad Meyer 	if (dolongline && llct > tlongline)
361f45dd010SGiorgos Keramidas 		tlongline = llct;
362f09bc093SPawel Jakub Dawidek 	show_cnt(file, linect, wordct, charct, llct);
3639b50d902SRodney W. Grimes 	(void)close(fd);
3642c51e5edSBruce Evans 	return (0);
3659b50d902SRodney W. Grimes }
3669b50d902SRodney W. Grimes 
367a821e36eSMike Barcroft static void
3680970727fSEd Schouten usage(void)
3699b50d902SRodney W. Grimes {
3706711c482SMarcel Moolenaar 	xo_error("usage: wc [-Lclmw] [file ...]\n");
3719b50d902SRodney W. Grimes 	exit(1);
3729b50d902SRodney W. Grimes }
373