From 12aea7ca34caaa4af42b1bead712b6845447d47e Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 7 Nov 2010 09:20:11 -0800 Subject: [PATCH] libutil - Add humanize_unsigned() * 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 --- lib/libutil/Makefile | 5 +- lib/libutil/humanize_unsigned.3 | 125 ++++++++++++++++++++++++++++++++++++++++ lib/libutil/humanize_unsigned.c | 107 ++++++++++++++++++++++++++++++++++ lib/libutil/libutil.h | 3 + 4 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 lib/libutil/humanize_unsigned.3 create mode 100644 lib/libutil/humanize_unsigned.c diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 9f8db8ee57..3a81293461 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -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 index 0000000000..c571c003db --- /dev/null +++ b/lib/libutil/humanize_unsigned.3 @@ -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 index 0000000000..cc788fc0b0 --- /dev/null +++ b/lib/libutil/humanize_unsigned.c @@ -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 +#include + +#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); +} diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index e00676c37d..77bf3df7c9 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -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 *); -- 2.11.4.GIT