Subject: bin/23870: humanize ls(1)
To: None <gnats-bugs@gnats.netbsd.org>
From: None <daver@metropolis.localnet.gomerbud.com>
List: netbsd-bugs
Date: 12/24/2003 01:30:37
>Number:         23870
>Category:       bin
>Synopsis:       humanize ls(1)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Dec 24 12:21:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     David P. Reese Jr.
>Release:        NetBSD 1.6ZG
>Organization:
	
>Environment:
	
	
System: NetBSD metropolis.localnet.gomerbud.com 1.6ZG NetBSD 1.6ZG (METROPOLIS) #8: Sun Dec 21 02:03:41 PST 2003 daver@metropolis.localnet.gomerbud.com:/home/daver/netbsd/src/sys/arch/i386/compile/METROPOLIS i386
Architecture: i386
Machine: i386
>Description:
ls(1) does not yet humanize it's output.
>How-To-Repeat:
man 1 ls
>Fix:
Index: ls.1
===================================================================
RCS file: /cvsroot/src/bin/ls/ls.1,v
retrieving revision 1.46
diff -u -u -r1.46 ls.1
--- ls.1	2003/09/22 06:01:43	1.46
+++ ls.1	2003/12/24 12:18:43
@@ -40,7 +40,7 @@
 .Nd list directory contents
 .Sh SYNOPSIS
 .Nm
-.Op Fl AaBbCcdFfgikLlmnopqRrSsTtuWwx1
+.Op Fl AaBbCcdFfghikLlmnopqRrSsTtuWwx1
 .Op Ar
 .Sh DESCRIPTION
 For each operand that names a
@@ -117,6 +117,13 @@
 The same as
 .Fl l ,
 except that the owner is not printed.
+.It Fl h
+Modifies the
+.Fl s
+and
+.Fl l
+options, causing the sizes to be reported in bytes displayed in a human
+readable format.
 .It Fl i
 For each file, print the file's file serial number (inode number).
 .It Fl k
Index: ls.c
===================================================================
RCS file: /cvsroot/src/bin/ls/ls.c,v
retrieving revision 1.52
diff -u -u -r1.52 ls.c
--- ls.c	2003/09/22 02:43:20	1.52
+++ ls.c	2003/12/24 12:18:43
@@ -88,6 +88,7 @@
 int f_columnacross;		/* columnated format, sorted across */
 int f_flags;			/* show flags associated with a file */
 int f_grouponly;		/* long listing without owner */
+int f_humanize;			/* humanize the size field */
 int f_inode;			/* print inode */
 int f_listdir;			/* list actual directory, not contents */
 int f_listdot;			/* list files beginning with . */
@@ -135,7 +136,7 @@
 		f_listdot = 1;
 
 	fts_options = FTS_PHYSICAL;
-	while ((ch = getopt(argc, argv, "1ABCFLRSTWabcdfgiklmnopqrstuwx")) != -1) {
+	while ((ch = getopt(argc, argv, "1ABCFLRSTWabcdfghiklmnopqrstuwx")) != -1) {
 		switch (ch) {
 		/*
 		 * The -1, -C, -l, -m and -x options all override each other so
@@ -223,6 +224,13 @@
 			blocksize = 1024;
 			kflag = 1;
 			break;
+		/*
+		 * The -h option forces all sizes to be measured in bytes.
+		 * It also makes -l suppress -s.
+		 */
+		case 'h':
+			f_humanize = 1;
+			break;
 		case 'n':
 			f_numericonly = 1;
 			break;
@@ -442,7 +450,7 @@
 	DISPLAY d;
 	FTSENT *cur;
 	NAMES *np;
-	u_int64_t btotal, maxblock, maxsize;
+	u_int64_t btotal, stotal, maxblock, maxsize;
 	int maxinode, maxnlink, maxmajor, maxminor;
 	int bcfile, entries, flen, glen, ulen, maxflags, maxgroup, maxlen;
 	int maxuser, needstats;
@@ -471,7 +479,7 @@
 	maxinode = maxnlink = 0;
 	bcfile = 0;
 	maxuser = maxgroup = maxflags = maxlen = 0;
-	btotal = maxblock = maxsize = 0;
+	btotal = stotal = maxblock = maxsize = 0;
 	maxmajor = maxminor = 0;
 	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
 		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
@@ -520,6 +528,7 @@
 			}
 
 			btotal += sp->st_blocks;
+			stotal += sp->st_size;
 			if (f_longform) {
 				if (f_numericonly ||
 				    (user = user_from_uid(sp->st_uid, 0)) ==
@@ -574,17 +583,24 @@
 	d.maxlen = maxlen;
 	if (needstats) {
 		d.btotal = btotal;
-		(void)snprintf(buf, sizeof(buf), "%llu",
-		    (long long)howmany(maxblock, blocksize));
-		d.s_block = strlen(buf);
+		d.stotal = stotal;
+		if (!f_humanize) {
+			(void)snprintf(buf, sizeof(buf), "%llu",
+			    (long long)howmany(maxblock, blocksize));
+			d.s_block = strlen(buf);
+		}
 		d.s_flags = maxflags;
 		d.s_group = maxgroup;
 		(void)snprintf(buf, sizeof(buf), "%u", maxinode);
 		d.s_inode = strlen(buf);
 		(void)snprintf(buf, sizeof(buf), "%u", maxnlink);
 		d.s_nlink = strlen(buf);
-		(void)snprintf(buf, sizeof(buf), "%llu", (long long)maxsize);
-		d.s_size = strlen(buf);
+		if (f_humanize) {
+			d.s_size = 4; /* min buffer length for humanize_number */
+		} else {
+			(void)snprintf(buf, sizeof(buf), "%llu", (long long)maxsize);
+			d.s_size = strlen(buf);
+		}
 		d.s_user = maxuser;
 		if (bcfile) {
 			(void)snprintf(buf, sizeof(buf), "%u", maxmajor);
Index: ls.h
===================================================================
RCS file: /cvsroot/src/bin/ls/ls.h,v
retrieving revision 1.15
diff -u -u -r1.15 ls.h
--- ls.h	2003/09/22 02:43:20	1.15
+++ ls.h	2003/12/24 12:18:43
@@ -41,6 +41,7 @@
 extern int f_accesstime;	/* use time of last access */
 extern int f_flags;		/* show flags associated with a file */
 extern int f_grouponly;		/* long listing without owner */
+extern int f_humanize;		/* humanize size field */
 extern int f_inode;		/* print inode */
 extern int f_longform;		/* long listing format */
 extern int f_octal;		/* print octal escapes for nongraphic characters */
@@ -55,6 +56,7 @@
 typedef struct {
 	FTSENT *list;
 	u_int64_t btotal;
+	u_int64_t stotal;
 	int entries;
 	int maxlen;
 	int s_block;
Index: print.c
===================================================================
RCS file: /cvsroot/src/bin/ls/print.c,v
retrieving revision 1.37
diff -u -u -r1.37 print.c
--- print.c	2003/09/22 02:43:20	1.37
+++ print.c	2003/12/24 12:18:46
@@ -55,6 +55,7 @@
 #include <time.h>
 #include <tzfile.h>
 #include <unistd.h>
+#include <util.h>
 
 #include "ls.h"
 #include "extern.h"
@@ -89,13 +90,22 @@
 	struct stat *sp;
 	FTSENT *p;
 	NAMES *np;
-	char buf[20];
+	char buf[20], szbuf[5];
 
 	now = time(NULL);
 
-	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
-		(void)printf("total %llu\n",
-		    (long long)(howmany(dp->btotal, blocksize)));
+	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) {
+		if (f_humanize) {
+			if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal,
+			    "", HN_AUTOSCALE,
+			    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+				err(1, "humanize_number");
+			(void)printf("total %s\n", szbuf);
+		} else {
+			(void)printf("total %llu\n",
+			    (long long)(howmany(dp->btotal, blocksize)));
+		}
+	}
 
 	for (p = dp->list; p; p = p->fts_link) {
 		if (IS_NOPRINT(p))
@@ -104,9 +114,10 @@
 		if (f_inode)
 			(void)printf("%*lu ", dp->s_inode,
 			    (unsigned long)sp->st_ino);
-		if (f_size)
+		if (f_size && !f_humanize) {
 			(void)printf("%*llu ", dp->s_block,
 			    (long long)howmany(sp->st_blocks, blocksize));
+		}
 		(void)strmode(sp->st_mode, buf);
 		np = p->fts_pointer;
 		(void)printf("%s %*lu ", buf, dp->s_nlink,
@@ -121,8 +132,16 @@
 			    dp->s_major, major(sp->st_rdev), dp->s_minor,
 			    minor(sp->st_rdev));
 		else
-			(void)printf("%*llu ", dp->s_size,
-			    (long long)sp->st_size);
+			if (f_humanize) {
+				if ((humanize_number(szbuf, sizeof(szbuf),
+				    sp->st_size, "", HN_AUTOSCALE,
+				    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+					err(1, "humanize_number");
+				(void)printf("%*s ", dp->s_size, szbuf);
+			} else {
+				(void)printf("%*llu ", dp->s_size,
+				    (long long)sp->st_size);
+			}
 		if (f_accesstime)
 			printtime(sp->st_atime);
 		else if (f_statustime)
@@ -152,12 +171,17 @@
 	FTSENT *p;
 	int base, chcnt, col, colwidth, num;
 	int numcols, numrows, row;
+	char szbuf[5];
 
 	colwidth = dp->maxlen;
 	if (f_inode)
 		colwidth += dp->s_inode + 1;
-	if (f_size)
-		colwidth += dp->s_block + 1;
+	if (f_size) {
+		if (f_humanize)
+			colwidth += dp->s_size + 1;
+		else
+			colwidth += dp->s_block + 1;
+	}
 	if (f_type || f_typedir)
 		colwidth += 1;
 
@@ -190,13 +214,22 @@
 	if (num % numcols)
 		++numrows;
 
-	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
-		(void)printf("total %llu\n",
-		    (long long)(howmany(dp->btotal, blocksize)));
+	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) {
+		if (f_humanize) {
+			if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal,
+			    "", HN_AUTOSCALE,
+			    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+				err(1, "humanize_number");
+			(void)printf("total %s\n", szbuf);
+		} else {
+			(void)printf("total %llu\n",
+			    (long long)(howmany(dp->btotal, blocksize)));
+		}
+	}
 	for (row = 0; row < numrows; ++row) {
 		for (base = row, chcnt = col = 0; col < numcols; ++col) {
 			chcnt = printaname(array[base], dp->s_inode,
-			    dp->s_block);
+			    f_humanize ? dp->s_size : dp->s_block);
 			if ((base += numrows) >= num)
 				break;
 			while (chcnt++ < colwidth)
@@ -212,12 +245,17 @@
 	FTSENT *p;
 	int chcnt, col, colwidth;
 	int numcols;
+	char szbuf[5];
 
 	colwidth = dp->maxlen;
 	if (f_inode)
 		colwidth += dp->s_inode + 1;
-	if (f_size)
-		colwidth += dp->s_block + 1;
+	if (f_size) {
+		if (f_humanize)
+			colwidth += dp->s_size + 1;
+		else
+			colwidth += dp->s_block + 1;
+	}
 	if (f_type || f_typedir)
 		colwidth += 1;
 
@@ -231,9 +269,18 @@
 	numcols = termwidth / colwidth;
 	colwidth = termwidth / numcols;		/* spread out if possible */
 
-	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
-		(void)printf("total %llu\n",
-		    (long long)(howmany(dp->btotal, blocksize)));
+	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) {
+		if (f_humanize) {
+			if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal,
+			    "", HN_AUTOSCALE,
+			    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+				err(1, "humanize_number");
+			(void)printf("total %s\n", szbuf);
+		} else {
+			(void)printf("total %llu\n",
+			    (long long)(howmany(dp->btotal, blocksize)));
+		}
+	}
 	chcnt = col = 0;
 	for (p = dp->list; p; p = p->fts_link) {
 		if (IS_NOPRINT(p))
@@ -242,7 +289,8 @@
 			chcnt = col = 0;
 			(void)putchar('\n');
 		}
-		chcnt = printaname(p, dp->s_inode, dp->s_block);
+		chcnt = printaname(p, dp->s_inode,
+		    f_humanize ? dp->s_size : dp->s_block);
 		while (chcnt++ < colwidth)
 			(void)putchar(' ');
 		col++;
@@ -260,8 +308,12 @@
 	extwidth = 0;
 	if (f_inode)
 		extwidth += dp->s_inode + 1;
-	if (f_size)
-		extwidth += dp->s_block + 1;
+	if (f_size) {
+		if (f_humanize)
+			extwidth += dp->s_size + 1;
+		else 
+			extwidth += dp->s_block + 1;
+	}
 	if (f_type)
 		extwidth += 1;
 
@@ -275,7 +327,8 @@
 			else
 				(void)putchar(' '), col++;
 		}
-		col += printaname(p, dp->s_inode, dp->s_block);
+		col += printaname(p, dp->s_inode,
+		    f_humanize ? dp->s_size : dp->s_block);
 	}
 	(void)putchar('\n');
 }
@@ -289,14 +342,24 @@
 {
 	struct stat *sp;
 	int chcnt;
+	char szbuf[5];
 
 	sp = p->fts_statp;
 	chcnt = 0;
 	if (f_inode)
 		chcnt += printf("%*lu ", inodefield, (unsigned long)sp->st_ino);
-	if (f_size)
-		chcnt += printf("%*llu ", sizefield,
-		    (long long)howmany(sp->st_blocks, blocksize));
+	if (f_size) {
+		if (f_humanize) {
+			if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size,
+			    "", HN_AUTOSCALE,
+			    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+				err(1, "humanize_number");
+			chcnt += printf("%*s ", sizefield, szbuf);
+		} else {
+			chcnt += printf("%*llu ", sizefield,
+			    (long long)howmany(sp->st_blocks, blocksize));
+		}
+	}
 	if (f_octal || f_octal_escape)
 		chcnt += safe_print(p->fts_name);
 	else if (f_nonprint)
>Release-Note:
>Audit-Trail:
>Unformatted: