1ddba0402SEnji Cooper /* $NetBSD: t_humanize_number.c,v 1.9 2017/01/10 15:20:44 christos Exp $ */ 257718be8SEnji Cooper 357718be8SEnji Cooper /*- 457718be8SEnji Cooper * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 557718be8SEnji Cooper * All rights reserved. 657718be8SEnji Cooper * 757718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 857718be8SEnji Cooper * modification, are permitted provided that the following conditions 957718be8SEnji Cooper * are met: 1057718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 1157718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 1257718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 1357718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 1457718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 1557718be8SEnji Cooper * 1657718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1757718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1857718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1957718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2057718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2157718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2257718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2357718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2457718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2557718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2657718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE. 2757718be8SEnji Cooper */ 2857718be8SEnji Cooper 2957718be8SEnji Cooper #include <atf-c.h> 3057718be8SEnji Cooper 3157718be8SEnji Cooper #include <err.h> 3257718be8SEnji Cooper #include <inttypes.h> 3357718be8SEnji Cooper #include <stdarg.h> 3457718be8SEnji Cooper #include <stdio.h> 3557718be8SEnji Cooper #include <stdlib.h> 3657718be8SEnji Cooper #include <string.h> 37*9a62e988SEnji Cooper #include <util.h> 3857718be8SEnji Cooper 3957718be8SEnji Cooper const struct hnopts { 4057718be8SEnji Cooper size_t ho_len; 4157718be8SEnji Cooper int64_t ho_num; 4257718be8SEnji Cooper const char *ho_suffix; 4357718be8SEnji Cooper int ho_scale; 4457718be8SEnji Cooper int ho_flags; 4557718be8SEnji Cooper int ho_retval; /* expected return value */ 4657718be8SEnji Cooper const char *ho_retstr; /* expected string in buffer */ 4757718be8SEnji Cooper } hnopts[] = { 4857718be8SEnji Cooper /* 4957718be8SEnji Cooper * Rev. 1.6 produces "10.0". 5057718be8SEnji Cooper */ 5157718be8SEnji Cooper { 5, 10737418236ULL * 1024, "", 5257718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10T" }, 5357718be8SEnji Cooper 5457718be8SEnji Cooper { 5, 10450000, "", 5557718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10M" }, 5657718be8SEnji Cooper { 5, 10500000, "", /* just for reference */ 5757718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10M" }, 5857718be8SEnji Cooper 5957718be8SEnji Cooper /* 6057718be8SEnji Cooper * Trailing space. Rev. 1.7 produces "1 ". 6157718be8SEnji Cooper */ 6257718be8SEnji Cooper { 5, 1, "", 0, HN_NOSPACE, 1, "1" }, 6357718be8SEnji Cooper 6457718be8SEnji Cooper { 5, 1, "", 0, 0, 2, "1 " }, /* just for reference */ 6557718be8SEnji Cooper { 5, 1, "", 0, HN_B, 3, "1 B" }, /* and more ... */ 6657718be8SEnji Cooper { 5, 1, "", 0, HN_DECIMAL, 2, "1 " }, 6757718be8SEnji Cooper { 5, 1, "", 0, HN_NOSPACE | HN_B, 2, "1B" }, 6857718be8SEnji Cooper { 5, 1, "", 0, HN_B | HN_DECIMAL, 3, "1 B" }, 6957718be8SEnji Cooper { 5, 1, "", 0, HN_NOSPACE | HN_B | HN_DECIMAL, 2, "1B" }, 7057718be8SEnji Cooper 7157718be8SEnji Cooper /* 7257718be8SEnji Cooper * Space and HN_B. Rev. 1.7 produces "1B". 7357718be8SEnji Cooper */ 7457718be8SEnji Cooper { 5, 1, "", HN_AUTOSCALE, HN_B, 3, "1 B" }, 7557718be8SEnji Cooper { 5, 1000, "", /* just for reference */ 7657718be8SEnji Cooper HN_AUTOSCALE, HN_B, 3, "1 K" }, 7757718be8SEnji Cooper 7857718be8SEnji Cooper /* 7957718be8SEnji Cooper * Truncated output. Rev. 1.7 produces "1.0 K". 8057718be8SEnji Cooper */ 81ff0ba872SEnji Cooper #ifndef __FreeBSD__ 8257718be8SEnji Cooper { 6, 1000, "A", HN_AUTOSCALE, HN_DECIMAL, -1, "" }, 8357718be8SEnji Cooper 8457718be8SEnji Cooper /* 8557718be8SEnji Cooper * Failure case reported by Greg Troxel <gdt@NetBSD.org>. 8657718be8SEnji Cooper * Rev. 1.11 incorrectly returns 5 with filling the buffer 8757718be8SEnji Cooper * with "1000". 8857718be8SEnji Cooper */ 8957718be8SEnji Cooper { 5, 1048258238, "", 9057718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0G" }, 9157718be8SEnji Cooper /* Similar case it prints 1000 where it shouldn't */ 9257718be8SEnji Cooper { 5, 1023488, "", 9357718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0M" }, 946cf117d7SEnji Cooper #endif 9557718be8SEnji Cooper { 5, 1023999, "", 9657718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0M" }, 9757718be8SEnji Cooper }; 9857718be8SEnji Cooper 9957718be8SEnji Cooper struct hnflags { 10057718be8SEnji Cooper int hf_flags; 10157718be8SEnji Cooper const char *hf_name; 10257718be8SEnji Cooper }; 10357718be8SEnji Cooper 10457718be8SEnji Cooper const struct hnflags scale_flags[] = { 10557718be8SEnji Cooper { HN_GETSCALE, "HN_GETSCALE" }, 10657718be8SEnji Cooper { HN_AUTOSCALE, "HN_AUTOSCALE" }, 10757718be8SEnji Cooper }; 10857718be8SEnji Cooper const struct hnflags normal_flags[] = { 10957718be8SEnji Cooper { HN_DECIMAL, "HN_DECIMAL" }, 11057718be8SEnji Cooper { HN_NOSPACE, "HN_NOSPACE" }, 11157718be8SEnji Cooper { HN_B, "HN_B" }, 11257718be8SEnji Cooper { HN_DIVISOR_1000, "HN_DIVISOR_1000" }, 11357718be8SEnji Cooper }; 11457718be8SEnji Cooper 11557718be8SEnji Cooper const char *formatflags(char *, size_t, const struct hnflags *, size_t, int); 11657718be8SEnji Cooper void newline(void); 11757718be8SEnji Cooper void w_printf(const char *, ...) __printflike(1, 2); 11857718be8SEnji Cooper int main(int, char *[]); 11957718be8SEnji Cooper 12057718be8SEnji Cooper const char * 12157718be8SEnji Cooper formatflags(char *buf, size_t buflen, const struct hnflags *hfs, 12257718be8SEnji Cooper size_t hfslen, int flags) 12357718be8SEnji Cooper { 12457718be8SEnji Cooper const struct hnflags *hf; 12557718be8SEnji Cooper char *p = buf; 12657718be8SEnji Cooper ssize_t len = buflen; 12757718be8SEnji Cooper unsigned int i, found; 12857718be8SEnji Cooper int n; 12957718be8SEnji Cooper 13057718be8SEnji Cooper if (flags == 0) { 13157718be8SEnji Cooper snprintf(buf, buflen, "0"); 13257718be8SEnji Cooper return (buf); 13357718be8SEnji Cooper } 13457718be8SEnji Cooper for (i = found = 0; i < hfslen && flags & ~found; i++) { 13557718be8SEnji Cooper hf = &hfs[i]; 13657718be8SEnji Cooper if (flags & hf->hf_flags) { 13757718be8SEnji Cooper found |= hf->hf_flags; 13857718be8SEnji Cooper n = snprintf(p, len, "|%s", hf->hf_name); 13957718be8SEnji Cooper if (n >= len) { 14057718be8SEnji Cooper p = buf; 14157718be8SEnji Cooper len = buflen; 14257718be8SEnji Cooper /* Print `flags' as number */ 14357718be8SEnji Cooper goto bad; 14457718be8SEnji Cooper } 14557718be8SEnji Cooper p += n; 14657718be8SEnji Cooper len -= n; 14757718be8SEnji Cooper } 14857718be8SEnji Cooper } 14957718be8SEnji Cooper flags &= ~found; 15057718be8SEnji Cooper if (flags) 15157718be8SEnji Cooper bad: 15257718be8SEnji Cooper snprintf(p, len, "|0x%x", flags); 15357718be8SEnji Cooper return (*buf == '|' ? buf + 1 : buf); 15457718be8SEnji Cooper } 15557718be8SEnji Cooper 15657718be8SEnji Cooper static int col, bol = 1; 15757718be8SEnji Cooper void 15857718be8SEnji Cooper newline(void) 15957718be8SEnji Cooper { 16057718be8SEnji Cooper 16157718be8SEnji Cooper fprintf(stderr, "\n"); 16257718be8SEnji Cooper col = 0; 16357718be8SEnji Cooper bol = 1; 16457718be8SEnji Cooper } 16557718be8SEnji Cooper 16657718be8SEnji Cooper void 16757718be8SEnji Cooper w_printf(const char *fmt, ...) 16857718be8SEnji Cooper { 16957718be8SEnji Cooper char buf[80]; 17057718be8SEnji Cooper va_list ap; 17157718be8SEnji Cooper int n; 17257718be8SEnji Cooper 17357718be8SEnji Cooper va_start(ap, fmt); 17457718be8SEnji Cooper if (col >= 0) { 17557718be8SEnji Cooper n = vsnprintf(buf, sizeof(buf), fmt, ap); 17657718be8SEnji Cooper if (n >= (int)sizeof(buf)) { 17757718be8SEnji Cooper col = -1; 17857718be8SEnji Cooper goto overflow; 17957718be8SEnji Cooper } else if (n == 0) 18057718be8SEnji Cooper goto out; 18157718be8SEnji Cooper 18257718be8SEnji Cooper if (!bol) { 18357718be8SEnji Cooper if (col + n > 75) 18457718be8SEnji Cooper fprintf(stderr, "\n "), col = 4; 18557718be8SEnji Cooper else 18657718be8SEnji Cooper fprintf(stderr, " "), col++; 18757718be8SEnji Cooper } 18857718be8SEnji Cooper fprintf(stderr, "%s", buf); 18957718be8SEnji Cooper col += n; 19057718be8SEnji Cooper bol = 0; 19157718be8SEnji Cooper } else { 19257718be8SEnji Cooper overflow: 19357718be8SEnji Cooper vfprintf(stderr, fmt, ap); 19457718be8SEnji Cooper } 19557718be8SEnji Cooper out: 19657718be8SEnji Cooper va_end(ap); 19757718be8SEnji Cooper } 19857718be8SEnji Cooper 19957718be8SEnji Cooper ATF_TC(humanize_number_basic); 20057718be8SEnji Cooper ATF_TC_HEAD(humanize_number_basic, tc) 20157718be8SEnji Cooper { 20257718be8SEnji Cooper 20357718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test humanize_number(3)"); 20457718be8SEnji Cooper } 20557718be8SEnji Cooper 20657718be8SEnji Cooper ATF_TC_BODY(humanize_number_basic, tc) 20757718be8SEnji Cooper { 20857718be8SEnji Cooper char fbuf[128]; 20957718be8SEnji Cooper const struct hnopts *ho; 21057718be8SEnji Cooper char *buf = NULL; 21157718be8SEnji Cooper size_t buflen = 0; 21257718be8SEnji Cooper unsigned int i; 21357718be8SEnji Cooper int rv = 0; 21457718be8SEnji Cooper 21557718be8SEnji Cooper for (i = 0; i < __arraycount(hnopts); i++) { 21657718be8SEnji Cooper ho = &hnopts[i]; 21757718be8SEnji Cooper if (buflen < ho->ho_len) { 21857718be8SEnji Cooper buflen = ho->ho_len; 21957718be8SEnji Cooper buf = realloc(buf, buflen); 22057718be8SEnji Cooper if (buf == NULL) 22157718be8SEnji Cooper atf_tc_fail("realloc(..., %zu) failed", buflen); 22257718be8SEnji Cooper } 22357718be8SEnji Cooper 22457718be8SEnji Cooper rv = humanize_number(buf, ho->ho_len, ho->ho_num, 22557718be8SEnji Cooper ho->ho_suffix, ho->ho_scale, ho->ho_flags); 22657718be8SEnji Cooper 22757718be8SEnji Cooper if (rv == ho->ho_retval && 22857718be8SEnji Cooper (rv == -1 || strcmp(buf, ho->ho_retstr) == 0)) 22957718be8SEnji Cooper continue; 23057718be8SEnji Cooper 23157718be8SEnji Cooper w_printf("humanize_number(\"%s\", %zu, %" PRId64 ",", 23257718be8SEnji Cooper ho->ho_retstr, ho->ho_len, ho->ho_num); 23357718be8SEnji Cooper w_printf("\"%s\",", ho->ho_suffix); 23457718be8SEnji Cooper w_printf("%s,", formatflags(fbuf, sizeof(fbuf), scale_flags, 23557718be8SEnji Cooper sizeof(scale_flags) / sizeof(scale_flags[0]), 23657718be8SEnji Cooper ho->ho_scale)); 23757718be8SEnji Cooper w_printf("%s)", formatflags(fbuf, sizeof(fbuf), normal_flags, 23857718be8SEnji Cooper sizeof(normal_flags) / sizeof(normal_flags[0]), 23957718be8SEnji Cooper ho->ho_flags)); 24057718be8SEnji Cooper w_printf("= %d,", ho->ho_retval); 24157718be8SEnji Cooper w_printf("but got"); 24257718be8SEnji Cooper w_printf("%d/[%s]", rv, rv == -1 ? "" : buf); 24357718be8SEnji Cooper newline(); 24457718be8SEnji Cooper atf_tc_fail_nonfatal("Failed for table entry %d", i); 24557718be8SEnji Cooper } 246251d8e77SEnji Cooper free(buf); 24757718be8SEnji Cooper } 24857718be8SEnji Cooper 24957718be8SEnji Cooper ATF_TC(humanize_number_big); 25057718be8SEnji Cooper ATF_TC_HEAD(humanize_number_big, tc) 25157718be8SEnji Cooper { 25257718be8SEnji Cooper 25357718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test humanize " 25457718be8SEnji Cooper "big numbers (PR lib/44097)"); 25557718be8SEnji Cooper } 25657718be8SEnji Cooper 25757718be8SEnji Cooper ATF_TC_BODY(humanize_number_big, tc) 25857718be8SEnji Cooper { 25957718be8SEnji Cooper char buf[1024]; 26057718be8SEnji Cooper int rv; 26157718be8SEnji Cooper 26257718be8SEnji Cooper /* 26357718be8SEnji Cooper * Seems to work. 26457718be8SEnji Cooper */ 26557718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 26657718be8SEnji Cooper 26757718be8SEnji Cooper rv = humanize_number(buf, 10, 10000, "", HN_AUTOSCALE, HN_NOSPACE); 26857718be8SEnji Cooper 26957718be8SEnji Cooper ATF_REQUIRE(rv != -1); 27057718be8SEnji Cooper ATF_CHECK_STREQ(buf, "10000"); 27157718be8SEnji Cooper 27257718be8SEnji Cooper /* 27357718be8SEnji Cooper * A bogus value with large number. 27457718be8SEnji Cooper */ 27557718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 27657718be8SEnji Cooper 27757718be8SEnji Cooper rv = humanize_number(buf, 10, INT64_MAX, "", HN_AUTOSCALE, HN_NOSPACE); 27857718be8SEnji Cooper 27957718be8SEnji Cooper ATF_REQUIRE(rv != -1); 28057718be8SEnji Cooper ATF_REQUIRE(strcmp(buf, "0") != 0); 28157718be8SEnji Cooper 28257718be8SEnji Cooper /* 28357718be8SEnji Cooper * Large buffer with HN_AUTOSCALE. Entirely bogus. 28457718be8SEnji Cooper */ 28557718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 28657718be8SEnji Cooper 28757718be8SEnji Cooper rv = humanize_number(buf, sizeof(buf), 10000, "", 28857718be8SEnji Cooper HN_AUTOSCALE, HN_NOSPACE); 28957718be8SEnji Cooper 29057718be8SEnji Cooper ATF_REQUIRE(rv != -1); 29157718be8SEnji Cooper ATF_REQUIRE(strcmp(buf, "0%d%s%d%s%s%s") != 0); 29257718be8SEnji Cooper 29357718be8SEnji Cooper /* 29457718be8SEnji Cooper * Tight buffer. 29557718be8SEnji Cooper * 29657718be8SEnji Cooper * The man page says that len must be at least 4. 29757718be8SEnji Cooper * 3 works, but anything less that will not. This 29857718be8SEnji Cooper * is because baselen starts with 2 for positive 29957718be8SEnji Cooper * numbers. 30057718be8SEnji Cooper */ 30157718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 30257718be8SEnji Cooper 30357718be8SEnji Cooper rv = humanize_number(buf, 3, 1, "", HN_AUTOSCALE, HN_NOSPACE); 30457718be8SEnji Cooper 30557718be8SEnji Cooper ATF_REQUIRE(rv != -1); 30657718be8SEnji Cooper } 30757718be8SEnji Cooper 30857718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 30957718be8SEnji Cooper { 31057718be8SEnji Cooper 31157718be8SEnji Cooper ATF_TP_ADD_TC(tp, humanize_number_basic); 31257718be8SEnji Cooper ATF_TP_ADD_TC(tp, humanize_number_big); 31357718be8SEnji Cooper 31457718be8SEnji Cooper return atf_no_error(); 31557718be8SEnji Cooper } 316