git: b2b8fa1a64af - main - Add libxo support to du

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 29 Apr 2024 14:22:51 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=b2b8fa1a64af81e940d7b3ab71fd4c583b4abe0f

commit b2b8fa1a64af81e940d7b3ab71fd4c583b4abe0f
Author:     Nathan Huff <nhuff@acm.org>
AuthorDate: 2024-04-29 04:59:18 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-04-29 14:22:39 +0000

    Add libxo support to du
    
    Convert du to use libxo enabling structured output.
    
    [[ minor style fixes by imp ]]
    
    Signed-off-by: Nathan Huff <nhuff@acm.org>
    Reviewed by: imp
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1145
---
 usr.bin/du/Makefile |  2 +-
 usr.bin/du/du.1     | 12 ++++++++++-
 usr.bin/du/du.c     | 57 ++++++++++++++++++++++++++++++++++-------------------
 3 files changed, 49 insertions(+), 22 deletions(-)

diff --git a/usr.bin/du/Makefile b/usr.bin/du/Makefile
index 38f638a04de6..7fb61d0423df 100644
--- a/usr.bin/du/Makefile
+++ b/usr.bin/du/Makefile
@@ -3,7 +3,7 @@
 
 PACKAGE=	runtime
 PROG=	du
-LIBADD=	util
+LIBADD=	xo util
 
 HAS_TESTS=
 SUBDIR.${MK_TESTS}+=	tests
diff --git a/usr.bin/du/du.1 b/usr.bin/du/du.1
index 931ca137ee9b..568fded38073 100644
--- a/usr.bin/du/du.1
+++ b/usr.bin/du/du.1
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd August 1, 2019
+.Dd April 29, 2024
 .Dt DU 1
 .Os
 .Sh NAME
@@ -33,6 +33,7 @@
 .Nd display disk usage statistics
 .Sh SYNOPSIS
 .Nm
+.Op Fl -libxo
 .Op Fl Aclnx
 .Op Fl H | L | P
 .Op Fl g | h | k | m
@@ -52,6 +53,13 @@ the current directory is displayed.
 .Pp
 The options are as follows:
 .Bl -tag -width indent
+.It Fl -libxo
+Generate output via
+.Xr libxo 3
+in a selection of different human and machine readable formats.
+See
+.Xr xo_parse_args 3
+for details on command line arguments.
 .It Fl A
 Display the apparent size instead of the disk usage.
 This can be helpful when operating on compressed volumes or sparse files.
@@ -216,6 +224,8 @@ Also display a grand total at the end:
 .Xr df 1 ,
 .Xr chflags 2 ,
 .Xr fts 3 ,
+.Xr libxo 3 ,
+.Xr xo_parse_args 3 ,
 .Xr symlink 7 ,
 .Xr quot 8
 .Sh STANDARDS
diff --git a/usr.bin/du/du.c b/usr.bin/du/du.c
index cda2470ccca9..96ad7c037dfd 100644
--- a/usr.bin/du/du.c
+++ b/usr.bin/du/du.c
@@ -48,6 +48,7 @@
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
+#include <libxo/xo.h>
 
 #define SI_OPT	(CHAR_MAX + 1)
 
@@ -62,7 +63,7 @@ struct ignentry {
 
 static int	linkchk(FTSENT *);
 static void	usage(void);
-static void	prthumanval(int64_t);
+static void	prthumanval(const char *, int64_t);
 static void	ignoreadd(const char *);
 static void	ignoreclean(void);
 static int	ignorep(FTSENT *);
@@ -107,6 +108,10 @@ main(int argc, char *argv[])
 	depth = INT_MAX;
 	SLIST_INIT(&ignores);
 
+	argc = xo_parse_args(argc, argv);
+	if (argc < 0)
+		exit(EX_USAGE);
+
 	while ((ch = getopt_long(argc, argv, "+AB:HI:LPasd:cghklmnrt:x",
 	    long_options, NULL)) != -1)
 		switch (ch) {
@@ -117,7 +122,7 @@ main(int argc, char *argv[])
 			errno = 0;
 			cblocksize = atoi(optarg);
 			if (errno == ERANGE || cblocksize <= 0) {
-				warnx("invalid argument to option B: %s",
+				xo_warnx("invalid argument to option B: %s",
 				    optarg);
 				usage();
 			}
@@ -147,7 +152,7 @@ main(int argc, char *argv[])
 			errno = 0;
 			depth = atoi(optarg);
 			if (errno == ERANGE || depth < 0) {
-				warnx("invalid argument to option d: %s",
+				xo_warnx("invalid argument to option d: %s",
 				    optarg);
 				usage();
 			}
@@ -181,7 +186,7 @@ main(int argc, char *argv[])
 		case 't' :
 			if (expand_number(optarg, &threshold) != 0 ||
 			    threshold == 0) {
-				warnx("invalid threshold: %s", optarg);
+				xo_warnx("invalid threshold: %s", optarg);
 				usage();
 			} else if (threshold < 0)
 				threshold_sign = -1;
@@ -254,6 +259,8 @@ main(int argc, char *argv[])
 	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
 		err(1, "fts_open");
 
+	xo_open_container("disk-usage-information");
+	xo_open_list("paths");
 	while (errno = 0, (p = fts_read(fts)) != NULL) {
 		switch (p->fts_info) {
 		case FTS_D:			/* Ignore. */
@@ -273,15 +280,18 @@ main(int argc, char *argv[])
 			if (p->fts_level <= depth && threshold <=
 			    threshold_sign * howmany(p->fts_bignum *
 			    cblocksize, blocksize)) {
+				xo_open_instance("paths");
 				if (hflag > 0) {
-					prthumanval(p->fts_bignum);
-					(void)printf("\t%s\n", p->fts_path);
+					prthumanval("{:blocks/%4s}",
+					    p->fts_bignum);
+					xo_emit("\t{:path/%s}\n", p->fts_path);
 				} else {
-					(void)printf("%jd\t%s\n",
+					xo_emit("{:blocks/%jd}\t{:path/%s}\n",
 					    (intmax_t)howmany(p->fts_bignum *
 					    cblocksize, blocksize),
 					    p->fts_path);
 				}
+				xo_close_instance("paths");
 			}
 			if (info) {
 				info = 0;
@@ -293,7 +303,7 @@ main(int argc, char *argv[])
 		case FTS_DNR:			/* Warn, continue. */
 		case FTS_ERR:
 		case FTS_NS:
-			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			xo_warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
 			rval = 1;
 			break;
 		default:
@@ -309,36 +319,43 @@ main(int argc, char *argv[])
 			    howmany(p->fts_statp->st_blocks, cblocksize);
 
 			if (aflag || p->fts_level == 0) {
+				xo_open_instance("paths");
 				if (hflag > 0) {
-					prthumanval(curblocks);
-					(void)printf("\t%s\n", p->fts_path);
+					prthumanval("{:blocks/%4s}", curblocks);
+					xo_emit("\t{:path/%s}\n", p->fts_path);
 				} else {
-					(void)printf("%jd\t%s\n",
+					xo_emit("{:blocks/%jd}\t{:path/%s}\n",
 					    (intmax_t)howmany(curblocks *
 					    cblocksize, blocksize),
 					    p->fts_path);
 				}
+				xo_close_instance("paths");
 			}
 
 			p->fts_parent->fts_bignum += curblocks;
 		}
 		savednumber = p->fts_parent->fts_bignum;
 	}
+	xo_close_list("paths");
 
 	if (errno)
-		err(1, "fts_read");
+		xo_err(1, "fts_read");
 
 	if (cflag) {
 		if (hflag > 0) {
-			prthumanval(savednumber);
-			(void)printf("\ttotal\n");
+			prthumanval("{:total-blocks/%4s}\ttotal\n",
+			    savednumber);
 		} else {
-			(void)printf("%jd\ttotal\n", (intmax_t)howmany(
+			xo_emit("{:total-blocks/%jd}\ttotal\n",
+			    (intmax_t)howmany(
 			    savednumber * cblocksize, blocksize));
 		}
 	}
 
 	ignoreclean();
+	xo_close_container("disk-usage-information");
+	if (xo_finish() < 0)
+		xo_err(1, "stdout");
 	exit(rval);
 }
 
@@ -392,7 +409,7 @@ linkchk(FTSENT *p)
 
 		if (new_buckets == NULL) {
 			stop_allocating = 1;
-			warnx("No more memory for tracking hard links");
+			xo_warnx("No more memory for tracking hard links");
 		} else {
 			for (i = 0; i < number_buckets; i++) {
 				while (buckets[i] != NULL) {
@@ -458,7 +475,7 @@ linkchk(FTSENT *p)
 		le = malloc(sizeof(struct links_entry));
 	if (le == NULL) {
 		stop_allocating = 1;
-		warnx("No more memory for tracking hard links");
+		xo_warnx("No more memory for tracking hard links");
 		return (0);
 	}
 	le->dev = st->st_dev;
@@ -474,7 +491,7 @@ linkchk(FTSENT *p)
 }
 
 static void
-prthumanval(int64_t bytes)
+prthumanval(const char *fmt, int64_t bytes)
 {
 	char buf[5];
 	int flags;
@@ -488,13 +505,13 @@ prthumanval(int64_t bytes)
 
 	humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, flags);
 
-	(void)printf("%4s", buf);
+	xo_emit(fmt, buf);
 }
 
 static void
 usage(void)
 {
-	(void)fprintf(stderr,
+	xo_error(
 		"usage: du [-Aclnx] [-H | -L | -P] [-g | -h | -k | -m] "
 		"[-a | -s | -d depth] [-B blocksize] [-I mask] "
 		"[-t threshold] [file ...]\n");