123d1a178SPawel Jakub Dawidek /* $NetBSD: humanize_number.c,v 1.5 2003/12/26 11:30:36 simonb Exp $ */ 223d1a178SPawel Jakub Dawidek 323d1a178SPawel Jakub Dawidek /* 423d1a178SPawel Jakub Dawidek * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. 523d1a178SPawel Jakub Dawidek * All rights reserved. 623d1a178SPawel Jakub Dawidek * 723d1a178SPawel Jakub Dawidek * This code is derived from software contributed to The NetBSD Foundation 823d1a178SPawel Jakub Dawidek * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 923d1a178SPawel Jakub Dawidek * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson. 1023d1a178SPawel Jakub Dawidek * 1123d1a178SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 1223d1a178SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 1323d1a178SPawel Jakub Dawidek * are met: 1423d1a178SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 1523d1a178SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 1623d1a178SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 1723d1a178SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 1823d1a178SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 1923d1a178SPawel Jakub Dawidek * 3. All advertising materials mentioning features or use of this software 2023d1a178SPawel Jakub Dawidek * must display the following acknowledgement: 2123d1a178SPawel Jakub Dawidek * This product includes software developed by the NetBSD 2223d1a178SPawel Jakub Dawidek * Foundation, Inc. and its contributors. 2323d1a178SPawel Jakub Dawidek * 4. Neither the name of The NetBSD Foundation nor the names of its 2423d1a178SPawel Jakub Dawidek * contributors may be used to endorse or promote products derived 2523d1a178SPawel Jakub Dawidek * from this software without specific prior written permission. 2623d1a178SPawel Jakub Dawidek * 2723d1a178SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2823d1a178SPawel Jakub Dawidek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2923d1a178SPawel Jakub Dawidek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 3023d1a178SPawel Jakub Dawidek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3123d1a178SPawel Jakub Dawidek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3223d1a178SPawel Jakub Dawidek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3323d1a178SPawel Jakub Dawidek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3423d1a178SPawel Jakub Dawidek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3523d1a178SPawel Jakub Dawidek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3623d1a178SPawel Jakub Dawidek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3723d1a178SPawel Jakub Dawidek * POSSIBILITY OF SUCH DAMAGE. 3823d1a178SPawel Jakub Dawidek */ 3923d1a178SPawel Jakub Dawidek 4023d1a178SPawel Jakub Dawidek #include <sys/cdefs.h> 4123d1a178SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 4223d1a178SPawel Jakub Dawidek 4323d1a178SPawel Jakub Dawidek #include <sys/types.h> 4423d1a178SPawel Jakub Dawidek #include <assert.h> 4523d1a178SPawel Jakub Dawidek #include <stdio.h> 4623d1a178SPawel Jakub Dawidek #include <stdlib.h> 4723d1a178SPawel Jakub Dawidek #include <string.h> 4823d1a178SPawel Jakub Dawidek #include <locale.h> 4923d1a178SPawel Jakub Dawidek #include <libutil.h> 5023d1a178SPawel Jakub Dawidek 5123d1a178SPawel Jakub Dawidek int 5223d1a178SPawel Jakub Dawidek humanize_number(char *buf, size_t len, int64_t bytes, 5323d1a178SPawel Jakub Dawidek const char *suffix, int scale, int flags) 5423d1a178SPawel Jakub Dawidek { 5523d1a178SPawel Jakub Dawidek const char *prefixes; 5623d1a178SPawel Jakub Dawidek int i, r; 5723d1a178SPawel Jakub Dawidek int64_t divisor, max, s1, s2, sign; 5823d1a178SPawel Jakub Dawidek size_t baselen, suffixlen; 5923d1a178SPawel Jakub Dawidek 6023d1a178SPawel Jakub Dawidek assert(buf != NULL); 6123d1a178SPawel Jakub Dawidek assert(suffix != NULL); 6223d1a178SPawel Jakub Dawidek assert(scale >= 0); 6323d1a178SPawel Jakub Dawidek 6423d1a178SPawel Jakub Dawidek if (flags & HN_DIVISOR_1000) { 6523d1a178SPawel Jakub Dawidek /* SI for decimal multiplies */ 6623d1a178SPawel Jakub Dawidek divisor = 1000; 6723d1a178SPawel Jakub Dawidek prefixes = " kMGTPE"; 6823d1a178SPawel Jakub Dawidek } else { 6923d1a178SPawel Jakub Dawidek /* 7023d1a178SPawel Jakub Dawidek * binary multiplies 7123d1a178SPawel Jakub Dawidek * XXX IEC 60027-2 recommends Ki, Mi, Gi... 7223d1a178SPawel Jakub Dawidek */ 7323d1a178SPawel Jakub Dawidek divisor = 1024; 7423d1a178SPawel Jakub Dawidek prefixes = " KMGTPE"; 7523d1a178SPawel Jakub Dawidek } 7623d1a178SPawel Jakub Dawidek 7723d1a178SPawel Jakub Dawidek if ((size_t) scale >= strlen(prefixes) && scale != HN_AUTOSCALE && 7823d1a178SPawel Jakub Dawidek scale != HN_GETSCALE) 7923d1a178SPawel Jakub Dawidek return (-1); 8023d1a178SPawel Jakub Dawidek 8123d1a178SPawel Jakub Dawidek if (buf == NULL || suffix == NULL) 8223d1a178SPawel Jakub Dawidek return (-1); 8323d1a178SPawel Jakub Dawidek 8423d1a178SPawel Jakub Dawidek if (len > 0) 8523d1a178SPawel Jakub Dawidek buf[0] = '\0'; 8623d1a178SPawel Jakub Dawidek if (bytes < 0) { 8723d1a178SPawel Jakub Dawidek sign = -1; 8823d1a178SPawel Jakub Dawidek bytes *= -100; 8923d1a178SPawel Jakub Dawidek baselen = 4; 9023d1a178SPawel Jakub Dawidek } else { 9123d1a178SPawel Jakub Dawidek sign = 1; 9223d1a178SPawel Jakub Dawidek bytes *= 100; 9323d1a178SPawel Jakub Dawidek baselen = 3; 9423d1a178SPawel Jakub Dawidek } 9523d1a178SPawel Jakub Dawidek 9623d1a178SPawel Jakub Dawidek suffixlen = strlen(suffix); 9723d1a178SPawel Jakub Dawidek 9823d1a178SPawel Jakub Dawidek /* check if enough room for `x y' + suffix + `\0' */ 9923d1a178SPawel Jakub Dawidek if (len < baselen + suffixlen + 1) 10023d1a178SPawel Jakub Dawidek return (-1); 10123d1a178SPawel Jakub Dawidek 10223d1a178SPawel Jakub Dawidek if (flags & HN_DIVISOR_1000) 10323d1a178SPawel Jakub Dawidek divisor = 1000; 10423d1a178SPawel Jakub Dawidek else 10523d1a178SPawel Jakub Dawidek divisor = 1024; 10623d1a178SPawel Jakub Dawidek 10723d1a178SPawel Jakub Dawidek max = 100; 10823d1a178SPawel Jakub Dawidek for (i = 0; 10923d1a178SPawel Jakub Dawidek (size_t) i < len - suffixlen - baselen + ((flags & HN_NOSPACE) ? 11023d1a178SPawel Jakub Dawidek 1 : 0); i++) 11123d1a178SPawel Jakub Dawidek max *= 10; 11223d1a178SPawel Jakub Dawidek 11323d1a178SPawel Jakub Dawidek if ((scale & HN_AUTOSCALE) || (scale & HN_GETSCALE)) { 11423d1a178SPawel Jakub Dawidek for (i = 0; bytes >= max && prefixes[i + 1]; i++) 11523d1a178SPawel Jakub Dawidek bytes /= divisor; 11623d1a178SPawel Jakub Dawidek } else { 11723d1a178SPawel Jakub Dawidek for (i = 0; i < scale && prefixes[i + 1]; i++) 11823d1a178SPawel Jakub Dawidek bytes /= divisor; 11923d1a178SPawel Jakub Dawidek } 12023d1a178SPawel Jakub Dawidek 12123d1a178SPawel Jakub Dawidek if (scale & HN_GETSCALE) 12223d1a178SPawel Jakub Dawidek return (i); 12323d1a178SPawel Jakub Dawidek 12423d1a178SPawel Jakub Dawidek if (bytes < 1000 && flags & HN_DECIMAL) { 12523d1a178SPawel Jakub Dawidek if (len < (baselen + 2 + ((flags & HN_NOSPACE) || (i == 0 && 12623d1a178SPawel Jakub Dawidek !(flags & HN_B)) ? 0 : 1))) 12723d1a178SPawel Jakub Dawidek return (-1); 12823d1a178SPawel Jakub Dawidek s1 = bytes / 100; 12923d1a178SPawel Jakub Dawidek if ((s2 = (((bytes % 100) + 5) / 10)) == 10) { 13023d1a178SPawel Jakub Dawidek s1++; 13123d1a178SPawel Jakub Dawidek s2 = 0; 13223d1a178SPawel Jakub Dawidek } 13323d1a178SPawel Jakub Dawidek if (s1 < 10 && i == 0) 13423d1a178SPawel Jakub Dawidek /* Don't ever use .0 for a number less than 10. */ 13523d1a178SPawel Jakub Dawidek r = snprintf(buf, len, "%lld%s%c%s", 13623d1a178SPawel Jakub Dawidek /* LONGLONG */ 13723d1a178SPawel Jakub Dawidek (long long)(sign * s1), 13823d1a178SPawel Jakub Dawidek (i == 0 && !(flags & HN_B)) || flags & HN_NOSPACE ? 13923d1a178SPawel Jakub Dawidek "" : " ", (i == 0 && (flags & HN_B)) ? 'B' : 14023d1a178SPawel Jakub Dawidek prefixes[i], suffix); 14123d1a178SPawel Jakub Dawidek else 14223d1a178SPawel Jakub Dawidek r = snprintf(buf, len, "%lld%s%lld%s%c%s", 14323d1a178SPawel Jakub Dawidek /* LONGLONG */ 14423d1a178SPawel Jakub Dawidek (long long)(sign * s1), 14523d1a178SPawel Jakub Dawidek localeconv()->decimal_point, 14623d1a178SPawel Jakub Dawidek /* LONGLONG */ 14723d1a178SPawel Jakub Dawidek (long long)s2, 14823d1a178SPawel Jakub Dawidek (i == 0 && !(flags & HN_B)) || flags & HN_NOSPACE ? 14923d1a178SPawel Jakub Dawidek "" : " ", (i == 0 && (flags & HN_B)) ? 'B' : 15023d1a178SPawel Jakub Dawidek prefixes[i], suffix); 15123d1a178SPawel Jakub Dawidek 15223d1a178SPawel Jakub Dawidek } else 15323d1a178SPawel Jakub Dawidek r = snprintf(buf, len, "%lld%s%c%s", 15423d1a178SPawel Jakub Dawidek /* LONGLONG */ 15523d1a178SPawel Jakub Dawidek (long long)(sign * ((bytes + 50) / 100)), 15623d1a178SPawel Jakub Dawidek i == 0 || flags & HN_NOSPACE ? "" : " ", (i == 0 && 15723d1a178SPawel Jakub Dawidek (flags & HN_B)) ? 'B' : prefixes[i], suffix); 15823d1a178SPawel Jakub Dawidek 15923d1a178SPawel Jakub Dawidek return (r); 16023d1a178SPawel Jakub Dawidek } 161