summaryrefslogtreecommitdiff
path: root/usr/src/lib/libcmdutils
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libcmdutils')
-rw-r--r--usr/src/lib/libcmdutils/Makefile.com2
-rw-r--r--usr/src/lib/libcmdutils/common/mapfile-vers2
-rw-r--r--usr/src/lib/libcmdutils/common/nicenum.c115
-rw-r--r--usr/src/lib/libcmdutils/libcmdutils.h8
4 files changed, 126 insertions, 1 deletions
diff --git a/usr/src/lib/libcmdutils/Makefile.com b/usr/src/lib/libcmdutils/Makefile.com
index ffe3c9cba5..9cb35f8795 100644
--- a/usr/src/lib/libcmdutils/Makefile.com
+++ b/usr/src/lib/libcmdutils/Makefile.com
@@ -26,7 +26,7 @@
LIBRARY= libcmdutils.a
VERS= .1
CMD_OBJS= avltree.o sysattrs.o writefile.o process_xattrs.o uid.o gid.o \
- custr.o
+ custr.o nicenum.o
COM_OBJS= list.o
OBJECTS= $(CMD_OBJS) $(COM_OBJS)
diff --git a/usr/src/lib/libcmdutils/common/mapfile-vers b/usr/src/lib/libcmdutils/common/mapfile-vers
index 1f63d4eee0..0ac77eb010 100644
--- a/usr/src/lib/libcmdutils/common/mapfile-vers
+++ b/usr/src/lib/libcmdutils/common/mapfile-vers
@@ -72,6 +72,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
list_remove_head;
list_remove_tail;
list_tail;
+ nicenum;
+ nicenum_scale;
tnode_compare;
sysattr_type;
sysattr_support;
diff --git a/usr/src/lib/libcmdutils/common/nicenum.c b/usr/src/lib/libcmdutils/common/nicenum.c
new file mode 100644
index 0000000000..ca5f15b4cf
--- /dev/null
+++ b/usr/src/lib/libcmdutils/common/nicenum.c
@@ -0,0 +1,115 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Jason king
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "libcmdutils.h"
+
+#define INDEX_MAX (7) /* the largest prefix supported */
+
+void
+nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
+ uint32_t flags)
+{
+ uint64_t divamt = 1024;
+ uint64_t divisor = 1;
+ int index = 0;
+ int rc = 0;
+ char u;
+
+ if (units == 0)
+ units = 1;
+
+ if (n > 0) {
+ n *= units;
+ if (n < units)
+ goto overflow;
+ }
+
+ if (flags & NN_DIVISOR_1000)
+ divamt = 1000;
+
+ while (index < INDEX_MAX) {
+ uint64_t newdiv = divisor * divamt;
+
+ if (newdiv < divamt)
+ goto overflow;
+
+ if (n < newdiv)
+ break;
+
+ divisor = newdiv;
+ index++;
+ }
+
+ u = " KMGTPE"[index];
+
+ if (index == 0) {
+ rc = snprintf(buf, buflen, "%llu", n);
+ } else if (n % divisor == 0) {
+ /*
+ * If this is an even multiple of the base, always display
+ * without any decimal precision.
+ */
+ rc = snprintf(buf, buflen, "%llu%c", n / divisor, u);
+ } else {
+ /*
+ * We want to choose a precision that reflects the best choice
+ * for fitting in 5 characters. This can get rather tricky
+ * when we have numbers that are very close to an order of
+ * magnitude. For example, when displaying 10239 (which is
+ * really 9.999K), we want only a single place of precision
+ * for 10.0K. We could develop some complex heuristics for
+ * this, but it's much easier just to try each combination
+ * in turn.
+ */
+ int i;
+ for (i = 2; i >= 0; i--) {
+ if ((rc = snprintf(buf, buflen, "%.*f%c", i,
+ (double)n / divisor, u)) <= 5)
+ break;
+ }
+ }
+
+ if (rc + 1 > buflen || rc < 0)
+ goto overflow;
+
+ return;
+
+overflow:
+ /* prefer a more verbose message if possible */
+ if (buflen > 10)
+ (void) strlcpy(buf, "<overflow>", buflen);
+ else
+ (void) strlcpy(buf, "??", buflen);
+}
+
+void
+nicenum(uint64_t num, char *buf, size_t buflen)
+{
+ nicenum_scale(num, 1, buf, buflen, 0);
+}
diff --git a/usr/src/lib/libcmdutils/libcmdutils.h b/usr/src/lib/libcmdutils/libcmdutils.h
index 933ceb0fde..5f9957b861 100644
--- a/usr/src/lib/libcmdutils/libcmdutils.h
+++ b/usr/src/lib/libcmdutils/libcmdutils.h
@@ -216,6 +216,14 @@ extern void custr_reset(custr_t *);
*/
extern const char *custr_cstr(custr_t *str);
+#define NN_DIVISOR_1000 (1U << 0)
+
+/* Minimum size for the output of nicenum, including NULL */
+#define NN_NUMBUF_SZ (6)
+
+void nicenum(uint64_t, char *, size_t);
+void nicenum_scale(uint64_t, size_t, char *, size_t, uint32_t);
+
#ifdef __cplusplus
}
#endif