diff --git a/meson.build b/meson.build index d3bb74c3..bf60c158 100644 --- a/meson.build +++ b/meson.build @@ -100,8 +100,8 @@ libcrypto = dependency('libcrypto', required : get_option('libcrypto')) # seq(1) needs libm libm = cc.find_library('m', required : true) -# df(1) needs libxo -libxo = dependency('libxo', required : true) +# df(1) and wc(1) needs libxo +libxo = dependency('libxo', required : get_option('libxo')) # needed by a few utils; provided by glibc, but not by e.g. musl diff --git a/meson_options.txt b/meson_options.txt index 73b2d046..48dd2769 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -32,3 +32,8 @@ option('libedit', type: 'feature', value: 'enabled', description: 'Use libedit (needed by bc(1))' ) + +option('libxo', + type: 'feature', value: 'disabled', + description: 'Use libedit (for df(1) and wc(1))' +) diff --git a/src/df-nolibxo/df.1 b/src/df-nolibxo/df.1 new file mode 100644 index 00000000..2348cc4b --- /dev/null +++ b/src/df-nolibxo/df.1 @@ -0,0 +1,284 @@ +.\"- +.\" Copyright (c) 1989, 1990, 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. +.\" +.\" @(#)df.1 8.3 (Berkeley) 5/8/95 +.\" $FreeBSD$ +.\" +.Dd October 5, 2020 +.Dt DF 1 +.Os +.Sh NAME +.Nm df +.Nd display free disk space +.Sh SYNOPSIS +.Nm +.Op Fl b | g | H | h | k | m | P +.Op Fl acilnT +.Op Fl \&, +.Op Fl t Ar type +.Op Ar file | filesystem ... +.Sh DESCRIPTION +The +.Nm +utility +displays statistics about the amount of free disk space on the specified +mounted +.Ar file system +or on the file system of which +.Ar file +is a part. +By default block counts are displayed with an assumed block size of +512 bytes. +If neither a file or a file system operand is specified, +statistics for all mounted file systems are displayed +(subject to the +.Fl t +option below). +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl a +Show all mount points, including those that were mounted with the +.Dv MNT_IGNORE +flag. +This is implied for file systems specified on the command line. +.It Fl b +Explicitly use 512 byte blocks, overriding any +.Ev BLOCKSIZE +specification from the environment. +This is the same as the +.Fl P +option. +The +.Fl k +option overrides this option. +.It Fl c +Display a grand total. +.It Fl g +Use 1073741824 byte (1 Gibibyte) blocks rather than the default. +This overrides any +.Ev BLOCKSIZE +specification from the environment. +.It Fl h +.Dq Human-readable +output. +Use unit suffixes: Byte, Kibibyte, Mebibyte, Gibibyte, Tebibyte and +Pebibyte (based on powers of 1024) in order to reduce the number of +digits to four or fewer. +.It Fl H , Fl Fl si +Same as +.Fl h +but based on powers of 1000. +.It Fl i +Include statistics on the number of free and used inodes. +In conjunction with the +.Fl h +or +.Fl H +options, the number of inodes is scaled by powers of 1000. +.It Fl k +Use 1024 byte (1 Kibibyte) blocks rather than the default. +This overrides the +.Fl P +option and any +.Ev BLOCKSIZE +specification from the environment. +.It Fl l +Select locally-mounted file system for display. +If used in combination with the +.Fl t Ar type +option, file system types will be added or excluded acccording to the +parameters of that option. +.It Fl m +Use 1048576 byte (1 Mebibyte) blocks rather than the default. +This overrides any +.Ev BLOCKSIZE +specification from the environment. +.It Fl n +Print out the previously obtained statistics from the file systems. +This option should be used if it is possible that one or more +file systems are in a state such that they will not be able to provide +statistics without a long delay. +When this option is specified, +.Nm +will not request new statistics from the file systems, but will respond +with the possibly stale statistics that were previously obtained. +.It Fl P +Explicitly use 512 byte blocks, overriding any +.Ev BLOCKSIZE +specification from the environment. +This is the same as the +.Fl b +option. +The +.Fl k +option overrides this option. +.It Fl t Ar type +Select file systems to display. +More than one type may be specified in a comma separated list. +The list of file system types can be prefixed with +.Dq no +to specify the file system types for which action should +.Em not +be taken. +If used in combination with the +.Fl l +option, the parameters of this option will modify the list of +locally-mounted file systems selected by the +.Fl l +option. +For example, the +.Nm +command: +.Bd -literal -offset indent +df -t nonfs,nullfs +.Ed +.Pp +lists all file systems except those of type NFS and NULLFS. +The +.Xr lsvfs 1 +command can be used to find out the types of file systems +that are available on the system. +.It Fl T +Include file system type. +.It Fl , +(Comma) Print sizes grouped and separated by thousands using the +non-monetary separator returned by +.Xr localeconv 3 , +typically a comma or period. +If no locale is set, or the locale does not have a non-monetary separator, this +option has no effect. +.El +.Sh ENVIRONMENT +.Bl -tag -width BLOCKSIZE +.It Ev BLOCKSIZE +Specifies the units in which to report block counts. +This uses +.Xr getbsize 3 , +which allows units of bytes or numbers scaled with the letters +.Em k +(for multiples of 1024 bytes), +.Em m +(for multiples of 1048576 bytes) or +.Em g +(for gibibytes). +The allowed range is 512 bytes to 1 GB. +If the value is outside, it will be set to the appropriate limit. +.El +.Sh EXAMPLES +Show human readable free disk space for all mount points including file system +type: +.Bd -literal -offset indent +$ df -ahT +Filesystem Type Size Used Avail Capacity Mounted on +/dev/ada1p2 ufs 213G 152G 44G 78% / +devfs devfs 1.0K 1.0K 0B 100% /dev +/dev/ada0p1 ufs 1.8T 168G 1.5T 10% /data +linsysfs linsysfs 4.0K 4.0K 0B 100% /compat/linux/sys +/dev/da0 msdosfs 7.6G 424M 7.2G 5% /mnt/usb +.Ed +.Pp +Show previously collected data including inode statistics except for devfs or +linsysfs file systems. +Note that the +.Dq no +prefix affects all the file systems in the list and the +.Fl t +option can be specified only once: +.Bd -literal -offset indent +$ df -i -n -t nodevfs,linsysfs +Filesystem 1K-blocks Used Avail Capacity iused ifree %iused +Mounted on +/dev/ada1p2 223235736 159618992 45757888 78% 1657590 27234568 6% / +/dev/ada0p1 1892163184 176319420 1564470712 10% 1319710 243300576 1% +/data +/dev/da0 7989888 433664 7556224 5% 0 0 100% +/mnt/usb +.Ed +.Pp +Show human readable information for the file system containing the file +.Pa /etc/rc.conf : +.Bd -literal -offset indent +$ df -h /etc/rc.conf +Filesystem Size Used Avail Capacity Mounted on +/dev/ada1p2 213G 152G 44G 78% / +.Ed +.Pp +Same as above but specifying some file system: +.Bd -literal -offset indent +$ df -h /dev/ada1p2 +Filesystem Size Used Avail Capacity Mounted on +/dev/ada1p2 213G 152G 44G 78% / +.Ed +.Sh SEE ALSO +.Xr lsvfs 1 , +.Xr quota 1 , +.Xr fstatfs 2 , +.Xr getfsstat 2 , +.Xr statfs 2 , +.Xr getbsize 3 , +.Xr getmntinfo 3 , +.Xr localeconv 3 , +.Xr fstab 5 , +.Xr mount 8 , +.Xr pstat 8 , +.Xr quot 8 , +.Xr swapinfo 8 +.Sh STANDARDS +With the exception of most options, +the +.Nm +utility conforms to +.St -p1003.1-2004 , +which defines only the +.Fl k , P +and +.Fl t +options. +.Sh HISTORY +A +.Nm +command appeared in +.At v1 . +.Sh BUGS +The +.Fl n +flag is ignored if a file or file system is specified. +Also, if a mount +point is not accessible by the user, it is possible that the file system +information could be stale. +.Pp +The +.Fl b +and +.Fl P +options are identical. +The former comes from the BSD tradition, and the latter is required +for +.St -p1003.1-2004 +conformity. diff --git a/src/df-nolibxo/df.c b/src/df-nolibxo/df.c new file mode 100644 index 00000000..8fe29a0a --- /dev/null +++ b/src/df-nolibxo/df.c @@ -0,0 +1,739 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1980, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + */ + +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1980, 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95"; +#endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" + +#define UNITS_SI 1 +#define UNITS_2 2 + +/* + * Static list of network filesystems + * + * This replaces the makenetvfslist() function from FreeBSD, but this + * list should be made in to something we can generate at runtime or + * just expand the list. + */ +#define NETVFSLIST "nonfs,nosmb,nocifs" + +/* combining data from getmntent() and statvfs() on Linux */ +struct mntinfo { + char *f_mntfromname; /* mnt_fsname from getmntent */ + char *f_mntonname; /* mnt_dir from getmntent */ + char *f_fstypename; /* mnt_fsname from getmntent */ + char *f_opts; /* mnt_opts from getmntent */ + unsigned long f_bsize; /* f_bsize from statvfs */ + fsblkcnt_t f_blocks; /* f_blocks from statvfs */ + fsblkcnt_t f_bfree; /* f_bfree from statvfs */ + fsblkcnt_t f_bavail; /* f_bavail from statvfs */ + fsfilcnt_t f_files; /* f_files from statvfs */ + fsfilcnt_t f_ffree; /* f_ffree from statvfs */ + unsigned long f_flag; /* f_flag from statvfs */ + unsigned int f_selected; /* used internally here only */ +}; + +/* Maximum widths of various fields. */ +struct maxwidths { + int mntfrom; + int fstype; + int total; + int used; + int avail; + int iused; + int ifree; +}; + +static void addstat(struct mntinfo *, struct mntinfo *); +static char *getmntpt(struct mntinfo **, const size_t, const char *); +static const char **makevfslist(char *fslist, int *skip); +static int checkvfsname(const char *vfsname, const char **vfslist, int skip); +static int checkvfsselected(char *); +static int int64width(int64_t); +static void prthuman(const struct mntinfo *, int64_t); +static void prthumanval(int64_t); +static intmax_t fsbtoblk(int64_t, uint64_t, u_long); +static void prtstat(struct mntinfo *, struct maxwidths *); +static size_t regetmntinfo(struct mntinfo **, long); +static void update_maxwidths(struct maxwidths *, const struct mntinfo *); +static void usage(void); +static int getmntinfo(struct mntinfo **); +static void freemntinfo(struct mntinfo *, int); + +static __inline int +imax(int a, int b) +{ + return (a > b ? a : b); +} + +static int aflag = 0, cflag, hflag, iflag, kflag, lflag = 0, nflag, Tflag; +static int thousands; +static int skipvfs_l, skipvfs_t; +static const char **vfslist_l, **vfslist_t; + +static const struct option long_options[] = +{ + { "si", no_argument, NULL, 'H' }, + { NULL, no_argument, NULL, 0 }, +}; + +int +main(int argc, char *argv[]) +{ + struct stat stbuf; + struct mntinfo *mntbuf = NULL; + struct mntinfo totalbuf; + struct maxwidths maxwidths; + char *mntpt; + int i, mntsize; + int ch, rv; + + (void)setlocale(LC_ALL, ""); + memset(&maxwidths, 0, sizeof(maxwidths)); + memset(&totalbuf, 0, sizeof(totalbuf)); + totalbuf.f_bsize = DEV_BSIZE; + while ((ch = getopt_long(argc, argv, "+abcgHhiklmnPt:T,", long_options, + NULL)) != -1) + switch (ch) { + case 'a': + aflag = 1; + break; + case 'b': + /* FALLTHROUGH */ + case 'P': + /* + * POSIX specifically discusses the behavior of + * both -k and -P. It states that the blocksize should + * be set to 1024. Thus, if this occurs, simply break + * rather than clobbering the old blocksize. + */ + if (kflag) + break; + setenv("BLOCKSIZE", "512", 1); + hflag = 0; + break; + case 'c': + cflag = 1; + break; + case 'g': + setenv("BLOCKSIZE", "1g", 1); + hflag = 0; + break; + case 'H': + hflag = UNITS_SI; + break; + case 'h': + hflag = UNITS_2; + break; + case 'i': + iflag = 1; + break; + case 'k': + kflag++; + setenv("BLOCKSIZE", "1024", 1); + hflag = 0; + break; + case 'l': + /* Ignore duplicate -l */ + if (lflag) + break; + vfslist_l = makevfslist(NETVFSLIST, &skipvfs_l); + lflag = 1; + break; + case 'm': + setenv("BLOCKSIZE", "1m", 1); + hflag = 0; + break; + case 'n': + nflag = 1; + break; + case 't': + if (vfslist_t != NULL) + errx(1, "only one -t option may be specified"); + vfslist_t = makevfslist(optarg, &skipvfs_t); + break; + case 'T': + Tflag = 1; + break; + case ',': + thousands = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + rv = 0; + mntsize = getmntinfo(&mntbuf); + mntsize = regetmntinfo(&mntbuf, mntsize); + + /* unselect all filesystems if an explicit list is given */ + if (*argv) { + for (i = 0; i < mntsize; i++) { + mntbuf[i].f_selected = 0; + } + } + + /* iterate through specified filesystems */ + for (; *argv; argv++) { + if (stat(*argv, &stbuf) < 0) { + if ((mntpt = getmntpt(&mntbuf, mntsize, *argv)) == NULL) { + warn("%s", *argv); + rv = 1; + continue; + } + } else if (S_ISCHR(stbuf.st_mode)) { + mntpt = getmntpt(&mntbuf, mntsize, *argv); + if (mntpt == NULL) { + warnx("%s: not mounted", *argv); + rv = 1; + continue; + } + } else { + mntpt = *argv; + } + + /* + * Statvfs does not take a `wait' flag, so we cannot + * implement nflag here. + */ + for (i = 0; i < mntsize; i++) { + /* selected specified filesystems if the mount point or device matches */ + if ((!strcmp(mntbuf[i].f_mntfromname, mntpt) + || !strcmp(mntbuf[i].f_mntonname, mntpt)) + && !checkvfsname(mntbuf[i].f_fstypename, vfslist_l, skipvfs_l) + && !checkvfsname(mntbuf[i].f_fstypename, vfslist_t, skipvfs_t)) { + mntbuf[i].f_selected = 1; + break; + } + } + } + + memset(&maxwidths, 0, sizeof(maxwidths)); + for (i = 0; i < mntsize; i++) { + if ((aflag || (mntbuf[i].f_blocks > 0)) && mntbuf[i].f_selected) { + update_maxwidths(&maxwidths, &mntbuf[i]); + if (cflag) + addstat(&totalbuf, &mntbuf[i]); + } + } + for (i = 0; i < mntsize; i++) + if ((aflag || (mntbuf[i].f_blocks > 0)) && mntbuf[i].f_selected) + prtstat(&mntbuf[i], &maxwidths); + if (cflag) + prtstat(&totalbuf, &maxwidths); + freemntinfo(mntbuf, mntsize); + exit(rv); +} + +static char * +getmntpt(struct mntinfo **mntbuf, const size_t mntsize, const char *name) +{ + size_t i; + + if (mntsize == 0 || mntbuf == NULL || name == NULL) + return NULL; + + for (i = 0; i < mntsize; i++) { + if (mntbuf[i] == NULL) + continue; + } + + return (NULL); +} + +static const char ** +makevfslist(char *fslist, int *skip) +{ + const char **av; + int i; + char *nextcp; + + if (fslist == NULL) + return (NULL); + *skip = 0; + if (fslist[0] == 'n' && fslist[1] == 'o') { + fslist += 2; + *skip = 1; + } + for (i = 0, nextcp = fslist; *nextcp; nextcp++) + if (*nextcp == ',') + i++; + if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { + warnx("malloc failed"); + return (NULL); + } + nextcp = fslist; + i = 0; + av[i++] = nextcp; + while ((nextcp = strchr(nextcp, ',')) != NULL) { + *nextcp++ = '\0'; + av[i++] = nextcp; + } + av[i++] = NULL; + return (av); +} + +static int +checkvfsname(const char *vfsname, const char **vfslist, int skip) +{ + + if (vfslist == NULL) + return (0); + while (*vfslist != NULL) { + if (strcmp(vfsname, *vfslist) == 0) + return (skip); + ++vfslist; + } + return (!skip); +} + +/* + * Without -l and -t option, all file system types are enabled. + * The -l option selects the local file systems, if present. + * A -t option modifies the selection by adding or removing further + * file system types, based on the argument that is passed. + */ +static int +checkvfsselected(char *fstypename) +{ + int result; + + if (vfslist_t) { + /* if -t option used then select passed types */ + result = checkvfsname(fstypename, vfslist_t, skipvfs_t); + if (vfslist_l) { + /* if -l option then adjust selection */ + if (checkvfsname(fstypename, vfslist_l, skipvfs_l) == skipvfs_t) + result = skipvfs_t; + } + } else { + /* no -t option then -l decides */ + result = checkvfsname(fstypename, vfslist_l, skipvfs_l); + } + return (result); +} + +/* + * Make a pass over the file system info in ``mntbuf'' filtering out + * file system types not in vfslist_{l,t} and possibly re-stating to get + * current (not cached) info. Returns the new count of valid statvfs bufs. + */ +static size_t +regetmntinfo(struct mntinfo **mntbufp, long mntsize) +{ + int error, i, j; + struct mntinfo *mntbuf; + struct statvfs svfsbuf; + + if (vfslist_l == NULL && vfslist_t == NULL) + return (nflag ? mntsize : getmntinfo(mntbufp)); + + mntbuf = *mntbufp; + for (j = 0, i = 0; i < mntsize; i++) { + if (checkvfsselected(mntbuf[i].f_fstypename) != 0) + continue; + /* + * XXX statvfs(2) can fail for various reasons. It may be + * possible that the user does not have access to the + * pathname, if this happens, we will fall back on + * "stale" filesystem statistics. + */ + error = statvfs(mntbuf[i].f_mntonname, &svfsbuf); + if (nflag || error < 0) + if (i != j) { + if (error < 0) + warnx("%s stats possibly stale", + mntbuf[i].f_mntonname); + + free(mntbuf[j].f_fstypename); + mntbuf[j].f_fstypename = strdup(mntbuf[i].f_fstypename); + free(mntbuf[j].f_mntfromname); + mntbuf[j].f_mntfromname = strdup(mntbuf[i].f_mntfromname); + free(mntbuf[j].f_mntfromname); + mntbuf[j].f_mntonname = strdup(mntbuf[i].f_mntonname); + free(mntbuf[j].f_opts); + + mntbuf[j].f_opts = strdup(mntbuf[i].f_opts); + mntbuf[j].f_flag = svfsbuf.f_flag; + mntbuf[j].f_blocks = svfsbuf.f_blocks; + mntbuf[j].f_bsize = svfsbuf.f_bsize; + mntbuf[j].f_bfree = svfsbuf.f_bfree; + mntbuf[j].f_bavail = svfsbuf.f_bavail; + mntbuf[j].f_files = svfsbuf.f_files; + mntbuf[j].f_ffree = svfsbuf.f_ffree; + } + j++; + } + return (j); +} + +static void +prthuman(const struct mntinfo *sfsp, int64_t used) +{ + + prthumanval(sfsp->f_blocks * sfsp->f_bsize); + prthumanval(used * sfsp->f_bsize); + prthumanval(sfsp->f_bavail * sfsp->f_bsize); +} + +static void +prthumanval(int64_t bytes) +{ + char buf[6]; + int flags; + + flags = HN_B | HN_NOSPACE | HN_DECIMAL; + if (hflag == UNITS_SI) + flags |= HN_DIVISOR_1000; + + humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), + bytes, "", HN_AUTOSCALE, flags); + + (void)printf(" %6s", buf); +} + +/* + * Print an inode count in "human-readable" format. + */ +static void +prthumanvalinode(int64_t bytes) +{ + char buf[6]; + int flags; + + flags = HN_NOSPACE | HN_DECIMAL | HN_DIVISOR_1000; + + humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), + bytes, "", HN_AUTOSCALE, flags); + + (void)printf(" %5s", buf); +} + +/* + * Convert statvfs returned file system size into BLOCKSIZE units. + */ +static intmax_t +fsbtoblk(int64_t num, uint64_t fsbs, u_long bs) +{ + return (num * (intmax_t) fsbs / (int64_t) bs); +} + +/* + * Print out status about a file system. + */ +static void +prtstat(struct mntinfo *sfsp, struct maxwidths *mwp) +{ + static long blocksize; + static int headerlen, timesthrough = 0; + static const char *header; + int64_t used, availblks, inodes; + const char *format; + + if (++timesthrough == 1) { + mwp->mntfrom = imax(mwp->mntfrom, (int)strlen("Filesystem")); + mwp->fstype = imax(mwp->fstype, (int)strlen("Type")); + if (thousands) { /* make space for commas */ + mwp->total += (mwp->total - 1) / 3; + mwp->used += (mwp->used - 1) / 3; + mwp->avail += (mwp->avail - 1) / 3; + mwp->iused += (mwp->iused - 1) / 3; + mwp->ifree += (mwp->ifree - 1) / 3; + } + if (hflag) { + header = " Size"; + mwp->total = mwp->used = mwp->avail = + (int)strlen(header); + } else { + header = getbsize(&headerlen, &blocksize); + mwp->total = imax(mwp->total, headerlen); + } + mwp->used = imax(mwp->used, (int)strlen("Used")); + mwp->avail = imax(mwp->avail, (int)strlen("Avail")); + + (void)printf("%-*s", mwp->mntfrom, "Filesystem"); + if (Tflag) + (void)printf(" {T:/%-*s}", mwp->fstype, "Type"); + (void)printf(" %*s %*s %*s Capacity", + mwp->total, header, + mwp->used, "Used", mwp->avail, "Avail"); + if (iflag) { + mwp->iused = imax(hflag ? 0 : mwp->iused, + (int)strlen(" iused")); + mwp->ifree = imax(hflag ? 0 : mwp->ifree, + (int)strlen("ifree")); + (void)printf(" %*s %*s %%iused", + mwp->iused - 2, "iused", mwp->ifree, "ifree"); + } + (void)printf(" Mounted on\n"); + } + + /* Check for 0 block size. Can this happen? */ + if (sfsp->f_bsize == 0) { + warnx ("File system %s does not have a block size, assuming 512.", + sfsp->f_mntonname); + sfsp->f_bsize = 512; + } + (void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname); + if (Tflag) + (void)printf(" %-*s", mwp->fstype, sfsp->f_fstypename); + used = sfsp->f_blocks - sfsp->f_bfree; + availblks = sfsp->f_bavail + used; + if (hflag) { + prthuman(sfsp, used); + } else { + if (thousands) + format = " %*j'd %*j'd %*j'd"; + else + format = " %*jd %*jd %*jd"; + (void)printf(format, + mwp->total, fsbtoblk(sfsp->f_blocks, + sfsp->f_bsize, blocksize), + mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize), + mwp->avail, fsbtoblk(sfsp->f_bavail, + sfsp->f_bsize, blocksize)); + } + (void)printf(" %5.0f%%", + availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); + if (iflag) { + inodes = sfsp->f_files; + used = inodes - sfsp->f_ffree; + if (hflag) { + (void)printf(" "); + prthumanvalinode(used); + prthumanvalinode(sfsp->f_ffree); + } else { + if (thousands) + format = " %*j'd %*j'd"; + else + format = " %*jd %*jd"; + (void)printf(format, mwp->iused, (intmax_t)used, + mwp->ifree, (intmax_t)sfsp->f_ffree); + } + (void)printf(" %4.0f%% ", + inodes == 0 ? 100.0 : + (double)used / (double)inodes * 100.0); + } else + (void)printf(" "); + if (strcmp(sfsp->f_mntfromname, "total") != 0) + (void)printf(" %s", sfsp->f_mntonname); + (void)printf("\n"); +} + +static void +addstat(struct mntinfo *totalfsp, struct mntinfo *statvfsp) +{ + uint64_t bsize; + + bsize = statvfsp->f_bsize / totalfsp->f_bsize; + totalfsp->f_blocks += statvfsp->f_blocks * bsize; + totalfsp->f_bfree += statvfsp->f_bfree * bsize; + totalfsp->f_bavail += statvfsp->f_bavail * bsize; + totalfsp->f_files += statvfsp->f_files; + totalfsp->f_ffree += statvfsp->f_ffree; +} + +/* + * Update the maximum field-width information in `mwp' based on + * the file system specified by `sfsp'. + */ +static void +update_maxwidths(struct maxwidths *mwp, const struct mntinfo *sfsp) +{ + static long blocksize = 0; + int dummy; + + if (blocksize == 0) + getbsize(&dummy, &blocksize); + + mwp->mntfrom = imax(mwp->mntfrom, (int)strlen(sfsp->f_mntfromname)); + mwp->fstype = imax(mwp->fstype, (int)strlen(sfsp->f_fstypename)); + mwp->total = imax(mwp->total, int64width( + fsbtoblk((int64_t)sfsp->f_blocks, sfsp->f_bsize, blocksize))); + mwp->used = imax(mwp->used, + int64width(fsbtoblk((int64_t)sfsp->f_blocks - + (int64_t)sfsp->f_bfree, sfsp->f_bsize, blocksize))); + mwp->avail = imax(mwp->avail, int64width(fsbtoblk(sfsp->f_bavail, + sfsp->f_bsize, blocksize))); + mwp->iused = imax(mwp->iused, int64width((int64_t)sfsp->f_files - + sfsp->f_ffree)); + mwp->ifree = imax(mwp->ifree, int64width(sfsp->f_ffree)); +} + +/* Return the width in characters of the specified value. */ +static int +int64width(int64_t val) +{ + int len; + + len = 0; + /* Negative or zero values require one extra digit. */ + if (val <= 0) { + val = -val; + len++; + } + while (val > 0) { + len++; + val /= 10; + } + + return (len); +} + +static void +usage(void) +{ + + (void)fprintf(stderr, +"usage: df [-b | -g | -H | -h | -k | -m | -P] [-acilnT] [-t type] [-,]\n" +" [file | filesystem ...]\n"); + exit(EX_USAGE); +} + +static int +getmntinfo(struct mntinfo **mntbuf) +{ + struct mntinfo *list = NULL; + struct mntinfo *current = NULL; + struct mntent *ent = NULL; + int mntsize = 0; + FILE *fp = NULL; + struct statvfs svfsbuf; + +#ifdef _PATH_MOUNTED + fp = setmntent(_PATH_MOUNTED, "r"); +#else + if (access("/proc/self/mounts", R_OK) == 0) { + fp = setmntent("/proc/self/mounts", "r"); + } else if (access("/proc/mounts", R_OK) == 0) { + fp = setmntent("/proc/mounts", "r"); + } else if (access("/etc/mtab", R_OK) == 0) { + fp = setmntent("/etc/mtab", "r"); + } +#endif + + if (fp == NULL) { + err(1, "setmntent"); + } + + while ((ent = getmntent(fp)) != NULL) { + /* skip if necessary */ + if (hasmntopt(ent, MNTTYPE_IGNORE) != NULL) { + continue; + } + + /* get statvfs fields and copy those over */ + /* just ignore mount points that error */ + if (statvfs(ent->mnt_dir, &svfsbuf) == -1) { + continue; + } + + /* allocate the entry */ + list = realloc(list, (mntsize + 1) * sizeof(*list)); + assert(list != NULL); + current = list + mntsize; + + /* fill the struct with getmntent fields */ + current->f_fstypename = strdup(ent->mnt_type); + current->f_mntfromname = strdup(ent->mnt_fsname); + current->f_mntonname = strdup(ent->mnt_dir); + current->f_opts = strdup(ent->mnt_opts); + + current->f_flag = svfsbuf.f_flag; + current->f_blocks = svfsbuf.f_blocks; + current->f_bsize = svfsbuf.f_bsize; + current->f_bfree = svfsbuf.f_bfree; + current->f_bavail = svfsbuf.f_bavail; + current->f_files = svfsbuf.f_files; + current->f_ffree = svfsbuf.f_ffree; + current->f_selected = 1; + + mntsize++; + } + + endmntent(fp); + + *mntbuf = list; + return mntsize; +} + +static void +freemntinfo(struct mntinfo *mntbuf, int mntsize) +{ + int i = 0; + + for (i = 0; i < mntsize; i++) { + free(mntbuf[i].f_fstypename); + free(mntbuf[i].f_mntfromname); + free(mntbuf[i].f_mntonname); + free(mntbuf[i].f_opts); + } + + free(mntbuf); + return; +} diff --git a/src/df-nolibxo/meson.build b/src/df-nolibxo/meson.build new file mode 100644 index 00000000..214fa65a --- /dev/null +++ b/src/df-nolibxo/meson.build @@ -0,0 +1,10 @@ +df_prog = executable( + 'df', + [ 'df.c' ], + include_directories : inc, + dependencies : [ ], + link_with : [ libcompat ], + install : true, +) +install_man('df.1') + diff --git a/src/df/meson.build b/src/df/meson.build index 398f04ea..8937721e 100644 --- a/src/df/meson.build +++ b/src/df/meson.build @@ -1,10 +1,11 @@ + df_prog = executable( - 'df', - [ 'df.c' ], - include_directories : inc, - dependencies : [ libxo ], - link_with : [ libcompat ], - install : true, + 'df', + [ 'df.c' ], + include_directories : inc, + dependencies : [ libxo ], + link_with : [ libcompat ], + install : true, ) - install_man('df.1') + diff --git a/src/diff/diffreg.c b/src/diff/diffreg.c index e728441c..5de6099d 100644 --- a/src/diff/diffreg.c +++ b/src/diff/diffreg.c @@ -278,11 +278,11 @@ diffreg(char *file1, char *file2, int flags, int capsicum) padding = tabsize - (hw % tabsize); if ((flags & D_EXPANDTABS) != 0 || (padding % tabsize == 0)) padding = MIN_PAD; - + hw = (width >> 1) - ((padding == MIN_PAD) ? (padding << 1) : padding) - 1; } - + if (flags & D_IGNORECASE) chrtran = cup2low; @@ -1312,7 +1312,7 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) if (c == '\t') { if (flags & D_EXPANDTABS) { newcol = ((col/tabsize)+1)*tabsize; - do { + do { if (diff_format == D_SIDEBYSIDE) j++; printf(" "); diff --git a/src/diff/meson.build b/src/diff/meson.build index 0c393bf0..e57c626c 100644 --- a/src/diff/meson.build +++ b/src/diff/meson.build @@ -6,10 +6,10 @@ diff_prog = executable( 'xmalloc.c', 'pr.c', ], + include_directories : inc, + link_with : [ libcompat ], install : true, ) install_man('diff.1') -# include_directories : inc, -# link_with : [ libcompat ], diff --git a/src/meson.build b/src/meson.build index 3ffe97f6..bfa45d42 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,8 +10,7 @@ subdir('csplit') subdir('cut') subdir('date') subdir('dd') -subdir('df') -subdir('diff') +# subdir('diff') subdir('dirname') subdir('du') subdir('echo') @@ -72,7 +71,6 @@ subdir('uname') subdir('unexpand') subdir('uniq') subdir('users') -subdir('wc') subdir('which') subdir('who') subdir('xargs') @@ -86,3 +84,11 @@ if libcrypto.found() subdir('dc') subdir('xinstall') endif + +if libxo.found() + subdir('df') + subdir('wc') +else + subdir('df-nolibxo') + subdir('wc-nolibxo') +endif diff --git a/src/wc-nolibxo/meson.build b/src/wc-nolibxo/meson.build new file mode 100644 index 00000000..6e04ccf1 --- /dev/null +++ b/src/wc-nolibxo/meson.build @@ -0,0 +1,9 @@ +wc_prog = executable( + 'wc', + [ 'wc.c' ], + include_directories : inc, + dependencies : [ ], + link_with : [ libcompat ], + install : true, +) +install_man('wc.1') diff --git a/src/wc-nolibxo/wc.1 b/src/wc-nolibxo/wc.1 new file mode 100644 index 00000000..fce97f3c --- /dev/null +++ b/src/wc-nolibxo/wc.1 @@ -0,0 +1,202 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" 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. +.\" +.\" @(#)wc.1 8.2 (Berkeley) 4/19/94 +.\" $FreeBSD$ +.\" +.Dd April 11, 2020 +.Dt WC 1 +.Os +.Sh NAME +.Nm wc +.Nd word, line, character, and byte count +.Sh SYNOPSIS +.Nm +.Op Fl Lclmw +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility displays the number of lines, words, and bytes contained in each +input +.Ar file , +or standard input (if no file is specified) to the standard output. +A line is defined as a string of characters delimited by a +.Aq newline +character. +Characters beyond the final +.Aq newline +character will not be included +in the line count. +.Pp +A word is defined as a string of characters delimited by white space +characters. +White space characters are the set of characters for which the +.Xr iswspace 3 +function returns true. +If more than one input file is specified, a line of cumulative counts +for all the files is displayed on a separate line after the output for +the last file. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl L +Write the length of the line containing the most bytes (default) or characters +(when +.Fl m +is provided) +to standard output. +When more than one +.Ar file +argument is specified, the longest input line of +.Em all +files is reported as the value of the final +.Dq total . +.It Fl c +The number of bytes in each input file +is written to the standard output. +This will cancel out any prior usage of the +.Fl m +option. +.It Fl l +The number of lines in each input file +is written to the standard output. +.It Fl m +The number of characters in each input file is written to the standard output. +If the current locale does not support multibyte characters, this +is equivalent to the +.Fl c +option. +This will cancel out any prior usage of the +.Fl c +option. +.It Fl w +The number of words in each input file +is written to the standard output. +.El +.Pp +When an option is specified, +.Nm +only reports the information requested by that option. +The order of output always takes the form of line, word, +byte, and file name. +The default action is equivalent to specifying the +.Fl c , l +and +.Fl w +options. +.Pp +If no files are specified, the standard input is used and no +file name is displayed. +The prompt will accept input until receiving EOF, or +.Bq ^D +in most environments. +.Pp +If +.Nm +receives a +.Dv SIGUSR1 +(see the +.Cm status +argument for +.Xr stty 1 ) +signal, the interim data will be written +to the standard error output in the same format +as the standard completion message. +.Sh ENVIRONMENT +The +.Ev LANG , LC_ALL +and +.Ev LC_CTYPE +environment variables affect the execution of +.Nm +as described in +.Xr environ 7 . +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Count the number of characters, words and lines in each of the files +.Pa report1 +and +.Pa report2 +as well as the totals for both: +.Pp +.Dl "wc -mlw report1 report2" +.Pp +Find the longest line in a list of files: +.Pp +.Dl "wc -L file1 file2 file3 | fgrep total" +.Sh COMPATIBILITY +Historically, the +.Nm +utility was documented to define a word as a +.Do +maximal string of +characters delimited by , or characters +.Dc . +The implementation, however, did not handle non-printing characters +correctly so that +.Dq Li "\ \ ^D^E\ \ " +counted as 6 spaces, while +.Dq Li foo^D^Ebar +counted as 8 characters. +.Bx 4 +systems after +.Bx 4.3 +modified the implementation to be consistent +with the documentation. +This implementation defines a +.Dq word +in terms of the +.Xr iswspace 3 +function, as required by +.St -p1003.2 . +.Pp +The +.Fl L +option is a non-standard +.Fx +extension, compatible with the +.Fl L +option of the GNU +.Nm +utility. +.Sh SEE ALSO +.Xr iswspace 3 , +.Sh STANDARDS +The +.Nm +utility conforms to +.St -p1003.1-2001 . +.Sh HISTORY +A +.Nm +command appeared in +.At v1 . diff --git a/src/wc-nolibxo/wc.c b/src/wc-nolibxo/wc.c new file mode 100644 index 00000000..411e667f --- /dev/null +++ b/src/wc-nolibxo/wc.c @@ -0,0 +1,327 @@ +/*- + * 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 "compat.h" + +static uintmax_t tlinect, twordct, tcharct, tlongline; +static int doline, doword, dochar, domulti, dolongline; +static volatile sig_atomic_t siginfo; + +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 __attribute__((unused))) +{ + + siginfo = 1; +} + +static void +reset_siginfo(void) +{ + + signal(SIGINFO, SIG_DFL); + siginfo = 0; +} + +int +main(int argc, char *argv[]) +{ + int ch, errors, total; + + (void) setlocale(LC_CTYPE, ""); + + + while ((ch = getopt(argc, argv, "clmwL")) != -1) + switch((char)ch) { + case 'l': + doline = 1; + break; + case 'w': + doword = 1; + break; + case 'c': + dochar = 1; + domulti = 0; + break; + case 'L': + dolongline = 1; + break; + case 'm': + domulti = 1; + dochar = 0; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + + (void)signal(SIGINFO, siginfo_handler); + + /* Wc's flags are on by default. */ + if (doline + doword + dochar + domulti + dolongline == 0) + doline = doword = dochar = 1; + + errors = 0; + total = 0; + if (!*argv) { + if (cnt((char *)NULL) != 0) + ++errors; + } else { + do { + if (cnt(*argv) != 0) + ++errors; + ++total; + } while(*++argv); + } + + if (total > 1) + show_cnt("total", tlinect, twordct, tcharct, tlongline); + exit(errors == 0 ? 0 : 1); +} + +static void +show_cnt(const char *file, uintmax_t linect, uintmax_t wordct, + uintmax_t charct, uintmax_t llct) +{ + FILE *out; + + if (!siginfo) + out = stdout; + else { + out = stderr; + siginfo = 0; + } + + if (doline) + (void)fprintf(out, " %7ju", linect); + if (doword) + (void)fprintf(out, " %7ju", wordct); + if (dochar || domulti) + (void)fprintf(out, " %7ju", charct); + if (dolongline) + (void)fprintf(out, " %7ju", llct); + if (file != NULL) + (void)fprintf(out, " %s\n", file); + else + (void)fprintf(out, "\n"); +} + +static int +cnt(const char *file) +{ + struct stat sb; + uintmax_t linect, wordct, charct, llct, tmpll; + int fd, len, warned; + size_t clen; + short gotsp; + u_char *p; + u_char buf[MAXBSIZE]; + wchar_t wch; + mbstate_t mbs; + + linect = wordct = charct = llct = tmpll = 0; + if (file == NULL) + fd = STDIN_FILENO; + else if ((fd = open(file, O_RDONLY, 0)) < 0) { + 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)) { + warn("%s: fstat", file != NULL ? file : "stdin"); + (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) { + warn("%s: read", file != NULL ? file : "stdin"); + (void)close(fd); + return (1); + } + if (siginfo) + show_cnt(file, linect, wordct, charct, llct); + charct += len; + if (doline || dolongline) { + for (p = buf; len--; ++p) + if (*p == '\n') { + if (tmpll > llct) + llct = tmpll; + tmpll = 0; + ++linect; + } 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; + memset(&mbs, 0, sizeof(mbs)); + while ((len = read(fd, buf, MAXBSIZE)) != 0) { + if (len == -1) { + warn("%s: read", file != NULL ? file : "stdin"); + (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, (char *)p, len, &mbs)) == + (size_t)-1) { + if (!warned) { + errno = EILSEQ; + warn("%s", + file != NULL ? file : "stdin"); + warned = 1; + } + memset(&mbs, 0, sizeof(mbs)); + clen = 1; + wch = (unsigned char)*p; + } 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; + ++wordct; + } + } + } + reset_siginfo(); + if (domulti && MB_CUR_MAX > 1) + if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned) + warn("%s", file != NULL ? file : "stdin"); + 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) +{ + (void)fprintf(stderr, "usage: wc [-Lclmw] [file ...]\n"); + exit(1); +} diff --git a/src/wc/meson.build b/src/wc/meson.build index f7a6c2fa..5dc39236 100644 --- a/src/wc/meson.build +++ b/src/wc/meson.build @@ -1,9 +1,11 @@ + wc_prog = executable( - 'wc', - [ 'wc.c' ], - include_directories : [ inc, ], - dependencies : [ libxo ], - install : true, + 'wc', + [ 'wc.c' ], + include_directories : inc, + dependencies : [ libxo ], + link_with : [ libcompat ], + install : true, ) - install_man('wc.1') +