1*57718be8SEnji Cooper /* $NetBSD: t_humanize_number.c,v 1.8 2012/03/18 07:14:08 jruoho Exp $ */ 2*57718be8SEnji Cooper 3*57718be8SEnji Cooper /*- 4*57718be8SEnji Cooper * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 5*57718be8SEnji Cooper * All rights reserved. 6*57718be8SEnji Cooper * 7*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 8*57718be8SEnji Cooper * modification, are permitted provided that the following conditions 9*57718be8SEnji Cooper * are met: 10*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 11*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 12*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 13*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 14*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 15*57718be8SEnji Cooper * 16*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17*57718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18*57718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19*57718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20*57718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21*57718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22*57718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23*57718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24*57718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25*57718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26*57718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE. 27*57718be8SEnji Cooper */ 28*57718be8SEnji Cooper 29*57718be8SEnji Cooper #include <atf-c.h> 30*57718be8SEnji Cooper 31*57718be8SEnji Cooper #include <err.h> 32*57718be8SEnji Cooper #include <inttypes.h> 33*57718be8SEnji Cooper #include <stdarg.h> 34*57718be8SEnji Cooper #include <stdio.h> 35*57718be8SEnji Cooper #include <stdlib.h> 36*57718be8SEnji Cooper #include <string.h> 37*57718be8SEnji Cooper #include <util.h> 38*57718be8SEnji Cooper 39*57718be8SEnji Cooper const struct hnopts { 40*57718be8SEnji Cooper size_t ho_len; 41*57718be8SEnji Cooper int64_t ho_num; 42*57718be8SEnji Cooper const char *ho_suffix; 43*57718be8SEnji Cooper int ho_scale; 44*57718be8SEnji Cooper int ho_flags; 45*57718be8SEnji Cooper int ho_retval; /* expected return value */ 46*57718be8SEnji Cooper const char *ho_retstr; /* expected string in buffer */ 47*57718be8SEnji Cooper } hnopts[] = { 48*57718be8SEnji Cooper /* 49*57718be8SEnji Cooper * Rev. 1.6 produces "10.0". 50*57718be8SEnji Cooper */ 51*57718be8SEnji Cooper { 5, 10737418236ULL * 1024, "", 52*57718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10T" }, 53*57718be8SEnji Cooper 54*57718be8SEnji Cooper { 5, 10450000, "", 55*57718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10M" }, 56*57718be8SEnji Cooper { 5, 10500000, "", /* just for reference */ 57*57718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10M" }, 58*57718be8SEnji Cooper 59*57718be8SEnji Cooper /* 60*57718be8SEnji Cooper * Trailing space. Rev. 1.7 produces "1 ". 61*57718be8SEnji Cooper */ 62*57718be8SEnji Cooper { 5, 1, "", 0, HN_NOSPACE, 1, "1" }, 63*57718be8SEnji Cooper 64*57718be8SEnji Cooper { 5, 1, "", 0, 0, 2, "1 " }, /* just for reference */ 65*57718be8SEnji Cooper { 5, 1, "", 0, HN_B, 3, "1 B" }, /* and more ... */ 66*57718be8SEnji Cooper { 5, 1, "", 0, HN_DECIMAL, 2, "1 " }, 67*57718be8SEnji Cooper { 5, 1, "", 0, HN_NOSPACE | HN_B, 2, "1B" }, 68*57718be8SEnji Cooper { 5, 1, "", 0, HN_B | HN_DECIMAL, 3, "1 B" }, 69*57718be8SEnji Cooper { 5, 1, "", 0, HN_NOSPACE | HN_B | HN_DECIMAL, 2, "1B" }, 70*57718be8SEnji Cooper 71*57718be8SEnji Cooper /* 72*57718be8SEnji Cooper * Space and HN_B. Rev. 1.7 produces "1B". 73*57718be8SEnji Cooper */ 74*57718be8SEnji Cooper { 5, 1, "", HN_AUTOSCALE, HN_B, 3, "1 B" }, 75*57718be8SEnji Cooper { 5, 1000, "", /* just for reference */ 76*57718be8SEnji Cooper HN_AUTOSCALE, HN_B, 3, "1 K" }, 77*57718be8SEnji Cooper 78*57718be8SEnji Cooper /* 79*57718be8SEnji Cooper * Truncated output. Rev. 1.7 produces "1.0 K". 80*57718be8SEnji Cooper */ 81*57718be8SEnji Cooper { 6, 1000, "A", HN_AUTOSCALE, HN_DECIMAL, -1, "" }, 82*57718be8SEnji Cooper 83*57718be8SEnji Cooper /* 84*57718be8SEnji Cooper * Failure case reported by Greg Troxel <gdt@NetBSD.org>. 85*57718be8SEnji Cooper * Rev. 1.11 incorrectly returns 5 with filling the buffer 86*57718be8SEnji Cooper * with "1000". 87*57718be8SEnji Cooper */ 88*57718be8SEnji Cooper { 5, 1048258238, "", 89*57718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0G" }, 90*57718be8SEnji Cooper /* Similar case it prints 1000 where it shouldn't */ 91*57718be8SEnji Cooper { 5, 1023488, "", 92*57718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0M" }, 93*57718be8SEnji Cooper { 5, 1023999, "", 94*57718be8SEnji Cooper HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0M" }, 95*57718be8SEnji Cooper }; 96*57718be8SEnji Cooper 97*57718be8SEnji Cooper struct hnflags { 98*57718be8SEnji Cooper int hf_flags; 99*57718be8SEnji Cooper const char *hf_name; 100*57718be8SEnji Cooper }; 101*57718be8SEnji Cooper 102*57718be8SEnji Cooper const struct hnflags scale_flags[] = { 103*57718be8SEnji Cooper { HN_GETSCALE, "HN_GETSCALE" }, 104*57718be8SEnji Cooper { HN_AUTOSCALE, "HN_AUTOSCALE" }, 105*57718be8SEnji Cooper }; 106*57718be8SEnji Cooper const struct hnflags normal_flags[] = { 107*57718be8SEnji Cooper { HN_DECIMAL, "HN_DECIMAL" }, 108*57718be8SEnji Cooper { HN_NOSPACE, "HN_NOSPACE" }, 109*57718be8SEnji Cooper { HN_B, "HN_B" }, 110*57718be8SEnji Cooper { HN_DIVISOR_1000, "HN_DIVISOR_1000" }, 111*57718be8SEnji Cooper }; 112*57718be8SEnji Cooper 113*57718be8SEnji Cooper const char *formatflags(char *, size_t, const struct hnflags *, size_t, int); 114*57718be8SEnji Cooper void newline(void); 115*57718be8SEnji Cooper void w_printf(const char *, ...) __printflike(1, 2); 116*57718be8SEnji Cooper int main(int, char *[]); 117*57718be8SEnji Cooper 118*57718be8SEnji Cooper const char * 119*57718be8SEnji Cooper formatflags(char *buf, size_t buflen, const struct hnflags *hfs, 120*57718be8SEnji Cooper size_t hfslen, int flags) 121*57718be8SEnji Cooper { 122*57718be8SEnji Cooper const struct hnflags *hf; 123*57718be8SEnji Cooper char *p = buf; 124*57718be8SEnji Cooper ssize_t len = buflen; 125*57718be8SEnji Cooper unsigned int i, found; 126*57718be8SEnji Cooper int n; 127*57718be8SEnji Cooper 128*57718be8SEnji Cooper if (flags == 0) { 129*57718be8SEnji Cooper snprintf(buf, buflen, "0"); 130*57718be8SEnji Cooper return (buf); 131*57718be8SEnji Cooper } 132*57718be8SEnji Cooper for (i = found = 0; i < hfslen && flags & ~found; i++) { 133*57718be8SEnji Cooper hf = &hfs[i]; 134*57718be8SEnji Cooper if (flags & hf->hf_flags) { 135*57718be8SEnji Cooper found |= hf->hf_flags; 136*57718be8SEnji Cooper n = snprintf(p, len, "|%s", hf->hf_name); 137*57718be8SEnji Cooper if (n >= len) { 138*57718be8SEnji Cooper p = buf; 139*57718be8SEnji Cooper len = buflen; 140*57718be8SEnji Cooper /* Print `flags' as number */ 141*57718be8SEnji Cooper goto bad; 142*57718be8SEnji Cooper } 143*57718be8SEnji Cooper p += n; 144*57718be8SEnji Cooper len -= n; 145*57718be8SEnji Cooper } 146*57718be8SEnji Cooper } 147*57718be8SEnji Cooper flags &= ~found; 148*57718be8SEnji Cooper if (flags) 149*57718be8SEnji Cooper bad: 150*57718be8SEnji Cooper snprintf(p, len, "|0x%x", flags); 151*57718be8SEnji Cooper return (*buf == '|' ? buf + 1 : buf); 152*57718be8SEnji Cooper } 153*57718be8SEnji Cooper 154*57718be8SEnji Cooper static int col, bol = 1; 155*57718be8SEnji Cooper void 156*57718be8SEnji Cooper newline(void) 157*57718be8SEnji Cooper { 158*57718be8SEnji Cooper 159*57718be8SEnji Cooper fprintf(stderr, "\n"); 160*57718be8SEnji Cooper col = 0; 161*57718be8SEnji Cooper bol = 1; 162*57718be8SEnji Cooper } 163*57718be8SEnji Cooper 164*57718be8SEnji Cooper void 165*57718be8SEnji Cooper w_printf(const char *fmt, ...) 166*57718be8SEnji Cooper { 167*57718be8SEnji Cooper char buf[80]; 168*57718be8SEnji Cooper va_list ap; 169*57718be8SEnji Cooper int n; 170*57718be8SEnji Cooper 171*57718be8SEnji Cooper va_start(ap, fmt); 172*57718be8SEnji Cooper if (col >= 0) { 173*57718be8SEnji Cooper n = vsnprintf(buf, sizeof(buf), fmt, ap); 174*57718be8SEnji Cooper if (n >= (int)sizeof(buf)) { 175*57718be8SEnji Cooper col = -1; 176*57718be8SEnji Cooper goto overflow; 177*57718be8SEnji Cooper } else if (n == 0) 178*57718be8SEnji Cooper goto out; 179*57718be8SEnji Cooper 180*57718be8SEnji Cooper if (!bol) { 181*57718be8SEnji Cooper if (col + n > 75) 182*57718be8SEnji Cooper fprintf(stderr, "\n "), col = 4; 183*57718be8SEnji Cooper else 184*57718be8SEnji Cooper fprintf(stderr, " "), col++; 185*57718be8SEnji Cooper } 186*57718be8SEnji Cooper fprintf(stderr, "%s", buf); 187*57718be8SEnji Cooper col += n; 188*57718be8SEnji Cooper bol = 0; 189*57718be8SEnji Cooper } else { 190*57718be8SEnji Cooper overflow: 191*57718be8SEnji Cooper vfprintf(stderr, fmt, ap); 192*57718be8SEnji Cooper } 193*57718be8SEnji Cooper out: 194*57718be8SEnji Cooper va_end(ap); 195*57718be8SEnji Cooper } 196*57718be8SEnji Cooper 197*57718be8SEnji Cooper ATF_TC(humanize_number_basic); 198*57718be8SEnji Cooper ATF_TC_HEAD(humanize_number_basic, tc) 199*57718be8SEnji Cooper { 200*57718be8SEnji Cooper 201*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test humanize_number(3)"); 202*57718be8SEnji Cooper } 203*57718be8SEnji Cooper 204*57718be8SEnji Cooper ATF_TC_BODY(humanize_number_basic, tc) 205*57718be8SEnji Cooper { 206*57718be8SEnji Cooper char fbuf[128]; 207*57718be8SEnji Cooper const struct hnopts *ho; 208*57718be8SEnji Cooper char *buf = NULL; 209*57718be8SEnji Cooper size_t buflen = 0; 210*57718be8SEnji Cooper unsigned int i; 211*57718be8SEnji Cooper int rv = 0; 212*57718be8SEnji Cooper 213*57718be8SEnji Cooper for (i = 0; i < __arraycount(hnopts); i++) { 214*57718be8SEnji Cooper ho = &hnopts[i]; 215*57718be8SEnji Cooper if (buflen < ho->ho_len) { 216*57718be8SEnji Cooper buflen = ho->ho_len; 217*57718be8SEnji Cooper buf = realloc(buf, buflen); 218*57718be8SEnji Cooper if (buf == NULL) 219*57718be8SEnji Cooper atf_tc_fail("realloc(..., %zu) failed", buflen); 220*57718be8SEnji Cooper } 221*57718be8SEnji Cooper 222*57718be8SEnji Cooper rv = humanize_number(buf, ho->ho_len, ho->ho_num, 223*57718be8SEnji Cooper ho->ho_suffix, ho->ho_scale, ho->ho_flags); 224*57718be8SEnji Cooper 225*57718be8SEnji Cooper if (rv == ho->ho_retval && 226*57718be8SEnji Cooper (rv == -1 || strcmp(buf, ho->ho_retstr) == 0)) 227*57718be8SEnji Cooper continue; 228*57718be8SEnji Cooper 229*57718be8SEnji Cooper w_printf("humanize_number(\"%s\", %zu, %" PRId64 ",", 230*57718be8SEnji Cooper ho->ho_retstr, ho->ho_len, ho->ho_num); 231*57718be8SEnji Cooper w_printf("\"%s\",", ho->ho_suffix); 232*57718be8SEnji Cooper w_printf("%s,", formatflags(fbuf, sizeof(fbuf), scale_flags, 233*57718be8SEnji Cooper sizeof(scale_flags) / sizeof(scale_flags[0]), 234*57718be8SEnji Cooper ho->ho_scale)); 235*57718be8SEnji Cooper w_printf("%s)", formatflags(fbuf, sizeof(fbuf), normal_flags, 236*57718be8SEnji Cooper sizeof(normal_flags) / sizeof(normal_flags[0]), 237*57718be8SEnji Cooper ho->ho_flags)); 238*57718be8SEnji Cooper w_printf("= %d,", ho->ho_retval); 239*57718be8SEnji Cooper w_printf("but got"); 240*57718be8SEnji Cooper w_printf("%d/[%s]", rv, rv == -1 ? "" : buf); 241*57718be8SEnji Cooper newline(); 242*57718be8SEnji Cooper atf_tc_fail_nonfatal("Failed for table entry %d", i); 243*57718be8SEnji Cooper } 244*57718be8SEnji Cooper } 245*57718be8SEnji Cooper 246*57718be8SEnji Cooper ATF_TC(humanize_number_big); 247*57718be8SEnji Cooper ATF_TC_HEAD(humanize_number_big, tc) 248*57718be8SEnji Cooper { 249*57718be8SEnji Cooper 250*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test humanize " 251*57718be8SEnji Cooper "big numbers (PR lib/44097)"); 252*57718be8SEnji Cooper } 253*57718be8SEnji Cooper 254*57718be8SEnji Cooper ATF_TC_BODY(humanize_number_big, tc) 255*57718be8SEnji Cooper { 256*57718be8SEnji Cooper char buf[1024]; 257*57718be8SEnji Cooper int rv; 258*57718be8SEnji Cooper 259*57718be8SEnji Cooper /* 260*57718be8SEnji Cooper * Seems to work. 261*57718be8SEnji Cooper */ 262*57718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 263*57718be8SEnji Cooper 264*57718be8SEnji Cooper rv = humanize_number(buf, 10, 10000, "", HN_AUTOSCALE, HN_NOSPACE); 265*57718be8SEnji Cooper 266*57718be8SEnji Cooper ATF_REQUIRE(rv != -1); 267*57718be8SEnji Cooper ATF_CHECK_STREQ(buf, "10000"); 268*57718be8SEnji Cooper 269*57718be8SEnji Cooper /* 270*57718be8SEnji Cooper * A bogus value with large number. 271*57718be8SEnji Cooper */ 272*57718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 273*57718be8SEnji Cooper 274*57718be8SEnji Cooper rv = humanize_number(buf, 10, INT64_MAX, "", HN_AUTOSCALE, HN_NOSPACE); 275*57718be8SEnji Cooper 276*57718be8SEnji Cooper ATF_REQUIRE(rv != -1); 277*57718be8SEnji Cooper ATF_REQUIRE(strcmp(buf, "0") != 0); 278*57718be8SEnji Cooper 279*57718be8SEnji Cooper /* 280*57718be8SEnji Cooper * Large buffer with HN_AUTOSCALE. Entirely bogus. 281*57718be8SEnji Cooper */ 282*57718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 283*57718be8SEnji Cooper 284*57718be8SEnji Cooper rv = humanize_number(buf, sizeof(buf), 10000, "", 285*57718be8SEnji Cooper HN_AUTOSCALE, HN_NOSPACE); 286*57718be8SEnji Cooper 287*57718be8SEnji Cooper ATF_REQUIRE(rv != -1); 288*57718be8SEnji Cooper ATF_REQUIRE(strcmp(buf, "0%d%s%d%s%s%s") != 0); 289*57718be8SEnji Cooper 290*57718be8SEnji Cooper /* 291*57718be8SEnji Cooper * Tight buffer. 292*57718be8SEnji Cooper * 293*57718be8SEnji Cooper * The man page says that len must be at least 4. 294*57718be8SEnji Cooper * 3 works, but anything less that will not. This 295*57718be8SEnji Cooper * is because baselen starts with 2 for positive 296*57718be8SEnji Cooper * numbers. 297*57718be8SEnji Cooper */ 298*57718be8SEnji Cooper (void)memset(buf, 0, sizeof(buf)); 299*57718be8SEnji Cooper 300*57718be8SEnji Cooper rv = humanize_number(buf, 3, 1, "", HN_AUTOSCALE, HN_NOSPACE); 301*57718be8SEnji Cooper 302*57718be8SEnji Cooper ATF_REQUIRE(rv != -1); 303*57718be8SEnji Cooper } 304*57718be8SEnji Cooper 305*57718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 306*57718be8SEnji Cooper { 307*57718be8SEnji Cooper 308*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, humanize_number_basic); 309*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, humanize_number_big); 310*57718be8SEnji Cooper 311*57718be8SEnji Cooper return atf_no_error(); 312*57718be8SEnji Cooper } 313