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