/*
 * DF-5675 — userland differential against the SAME libprop source that is
 * compiled into the kernel (/usr/src/sys/libprop).
 *
 *   internalize(depth=N)  -> iterative, SUCCEEDS for any N (prints count)
 *   externalize()         -> recursive, dies once frames * depth > rlimit
 *
 * Run under a small stack rlimit to make the asymmetry visible:
 *   ulimit -s 1024 ; ./df5675_userland 20000   -> SIGSEGV in externalize
 *   ulimit -s 1024 ; ./df5675_userland 300     -> prints both lengths, exit 0
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libprop/proplib.h>

static char *
build_deep_plist(int depth, size_t *lenp)
{
	size_t cap = (size_t)depth * 32 + 4096;
	char *xml = malloc(cap);
	size_t off = 0;
	int i;

	off += sprintf(xml + off, "<plist version=\"1.0\"><dict><key>a</key>");
	for (i = 0; i < depth; i++)
		off += sprintf(xml + off, "<array>");
	off += sprintf(xml + off, "<true/>");
	for (i = 0; i < depth; i++)
		off += sprintf(xml + off, "</array>");
	off += sprintf(xml + off, "</dict></plist>");
	*lenp = off;
	return (xml);
}

int
main(int argc, char **argv)
{
	int depth = argc > 1 ? atoi(argv[1]) : 20000;
	prop_dictionary_t dict;
	char *xml, *out;
	size_t len;

	xml = build_deep_plist(depth, &len);
	fprintf(stderr, "internalize depth=%d (%zu bytes xml)...\n", depth, len);

	dict = prop_dictionary_internalize(xml);
	if (dict == NULL) {
		fprintf(stderr, "internalize FAILED (parser rejected depth)\n");
		return (1);
	}
	fprintf(stderr, "internalize OK (iterative parser handles any depth)\n");

	fprintf(stderr, "externalize (recursive)...\n");
	fflush(stderr);
	out = prop_dictionary_externalize(dict);
	if (out == NULL) {
		fprintf(stderr, "externalize returned NULL (no crash)\n");
		return (2);
	}
	fprintf(stderr, "externalize OK, output %zu bytes (no crash)\n",
	    strlen(out));
	free(out);
	prop_object_release(dict);
	return (0);
}
