Home | History | Annotate | Line # | Download | only in libutil
t_snprintb.c revision 1.9
      1  1.9    rillig /* $NetBSD: t_snprintb.c,v 1.9 2024/01/25 18:13:14 rillig Exp $ */
      2  1.1      jmmv 
      3  1.1      jmmv /*
      4  1.9    rillig  * Copyright (c) 2002, 2004, 2008, 2010, 2024 The NetBSD Foundation, Inc.
      5  1.1      jmmv  * All rights reserved.
      6  1.1      jmmv  *
      7  1.9    rillig  * This code was contributed to The NetBSD Foundation by Christos Zoulas and
      8  1.9    rillig  * Roland Illig.
      9  1.1      jmmv  *
     10  1.1      jmmv  * Redistribution and use in source and binary forms, with or without
     11  1.1      jmmv  * modification, are permitted provided that the following conditions
     12  1.1      jmmv  * are met:
     13  1.1      jmmv  * 1. Redistributions of source code must retain the above copyright
     14  1.1      jmmv  *    notice, this list of conditions and the following disclaimer.
     15  1.1      jmmv  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1      jmmv  *    notice, this list of conditions and the following disclaimer in the
     17  1.1      jmmv  *    documentation and/or other materials provided with the distribution.
     18  1.1      jmmv  *
     19  1.1      jmmv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1      jmmv  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1      jmmv  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1      jmmv  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1      jmmv  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1      jmmv  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1      jmmv  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1      jmmv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1      jmmv  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1      jmmv  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1      jmmv  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1      jmmv  */
     31  1.1      jmmv 
     32  1.1      jmmv #include <sys/cdefs.h>
     33  1.1      jmmv __COPYRIGHT("@(#) Copyright (c) 2008, 2010\
     34  1.1      jmmv  The NetBSD Foundation, inc. All rights reserved.");
     35  1.9    rillig __RCSID("$NetBSD: t_snprintb.c,v 1.9 2024/01/25 18:13:14 rillig Exp $");
     36  1.1      jmmv 
     37  1.9    rillig #include <stdio.h>
     38  1.1      jmmv #include <string.h>
     39  1.1      jmmv #include <util.h>
     40  1.9    rillig #include <vis.h>
     41  1.1      jmmv 
     42  1.1      jmmv #include <atf-c.h>
     43  1.1      jmmv 
     44  1.9    rillig static const char *
     45  1.9    rillig vis_fmt(const char *fmt, size_t fmtlen)
     46  1.9    rillig {
     47  1.9    rillig 	static char buf[4][1024];
     48  1.9    rillig 	static size_t i;
     49  1.9    rillig 
     50  1.9    rillig 	i = (i + 1) % 4;
     51  1.9    rillig 	ATF_REQUIRE_MSG(
     52  1.9    rillig 	    strnvisx(buf[i], sizeof(buf[i]), fmt, fmtlen, VIS_WHITE | VIS_OCTAL) >= 0,
     53  1.9    rillig 	    "strnvisx failed for length %zu", fmtlen);
     54  1.9    rillig 	return buf[i];
     55  1.9    rillig }
     56  1.9    rillig 
     57  1.1      jmmv static void
     58  1.9    rillig h_snprintb(const char *file, size_t line, const char *fmt, size_t fmtlen, uint64_t val,
     59  1.9    rillig     const char *res, size_t reslen)
     60  1.1      jmmv {
     61  1.9    rillig 	char buf[1024];
     62  1.9    rillig 
     63  1.9    rillig 	int rv = snprintb(buf, sizeof(buf), fmt, val);
     64  1.1      jmmv 
     65  1.9    rillig 	ATF_REQUIRE_MSG(rv > 0, "formatting %jx with '%s' returns error %d",
     66  1.9    rillig 	    (uintmax_t)val, vis_fmt(fmt, fmtlen), rv);
     67  1.1      jmmv 
     68  1.9    rillig 	size_t buflen = rv;
     69  1.9    rillig 	ATF_CHECK_MSG(
     70  1.9    rillig 	    buflen == reslen && memcmp(buf, res, reslen) == 0,
     71  1.9    rillig 	    "failed:\n"
     72  1.9    rillig 	    "\ttest case: %s:%zu\n"
     73  1.9    rillig 	    "\tformat: %s\n"
     74  1.9    rillig 	    "\tvalue: %#jx\n"
     75  1.9    rillig 	    "\twant: %3zu bytes %s\n"
     76  1.9    rillig 	    "\thave: %3zu bytes %s\n",
     77  1.9    rillig 	    file, line,
     78  1.9    rillig 	    vis_fmt(fmt, fmtlen), (uintmax_t)val,
     79  1.9    rillig 	    reslen, vis_fmt(res, reslen),
     80  1.9    rillig 	    buflen, vis_fmt(buf, buflen));
     81  1.1      jmmv }
     82  1.1      jmmv 
     83  1.9    rillig #define	h_snprintb(fmt, val, res)					\
     84  1.9    rillig 	h_snprintb(__FILE__, __LINE__, fmt, sizeof(fmt) - 1,		\
     85  1.9    rillig 	    val, res, sizeof(res) - 1)
     86  1.9    rillig 
     87  1.1      jmmv ATF_TC(snprintb);
     88  1.1      jmmv ATF_TC_HEAD(snprintb, tc)
     89  1.1      jmmv {
     90  1.1      jmmv 	atf_tc_set_md_var(tc, "descr", "Checks snprintb(3)");
     91  1.1      jmmv }
     92  1.1      jmmv ATF_TC_BODY(snprintb, tc)
     93  1.1      jmmv {
     94  1.9    rillig 	h_snprintb(
     95  1.9    rillig 	    "\010"
     96  1.9    rillig 	    "\002BITTWO"
     97  1.9    rillig 	    "\001BITONE",
     98  1.9    rillig 	    3,
     99  1.9    rillig 	    "03<BITTWO,BITONE>");
    100  1.9    rillig 
    101  1.9    rillig 	h_snprintb(
    102  1.9    rillig 	    "\177\20"
    103  1.9    rillig 	    "b\0A\0",
    104  1.9    rillig 	    0,
    105  1.9    rillig 	    "0");
    106  1.9    rillig 
    107  1.9    rillig 	h_snprintb(
    108  1.9    rillig 	    "\177\020"
    109  1.9    rillig 	    "b\05NOTBOOT\0"
    110  1.9    rillig 	    "b\06FPP\0"
    111  1.9    rillig 	    "b\13SDVMA\0"
    112  1.9    rillig 	    "b\15VIDEO\0"
    113  1.9    rillig 	    "b\20LORES\0"
    114  1.9    rillig 	    "b\21FPA\0"
    115  1.9    rillig 	    "b\22DIAG\0"
    116  1.9    rillig 	    "b\16CACHE\0"
    117  1.9    rillig 	    "b\17IOCACHE\0"
    118  1.9    rillig 	    "b\22LOOPBACK\0"
    119  1.9    rillig 	    "b\04DBGCACHE\0",
    120  1.9    rillig 	    0xe860,
    121  1.9    rillig 	    "0xe860<NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE>");
    122  1.9    rillig 
    123  1.9    rillig 	h_snprintb(
    124  1.9    rillig 	    "\177\20"
    125  1.9    rillig 	    "f\0\4FOO\0"
    126  1.9    rillig 		"=\1ONE\0"
    127  1.9    rillig 		"=\2TWO\0",
    128  1.9    rillig 	    1,
    129  1.5       ryo 	    "0x1<FOO=0x1=ONE>");
    130  1.9    rillig 	h_snprintb(
    131  1.9    rillig 	    "\177\20"
    132  1.9    rillig 	    "f\0\4X\0"
    133  1.9    rillig 		"=\1ONE\0"
    134  1.9    rillig 		"=\2TWO\0",
    135  1.9    rillig 	    1,
    136  1.5       ryo 	    "0x1<X=0x1=ONE>");
    137  1.9    rillig 	h_snprintb(
    138  1.9    rillig 	    "\177\20"
    139  1.9    rillig 	    "F\0\4\0"
    140  1.9    rillig 		":\1ONE\0"
    141  1.9    rillig 		":\2TWO\0",
    142  1.9    rillig 	    1,
    143  1.6       kre 	    "0x1<ONE>");
    144  1.5       ryo 
    145  1.9    rillig 	h_snprintb(
    146  1.9    rillig 	    "\177\20"
    147  1.9    rillig 	    "f\0\4FOO\0"
    148  1.9    rillig 		"=\1ONE\0"
    149  1.9    rillig 		"=\2TWO\0",
    150  1.9    rillig 	    2,
    151  1.6       kre 	    "0x2<FOO=0x2=TWO>");
    152  1.9    rillig 	h_snprintb(
    153  1.9    rillig 	    "\177\20"
    154  1.9    rillig 	    "f\0\4X\0"
    155  1.9    rillig 		"=\1ONE\0"
    156  1.9    rillig 		"=\2TWO\0",
    157  1.9    rillig 	    2,
    158  1.6       kre 	    "0x2<X=0x2=TWO>");
    159  1.9    rillig 	h_snprintb(
    160  1.9    rillig 	    "\177\020"
    161  1.9    rillig 	    "F\0\4\0"
    162  1.9    rillig 		":\1ONE\0"
    163  1.9    rillig 		":\2TWO\0",
    164  1.9    rillig 	    2,
    165  1.6       kre 	    "0x2<TWO>");
    166  1.6       kre 
    167  1.9    rillig 	h_snprintb(
    168  1.9    rillig 	    "\177\20"
    169  1.9    rillig 	    "f\0\4FOO\0"
    170  1.9    rillig 		"=\1ONE\0"
    171  1.9    rillig 		"=\2TWO\0"
    172  1.9    rillig 		"*=OTHER\0",
    173  1.9    rillig 	    3,
    174  1.6       kre 	    "0x3<FOO=0x3=OTHER>");
    175  1.9    rillig 	h_snprintb(
    176  1.9    rillig 	    "\177\20"
    177  1.9    rillig 	    "f\0\4X\0"
    178  1.9    rillig 		"=\1ONE\0"
    179  1.9    rillig 		"=\2TWO\0"
    180  1.9    rillig 		"*=Other(%jd)\0",
    181  1.9    rillig 	    3,
    182  1.6       kre 	    "0x3<X=0x3=Other(3)>");
    183  1.9    rillig 	h_snprintb(
    184  1.9    rillig 	    "\177\20"
    185  1.9    rillig 	    "f\0\x8X\0"
    186  1.9    rillig 		"=\1ONE\0"
    187  1.9    rillig 		"=\2TWO\0"
    188  1.9    rillig 		"*=other(%jo)\0",
    189  1.9    rillig 	    0x20,
    190  1.6       kre 	    "0x20<X=0x20=other(40)>");
    191  1.9    rillig 	h_snprintb(
    192  1.9    rillig 	    "\177\020"
    193  1.9    rillig 	    "F\0\4\0"
    194  1.9    rillig 		":\1ONE\0"
    195  1.9    rillig 		":\2TWO\0",
    196  1.9    rillig 	    3,
    197  1.6       kre 	    "0x3<>");
    198  1.6       kre 
    199  1.9    rillig 	h_snprintb(
    200  1.9    rillig 	    "\177\20"
    201  1.9    rillig 	    "f\0\4Field_1\0"
    202  1.9    rillig 		"=\1ONE\0"
    203  1.9    rillig 		"=\2TWO\0"
    204  1.9    rillig 	    "f\4\4Field_2\0"
    205  1.9    rillig 		"=\1ONE\0"
    206  1.9    rillig 		"=\2TWO\0",
    207  1.9    rillig 	    0x12,
    208  1.6       kre 	    "0x12<Field_1=0x2=TWO,Field_2=0x1=ONE>");
    209  1.6       kre 
    210  1.9    rillig 	h_snprintb(
    211  1.9    rillig 	    "\177\20"
    212  1.9    rillig 	    "f\0\4Field_1\0"
    213  1.9    rillig 		"=\1ONE\0"
    214  1.9    rillig 		"=\2TWO\0"
    215  1.9    rillig 	    "F\x8\4\0"
    216  1.9    rillig 		"*Field_3=%jd\0"
    217  1.9    rillig 	    "f\4\4Field_2\0"
    218  1.9    rillig 		":\1:ONE\0"
    219  1.9    rillig 		":\2:TWO\0",
    220  1.9    rillig 	    0xD12,
    221  1.6       kre 	    "0xd12<Field_1=0x2=TWO,Field_3=13,Field_2=0x1:ONE>");
    222  1.9    rillig 
    223  1.9    rillig 	// It is possible but cumbersome to implement a reduced variant of
    224  1.9    rillig 	// rot13 using snprintb, shown here for lowercase letters only.
    225  1.9    rillig 	for (char ch = 'A'; ch <= '~'; ch++) {
    226  1.9    rillig 		char rot13 = ch >= 'a' && ch <= 'm' ? ch + 13
    227  1.9    rillig 		    : ch >= 'n' && ch <= 'z' ? ch - 13
    228  1.9    rillig 		    : '?';
    229  1.9    rillig 		char expected[8];
    230  1.9    rillig 		ATF_REQUIRE_EQ(7,
    231  1.9    rillig 		    snprintf(expected, sizeof(expected), "%#x<%c>", ch, rot13));
    232  1.9    rillig 		h_snprintb(
    233  1.9    rillig 		    "\177\020"
    234  1.9    rillig 		    "F\000\010\0"
    235  1.9    rillig 		    ":an\0:bo\0:cp\0:dq\0:er\0:fs\0:gt\0:hu\0"
    236  1.9    rillig 		    ":iv\0:jw\0:kx\0:ly\0:mz\0"
    237  1.9    rillig 		    ":na\0:ob\0:pc\0:qd\0:re\0:sf\0:tg\0:uh\0"
    238  1.9    rillig 		    ":vi\0:wj\0:xk\0:yl\0:zm\0"
    239  1.9    rillig 		    // If snprintf accepted "%jc", it would be possible to
    240  1.9    rillig 		    // echo the non-alphabetic characters instead of a
    241  1.9    rillig 		    // catchall question mark.
    242  1.9    rillig 		    "*?\0",
    243  1.9    rillig 		    ch,
    244  1.9    rillig 		    expected);
    245  1.9    rillig 	}
    246  1.1      jmmv }
    247  1.1      jmmv 
    248  1.2  pgoyette static void
    249  1.9    rillig h_snprintb_m(const char *file, size_t line, const char *fmt, size_t fmtlen, uint64_t val, int line_max,
    250  1.9    rillig     const char *res, size_t reslen)
    251  1.2  pgoyette {
    252  1.2  pgoyette 	char buf[1024];
    253  1.2  pgoyette 
    254  1.9    rillig 	int rv = snprintb_m(buf, sizeof(buf), fmt, val, line_max);
    255  1.2  pgoyette 
    256  1.9    rillig 	ATF_REQUIRE_MSG(rv >= 0, "formatting %jx with '%s' returns error %d",
    257  1.9    rillig 	    (uintmax_t)val, vis_fmt(fmt, fmtlen), rv);
    258  1.9    rillig 
    259  1.9    rillig 	size_t buflen = rv;
    260  1.9    rillig 	ATF_CHECK_MSG(
    261  1.9    rillig 	    buflen == reslen && memcmp(buf, res, reslen) == 0,
    262  1.9    rillig 	    "failed:\n"
    263  1.9    rillig 	    "\ttest case: %s:%zu\n"
    264  1.9    rillig 	    "\tformat: %s\n"
    265  1.9    rillig 	    "\tvalue: %#jx\n"
    266  1.9    rillig 	    "\twant: %zu bytes %s\n"
    267  1.9    rillig 	    "\thave: %zu bytes %s\n",
    268  1.9    rillig 	    file, line,
    269  1.9    rillig 	    vis_fmt(fmt, fmtlen), (uintmax_t)val,
    270  1.9    rillig 	    reslen, vis_fmt(res, reslen),
    271  1.9    rillig 	    buflen, vis_fmt(buf, buflen));
    272  1.2  pgoyette }
    273  1.2  pgoyette 
    274  1.9    rillig #define	h_snprintb_m(fmt, val, line_max, res)				\
    275  1.9    rillig 	h_snprintb_m(__FILE__, __LINE__, fmt, sizeof(fmt) - 1,		\
    276  1.9    rillig 	    val, line_max, res, sizeof(res) - 1)
    277  1.9    rillig 
    278  1.2  pgoyette ATF_TC(snprintb_m);
    279  1.2  pgoyette ATF_TC_HEAD(snprintb_m, tc)
    280  1.2  pgoyette {
    281  1.2  pgoyette 	atf_tc_set_md_var(tc, "descr", "Checks snprintb_m(3)");
    282  1.2  pgoyette }
    283  1.2  pgoyette ATF_TC_BODY(snprintb_m, tc)
    284  1.2  pgoyette {
    285  1.9    rillig 	h_snprintb_m(
    286  1.9    rillig 	    "\177\020"
    287  1.9    rillig 	    "b\0LSB\0"
    288  1.9    rillig 	    "b\1_BITONE\0"
    289  1.9    rillig 	    "f\4\4NIBBLE2\0"
    290  1.9    rillig 	    "f\x10\4BURST\0"
    291  1.9    rillig 		"=\04FOUR\0"
    292  1.9    rillig 		"=\17FIFTEEN\0"
    293  1.9    rillig 	    "b\x1fMSB\0",
    294  1.9    rillig 	    0x800f0701,
    295  1.9    rillig 	    33,
    296  1.9    rillig 	    "0x800f0701<LSB,NIBBLE2=0>\0"
    297  1.9    rillig 	    "0x800f0701<BURST=0xf=FIFTEEN,MSB>\0");
    298  1.9    rillig 
    299  1.9    rillig 	h_snprintb_m(
    300  1.9    rillig 	    "\177\020"
    301  1.9    rillig 	    "b\0LSB\0"
    302  1.9    rillig 	    "b\1_BITONE\0"
    303  1.9    rillig 	    "f\4\4NIBBLE2\0"
    304  1.9    rillig 	    "f\x10\4BURST\0"
    305  1.9    rillig 		"=\04FOUR\0"
    306  1.9    rillig 		"=\17FIFTEEN\0"
    307  1.9    rillig 	    "b\x1fMSB\0",
    308  1.9    rillig 	    0x800f0701,
    309  1.9    rillig 	    32,
    310  1.9    rillig 	    "0x800f0701<LSB,NIBBLE2=0>\0"
    311  1.9    rillig 	    "0x800f0701<BURST=0xf=FIFTEEN>\0"
    312  1.9    rillig 	    "0x800f0701<MSB>\0");
    313  1.2  pgoyette }
    314  1.2  pgoyette 
    315  1.1      jmmv ATF_TP_ADD_TCS(tp)
    316  1.1      jmmv {
    317  1.1      jmmv 
    318  1.1      jmmv 	ATF_TP_ADD_TC(tp, snprintb);
    319  1.2  pgoyette 	ATF_TP_ADD_TC(tp, snprintb_m);
    320  1.1      jmmv 
    321  1.1      jmmv 	return atf_no_error();
    322  1.1      jmmv }
    323