diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 910db16f0d15..859b5c5ace7f 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -1,1166 +1,1168 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 tags=package=tests . bin cat .. chflags .. chmod .. cp .. date .. dd .. echo .. expr .. ln .. ls .. mkdir .. mv .. pax .. pkill .. pwait .. rm .. rmdir .. sh builtins .. errors .. execution .. expansion .. invocation .. parameters .. parser .. set-e .. .. sleep .. test .. timeout .. .. cddl lib .. sbin .. usr.bin ctfconvert .. ztest .. .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. env .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. sugar .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. i386 arrays .. funcs .. pid .. ustack .. .. amd64 arrays .. kinst .. .. .. zfsd .. .. .. etc rc.d .. .. examples .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. csu dynamic .. dynamiclib .. static .. .. googletest gmock .. gmock_main .. gtest .. gtest_main .. .. libarchive .. libbe .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. iconv .. inet .. locale .. net getaddrinfo data .. .. .. nss .. regex data .. .. resolv .. rpc .. ssp .. setjmp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcam .. libcasper services cap_dns .. cap_grp .. cap_pwd .. cap_sysctl .. .. .. libcrypt .. libdevdctl .. libexecinfo .. libkvm .. libmp .. libnv .. libproc .. libregex data .. .. librt .. libsbuf .. libsysdecode .. libthr dlopen .. .. libutil .. libxo .. msun .. .. libexec atf atf-check .. atf-pytest-wrapper .. atf-sh .. .. rc .. rtld-elf .. tftpd .. .. sbin bectl .. dhclient .. devd .. growfs .. ifconfig .. md5 .. mdconfig .. newfs_msdos .. nvmecontrol .. pfctl files .. .. ping .. route .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. googletest .. plain .. tap .. .. .. zoneinfo .. .. sys acl .. aio .. audit .. auditpipe .. capsicum .. cddl zfs bin .. include .. tests acl cifs .. nontrivial .. trivial .. .. atime .. bootfs .. cache .. cachefile .. clean_mirror .. cli_root zfs_upgrade .. zfs_promote .. zfs_clone .. zfs_property .. zfs_destroy .. zpool_create .. zpool_history .. zpool_expand .. zpool_remove .. zfs_mount .. zfs_unshare .. zdb .. zpool_online .. zpool_get .. zpool_export .. zfs_copies .. zfs_get .. zfs .. zpool_clear .. zpool_import blockfiles .. .. zpool .. zpool_offline .. zpool_replace .. zfs_rollback .. zpool_set .. zfs_send .. zfs_set .. zpool_detach .. zfs_diff .. zpool_scrub .. zfs_inherit .. zfs_snapshot .. zfs_share .. zpool_destroy .. zpool_status .. zfs_unmount .. zfs_receive .. zfs_create .. zpool_upgrade blockfiles .. .. zpool_add .. zfs_rename .. zpool_attach .. zfs_reservation .. .. cli_user misc .. zfs_list .. zpool_iostat .. zpool_list .. .. compression .. ctime .. delegate .. devices .. exec .. grow_pool .. grow_replicas .. history .. hotplug .. hotspare .. inheritance .. interop .. inuse .. iscsi .. large_files .. largest_pool .. link_count .. migration .. mmap .. mount .. mv_files .. nestedfs .. no_space .. online_offline .. pool_names .. poolversion .. quota .. redundancy .. refquota .. refreserv .. rename_dirs .. replacement .. reservation .. rootpool .. rsend .. scrub_mirror .. slog .. snapshot .. snapused .. sparse .. threadsappend .. truncate .. txg_integrity .. userquota .. utils_test .. write_dirs .. xattr .. zfsd .. zil .. zinject .. zones .. zvol zvol_ENOSPC .. zvol_cli .. zvol_misc .. zvol_swap .. .. zvol_thrash .. .. .. .. devrandom .. dtrace .. fifo .. file .. fs fusefs .. tarfs .. tmpfs .. .. geom class concat .. eli .. gate .. gpt .. mirror .. multipath .. nop .. part .. raid3 .. shsec .. stripe .. uzip etalon .. .. .. .. kern acct .. execve .. pipe .. .. kqueue libkqueue .. .. mac bsdextended .. portacl .. .. mqueue .. net if_ovpn .. routing .. .. netgraph .. netinet .. netinet6 frag6 .. .. netipsec tunnel .. .. netlink .. netmap .. netpfil common .. ipfw .. pf ioctl .. .. .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. utimensat .. .. posixshm .. sys .. vfs .. vm .. vmm .. .. usr.bin apply .. awk bugs-fixed .. netbsd .. .. basename .. bintrans .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. bsdcat .. calendar .. cmp .. compress .. cpio .. col .. comm .. csplit .. cut .. dc .. diff .. diff3 .. dirname .. du .. file2c .. file .. find .. fold .. getconf .. gh-bc .. grep .. gzip .. head .. hexdump .. ident .. indent .. join .. jot .. lastcomm .. limits .. locale .. m4 .. mkimg .. mktemp .. ncal .. opensm .. patch .. pr .. printf .. procstat .. renice .. rs .. sdiff .. sed regress.multitest.out .. .. seq .. soelim .. sort .. split .. stat .. tail .. tar .. tr .. truncate .. units .. unifdef .. uniq .. vmstat .. + wc + .. xargs .. xinstall .. xo .. yacc yacc .. .. .. usr.sbin chown .. daemon .. etcupdate .. extattr .. fstyp .. jail .. makefs .. mixer .. newsyslog .. nmtree .. praudit .. pw .. rpcbind .. sa .. .. .. # vim: set expandtab ts=4 sw=4: diff --git a/usr.bin/wc/Makefile b/usr.bin/wc/Makefile index 550b718e1478..060c67193e00 100644 --- a/usr.bin/wc/Makefile +++ b/usr.bin/wc/Makefile @@ -1,15 +1,18 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ .include PROG= wc LIBADD= xo .if ${MK_CASPER} != "no" LIBADD+= casper LIBADD+= cap_fileargs CFLAGS+=-DWITH_CASPER .endif +HAS_TESTS= +SUBDIR.${MK_TESTS}= tests + .include diff --git a/usr.bin/wc/tests/Makefile b/usr.bin/wc/tests/Makefile new file mode 100644 index 000000000000..81e6c4246544 --- /dev/null +++ b/usr.bin/wc/tests/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PACKAGE= tests + +ATF_TESTS_SH= wc_test +BINDIR= ${TESTSDIR} + +.include diff --git a/usr.bin/wc/tests/wc_test.sh b/usr.bin/wc/tests/wc_test.sh new file mode 100755 index 000000000000..574f2daacaca --- /dev/null +++ b/usr.bin/wc/tests/wc_test.sh @@ -0,0 +1,197 @@ +# +# Copyright (c) 2023 Klara, Inc. +# +# SPDX-License-Identifier: BSD-2-Clause +# + +# +# These tests need to run in a multibyte locale with non-localized +# error messages. +# +export LC_CTYPE=C.UTF-8 +export LC_MESSAGES=C + +# +# Sample text containing multibyte characters +# +tv="Der bode en underlig gråsprængt en +på den yderste nøgne ø; – +han gjorde visst intet menneske mén +hverken på land eller sjø; +dog stundom gnistred hans øjne stygt, – +helst mod uroligt vejr, – +og da mente folk, at han var forrykt, +og da var der få, som uden frykt +kom Terje Vigen nær. +" +tvl=10 +tvw=55 +tvc=300 +tvm=283 +tvcL=42 +tvmL=39 + +# +# Run a series of tests using the same input file. The first argument +# is the name of the file. The next three are the expected line, +# word, and byte counts. The optional fifth is the expected character +# count; if not provided, it is expected to be identical to the byte +# count. +# +atf_check_wc() { + local file="$1" + local l="$2" + local w="$3" + local c="$4" + local m="${5-$4}" + + atf_check -o match:"^ +${l} +${w} +${c}\$" wc <"${file}" + atf_check -o match:"^ +${l}\$" wc -l <"${file}" + atf_check -o match:"^ +${w}\$" wc -w <"${file}" + atf_check -o match:"^ +${c}\$" wc -c <"${file}" + atf_check -o match:"^ +${m}\$" wc -m <"${file}" + atf_check -o match:"^ +${l} +${w} +${c} ${file}\$" wc "$file" + atf_check -o match:"^ +${l} ${file}\$" wc -l "$file" + atf_check -o match:"^ +${w} ${file}\$" wc -w "$file" + atf_check -o match:"^ +${c} ${file}\$" wc -c "$file" + atf_check -o match:"^ +${m} ${file}\$" wc -m "$file" +} + +atf_test_case basic +basic_head() +{ + atf_set "descr" "Basic test case" +} +basic_body() +{ + printf "a b\n" >foo + atf_check_wc foo 1 2 4 +} + +atf_test_case blank +blank_head() +{ + atf_set "descr" "Input containing only blank lines" +} +blank_body() +{ + printf "\n\n\n" >foo + atf_check_wc foo 3 0 3 +} + +atf_test_case empty +empty_head() +{ + atf_set "descr" "Empty input" +} +empty_body() +{ + printf "" >foo + atf_check_wc foo 0 0 0 +} + +atf_test_case invalid +invalid_head() +{ + atf_set "descr" "Invalid multibyte input" +} +invalid_body() +{ + printf "a\377b\n" >foo + atf_check \ + -e match:"Illegal byte sequence" \ + -o match:"^ +4 foo$" \ + wc -m foo +} + +atf_test_case multiline +multiline_head() +{ + atf_set "descr" "Multiline, multibyte input" +} +multiline_body() +{ + printf "%s\n" "$tv" >foo + atf_check_wc foo $tvl $tvw $tvc $tvm + # longest line in bytes + atf_check -o match:"^ +$tvc +$tvcL foo" wc -cL foo + atf_check -o match:"^ +$tvc +$tvcL" wc -cL foo + atf_check_wc foo $((tvl*c)) $((tvw*c)) $((tvc*c)) $((tvm*c)) +} + +atf_test_case total +total_head() +{ + atf_set "descr" "Multiple inputs" +} +total_body() +{ + printf "%s\n" "$tv" >foo + printf "%s\n" "$tv" >bar + atf_check \ + -o match:"^ +$((tvl*2)) +$((tvw*2)) +$((tvc*2)) total$" \ + wc foo bar +} + +atf_test_case unterminated +unterminated_head() +{ + atf_set "descr" "Input not ending in newline" +} +unterminated_body() +{ + printf "a b" >foo + atf_check_wc foo 0 2 3 +} + +atf_test_case usage +usage_head() +{ + atf_set "descr" "Trigger usage message" +} +usage_body() +{ + atf_check -s exit:1 -e match:"usage: wc" wc -\? +} + +atf_test_case whitespace +whitespace_head() +{ + atf_set "descr" "Input containing only whitespace and newlines" +} +whitespace_body() +{ + printf "\n \n\t\n" >foo + atf_check_wc foo 3 0 5 +} + +atf_init_test_cases() +{ + atf_add_test_case basic + atf_add_test_case blank + atf_add_test_case empty + atf_add_test_case invalid + atf_add_test_case multiline + atf_add_test_case multiline_repeated + atf_add_test_case total + atf_add_test_case unterminated + atf_add_test_case usage + atf_add_test_case whitespace +} diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c index a12c13a3e36d..9c129917dd04 100644 --- a/usr.bin/wc/wc.c +++ b/usr.bin/wc/wc.c @@ -1,372 +1,368 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1987, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include +static const char *stdin_filename = "stdin"; + static fileargs_t *fa; static uintmax_t tlinect, twordct, tcharct, tlongline; -static int doline, doword, dochar, domulti, dolongline; +static bool doline, doword, dochar, domulti, dolongline; static volatile sig_atomic_t siginfo; static xo_handle_t *stderr_handle; static void show_cnt(const char *file, uintmax_t linect, uintmax_t wordct, uintmax_t charct, uintmax_t llct); static int cnt(const char *); static void usage(void); static void siginfo_handler(int sig __unused) { siginfo = 1; } static void reset_siginfo(void) { signal(SIGINFO, SIG_DFL); siginfo = 0; } int main(int argc, char *argv[]) { int ch, errors, total; cap_rights_t rights; (void) setlocale(LC_CTYPE, ""); argc = xo_parse_args(argc, argv); if (argc < 0) - return (argc); + exit(EXIT_FAILURE); while ((ch = getopt(argc, argv, "clmwL")) != -1) switch((char)ch) { case 'l': - doline = 1; + doline = true; break; case 'w': - doword = 1; + doword = true; break; case 'c': - dochar = 1; - domulti = 0; + dochar = true; + domulti = false; break; case 'L': - dolongline = 1; + dolongline = true; break; case 'm': - domulti = 1; - dochar = 0; + domulti = true; + dochar = false; break; case '?': default: usage(); } argv += optind; argc -= optind; (void)signal(SIGINFO, siginfo_handler); fa = fileargs_init(argc, argv, O_RDONLY, 0, cap_rights_init(&rights, CAP_READ, CAP_FSTAT), FA_OPEN); - if (fa == NULL) { - xo_warn("Unable to init casper"); - exit(1); - } - + if (fa == NULL) + xo_err(EXIT_FAILURE, "Unable to initialize casper"); caph_cache_catpages(); - if (caph_limit_stdio() < 0) { - xo_warn("Unable to limit stdio"); - fileargs_free(fa); - exit(1); - } - - if (caph_enter_casper() < 0) { - xo_warn("Unable to enter capability mode"); - fileargs_free(fa); - exit(1); - } + if (caph_limit_stdio() < 0) + xo_err(EXIT_FAILURE, "Unable to limit stdio"); + if (caph_enter_casper() < 0) + xo_err(EXIT_FAILURE, "Unable to enter capability mode"); /* Wc's flags are on by default. */ - if (doline + doword + dochar + domulti + dolongline == 0) - doline = doword = dochar = 1; + if (!(doline || doword || dochar || domulti || dolongline)) + doline = doword = dochar = true; stderr_handle = xo_create_to_file(stderr, XO_STYLE_TEXT, 0); xo_open_container("wc"); xo_open_list("file"); errors = 0; total = 0; - if (!*argv) { - xo_open_instance("file"); - if (cnt((char *)NULL) != 0) + if (argc == 0) { + xo_open_instance("file"); + if (cnt(NULL) != 0) ++errors; - xo_close_instance("file"); + xo_close_instance("file"); } else { - do { - xo_open_instance("file"); - if (cnt(*argv) != 0) + while (argc--) { + xo_open_instance("file"); + if (cnt(*argv++) != 0) ++errors; - xo_close_instance("file"); + xo_close_instance("file"); ++total; - } while(*++argv); + } } xo_close_list("file"); if (total > 1) { xo_open_container("total"); show_cnt("total", tlinect, twordct, tcharct, tlongline); xo_close_container("total"); } fileargs_free(fa); xo_close_container("wc"); - xo_finish(); - exit(errors == 0 ? 0 : 1); + if (xo_finish() < 0) + xo_err(EXIT_FAILURE, "stdout"); + exit(errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } static void show_cnt(const char *file, uintmax_t linect, uintmax_t wordct, uintmax_t charct, uintmax_t llct) { xo_handle_t *xop; if (!siginfo) xop = NULL; else { xop = stderr_handle; siginfo = 0; } if (doline) xo_emit_h(xop, " {:lines/%7ju/%ju}", linect); if (doword) xo_emit_h(xop, " {:words/%7ju/%ju}", wordct); if (dochar || domulti) xo_emit_h(xop, " {:characters/%7ju/%ju}", charct); if (dolongline) xo_emit_h(xop, " {:long-lines/%7ju/%ju}", llct); - if (file != NULL) + if (file != stdin_filename) xo_emit_h(xop, " {:filename/%s}\n", file); else xo_emit_h(xop, "\n"); } static int cnt(const char *file) { + char buf[MAXBSIZE], *p; struct stat sb; + mbstate_t mbs; uintmax_t linect, wordct, charct, llct, tmpll; - int fd, len, warned; + ssize_t len; size_t clen; - short gotsp; - u_char *p; - u_char buf[MAXBSIZE]; + int fd; wchar_t wch; - mbstate_t mbs; + bool gotsp, warned; linect = wordct = charct = llct = tmpll = 0; - if (file == NULL) + if (file == NULL) { fd = STDIN_FILENO; - else if ((fd = fileargs_open(fa, file)) < 0) { + file = stdin_filename; + } else if ((fd = fileargs_open(fa, file)) < 0) { xo_warn("%s: open", file); return (1); } if (doword || (domulti && MB_CUR_MAX != 1)) goto word; /* * If all we need is the number of characters and it's a regular file, * just stat it. */ if (doline == 0 && dolongline == 0) { if (fstat(fd, &sb)) { - xo_warn("%s: fstat", file != NULL ? file : "stdin"); + xo_warn("%s: fstat", file); (void)close(fd); return (1); } if (S_ISREG(sb.st_mode)) { reset_siginfo(); charct = sb.st_size; show_cnt(file, linect, wordct, charct, llct); tcharct += charct; (void)close(fd); return (0); } } /* * For files we can't stat, or if we need line counting, slurp the * file. Line counting is split out because it's a lot faster to get * lines than to get words, since the word count requires locale * handling. */ - while ((len = read(fd, buf, MAXBSIZE))) { - if (len == -1) { - xo_warn("%s: read", file != NULL ? file : "stdin"); + while ((len = read(fd, buf, sizeof(buf)))) { + if (len < 0) { + xo_warn("%s: read", file); (void)close(fd); return (1); } if (siginfo) show_cnt(file, linect, wordct, charct, llct); charct += len; if (doline || dolongline) { - for (p = buf; len--; ++p) + for (p = buf; len > 0; --len, ++p) { if (*p == '\n') { if (tmpll > llct) llct = tmpll; tmpll = 0; ++linect; - } else + } else { tmpll++; + } + } } } reset_siginfo(); if (doline) tlinect += linect; if (dochar) tcharct += charct; if (dolongline && llct > tlongline) tlongline = llct; show_cnt(file, linect, wordct, charct, llct); (void)close(fd); return (0); /* Do it the hard way... */ -word: gotsp = 1; - warned = 0; +word: gotsp = true; + warned = false; memset(&mbs, 0, sizeof(mbs)); - while ((len = read(fd, buf, MAXBSIZE)) != 0) { - if (len == -1) { - xo_warn("%s: read", file != NULL ? file : "stdin"); + while ((len = read(fd, buf, sizeof(buf))) != 0) { + if (len < 0) { + xo_warn("%s: read", file); (void)close(fd); return (1); } p = buf; while (len > 0) { if (siginfo) show_cnt(file, linect, wordct, charct, llct); if (!domulti || MB_CUR_MAX == 1) { clen = 1; wch = (unsigned char)*p; - } else if ((clen = mbrtowc(&wch, p, len, &mbs)) == - (size_t)-1) { + } else if ((clen = mbrtowc(&wch, p, len, &mbs)) == 0) { + clen = 1; + } else if (clen == (size_t)-1) { if (!warned) { errno = EILSEQ; - xo_warn("%s", - file != NULL ? file : "stdin"); - warned = 1; + xo_warn("%s", file); + warned = true; } memset(&mbs, 0, sizeof(mbs)); clen = 1; wch = (unsigned char)*p; - } else if (clen == (size_t)-2) + } else if (clen == (size_t)-2) { break; - else if (clen == 0) - clen = 1; + } charct++; if (wch != L'\n') tmpll++; len -= clen; p += clen; if (wch == L'\n') { if (tmpll > llct) llct = tmpll; tmpll = 0; ++linect; } - if (iswspace(wch)) - gotsp = 1; - else if (gotsp) { - gotsp = 0; + if (iswspace(wch)) { + gotsp = true; + } else if (gotsp) { + gotsp = false; ++wordct; } } } reset_siginfo(); - if (domulti && MB_CUR_MAX > 1) + if (domulti && MB_CUR_MAX > 1) { if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned) - xo_warn("%s", file != NULL ? file : "stdin"); + xo_warn("%s", file); + } if (doline) tlinect += linect; if (doword) twordct += wordct; if (dochar || domulti) tcharct += charct; if (dolongline && llct > tlongline) tlongline = llct; show_cnt(file, linect, wordct, charct, llct); (void)close(fd); return (0); } static void usage(void) { xo_error("usage: wc [-Lclmw] [file ...]\n"); - exit(1); + exit(EXIT_FAILURE); }