diff options
Diffstat (limited to 'usr/src/lib/libcmdutils')
-rw-r--r-- | usr/src/lib/libcmdutils/Makefile.com | 2 | ||||
-rw-r--r-- | usr/src/lib/libcmdutils/common/mapfile-vers | 2 | ||||
-rw-r--r-- | usr/src/lib/libcmdutils/common/nicenum.c | 115 | ||||
-rw-r--r-- | usr/src/lib/libcmdutils/libcmdutils.h | 8 |
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 |