1 /*- 2 * Copyright 2012 Clifton Royston 3 * Copyright 2013 John-Mark Gurney 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 * 29 */ 30 31 #include <sys/param.h> 32 #include <inttypes.h> 33 #include <libutil.h> 34 #include <limits.h> 35 #include <math.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #define MAX_STR_FLAGS_RESULT 80 42 #define MAX_INT_STR_DIGITS 12 43 44 static const int64_t halfExabyte = (int64_t)500*1000*1000*1000*1000*1000L; 45 46 static struct { 47 int retval; 48 const char *res; 49 int64_t num; 50 int flags; 51 int scale; 52 size_t buflen; 53 } test_args[] = { 54 /* tests 0-13 test 1000 suffixes */ 55 { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 56 { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 57 { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 58 { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 59 { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 60 { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 61 { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 62 { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 63 { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 64 { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 65 { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 66 { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 67 { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 68 { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 69 70 /* tests 14-27 test 1024 suffixes */ 71 { 2, "0 ", (int64_t)0L, 0, HN_AUTOSCALE, 4 }, 72 { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE, 4 }, 73 { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE, 4 }, 74 { 3, "1 G", (int64_t)512*1024*1024L, 0, HN_AUTOSCALE, 4 }, 75 { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, HN_AUTOSCALE, 4 }, 76 { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 }, 77 { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 }, 78 { 2, "1 ", (int64_t)1L, 0, HN_AUTOSCALE, 4 }, 79 { 3, "2 K", (int64_t)1536L, 0, HN_AUTOSCALE, 4 }, 80 { 3, "2 M", (int64_t)1536*1024L, 0, HN_AUTOSCALE, 4 }, 81 { 3, "2 G", (int64_t)1536*1024*1024L, 0, HN_AUTOSCALE, 4 }, 82 { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, HN_AUTOSCALE, 4 }, 83 { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 }, 84 { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 }, 85 86 /* tests 28-37 test rounding */ 87 { 3, "0 M", (int64_t)500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 88 { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 89 { 3, "1 M", (int64_t)1000*1000L + 500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 90 { 3, "2 M", (int64_t)1000*1000L + 500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 }, 91 { 3, "0 K", (int64_t)512L-1, 0, HN_AUTOSCALE, 4 }, 92 { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE, 4 }, 93 { 3, "0 M", (int64_t)512*1024L-1, 0, HN_AUTOSCALE, 4 }, 94 { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE, 4 }, 95 { 3, "1 M", (int64_t)1024*1024L + 512*1024L-1, 0, HN_AUTOSCALE, 4 }, 96 { 3, "2 M", (int64_t)1024*1024L + 512*1024L, 0, HN_AUTOSCALE, 4 }, 97 98 /* tests 38-61 test specific scale factors with 1000 divisor */ 99 { 3, "0 k", (int64_t)0L, HN_DIVISOR_1000, 1, 4 }, 100 { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, 1, 4 }, 101 { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, 2, 4 }, 102 { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, 2, 4 }, 103 { 3, "0 G", (int64_t)500*1000L, HN_DIVISOR_1000, 3, 4 }, 104 { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 3, 4 }, 105 { 3, "0 T", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 4, 4 }, 106 { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 4, 4 }, 107 { 3, "0 P", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 }, 108 { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 }, 109 { 3, "0 E", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 }, 110 { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 }, 111 { 3, "0 k", (int64_t)1L, HN_DIVISOR_1000, 1, 4 }, 112 { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, 1, 4 }, 113 { 3, "0 M", (int64_t)1500L, HN_DIVISOR_1000, 2, 4 }, 114 { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, 2, 4 }, 115 { 3, "0 G", (int64_t)1500*1000L, HN_DIVISOR_1000, 3, 4 }, 116 { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 3, 4 }, 117 { 3, "0 T", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 4, 4 }, 118 { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 4, 4 }, 119 { 3, "0 P", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 }, 120 { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 }, 121 { 3, "0 E", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 }, 122 { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 }, 123 124 /* tests 62-85 test specific scale factors with 1024 divisor */ 125 { 3, "0 K", (int64_t)0L, 0, 1, 4 }, 126 { 3, "1 K", (int64_t)512L, 0, 1, 4 }, 127 { 3, "0 M", (int64_t)512L, 0, 2, 4 }, 128 { 3, "1 M", (int64_t)512*1024L, 0, 2, 4 }, 129 { 3, "0 G", (int64_t)512*1024L, 0, 3, 4 }, 130 { 3, "1 G", (int64_t)512*1024*1024L, 0, 3, 4 }, 131 { 3, "0 T", (int64_t)512*1024*1024L, 0, 4, 4 }, 132 { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, 4, 4 }, 133 { 3, "0 P", (int64_t)512*1024*1024*1024L, 0, 5, 4 }, 134 { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, 5, 4 }, 135 { 3, "0 E", (int64_t)512*1024*1024*1024*1024L, 0, 6, 4 }, 136 { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, 6, 4 }, 137 { 3, "0 K", (int64_t)1L, 0, 1, 4 }, 138 { 3, "2 K", (int64_t)1536L, 0, 1, 4 }, 139 { 3, "0 M", (int64_t)1536L, 0, 2, 4 }, 140 { 3, "2 M", (int64_t)1536*1024L, 0, 2, 4 }, 141 { 3, "0 G", (int64_t)1536*1024L, 0, 3, 4 }, 142 { 3, "2 G", (int64_t)1536*1024*1024L, 0, 3, 4 }, 143 { 3, "0 T", (int64_t)1536*1024*1024L, 0, 4, 4 }, 144 { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, 4, 4 }, 145 { 3, "0 P", (int64_t)1536*1024*1024*1024L, 0, 5, 4 }, 146 { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, 5, 4 }, 147 { 3, "0 E", (int64_t)1536*1024*1024*1024*1024L, 0, 6, 4 }, 148 { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, 6, 4 }, 149 150 /* tests 86-99 test invalid specific scale values of < 0 or >= 7 with 151 and without HN_DIVISOR_1000 set */ 152 /* all should return errors with new code; with old, the latter 3 153 are instead processed as if having AUTOSCALE and/or GETSCALE set */ 154 { -1, "", (int64_t)1L, 0, 7, 4 }, 155 { -1, "", (int64_t)1L, HN_DIVISOR_1000, 7, 4 }, 156 { -1, "", (int64_t)1L, 0, 1000, 4 }, 157 { -1, "", (int64_t)1L, HN_DIVISOR_1000, 1000, 4 }, 158 { -1, "", (int64_t)0L, 0, 1000*1000, 4 }, 159 { -1, "", (int64_t)0L, HN_DIVISOR_1000, 1000*1000, 4 }, 160 { -1, "", (int64_t)0L, 0, INT_MAX, 4 }, 161 { -1, "", (int64_t)0L, HN_DIVISOR_1000, INT_MAX, 4 }, 162 163 /* Negative scale values are not handled well 164 by the existing library routine - should report as error */ 165 /* all should return errors with new code, fail assertion with old */ 166 167 { -1, "", (int64_t)1L, 0, -1, 4 }, 168 { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1, 4 }, 169 { -1, "", (int64_t)1L, 0, -1000, 4 }, 170 { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1000, 4 }, 171 172 /* __INT_MIN doesn't print properly, skipped. */ 173 174 { -1, "", (int64_t)1L, 0, -__INT_MAX, 4 }, 175 { -1, "", (int64_t)1L, HN_DIVISOR_1000, -__INT_MAX, 4 }, 176 177 178 /* tests for scale == 0, without autoscale */ 179 /* tests 100-114 test scale 0 with 1000 divisor - print first N digits */ 180 { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, 0, 4 }, 181 { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, 0, 4 }, 182 { 3, "10 ", (int64_t)10L, HN_DIVISOR_1000, 0, 4 }, 183 { 3, "0 M", (int64_t)150L, HN_DIVISOR_1000, HN_NOSPACE, 4 }, 184 { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, HN_NOSPACE, 4 }, 185 { 3, "0 M", (int64_t)999L, HN_DIVISOR_1000, HN_NOSPACE, 4 }, 186 { 4, "150", (int64_t)150L, HN_DIVISOR_1000, 0, 4 }, 187 { 4, "500", (int64_t)500L, HN_DIVISOR_1000, 0, 4 }, 188 { 4, "999", (int64_t)999L, HN_DIVISOR_1000, 0, 4 }, 189 { 5, "100", (int64_t)1000L, HN_DIVISOR_1000, 0, 4 }, 190 { 5, "150", (int64_t)1500L, HN_DIVISOR_1000, 0, 4 }, 191 { 7, "500", (int64_t)500*1000L, HN_DIVISOR_1000, 0, 4 }, 192 { 8, "150", (int64_t)1500*1000L, HN_DIVISOR_1000, 0, 4 }, 193 { 10, "500", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 0, 4 }, 194 { 11, "150", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 0, 4 }, 195 196 /* tests 115-126 test scale 0 with 1024 divisor - print first N digits */ 197 { 2, "0 ", (int64_t)0L, 0, 0, 4 }, 198 { 2, "1 ", (int64_t)1L, 0, 0, 4 }, 199 { 3, "10 ", (int64_t)10L, 0, 0, 4 }, 200 { 4, "150", (int64_t)150L, 0, 0, 4 }, 201 { 4, "500", (int64_t)500L, 0, 0, 4 }, 202 { 4, "999", (int64_t)999L, 0, 0, 4 }, 203 { 5, "100", (int64_t)1000L, 0, 0, 4 }, 204 { 5, "150", (int64_t)1500L, 0, 0, 4 }, 205 { 7, "500", (int64_t)500*1000L, 0, 0, 4 }, 206 { 8, "150", (int64_t)1500*1000L, 0, 0, 4 }, 207 { 10, "500", (int64_t)500*1000*1000L, 0, 0, 4 }, 208 { 11, "150", (int64_t)1500*1000*1000L, 0, 0, 4 }, 209 210 /* Test case for rounding of edge numbers around 999.5+, see PR224498. 211 * Require buflen >= 5 */ 212 { 4, "1.0M", (int64_t)1023500, HN_DECIMAL|HN_B|HN_NOSPACE, HN_AUTOSCALE, 5 }, 213 214 /* Test boundary cases for very large positive/negative number formatting */ 215 /* Explicit scale, divisor 1024 */ 216 217 /* Requires buflen >= 6 */ 218 { 3, "8 E", INT64_MAX, 0, 6, 6 }, 219 { 4, "-8 E", -INT64_MAX, 0, 6, 6 }, 220 { 3, "0 E", (int64_t)92*1024*1024*1024*1024*1024L, 0, 6, 6 }, 221 { 3, "0 E", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 6, 6 }, 222 { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, 0, 6, 6 }, 223 { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 6, 6 }, 224 { 3, "0 E", (int64_t)81*1024*1024*1024*1024*1024L, 0, 6, 6 }, 225 { 3, "0 E", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 6, 6 }, 226 { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, 5, 6 }, 227 { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 5, 6 }, 228 { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, 5, 6 }, 229 { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 5, 6 }, 230 { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, 5, 6 }, 231 { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 5, 6 }, 232 233 /* Explicit scale, divisor 1000 */ 234 { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, 6, 6 }, 235 { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, 6, 6 }, 236 { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 }, 237 { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 }, 238 { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 }, 239 { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 }, 240 { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 }, 241 { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 }, 242 { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 }, 243 { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 }, 244 245 /* Autoscale, divisor 1024 */ 246 { 3, "8 E", INT64_MAX, 0, HN_AUTOSCALE, 6 }, 247 { 4, "-8 E", -INT64_MAX, 0, HN_AUTOSCALE, 6 }, 248 { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 }, 249 { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 }, 250 { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 }, 251 { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 }, 252 { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 }, 253 { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 }, 254 /* Autoscale, divisor 1000 */ 255 { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 256 { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 257 { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 258 { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 259 { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 260 { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 261 262 /* 0 scale, divisor 1024 */ 263 { 12, "skdj", INT64_MAX, 0, 0, 6 }, 264 { 21, "-9223", -INT64_MAX, 0, 0, 6 }, 265 { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, 0, 0, 6 }, 266 { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 0, 6 }, 267 { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, 0, 0, 6 }, 268 { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 0, 6 }, 269 { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, 0, 0, 6 }, 270 { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 0, 6 }, 271 272 /* 0 scale, divisor 1000 */ 273 /* XXX - why does this fail? */ 274 { -1, "", INT64_MAX, HN_DIVISOR_1000, 0, 6 }, 275 { 21, "-9223", -INT64_MAX, HN_DIVISOR_1000, 0, 6 }, 276 { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 }, 277 { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 }, 278 { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 }, 279 { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 }, 280 /* Expected to pass */ 281 { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 }, 282 { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 }, 283 284 285 286 /* Need to implement tests for GETSCALE */ 287 /* { ?, "", (int64_t)0L, HN_DIVISOR_1000, HN_GETSCALE, 6 }, 288 ... 289 */ 290 /* Tests for HN_DECIMAL */ 291 /* Positive, Autoscale */ 292 { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 293 { 5, "994 k", (int64_t)994*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 294 { 5, "995 k", (int64_t)995*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 295 { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 296 { 5, "1.0 M", (int64_t)1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 297 { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 298 { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 299 { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 300 { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 301 { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 302 { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 303 { 5, "994 M", (int64_t)994*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 304 { 5, "995 M", (int64_t)995*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 305 { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 306 307 { 5, "500 K", (int64_t)500*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 308 { 5, "994 K", (int64_t)994*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 309 { 5, "995 K", (int64_t)995*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 310 { 5, "999 K", (int64_t)999*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 311 { 5, "1.0 M", (int64_t)1000*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 312 { 5, "1.0 M", (int64_t)1018*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 313 { 5, "1.0 M", (int64_t)1019*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 314 { 5, "1.5 M", (int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 315 { 5, "1.9 M", (int64_t)1996*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 316 { 5, "2.0 M", (int64_t)1997*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 317 { 5, "2.0 M", (int64_t)2047*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 318 { 5, "2.0 M", (int64_t)2048*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 319 { 5, "2.0 M", (int64_t)2099*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 320 { 5, "2.1 M", (int64_t)2100*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 321 { 5, "9.9 M", (int64_t)10188*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 322 /* XXX - shouldn't the following two be "10. M"? */ 323 { 4, "10 M", (int64_t)10189*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 324 { 4, "10 M", (int64_t)10240*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 325 { 5, "500 M", (int64_t)500*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 326 { 5, "994 M", (int64_t)994*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 327 { 5, "995 M", (int64_t)995*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 328 { 5, "999 M", (int64_t)999*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 329 { 5, "1.0 G", (int64_t)1000*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 330 { 5, "1.0 G", (int64_t)1023*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 331 332 /* Negative, Autoscale - should pass */ 333 { 6, "-1.5 ", -(int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 334 { 6, "-1.9 ", -(int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 335 { 6, "-9.9 ", -(int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 336 337 { 6, "-1.5 ", -(int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 338 { 6, "-1.9 ", -(int64_t)1949*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 339 { 6, "-9.7 ", -(int64_t)9949*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 }, 340 341 /* Positive/negative, at maximum scale */ 342 { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 343 { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 344 { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 345 { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 346 /* Negatives work with latest rev only: */ 347 { 6, "-9.2 ", -INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 348 { 6, "-8.9 ", -(int64_t)8949*1000*1000*1000*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 }, 349 350 { 5, "8.0 E", INT64_MAX, HN_DECIMAL, HN_AUTOSCALE, 6 }, 351 { 5, "7.9 E", INT64_MAX-(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE, 6 }, 352 { 6, "-8.0 ", -INT64_MAX, HN_DECIMAL, HN_AUTOSCALE, 6 }, 353 { 6, "-7.9 ", -INT64_MAX+(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE, 6 }, 354 355 /* Positive, Fixed scales */ 356 { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 }, 357 { 5, "0.5 M", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 358 { 5, "949 k", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 }, 359 { 5, "0.9 M", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 360 { 5, "950 k", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 }, 361 { 5, "1.0 M", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 362 { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 }, 363 { 5, "1.0 M", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 364 { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 365 { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 366 { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 367 { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 368 { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 369 { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 370 { 5, "0.5 G", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3, 6 }, 371 { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 }, 372 { 5, "1.0 G", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3, 6 }, 373 /* Positive/negative, at maximum scale */ 374 { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 5, 6 }, 375 { 5, "1.0 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 6 }, 376 { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 6 }, 377 { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 6 }, 378 { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, 6, 6 }, 379 380 /* HN_DECIMAL + binary + fixed scale cases not completed */ 381 { 5, "512 K", (int64_t)512*1024L, HN_DECIMAL, 1, 6 }, 382 { 5, "0.5 M", (int64_t)512*1024L, HN_DECIMAL, 2, 6 }, 383 384 /* Negative, Fixed scales */ 385 /* Not yet added, but should work with latest rev */ 386 387 }; 388 389 390 /* Command line options usage */ 391 static void 392 usage(char * progname) { 393 printf("%s: tests libutil humanize_number function\n", progname); 394 printf("Usage: %s [-nE] [-l num] [-v]\n\n", progname); 395 printf("Options:\n"); 396 printf("\t-l num\tSet max length for result; buflen = num + 1\n"); 397 printf("\t\t (NOTE: does not change expected result strings.)\n"); 398 printf("\t-n\tInclude negative scale tests, which cause older libutil\n"); 399 printf("\t\t version of function to coredump with assertion failure\n"); 400 printf("\t-E\tInclude numbers > 1/2 Exa[byte] which currently fail\n"); 401 printf("\t-v\tVerbose - always print summary results\n"); 402 printf("\t-h, -?\tShow options\n"); 403 } 404 405 /* Parse command line options */ 406 static void 407 read_options(int argc, char * const argv[], size_t *bufLength, 408 int *includeNegativeScale, int *includeExabytes, int *verbose) { 409 int ch; 410 size_t temp; 411 412 while ((ch = getopt(argc, argv, "nEh?vl:")) != -1) { 413 switch (ch) { 414 default: 415 usage(argv[0]); 416 exit(1); 417 break; /* UNREACHABLE */ 418 case 'h' : 419 case '?' : 420 usage(argv[0]); 421 exit(0); 422 break; /* UNREACHABLE */ 423 case 'l' : 424 sscanf(optarg, "%zu", &temp); 425 *bufLength = temp + 1; 426 break; 427 case 'n' : 428 *includeNegativeScale = 1; 429 break; 430 case 'E' : 431 *includeExabytes = 1; 432 break; 433 case 'v' : 434 *verbose = 1; 435 break; 436 } 437 } 438 } 439 440 static struct { 441 int value; 442 const char *name; 443 } flags[] = { 444 { HN_AUTOSCALE, "HN_AUTOSCALE" }, 445 { HN_GETSCALE, "HN_GETSCALE" }, 446 { HN_DIVISOR_1000, "HN_DIVISOR_1000" }, 447 { HN_B, "HN_B" }, 448 { HN_DECIMAL, "HN_DECIMAL" }, 449 }; 450 451 static const char *separator = "|"; 452 453 /* Format flags parameter for meaningful display */ 454 static char * 455 str_flags(int hn_flags, char *noFlags) { 456 size_t i; 457 char * result; 458 459 result = malloc(MAX_STR_FLAGS_RESULT); 460 result[0] = '\0'; 461 462 for (i = 0; i < sizeof flags / sizeof *flags; i++) { 463 if (hn_flags & flags[i].value) { 464 if (*result != 0) 465 strlcat(result, separator, 466 MAX_STR_FLAGS_RESULT); 467 strlcat(result, flags[i].name, MAX_STR_FLAGS_RESULT); 468 } 469 } 470 471 if (strlen(result) == 0) 472 strlcat(result, noFlags, MAX_STR_FLAGS_RESULT); 473 return result; 474 } 475 476 477 /* Format scale parameter for meaningful display */ 478 static char * 479 str_scale(int scale) { 480 char *result; 481 482 if (scale == HN_AUTOSCALE || scale == HN_GETSCALE) 483 return str_flags(scale, ""); 484 485 result = malloc(MAX_INT_STR_DIGITS); 486 result[0] = '\0'; 487 snprintf(result, MAX_INT_STR_DIGITS, "%d", scale); 488 return result; 489 } 490 491 static void 492 testskipped(size_t i) 493 { 494 495 printf("ok %zu # skip - not turned on\n", i); 496 } 497 498 int 499 main(int argc, char * const argv[]) 500 { 501 char *buf; 502 char *flag_str, *scale_str; 503 size_t blen, buflen, errcnt, i, skipped, tested; 504 int r; 505 int includeNegScale; 506 int includeExabyteTests; 507 int verbose; 508 509 buf = NULL; 510 buflen = 0; 511 includeNegScale = 0; 512 includeExabyteTests = 0; 513 verbose = 0; 514 515 read_options(argc, argv, &buflen, &includeNegScale, 516 &includeExabyteTests, &verbose); 517 518 errcnt = 0; 519 tested = 0; 520 skipped = 0; 521 522 if (buflen != 4) 523 printf("Warning: buffer size %zu != 4, expect some results to differ.\n", buflen); 524 525 printf("1..%zu\n", nitems(test_args)); 526 for (i = 0; i < nitems(test_args); i++) { 527 blen = (buflen > 0) ? buflen : test_args[i].buflen; 528 buf = realloc(buf, blen); 529 530 if (test_args[i].scale < 0 && ! includeNegScale) { 531 skipped++; 532 testskipped(i + 1); 533 continue; 534 } 535 if (test_args[i].num >= halfExabyte && ! includeExabyteTests) { 536 skipped++; 537 testskipped(i + 1); 538 continue; 539 } 540 541 r = humanize_number(buf, blen, test_args[i].num, "", 542 test_args[i].scale, test_args[i].flags); 543 flag_str = str_flags(test_args[i].flags, "[no flags]"); 544 scale_str = str_scale(test_args[i].scale); 545 546 if (r != test_args[i].retval) { 547 if (verbose) 548 printf("wrong return value on index %zu, " 549 "buflen: %zu, got: %d + \"%s\", " 550 "expected %d + \"%s\"; num = %jd, " 551 "scale = %s, flags= %s.\n", 552 i, blen, r, buf, test_args[i].retval, 553 test_args[i].res, 554 (intmax_t)test_args[i].num, 555 scale_str, flag_str); 556 else 557 printf("not ok %zu # return %d != %d\n", 558 i + 1, r, test_args[i].retval); 559 errcnt++; 560 } else if (strcmp(buf, test_args[i].res) != 0) { 561 if (verbose) 562 printf("result mismatch on index %zu, got: " 563 "\"%s\", expected \"%s\"; num = %jd, " 564 "buflen: %zu, scale = %s, flags= %s.\n", 565 i, buf, test_args[i].res, 566 (intmax_t)test_args[i].num, 567 blen, scale_str, flag_str); 568 else 569 printf("not ok %zu # buf \"%s\" != \"%s\"\n", 570 i + 1, buf, test_args[i].res); 571 errcnt++; 572 } else { 573 if (verbose) 574 printf("successful result on index %zu, " 575 "returned %d, got: \"%s\"; num = %jd, " 576 "buflen = %zd, scale = %s, flags= %s.\n", 577 i, r, buf, (intmax_t)test_args[i].num, 578 blen, scale_str, flag_str); 579 else 580 printf("ok %zu\n", i + 1); 581 } 582 tested++; 583 } 584 free(buf); 585 586 if (verbose) 587 printf("total errors: %zu/%zu tests, %zu skipped\n", errcnt, 588 tested, skipped); 589 590 if (errcnt) 591 return 1; 592 593 return 0; 594 } 595