/*
 * DF-2230 verification rig -- USERLAND UNIT test of the SAME source file.
 *
 * This binary #includes the audited /usr/src/sys/libprop/prop_number.c
 * DIRECTLY, compiled in userland mode with the exact flags the stock
 * libprop uses (-D_LIBPROP -D_REENTRANT -I/usr/src/sys).  That gives us
 * call access to the static parsers so we can observe, per case:
 *
 *   - what _prop_number_internalize_signed() returns,
 *   - the errno it leaves behind (the check the kernel compiles out),
 *   - the pnv it stored.
 *
 * and run the exact dispatch block of _prop_number_internalize()
 * (prop_number.c lines 577-587) against the real static functions,
 * showing that in userland the signed parse FAILS (ERANGE) and the
 * unsigned fallback RUNS for decimal values in (INT64_MAX, UINT64_MAX].
 *
 * Output lines:
 *	DF2230|UU|in=<input>|signed_rv=<0/1>|errno=<n>|stored=<dec>|is_unsigned=<0/1>
 *	DF2230|UD|in=<input>|dispatch=<signed|unsigned-fallback|none>|value=<dec> (0x<hex>)|is_unsigned=<0/1>
 */
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

/* The audited source, userland build.  build.sh sha256-gates this file. */
#include "prop_number.c"

static const char *df2230_vals[] = {
	"0",
	"42",
	"-1",
	"-9223372036854775808",
	"-9223372036854775809",
	"9223372036854775807",
	"9223372036854775808",
	"10000000000000000000",
	"18446744073709551615",
	"99999999999999999999",
	"0x7fffffffffffffff",
	"0x8000000000000000",
	"0xffffffffffffffff",
	"0Xffffffffffffffff",
};
#define	DF2230_NVALS	((int)(sizeof(df2230_vals) / sizeof(df2230_vals[0])))

static void
df2230_unit(const char *v)
{
	struct _prop_object_internalize_context ctx;
	struct _prop_number_value pnv;
	int rv;

	memset(&ctx, 0, sizeof(ctx));
	ctx.poic_cp = v;			/* parser sees the digits */
	ctx.poic_tagattr = NULL;
	ctx.poic_is_empty_element = false;

	memset(&pnv, 0, sizeof(pnv));
	errno = -1;				/* sentinel */
	rv = _prop_number_internalize_signed(&ctx, &pnv);
	printf("DF2230|UU|in=%s|signed_rv=%d|errno=%d|stored=%lld|"
	    "is_unsigned=%d\n", v, rv, errno, (long long)pnv.pnv_signed,
	    (int)pnv.pnv_is_unsigned);
}

/*
 * Replicates the dispatch of _prop_number_internalize() verbatim
 * (prop_number.c:577-587) using the real static parsers, so we can see
 * which branch wins for each input.
 */
static void
df2230_dispatch(const char *v)
{
	struct _prop_object_internalize_context ctx;
	struct _prop_number_value pnv;
	const char *how;
	uint64_t val;
	int isu;

	memset(&ctx, 0, sizeof(ctx));
	ctx.poic_cp = v;
	ctx.poic_tagattr = NULL;
	ctx.poic_is_empty_element = false;
	memset(&pnv, 0, sizeof(pnv));

	how = "none";
	val = 0;
	isu = 0;
	if (ctx.poic_cp[0] == '-') {
		if (_prop_number_internalize_signed(&ctx, &pnv) == false)
			how = "signed-failed-no-obj";
		else
			how = "signed";
	} else if (ctx.poic_cp[0] == '0' && ctx.poic_cp[1] == 'x') {
		if (_prop_number_internalize_unsigned(&ctx, &pnv) == false)
			how = "unsigned-failed-no-obj";
		else
			how = "unsigned-hex";
	} else {
		if (_prop_number_internalize_signed(&ctx, &pnv) == false &&
		    _prop_number_internalize_unsigned(&ctx, &pnv) == false) {
			how = "both-failed-no-obj";
		} else if (!pnv.pnv_is_unsigned) {
			how = "signed";
		} else {
			how = "unsigned-fallback";
		}
	}
	val = pnv.pnv_unsigned;
	isu = (int)pnv.pnv_is_unsigned;
	printf("DF2230|UD|in=%s|dispatch=%s|value=%llu (0x%llx)|"
	    "is_unsigned=%d\n", v, how, (unsigned long long)val,
	    (unsigned long long)val, isu);
}

int
main(void)
{
	int i;

	printf("DF2230|UU|BEGIN unit matrix (userland build of "
	    "sys/libprop/prop_number.c)\n");
	for (i = 0; i < DF2230_NVALS; i++)
		df2230_unit(df2230_vals[i]);
	printf("DF2230|UU|END\n");
	printf("DF2230|UD|BEGIN dispatch matrix\n");
	for (i = 0; i < DF2230_NVALS; i++)
		df2230_dispatch(df2230_vals[i]);
	printf("DF2230|UD|END\n");
	return (0);
}
