libutil - Add humanize_unsigned()
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 7 Nov 2010 17:20:11 +0000 (09:20 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 18 Nov 2010 17:42:23 +0000 (09:42 -0800)
* Add a humanize_unsigned() function as a companion to humanize_number()
  which does a much better job on large unsigned 64-bit quantities.

Submitted-by: Ilya Dryomov <idryomov@gmail.com>
lib/libutil/Makefile
lib/libutil/humanize_unsigned.3 [new file with mode: 0644]
lib/libutil/humanize_unsigned.c [new file with mode: 0644]
lib/libutil/libutil.h

index 9f8db8e..3a81293 100644 (file)
@@ -10,7 +10,7 @@ SRCS= flopen.c login.c login_tty.c logout.c logwtmp.c pty.c \
        login_cap.c login_class.c login_auth.c login_times.c login_ok.c \
        login_crypt.c _secure_path.c uucplock.c property.c auth.c \
        realhostname.c fparseln.c stub.c pidfile.c trimdomain.c \
-       dehumanize_number.c humanize_number.c pw_util.c
+       dehumanize_number.c humanize_number.c humanize_unsigned.c pw_util.c
 INCS=  libutil.h login_cap.h
 WARNS?=        3
 
@@ -20,13 +20,14 @@ MAN+=       flopen.3 login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
        login_cap.3 login_class.3 login_times.3 login_ok.3 \
        _secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
        realhostname_sa.3 trimdomain.3 fparseln.3 pidfile.3 \
-       humanize_number.3
+       humanize_number.3 humanize_unsigned.3
 MAN+=  login.conf.5 auth.conf.5
 MLINKS+= property.3 properties_read.3  property.3 properties_free.3
 MLINKS+= property.3 property_find.3
 MLINKS+= auth.3 auth_getval.3
 MLINKS+= pty.3 openpty.3  pty.3 forkpty.3
 MLINKS+=humanize_number.3 dehumanize_number.3
+MLINKS+=humanize_unsigned.3 format_bytes.3
 MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \
        login_cap.3 login_getclass.3 login_cap.3 login_getuserclass.3 \
        login_cap.3 login_getcapstr.3 login_cap.3 login_getcaplist.3 \
diff --git a/lib/libutil/humanize_unsigned.3 b/lib/libutil/humanize_unsigned.3
new file mode 100644 (file)
index 0000000..c571c00
--- /dev/null
@@ -0,0 +1,125 @@
+.\"    $NetBSD: humanize_number.9,v 1.9 2010/08/07 16:41:34 jruoho Exp $
+.\"
+.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd November 3, 2010
+.Dt HUMANIZE_UNSIGNED 3
+.Os
+.Sh NAME
+.Nm humanize_unsigned ,
+.Nm format_bytes
+.Nd human readable numbers
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft int
+.Fn humanize_unsigned \
+"char *buf" "size_t len" "uint64_t number" "const char *suffix" "int divisor"
+.Ft int
+.Fn format_bytes "char *buf" "size_t len" "uint64_t number"
+.Sh DESCRIPTION
+The
+.Fn humanize_unsigned
+function formats the unsigned 64-bit quantity given in
+.Fa number
+into
+.Fa buf .
+A space and then
+.Fa suffix
+is appended to the end.
+The supplied
+.Fa buf
+must be at least
+.Fa len
+bytes long.
+.Pp
+If the formatted number (including
+.Fa suffix )
+is too long to fit into
+.Fa buf ,
+.Fn humanize_unsigned
+divides
+.Fa number
+by
+.Fa divisor
+until it will fit.
+In this case,
+.Fa suffix
+is prefixed with the appropriate SI designator.
+Suitable values of
+.Fa divisor
+are 1024 or 1000 to remain consistent with the common meanings of the
+SI designator prefixes.
+.Pp
+The prefixes are:
+.Bl -column "Prefix" "Description" "Multiplier" -offset indent
+.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier"
+.It k  kilo    1024
+.It M  mega    1048576
+.It G  giga    1073741824
+.It T  tera    1099511627776
+.It P  peta    1125899906842624
+.It E  exa     1152921504606846976
+.El
+.Pp
+The
+.Fa len
+argument must be at least 4 plus the length of
+.Fa suffix ,
+in order to ensure a useful result in
+.Fa buf .
+.Pp
+The
+.Fn format_bytes
+function
+is a front-end to
+.Fn humanize_unsigned .
+It calls the latter with a
+.Fa suffix
+of
+.Dq B .
+Also, if the suffix in the returned
+.Fa buf
+would not have a prefix, the suffix is removed.
+This means that a result of
+.Dq 100000
+occurs, instead of
+.Dq 100000 B .
+.Sh RETURN VALUES
+Both functions return the number of characters stored in
+.Fa buf
+(excluding the terminating NUL) upon success, or \-1 upon failure.
+.Sh SEE ALSO
+.Xr humanize_number 3
+.Sh HISTORY
+These functions first appeared in
+.Nx 1.5
+and were later ported to
+.Dx 2.9 .
diff --git a/lib/libutil/humanize_unsigned.c b/lib/libutil/humanize_unsigned.c
new file mode 100644 (file)
index 0000000..cc788fc
--- /dev/null
@@ -0,0 +1,107 @@
+/*     $NetBSD: subr_humanize.c,v 1.1 2009/10/02 15:48:41 pooka Exp $  */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libutil.h"
+
+/*
+ * snprintf() `bytes' into `buf', reformatting it so that the number,
+ * plus a possible `x' + suffix extension) fits into len bytes (including
+ * the terminating NUL).
+ * Returns the number of bytes stored in buf, or -1 if there was a problem.
+ * E.g, given a len of 9 and a suffix of `B':
+ *     bytes           result
+ *     -----           ------
+ *     99999           `99999 B'
+ *     100000          `97 kB'
+ *     66715648        `65152 kB'
+ *     252215296       `240 MB'
+ */
+int
+humanize_unsigned(char *buf, size_t len, uint64_t bytes, const char *suffix,
+    int divisor)
+{
+       /* prefixes are: (none), kilo, Mega, Giga, Tera, Peta, Exa */
+       const char *prefixes;
+       int             r;
+       uint64_t        umax;
+       size_t          i, suffixlen;
+
+       if (buf == NULL || suffix == NULL)
+               return (-1);
+       if (len > 0)
+               buf[0] = '\0';
+       suffixlen = strlen(suffix);
+       /* check if enough room for `x y' + suffix + `\0' */
+       if (len < 4 + suffixlen)
+               return (-1);
+
+       if (divisor == 1024) {
+               /*
+                * binary multiplies
+                * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+                */
+               prefixes = " KMGTPE";
+       } else
+               prefixes = " kMGTPE"; /* SI for decimal multiplies */
+
+       umax = 1;
+       for (i = 0; i < len - suffixlen - 3; i++) {
+               umax *= 10;
+               if (umax > bytes)
+                       break;
+       }
+       for (i = 0; bytes >= umax && prefixes[i + 1]; i++)
+               bytes /= divisor;
+
+       r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes,
+           i == 0 ? "" : " ", prefixes[i], suffix);
+
+       return (r);
+}
+
+int
+format_bytes(char *buf, size_t len, uint64_t bytes)
+{
+       int     rv;
+       size_t  nlen;
+
+       rv = humanize_unsigned(buf, len, bytes, "B", 1024);
+       if (rv != -1) {
+                       /* nuke the trailing ` B' if it exists */
+               nlen = strlen(buf) - 2;
+               if (strcmp(&buf[nlen], " B") == 0)
+                       buf[nlen] = '\0';
+       }
+       return (rv);
+}
index e00676c..77bf3df 100644 (file)
@@ -73,6 +73,9 @@ int   openpty(int *, int *, char *, struct termios *, struct winsize *);
 int    forkpty(int *, char *, struct termios *, struct winsize *);
 int    dehumanize_number(const char *, int64_t *);
 int    humanize_number(char *, size_t, int64_t, const char *, int, int);
+int    humanize_unsigned(char *buf, size_t len, uint64_t bytes,
+                                       const char *suffix, int divisor);
+int    format_bytes(char *buf, size_t len, uint64_t bytes);
 const char *uu_lockerr(int);
 int    uu_lock(const char *);
 int    uu_unlock(const char *);