Module Name:    othersrc
Committed By:   dholland
Date:           Thu Feb  6 04:57:02 UTC 2014

Added Files:
        othersrc/external/bsd/jetlib: README TODO
        othersrc/external/bsd/jetlib/lib/libjet: Makefile jetfromtext.c
            jetlib.c jetlib.h jettobin.c jettotext.c

Log Message:
Import a copy of jetlib in othersrc. This is exactly the same as the
version I've had posted on my web page the last five years; it is from
October 17, 2008 and was written in a day or so after irritation at
one of the endless proplib flamewars boiled over.

This should be considered a straw man only; it is not quite finished
and there are some unresolved issues to sort out (particularly
pertaining to iteration) before it can be used for real. There are
also probably things I'd do differently if I wrote it again now, and I
haven't attended to any of those or even looked at the thing in any
detail.

Also IIRC it's never actually been run.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 othersrc/external/bsd/jetlib/README \
    othersrc/external/bsd/jetlib/TODO
cvs rdiff -u -r0 -r1.1 othersrc/external/bsd/jetlib/lib/libjet/Makefile \
    othersrc/external/bsd/jetlib/lib/libjet/jetfromtext.c \
    othersrc/external/bsd/jetlib/lib/libjet/jetlib.c \
    othersrc/external/bsd/jetlib/lib/libjet/jetlib.h \
    othersrc/external/bsd/jetlib/lib/libjet/jettobin.c \
    othersrc/external/bsd/jetlib/lib/libjet/jettotext.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: othersrc/external/bsd/jetlib/README
diff -u /dev/null othersrc/external/bsd/jetlib/README:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/README	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,6 @@
+This is like proplib, but better.
+
+or at least that's the idea.
+
+The name is obviously an in joke and would want to be changed before
+going into any kind of production.
Index: othersrc/external/bsd/jetlib/TODO
diff -u /dev/null othersrc/external/bsd/jetlib/TODO:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/TODO	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,12 @@
+todo:
+   COW for values, or at least large/expensive ones
+   other half of the bin transport
+   non-xml text transport
+   test it
+
+some plist urls:
+   http://en.wikipedia.org/wiki/Property_list
+   http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html
+
+some broader things:
+   should be able to specify the backend allocator

Index: othersrc/external/bsd/jetlib/lib/libjet/Makefile
diff -u /dev/null othersrc/external/bsd/jetlib/lib/libjet/Makefile:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/lib/libjet/Makefile	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,7 @@
+WARNS=4
+LIB=jet
+SRCS=jetlib.c jettotext.c jetfromtext.c jettobin.c
+
+NOLINT=1  # lint is currently too stupid
+
+.include <bsd.lib.mk>
Index: othersrc/external/bsd/jetlib/lib/libjet/jetfromtext.c
diff -u /dev/null othersrc/external/bsd/jetlib/lib/libjet/jetfromtext.c:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/lib/libjet/jetfromtext.c	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,449 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include "jetlib.h"
+
+struct jetparse_context {
+	const char *text;
+};
+
+////////////////////////////////////////////////////////////
+// utils
+
+static
+bool
+jetparse_match(struct jetparse_context *ctx, const char *str)
+{
+	size_t len;
+
+	len = strlen(str);
+	if (!strncmp(ctx->text, str, len)) {
+		ctx->text += len;
+		return true;
+	}
+	errno = EFTYPE;
+	return false;
+}
+
+static
+inline
+int
+is_hexdigit(unsigned char ch)
+{
+	return (ch >= '0' && ch <= '9') || 
+		(ch != 0 && strchr("abcdefABCDEF", ch) != NULL);
+}
+
+static
+inline
+int
+get_hexdigit(unsigned char ch)
+{
+	const char *x, *y;
+
+	if (ch >= '0' && ch <= '9') {
+		return ch - '0';
+	}
+
+	x = "abcdef";
+	y = strchr(x, ch);
+	if (y != NULL) {
+		return 10 + y-x;
+	}
+	x = "ABCDEF";
+	y = strchr(x, ch);
+	if (y != NULL) {
+		return 10 + y-x;
+	}
+	return -1;
+}
+
+static
+int
+jetparse_getint(struct jetparse_context *ctx, uintmax_t *retval)
+{
+	/* Why isn't there a strtouimax? */
+	uintmax_t val = 0;
+	unsigned d;
+	bool ok = false;
+
+	while (is_hexdigit(*ctx->text)) {
+		d = get_hexdigit(*ctx->text);
+		ctx->text++;
+		ok = true;
+		val = val*16 + d;
+		if (val > UINTMAX_MAX >> 4) {
+			/* next digit would overflow */
+			break;
+		}
+	}
+	if (!ok) {
+		/* no digits */
+		return -1;
+	}
+	*retval = val;
+	return 0;
+}
+
+static
+int
+jetparse_getdouble(struct jetparse_context *ctx, double *retval)
+{
+	char *t;
+	double val;
+
+	val = strtod(ctx->text, &t);
+	if (val == 0 && t == ctx->text) {
+		/* no conversion */
+		return -1;
+	}
+	if ((val == HUGE_VAL || val == -HUGE_VAL) && errno == ERANGE) {
+		/* overflow */
+		return -1;
+	}
+	if (val == 0 && errno == ERANGE) {
+		/* underflow */
+		return -1;
+	}
+
+	ctx->text = t;
+	*retval = val;
+	return 0;
+}
+
+static
+char *
+jetparse_buildstring(const char *s, size_t len)
+{
+	size_t i, j;
+	size_t retlen = 0;
+	char *r;
+
+	for (i=0; i<len; i++) {
+		if (s[i] == '&') {
+			if (!strncmp(s+i, "&amp;", 5)) {
+				s += 4;
+				retlen++;
+			}
+			else if (!strncmp(s+i, "&gt;", 4) ||
+				 !strncmp(s+i, "&lt;", 4)) {
+				s += 3;
+				retlen++;
+			}
+			else {
+				errno = EFTYPE;
+				return NULL;
+			}
+		}
+		else {
+			retlen++;
+		}
+	}
+
+	r = malloc(retlen+1);
+	if (r == NULL) {
+		return NULL;
+	}
+
+	for (i=j=0; i<len; i++) {
+		if (s[i] == '&') {
+			if (!strncmp(s+i, "&amp;", 5)) {
+				r[j++] = '&';
+				s += 4;
+			}
+			else if (!strncmp(s+i, "&gt;", 4)) {
+				r[j++] = '>';
+				s += 3;
+			}
+			else if (!strncmp(s+i, "&lt;", 4)) {
+				r[j++] = '<';
+				s += 3;
+			}
+			else {
+				/* impossible */
+			}
+		}
+		else {
+			r[j++] = s[i];
+		}
+	}
+	r[j] = 0;
+	return r;
+}
+
+static
+jetval *
+jetparse_buildblob(const char *hex, size_t hexlen)
+{
+	size_t binlen, i;
+	unsigned char *ret;
+	jetval *blob;
+	int sverrno;
+
+	/* XXX should really use some form of base64 */
+	binlen = hexlen/2;
+	ret = malloc(binlen);
+	if (ret == NULL) {
+		return NULL;
+	}
+
+	for (i=0; i<binlen; i++) {
+		char c1, c2;
+		unsigned char x;
+
+		c1 = hex[i*2];
+		c2 = hex[i*2+1];
+
+		if (!is_hexdigit(c1) || !is_hexdigit(c2)) {
+			free(ret);
+			errno = EFTYPE;
+			return NULL;
+		}
+		x = get_hexdigit(c1)*16 + get_hexdigit(c2);
+		ret[i] = x;
+	}
+
+	blob = jetval_blob_mustfree(ret, binlen);
+	if (blob == NULL) {
+		sverrno = errno;
+		free(ret);
+		errno = sverrno;
+		return NULL;
+	}
+
+	return blob;
+}
+
+////////////////////////////////////////////////////////////
+// parser
+
+static
+jetval *
+jetparse_get(struct jetparse_context *ctx)
+{
+	int sverrno;
+
+	if (jetparse_match(ctx, "<bool>")) {
+		bool val;
+
+		if (jetparse_match(ctx, "true")) {
+			val = true;
+		}
+		else if (jetparse_match(ctx, "false")) {
+			val = false;
+		}
+		else {
+			return NULL;
+		}
+		if (!jetparse_match(ctx, "</bool>\n")) {
+			return NULL;
+		}
+		return jetval_bool(val);
+	}
+	else if (jetparse_match(ctx, "<int>")) {
+		uintmax_t uval;
+		intmax_t val;
+		bool negative;
+
+		negative = jetparse_match(ctx, "-");
+		if (jetparse_getint(ctx, &uval) < 0) {
+			return NULL;
+		}
+		if (!jetparse_match(ctx, "</int>\n")) {
+			return NULL;
+		}
+
+		if (negative) {
+			if (uval > ((uintmax_t) -(INTMAX_MIN+1)) + 1) {
+				/* too big */
+				errno = EFTYPE;
+				return NULL;
+			}
+			/* avoid overflow */
+			val = ((intmax_t) -(uval-1)) - 1;
+		}
+		else {
+			if (uval > INTMAX_MAX) {
+				/* too big */
+				errno = EFTYPE;
+				return NULL;
+			}
+			val = (intmax_t) uval;
+		}
+		return jetval_int(val);
+	}
+	else if (jetparse_match(ctx, "<uint>")) {
+		uintmax_t val;
+
+		if (jetparse_getint(ctx, &val) < 0) {
+			return NULL;
+		}
+		if (!jetparse_match(ctx, "</uint>\n")) {
+			return NULL;
+		}
+
+		return jetval_uint(val);
+	}
+	else if (jetparse_match(ctx, "<double>")) {
+		double val;
+
+		if (jetparse_getdouble(ctx, &val) < 0) {
+			return NULL;
+		}
+		if (!jetparse_match(ctx, "</double>\n")) {
+			return NULL;
+		}
+
+		return jetval_double(val);
+	}
+	else if (jetparse_match(ctx, "<string>")) {
+		const char *start, *end;
+		char *val;
+		jetval *str;
+
+		start = ctx->text;
+		while (*ctx->text != '\0' && *ctx->text != '<') {
+			ctx->text++;
+		}
+		end = ctx->text;
+		if (!jetparse_match(ctx, "</string>\n")) {
+			return NULL;
+		}
+
+		val = jetparse_buildstring(start, end - start);
+		if (val == NULL) {
+			return NULL;
+		}
+		str = jetval_string(val);
+		if (str == NULL) {
+			sverrno = errno;
+			free(val);
+			errno = sverrno;
+			return NULL;
+		}
+		return str;
+	}
+	else if (jetparse_match(ctx, "<blob>")) {
+		const char *start, *end;
+
+		start = ctx->text;
+		while (*ctx->text != '\0' && *ctx->text != '<') {
+			ctx->text++;
+		}
+		end = ctx->text;
+		if (!jetparse_match(ctx, "</blob>\n")) {
+			return NULL;
+		}
+
+		return jetparse_buildblob(start, end - start);
+	}
+	else if (jetparse_match(ctx, "<array>")) {
+		jetval *array, *item;
+
+		array = jetval_emptyarray();
+		while (!jetparse_match(ctx, "</array>\n")) {
+			item = jetparse_get(ctx);
+			if (item == NULL) {
+				sverrno = errno;
+				jetval_decref(array);
+				errno = sverrno;
+				return NULL;
+			}
+			if (jetval_array_add_mustfree(array, item) < 0) {
+				sverrno = errno;
+				jetval_decref(item);
+				jetval_decref(array);
+				errno = sverrno;
+				return NULL;
+			}
+		}
+
+		return array;
+	}
+	else if (jetparse_match(ctx, "<dict>")) {
+		jetval *dict;
+		const char *keystart, *keyend;
+		char *key;
+		jetval *val;
+
+		dict = jetval_emptydict();
+		while (!jetparse_match(ctx, "</dict>\n")) {
+			if (!jetparse_match(ctx, "<key>")) {
+				jetval_decref(dict);
+				errno = EFTYPE;
+				return NULL;
+			}
+
+			keystart = ctx->text;
+			while (*ctx->text != '\0' && *ctx->text != '<') {
+				ctx->text++;
+			}
+			keyend = ctx->text;
+			if (!jetparse_match(ctx, "</key>\n")) {
+				jetval_decref(dict);
+				errno = EFTYPE;
+				return NULL;
+			}
+			key = jetparse_buildstring(keystart, keyend-keystart);
+			if (key == NULL) {
+				sverrno = errno;
+				jetval_decref(dict);
+				errno = sverrno;
+				return NULL;
+			}
+
+			val = jetparse_get(ctx);
+			if (val == NULL) {
+				sverrno = errno;
+				free(key);
+				jetval_decref(dict);
+				errno = sverrno;
+				return NULL;
+			}
+			if (jetval_dict_set_mustfree(dict, key, val) < 0) {
+				sverrno = errno;
+				jetval_decref(val);
+				free(key);
+				jetval_decref(dict);
+				errno = sverrno;
+				return NULL;
+			}
+		}
+
+		return dict;
+	}
+	else {
+		errno = EFTYPE;
+		return NULL;
+	}
+}
+
+jetval *
+text_to_jetval(const char *text)
+{
+	struct jetparse_context ctx;
+	jetval *ret;
+	int sverrno;
+
+	ctx.text = text;
+
+	if (!jetparse_match(&ctx, "<jet>\n")) {
+		return NULL;
+	}
+
+	ret = jetparse_get(&ctx);
+	if (ret == NULL) {
+		return NULL;
+	}
+
+	if (!jetparse_match(&ctx, "</jet>\n")) {
+		sverrno = errno;
+		jetval_decref(ret);
+		errno = sverrno;
+		return NULL;
+	}
+
+	return ret;
+}
+
Index: othersrc/external/bsd/jetlib/lib/libjet/jetlib.c
diff -u /dev/null othersrc/external/bsd/jetlib/lib/libjet/jetlib.c:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/lib/libjet/jetlib.c	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,1150 @@
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include "jetlib.h"
+
+struct jetdictentry {
+	char *key;
+	jetval *val;
+};
+typedef struct jetdictentry jetdictentry;
+
+enum jetval_types {
+	JT_BOOL,
+	JT_INT,
+	JT_UINT,
+	JT_DOUBLE,
+
+	JT_STRING,
+	JT_BLOB,
+
+	JT_ARRAY,
+	JT_DICT,
+};
+
+struct jetval {
+	unsigned jv_refcount;
+	enum jetval_types jv_type;
+	union {
+		bool jv_bool;
+		intmax_t jv_int;
+		uintmax_t jv_uint;
+		double jv_double;
+
+		char *jv_string;
+		struct {
+			void *data;
+			size_t len;
+		} jv_blob;
+
+		struct {
+			void **v;
+			unsigned num, max;
+		} jv_array;
+		struct {
+			jetdictentry *v;
+			unsigned num, max;
+			unsigned nullslots;
+		} jv_dict;
+	};
+};
+
+////////////////////////////////////////////////////////////
+// assertions
+
+#define JVASSERT(x) ((x) ? (void)0 : jetval_badassert(#x, __FILE__, __LINE__))
+
+static
+void
+jetval_badassert(const char *expr, const char *file, int line)
+{
+	warnx("jetlib assertion failure: %s, at %s:%d", expr, file, line);
+	abort();
+}
+
+////////////////////////////////////////////////////////////
+// memory management
+
+static
+jetval *
+jetval_create(enum jetval_types t)
+{
+	jetval *jv;
+
+	jv = malloc(sizeof(*jv));
+	jv->jv_refcount = 1;
+	jv->jv_type = t;
+	return jv;
+}
+
+jetval *
+jetval_clone(const jetval *from)
+{
+	jetval *to;
+
+	if (from->jv_type == JT_ARRAY) {
+		to = jetval_emptyarray();
+	}
+	else if (from->jv_type == JT_DICT) {
+		to = jetval_emptydict();
+	}
+	else {
+		to = jetval_create(from->jv_type);
+	}
+	if (to == NULL) {
+		return NULL;
+	}
+
+	switch (from->jv_type) {
+	    case JT_INT: to->jv_int = from->jv_int; break;
+	    case JT_UINT: to->jv_uint = from->jv_uint; break;
+	    case JT_BOOL: to->jv_bool = from->jv_bool; break;
+	    case JT_DOUBLE: to->jv_double = from->jv_double; break;
+	    case JT_STRING:
+		{
+			char *s;
+
+			s = strdup(from->jv_string);
+			if (s == NULL) {
+				free(to);
+				return NULL;
+			}
+			to->jv_string = s;
+		}
+		break;
+	    case JT_BLOB:
+		{
+			char *data;
+
+			data = malloc(from->jv_blob.len);
+			if (data == NULL) {
+				free(to);
+				return NULL;
+			}
+			memcpy(data, from->jv_blob.data, from->jv_blob.len);
+			to->jv_blob.data = data;
+			to->jv_blob.len = from->jv_blob.len;
+		}
+		break;
+	    case JT_ARRAY:
+		{
+			unsigned i;
+
+			if (jetval_array_setsize(to, from->jv_array.num) < 0) {
+				jetval_decref(to);
+				return NULL;
+			}
+			for (i=0; i<from->jv_array.num; i++) {
+				if (jetval_array_set(to, i,
+						     from->jv_array.v[i]) < 0){
+					jetval_decref(to);
+					return NULL;
+				}
+			}
+		}
+		break;
+	    case JT_DICT:
+		{
+			// XXX
+		}
+		break;
+	}
+
+	return to;
+}
+
+static
+void
+jetval_destroy(jetval *jv)
+{
+	switch (jv->jv_type) {
+	    case JT_BOOL:
+	    case JT_INT:
+	    case JT_UINT:
+	    case JT_DOUBLE:
+		break;
+
+	    case JT_STRING:
+		free(jv->jv_string);
+		jv->jv_string = NULL; /* for paranoia */
+		break;
+	    case JT_BLOB:
+		free(jv->jv_blob.data);
+		jv->jv_blob.data = NULL; /* for paranoia */
+		break;
+	    case JT_ARRAY:
+		{
+			unsigned i;
+			jetval *x;
+
+			for (i=0; i<jv->jv_array.num; i++) {
+				x = jv->jv_array.v[i];
+				if (x != NULL) {
+					jetval_decref(x);
+				}
+			}
+		}
+		break;
+	    case JT_DICT:
+		{
+			// XXX
+		}
+		break;
+	}
+	free(jv);
+}
+
+void
+jetval_incref(jetval *jv)
+{
+	jv->jv_refcount++;
+	JVASSERT(jv->jv_refcount != 0);
+}
+
+void
+jetval_decref(jetval *jv)
+{
+	JVASSERT(jv->jv_refcount > 0);
+	jv->jv_refcount--;
+	if (jv->jv_refcount == 0) {
+		jetval_destroy(jv);
+	}
+}
+
+////////////////////////////////////////////////////////////
+// iteration
+
+jetiterator *jetval_iterate(jetval *);
+const char *jetiterator_thiskey(const jetiterator *);
+unsigned jetiterator_thisindex(const jetiterator *);
+const jetval *jetiterator_thisval(const jetiterator *);
+bool jetiterator_inrange(const jetiterator *);
+bool jetiterator_next(jetiterator *);
+bool jetiterator_prev(jetiterator *);
+void jetiterator_rewind(jetiterator *);
+void jetiterator_destroy(jetiterator *);
+
+////////////////////////////////////////////////////////////
+// inspection and traversal
+
+void
+jetval_inspect(const jetval *jv, void *ud, const jetval_inspector *funcs)
+{
+	switch (jv->jv_type) {
+	    case JT_BOOL:   funcs->jvi_bool(ud,   jv->jv_bool);     break;
+	    case JT_INT:    funcs->jvi_int (ud,   jv->jv_int);      break;
+	    case JT_UINT:   funcs->jvi_uint(ud,   jv->jv_uint);     break;
+	    case JT_DOUBLE: funcs->jvi_double(ud, jv->jv_double);   break;
+	    case JT_STRING: funcs->jvi_string(ud, jv->jv_string);   break;
+	    case JT_BLOB:   funcs->jvi_blob(ud,   jv->jv_blob.data,
+					          jv->jv_blob.len); break;
+	    case JT_ARRAY:  funcs->jvi_array(ud,  jv);              break;
+	    case JT_DICT:   funcs->jvi_dict(ud,   jv);              break;
+	}
+}
+
+static
+void
+jetval_dotraverse(const char *key, const jetval *jv,
+		  void *ud, jetval_traverser func)
+{
+	unsigned i;
+	const char *thiskey;
+
+	switch (jv->jv_type) {
+	    case JT_BOOL:
+	    case JT_INT:
+	    case JT_UINT:
+	    case JT_DOUBLE:
+	    case JT_STRING:
+	    case JT_BLOB:
+		func(ud, key, jv, 0);
+		break;
+	    case JT_ARRAY:
+		func(ud, key, jv, 1);
+		for (i=0; i<jv->jv_array.num; i++) {
+			jetval_dotraverse(NULL, jv->jv_array.v[i], ud, func);
+		}
+		func(ud, NULL, jv, -1);
+		break;
+	    case JT_DICT:
+		func(ud, key, jv, 1);
+		for (i=0; i<jv->jv_dict.num; i++) {
+			thiskey = jv->jv_dict.v[i].key;
+			if (thiskey != NULL) {
+				jetval_dotraverse(thiskey,
+						  jv->jv_dict.v[i].val,
+						  ud, func);
+			}
+		}
+		func(ud, NULL, jv, -1);
+		break;
+	}
+}
+
+void
+jetval_traverse(const jetval *jv, void *ud, jetval_traverser func)
+{
+	jetval_dotraverse(NULL, jv, ud, func);
+}
+
+////////////////////////////////////////////////////////////
+// simple types
+
+#define JETVAL_DEFINE_SIMPLE(n, N, t) \
+	jetval *					\
+	jetval_##n(t val)				\
+	{						\
+		jetval *ret;				\
+							\
+		ret = jetval_create(JT_##N);		\
+		ret->jv_##n = val;			\
+		return ret;				\
+	}						\
+							\
+	bool						\
+	jetval_is##n(const jetval *jv)			\
+	{						\
+		return jv->jv_type == JT_##N;		\
+	}						\
+							\
+	t						\
+	jetval_##n##_get(const jetval *jv)		\
+	{						\
+		JVASSERT(jv->jv_type == JT_##N);	\
+		return jv->jv_##n;			\
+	}						\
+							\
+	void						\
+	jetval_##n##_set(jetval *jv, t val)		\
+	{						\
+		JVASSERT(jv->jv_type == JT_##N);	\
+		jv->jv_##n = val;			\
+	}
+
+JETVAL_DEFINE_SIMPLE(int,    INT,    intmax_t);
+JETVAL_DEFINE_SIMPLE(uint,   UINT,   uintmax_t);
+JETVAL_DEFINE_SIMPLE(bool,   BOOL,   bool);
+JETVAL_DEFINE_SIMPLE(double, DOUBLE, double);
+
+////////////////////////////////////////////////////////////
+// strings
+
+static
+char *
+jetval_strdup2(const char *s, const char *t)
+{
+	size_t slen, tlen;
+	char *r;
+
+	slen = strlen(s);
+	tlen = strlen(t);
+	r = malloc(slen+tlen+1);
+	if (r == NULL) {
+		return r;
+	}
+	strcpy(r, s);
+	strcpy(r+slen, t);
+	return r;
+}
+
+static
+char *
+jetval_strdup3(const char *s, const char *t, const char *u)
+{
+	size_t slen, tlen, ulen;
+	char *r;
+
+	slen = strlen(s);
+	tlen = strlen(t);
+	ulen = strlen(u);
+	r = malloc(slen+tlen+ulen+1);
+	if (r == NULL) {
+		return r;
+	}
+	strcpy(r, s);
+	strcpy(r+slen, t);
+	strcpy(r+slen+tlen, u);
+	return r;
+}
+
+static
+char *
+jetval_strdup_bylen(const char *s, size_t len)
+{
+	char *r;
+
+	r = malloc(len+1);
+	if (r == NULL) {
+		return r;
+	}
+	memcpy(r, s, len);
+	r[len] = 0;
+	return r;
+}
+
+bool
+jetval_isstring(const jetval *jv)
+{
+	return jv->jv_type == JT_STRING;
+}
+
+const char *
+jetval_string_get(const jetval *jv)
+{
+	JVASSERT(jv->jv_type == JT_STRING);
+	return jv->jv_string;
+}
+
+jetval *
+jetval_string_mustfree(char *s)
+{
+	jetval *ret;
+
+	ret = jetval_create(JT_STRING);
+	if (ret == NULL) {
+		return NULL;
+	}
+	ret->jv_string = s;
+
+	return ret;
+}
+
+jetval *
+jetval_string(const char *s)
+{
+	jetval *ret;
+	char *r;
+
+	r = strdup(s);
+	if (r == NULL) {
+		return NULL;
+	}
+	ret = jetval_string_mustfree(r);
+	if (ret == NULL) {
+		free(r);
+		return NULL;
+	}
+
+	return ret;
+}
+
+jetval *
+jetval_string2(const char *s, const char *t)
+{
+	jetval *ret;
+	char *r;
+
+	r = jetval_strdup2(s, t);
+	if (r == NULL) {
+		return NULL;
+	}
+	ret = jetval_string_mustfree(r);
+	if (ret == NULL) {
+		free(r);
+		return NULL;
+	}
+
+	return ret;
+}
+
+jetval *
+jetval_string3(const char *s, const char *t, const char *u)
+{
+	jetval *ret;
+	char *r;
+
+	r = jetval_strdup3(s, t, u);
+	if (r == NULL) {
+		return NULL;
+	}
+	ret = jetval_string_mustfree(r);
+	if (ret == NULL) {
+		free(r);
+		return NULL;
+	}
+
+	return ret;
+}
+
+jetval *
+jetval_string_bylen(const char *s, size_t len)
+{
+	jetval *ret;
+	char *r;
+
+	r = jetval_strdup_bylen(s, len);
+	if (r == NULL) {
+		return NULL;
+	}
+	ret = jetval_string_mustfree(r);
+	if (ret == NULL) {
+		free(r);
+		return NULL;
+	}
+
+	return ret;
+}
+
+void
+jetval_string_set_mustfree(jetval *jv, char *s)
+{
+	JVASSERT(jv->jv_type == JT_STRING);
+	free(jv->jv_string);
+	jv->jv_string = s;
+}
+
+int
+jetval_string_set(jetval *jv, const char *s)
+{
+	char *r;
+
+	r = strdup(s);
+	if (r == NULL) {
+		return -1;
+	}
+	jetval_string_set_mustfree(jv, r);
+	return 0;
+}
+
+int
+jetval_string_set2(jetval *jv, const char *s, const char *t)
+{
+	char *r;
+
+	r = jetval_strdup2(s, t);
+	if (r == NULL) {
+		return -1;
+	}
+	jetval_string_set_mustfree(jv, r);
+	return 0;
+}
+
+int
+jetval_string_set3(jetval *jv, const char *s, const char *t, const char *u)
+{
+	char *r;
+
+	r = jetval_strdup3(s, t, u);
+	if (r == NULL) {
+		return -1;
+	}
+	jetval_string_set_mustfree(jv, r);
+	return 0;
+}
+
+int
+jetval_string_set_bylen(jetval *jv, const char *s, size_t len)
+{
+	char *r;
+
+	r = jetval_strdup_bylen(s, len);
+	if (r == NULL) {
+		return -1;
+	}
+	jetval_string_set_mustfree(jv, r);
+	return 0;
+}
+
+int
+jetval_string_append(jetval *jv, const char *s)
+{
+	char *r;
+
+	JVASSERT(jv->jv_type == JT_STRING);
+	r = jetval_strdup2(jv->jv_string, s);
+	if (r == NULL) {
+		return -1;
+	}
+	jetval_string_set_mustfree(jv, r);
+	return 0;
+}
+
+////////////////////////////////////////////////////////////
+// blobs
+
+jetval *
+jetval_blob_mustfree(void *data, size_t len)
+{
+	jetval *ret;
+
+	ret = jetval_create(JT_BLOB);
+	if (ret == NULL) {
+		return NULL;
+	}
+	ret->jv_blob.data = data;
+	ret->jv_blob.len = len;
+
+	return ret;
+}
+
+jetval *
+jetval_blob(const void *data, size_t len)
+{
+	jetval *ret;
+	void *ndata;
+
+	ndata = malloc(len);
+	if (ndata == NULL) {
+		return NULL;
+	}
+	memcpy(ndata, data, len);
+	ret = jetval_blob_mustfree(ndata, len);
+	if (ret == NULL) {
+		free(ndata);
+		return NULL;
+	}
+
+	return ret;
+}
+
+bool
+jetval_isblob(const jetval *jv)
+{
+	return jv->jv_type == JT_BLOB;
+}
+
+const void *
+jetval_blob_getdata(const jetval *jv)
+{
+	JVASSERT(jv->jv_type == JT_BLOB);
+	return jv->jv_blob.data;
+}
+
+size_t
+jetval_blob_getlen(const jetval *jv)
+{
+	JVASSERT(jv->jv_type == JT_BLOB);
+	return jv->jv_blob.len;
+}
+
+////////////////////////////////////////////////////////////
+// arrays
+
+jetval *
+jetval_emptyarray(void)
+{
+	jetval *ret;
+
+	ret = jetval_create(JT_ARRAY);
+	ret->jv_array.v = NULL;
+	ret->jv_array.num = 0;
+	ret->jv_array.max = 0;
+
+	return ret;
+}
+
+bool
+jetval_isarray(const jetval *jv)
+{
+	return jv->jv_type == JT_ARRAY;
+}
+
+unsigned
+jetval_array_num(const jetval *jv)
+{
+	JVASSERT(jv->jv_type == JT_ARRAY);
+	return jv->jv_array.num;
+}
+
+int
+jetval_array_preallocate(jetval *jv, unsigned maxnum_req)
+{
+	unsigned newmax;
+	void **newv;
+
+	JVASSERT(jv->jv_type == JT_ARRAY);
+	if (maxnum_req > jv->jv_array.max) {
+		newmax = jv->jv_array.max;
+		while (newmax < maxnum_req) {
+			newmax = (newmax == 0) ? 4 : newmax*2;
+		}
+		newv = realloc(jv->jv_array.v,
+			       newmax*sizeof(jv->jv_array.v[0]));
+		if (newv == NULL) {
+			return -1;
+		}
+		jv->jv_array.v = newv;
+		jv->jv_array.max = newmax;
+	}
+	return 0;
+}
+
+int
+jetval_array_setsize(jetval *jv, unsigned num)
+{
+	unsigned oldnum, i;
+	jetval *x;
+
+	JVASSERT(jv->jv_type == JT_ARRAY);
+
+	oldnum = jv->jv_array.num;
+
+	if (num < oldnum) {
+		/* shrinking; delete any dropped elements */
+		for (i=num; i<oldnum; i++) {
+			x = jv->jv_array.v[i];
+			if (x != NULL) {
+				jetval_decref(x);
+				jv->jv_array.v[i] = NULL;
+			}
+		}
+	}
+
+	if (num > jv->jv_array.max) {
+		if (jetval_array_preallocate(jv, num) < 0) {
+			return -1;
+		}
+	}
+	JVASSERT(num <= jv->jv_array.max);
+
+	if (num > oldnum) {
+		/* growing; null out new space */
+		for (i=num; i<oldnum; i++) {
+			jv->jv_array.v[i] = NULL;
+		}
+	}
+
+	jv->jv_array.num = num;
+	return 0;
+}
+
+const jetval *
+jetval_array_get(const jetval *jv, unsigned ix)
+{
+	JVASSERT(jv->jv_type == JT_ARRAY);
+	JVASSERT(ix < jv->jv_array.num);
+	return jv->jv_array.v[ix];
+}
+
+void
+jetval_array_set_mustfree(jetval *array, unsigned ix, jetval *val)
+{
+	JVASSERT(array->jv_type == JT_ARRAY);
+	JVASSERT(ix < array->jv_array.num);
+
+	array->jv_array.v[ix] = val;
+}
+
+int
+jetval_array_set(jetval *array, unsigned ix, const jetval *val)
+{
+	jetval *newval;
+
+	newval = jetval_clone(val);
+	if (newval == NULL) {
+		return -1;
+	}
+
+	jetval_array_set_mustfree(array, ix, newval);
+	return 0;
+}
+
+int
+jetval_array_add(jetval *array, const jetval *val)
+{
+	unsigned ix;
+
+	JVASSERT(array->jv_type == JT_ARRAY);
+	ix = array->jv_array.num;
+
+	if (jetval_array_setsize(array, ix+1) < 0) {
+		return -1;
+	}
+	return jetval_array_set(array, ix, val);
+}
+
+int
+jetval_array_add_mustfree(jetval *array, jetval *val)
+{
+	unsigned ix;
+
+	JVASSERT(array->jv_type == JT_ARRAY);
+	ix = array->jv_array.num;
+
+	if (jetval_array_setsize(array, ix+1) < 0) {
+		return -1;
+	}
+	jetval_array_set_mustfree(array, ix, val);
+	return 0;
+}
+
+////////////////////////////////////////////////////////////
+// dictionaries
+
+/* Dictionaries */
+jetval *
+jetval_emptydict(void)
+{
+	jetval *ret;
+
+	ret = jetval_create(JT_DICT);
+	ret->jv_dict.v = NULL;
+	ret->jv_dict.num = 0;
+	ret->jv_dict.max = 0;
+	ret->jv_dict.nullslots = 0;
+
+	return ret;
+}
+
+bool
+jetval_isdict(const jetval *jv)
+{
+	return jv->jv_type == JT_DICT;
+}
+
+unsigned
+jetval_dict_num(const jetval *jv)
+{
+	JVASSERT(jv->jv_type == JT_DICT);
+	return jv->jv_dict.num - jv->jv_dict.nullslots;
+}
+
+static
+void
+jetval_dict_nullify_entry(const jetval *dict, unsigned ix)
+{
+	JVASSERT(dict->jv_type == JT_DICT);
+	free(dict->jv_dict.v[ix].key);
+	jetval_decref(dict->jv_dict.v[ix].val);
+	dict->jv_dict.v[ix].key = NULL;
+	dict->jv_dict.v[ix].val = NULL;
+}
+
+int
+jetval_dict_preallocate(jetval *dict, unsigned maxnum_req)
+{
+	unsigned newmax;
+	jetdictentry *newv;
+
+	JVASSERT(dict->jv_type == JT_DICT);
+	if (maxnum_req > dict->jv_dict.max) {
+		newmax = dict->jv_dict.max;
+		while (newmax < maxnum_req) {
+			newmax = (newmax == 0) ? 4 : newmax*2;
+		}
+		newv = realloc(dict->jv_dict.v,
+			       newmax*sizeof(dict->jv_dict.v[0]));
+		if (newv == NULL) {
+			return -1;
+		}
+		dict->jv_dict.v = newv;
+		dict->jv_dict.max = newmax;
+	}
+	return 0;
+}
+
+static
+int
+jetval_dict_setsize(jetval *jv, unsigned num)
+{
+	unsigned oldnum, i;
+	const char *thiskey;
+
+	JVASSERT(jv->jv_type == JT_DICT);
+
+	oldnum = jv->jv_dict.num;
+
+	if (num < oldnum) {
+		/* shrinking; delete any dropped elements */
+		for (i=num; i<oldnum; i++) {
+			thiskey = jv->jv_dict.v[i].key;
+			if (thiskey != NULL) {
+				jetval_dict_nullify_entry(jv, i);
+			}
+		}
+	}
+
+	if (num > jv->jv_dict.max) {
+		if (jetval_dict_preallocate(jv, num) < 0) {
+			return -1;
+		}
+	}
+	JVASSERT(num <= jv->jv_dict.max);
+
+	if (num > oldnum) {
+		/* growing; null out new space */
+		for (i=num; i<oldnum; i++) {
+			jv->jv_dict.v[i].key = NULL;
+			jv->jv_dict.v[i].val = NULL;
+		}
+	}
+
+	jv->jv_dict.num = num;
+	return 0;
+}
+
+const jetval *
+jetval_dict_get(const jetval *dict, const char *key)
+{
+	unsigned i;
+	const char *thiskey;
+
+	JVASSERT(dict->jv_type == JT_DICT);
+	for (i=0; i<dict->jv_dict.num; i++) {
+		thiskey = dict->jv_dict.v[i].key;
+		if (thiskey != NULL && !strcmp(thiskey, key)) {
+			return dict->jv_dict.v[i].val;
+		}
+	}
+	return NULL;
+}
+
+int
+jetval_dict_set_mustfree(jetval *dict, char *key, jetval *val)
+{
+	unsigned i, nullslot = (unsigned)-1;
+	const char *thiskey;
+	bool havenullslot = false;
+
+	JVASSERT(dict->jv_type == JT_DICT);
+	for (i=0; i<dict->jv_dict.num; i++) {
+		thiskey = dict->jv_dict.v[i].key;
+		if (thiskey == NULL && !havenullslot) {
+			nullslot = i;
+			havenullslot = true;
+		}
+		else if (!strcmp(thiskey, key)) {
+			jetval_decref(dict->jv_dict.v[i].val);
+			dict->jv_dict.v[i].val = val;
+			free(key);
+			return 0;
+		}
+	}
+
+	/* key not yet present */
+
+	if (!havenullslot) {
+		nullslot = dict->jv_dict.num;
+		if (jetval_dict_setsize(dict, nullslot+1) < 0) {
+			return -1;
+		}
+	}
+
+	dict->jv_dict.v[nullslot].key = key;
+	dict->jv_dict.v[nullslot].val = val;
+	if (havenullslot) {
+		dict->jv_dict.nullslots--;
+	}
+
+	return 0;
+}
+
+int
+jetval_dict_set(jetval *dict, const char *key, const jetval *val)
+{
+	char *mykey;
+	jetval *myval;
+
+	mykey = strdup(key);
+	if (mykey == NULL) {
+		return -1;
+	}
+	myval = jetval_clone(val);
+	if (myval == NULL) {
+		free(mykey);
+		return -1;
+	}
+
+	if (jetval_dict_set_mustfree(dict, mykey, myval)) {
+		jetval_decref(myval);
+		free(mykey);
+		return -1;
+	}
+	return 0;
+}
+
+void
+jetval_dict_unset(jetval *dict, const char *key)
+{
+	unsigned i;
+	const char *thiskey;
+
+	JVASSERT(dict->jv_type == JT_DICT);
+	for (i=0; i<dict->jv_dict.num; i++) {
+		thiskey = dict->jv_dict.v[i].key;
+		if (thiskey != NULL && !strcmp(thiskey, key)) {
+			jetval_dict_nullify_entry(dict, i);
+			dict->jv_dict.nullslots++;
+			return;
+		}
+	}
+}
+
+void
+jetval_dict_clear(jetval *dict)
+{
+	unsigned i;
+	const char *thiskey;
+
+	JVASSERT(dict->jv_type == JT_DICT);
+	for (i=0; i<dict->jv_dict.num; i++) {
+		thiskey = dict->jv_dict.v[i].key;
+		if (thiskey != NULL) {
+			jetval_dict_nullify_entry(dict, i);
+		}
+	}
+	dict->jv_dict.num = 0;
+	dict->jv_dict.nullslots = 0;
+}
+
+////////////////////////////////////////////////////////////
+// abstract type checks
+
+bool
+jetval_isanyinteger(const jetval *jv)
+{
+	return jv->jv_type == JT_INT || jv->jv_type == JT_UINT;
+}
+
+bool
+jetval_isanynumber(const jetval *jv)
+{
+	return jv->jv_type == JT_DOUBLE || jetval_isanyinteger(jv);
+}
+
+////////////////////////////////////////////////////////////
+// other tests
+
+bool
+jetval_sametype(const jetval *a, const jetval *b)
+{
+	return a->jv_type == b->jv_type;
+}
+
+bool
+jetval_eq(const jetval *a, const jetval *b)
+{
+	/*
+	 * Non-matching-type comparisons first
+	 */
+
+	/* signed vs. unsigned */
+	if (jetval_isint(a) && jetval_isuint(b)) {
+		intmax_t av;
+		uintmax_t bv;
+
+		av = jetval_int_get(a);
+		bv = jetval_uint_get(b);
+		if (av < 0) {
+			return false;
+		}
+		return (uintmax_t)av == bv;
+	}
+	if (jetval_isuint(a) && jetval_isint(b)) {
+		return jetval_eq(b, a);
+	}
+
+	/* integer vs. float */
+	if (jetval_isdouble(a) && jetval_isint(b)) {
+		double av;
+		intmax_t bv;
+
+		av = jetval_double_get(a);
+		bv = jetval_int_get(b);
+		return av == (double)bv;
+	}
+	if (jetval_isdouble(a) && jetval_isuint(b)) {
+		double av;
+		uintmax_t bv;
+
+		av = jetval_double_get(a);
+		bv = jetval_uint_get(b);
+		return av == (double)bv;
+	}
+	if (jetval_isdouble(b) && (jetval_isint(a) || jetval_isuint(a))) {
+		return jetval_eq(b, a);
+	}
+
+	/* all others are unequal if not the same type */
+	if (!jetval_sametype(a, b)) {
+		return false;
+	}
+
+	switch (a->jv_type) {
+	    case JT_BOOL: return a->jv_bool == b->jv_bool;
+	    case JT_INT: return a->jv_int == b->jv_int;
+	    case JT_UINT: return a->jv_uint == b->jv_uint;
+	    case JT_DOUBLE: return a->jv_double == b->jv_double;
+	    case JT_STRING: return !strcmp(a->jv_string, b->jv_string);
+	    case JT_BLOB:
+		return a->jv_blob.len == b->jv_blob.len &&
+			!memcmp(a->jv_blob.data, b->jv_blob.data,
+				a->jv_blob.len);
+	    case JT_ARRAY:
+		{
+			unsigned i;
+
+			if (a->jv_array.num != b->jv_array.num) {
+				return false;
+			}
+
+			for (i=0; i<a->jv_array.num; i++) {
+				if (!jetval_eq(a->jv_array.v[i],
+					       b->jv_array.v[i])) {
+					return false;
+				}
+			}
+		}
+		return true;
+	    case JT_DICT:
+		{
+			// XXX
+		}
+		break;
+	}
+	return false;
+}
+
+bool
+jetval_istrue(const jetval *jv)
+{
+	switch (jv->jv_type) {
+	    case JT_BOOL: return jv->jv_bool != false;
+	    case JT_INT: return jv->jv_int != 0;
+	    case JT_UINT: return jv->jv_uint != 0;
+	    case JT_DOUBLE: return jv->jv_double != 0.0;
+	    case JT_STRING: return jv->jv_string[0] != '\0';
+	    case JT_BLOB: return jv->jv_blob.len > 0;
+	    case JT_ARRAY: return jv->jv_array.num > 0;
+	    case JT_DICT: /* XXX */ break;
+	}
+	return false;
+}
+
+////////////////////////////////////////////////////////////
+// common-case combination functions
+
+bool
+jetval_eq_int(const jetval *a, intmax_t b)
+{
+	jetval *jvb;
+	bool ret;
+
+	jvb = jetval_int(b);
+	ret = jetval_eq(a, jvb);
+	jetval_decref(jvb);
+
+	return ret;
+}
+
+bool
+jetval_eq_uint(const jetval *a, uintmax_t b)
+{
+	jetval *jvb;
+	bool ret;
+
+	jvb = jetval_uint(b);
+	ret = jetval_eq(a, jvb);
+	jetval_decref(jvb);
+
+	return ret;
+}
+
+bool
+jetval_eq_string(const jetval *a, const char *b)
+{
+	return jetval_isstring(a) && !strcmp(jetval_string_get(a), b);
+}
+
+
Index: othersrc/external/bsd/jetlib/lib/libjet/jetlib.h
diff -u /dev/null othersrc/external/bsd/jetlib/lib/libjet/jetlib.h:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/lib/libjet/jetlib.h	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,144 @@
+#ifndef _JETLIB_H_
+#define _JETLIB_H_
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct jetval;		/* Opaque. */
+typedef struct jetval jetval;
+
+struct jetiterator;	/* Opaque. */
+typedef struct jetiterator jetiterator;
+
+/* Memory management */
+jetval *jetval_clone(const jetval *);
+void jetval_incref(jetval *);
+void jetval_decref(jetval *);
+
+/* Iteration */
+jetiterator *jetval_iterate(jetval *);
+const char *jetiterator_thiskey(const jetiterator *);
+unsigned jetiterator_thisindex(const jetiterator *);
+const jetval *jetiterator_thisval(const jetiterator *);
+bool jetiterator_inrange(const jetiterator *);
+bool jetiterator_next(jetiterator *);
+bool jetiterator_prev(jetiterator *);
+void jetiterator_rewind(jetiterator *);
+void jetiterator_destroy(jetiterator *);
+
+#define JETVAL_FORALL(sym, val) \
+    for (jetiterator *sym = jetval_iterate(val);	\
+         sym != NULL && jetiterator_inrange(sym);	\
+	 jetiterator_next(sym))
+
+/* Inspection and traversal */
+struct jetval_inspector {
+	void (*jvi_bool)(void *userdata, bool val);
+	void (*jvi_int)(void *userdata, intmax_t val);
+	void (*jvi_uint)(void *userdata, uintmax_t val);
+	void (*jvi_double)(void *userdata, double val);
+	void (*jvi_string)(void *userdata, const char *str);
+	void (*jvi_blob)(void *userdata, const void *data, size_t len);
+	void (*jvi_array)(void *userdata, const jetval *dict);
+	void (*jvi_dict)(void *userdata, const jetval *dict);
+};
+typedef struct jetval_inspector jetval_inspector;
+
+void jetval_inspect(const jetval *jv, void *userdata,
+			const jetval_inspector *funcs);
+
+typedef void (*jetval_traverser)
+    (void *userdata, const char *key, const jetval *jv, int depthchange);
+
+void jetval_traverse(const jetval *root, void *userdata,
+			jetval_traverser func);
+
+/*
+ * Specific types and operations thereon
+ *
+ * Each type should have a constructor, an is* test, and sufficient
+ * operations to allow working with values of that type. Simple types
+ * have a constructor named by the type and _get and _set methods.
+ * More complex types have more complex operations as needed.
+ */
+
+#define JETVAL_DECLARE_SIMPLE(n, t) \
+    jetval *jetval_##n(t);			\
+    bool jetval_is##n(const jetval *);		\
+    t jetval_##n##_get(const jetval *);		\
+    void jetval_##n##_set(jetval *, t)
+
+/* Simple types */
+JETVAL_DECLARE_SIMPLE(int, intmax_t);
+JETVAL_DECLARE_SIMPLE(uint, uintmax_t);
+JETVAL_DECLARE_SIMPLE(bool, bool);
+JETVAL_DECLARE_SIMPLE(double, double);
+
+/* Strings */
+bool jetval_isstring(const jetval *);
+const char *jetval_string_get(const jetval *);
+jetval *jetval_string(const char *);
+jetval *jetval_string2(const char *, const char *);
+jetval *jetval_string3(const char *, const char *, const char *);
+jetval *jetval_string_bylen(const char *, size_t len);
+jetval *jetval_string_mustfree(char *);
+int jetval_string_set(jetval *, const char *);
+int jetval_string_set2(jetval *, const char *, const char *);
+int jetval_string_set3(jetval *, const char *, const char *, const char *);
+int jetval_string_set_bylen(jetval *, const char *, size_t len);
+void jetval_string_set_mustfree(jetval *, char *);
+int jetval_string_append(jetval *, const char *);
+
+/* Blobs */
+jetval *jetval_blob(const void *data, size_t len);
+jetval *jetval_blob_mustfree(void *data, size_t len);
+bool jetval_isblob(const jetval *);
+const void *jetval_blob_getdata(const jetval *);
+size_t jetval_blob_getlen(const jetval *);
+
+/* Arrays */
+jetval *jetval_emptyarray(void);
+bool jetval_isarray(const jetval *);
+unsigned jetval_array_num(const jetval *);
+int jetval_array_preallocate(jetval *, unsigned maxnum);
+int jetval_array_setsize(jetval *, unsigned num);
+const jetval *jetval_array_get(const jetval *array, unsigned ix);
+int jetval_array_set(jetval *array, unsigned ix, const jetval *val);
+void jetval_array_set_mustfree(jetval *array, unsigned ix, jetval *val);
+int jetval_array_add(jetval *array, const jetval *val);
+int jetval_array_add_mustfree(jetval *array, jetval *val);
+
+/* Dictionaries */
+jetval *jetval_emptydict(void);
+bool jetval_isdict(const jetval *);
+unsigned jetval_dict_num(const jetval *);
+int jetval_dict_preallocate(jetval *, unsigned num);
+const jetval *jetval_dict_get(const jetval *dict, const char *key);
+int jetval_dict_set(jetval *, const char *key, const jetval *val);
+int jetval_dict_set_mustfree(jetval *, char *key, jetval *val);
+void jetval_dict_unset(jetval *, const char *key);
+void jetval_dict_clear(jetval *dict);
+
+/* Abstract type checks */
+bool jetval_isanynumber(const jetval *);
+bool jetval_isanyinteger(const jetval *);
+
+/* Other tests */
+bool jetval_istrue(const jetval *);
+bool jetval_eq(const jetval *, const jetval *);
+bool jetval_sametype(const jetval *, const jetval *);
+
+/* Common-case combination functions */
+bool jetval_eq_int(const jetval *, intmax_t);
+bool jetval_eq_uint(const jetval *, uintmax_t);
+bool jetval_eq_string(const jetval *, const char *);
+
+/* I/O */
+char *jetval_to_text(const jetval *jv);
+jetval *text_to_jetval(const char *text);
+
+jetval *jetval_to_blob(const jetval *jv);
+jetval *blob_to_jetval(const jetval *blob);
+
+#endif /* _JETLIB_H_ */
Index: othersrc/external/bsd/jetlib/lib/libjet/jettobin.c
diff -u /dev/null othersrc/external/bsd/jetlib/lib/libjet/jettobin.c:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/lib/libjet/jettobin.c	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,289 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include "jetlib.h"
+
+////////////////////////////////////////////////////////////
+// assertions
+
+#define JBASSERT(x) ((x) ? (void)0 : jetbin_badassert(#x, __FILE__, __LINE__))
+
+static
+void
+jetbin_badassert(const char *expr, const char *file, int line)
+{
+	warnx("jetlib assertion failure: %s, at %s:%d", expr, file, line);
+	abort();
+}
+
+////////////////////////////////////////////////////////////
+// support functions
+
+struct jetbin_context {
+	bool allocated;
+	unsigned char *buf;
+	size_t pos, max;
+
+	int depthchange;
+};
+
+static
+void
+jetbin_init(struct jetbin_context *ctx)
+{
+	ctx->allocated = false;
+	ctx->buf = NULL;
+	ctx->pos = 0;
+	ctx->max = 0;
+	ctx->depthchange = 0;
+}
+
+static
+int
+jetbin_allocate(struct jetbin_context *ctx)
+{
+	JBASSERT(ctx->allocated == false);
+	JBASSERT(ctx->max > 0);
+
+	ctx->buf = malloc(ctx->max);
+	if (ctx->buf == NULL) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static
+void
+jetbin_addch(struct jetbin_context *ctx, unsigned char ch)
+{
+	if (ctx->allocated) {
+		JBASSERT(ctx->pos + 1 < ctx->max);
+		ctx->buf[ctx->pos] = ch;
+		ctx->pos++;
+	}
+	else {
+		ctx->max++;
+	}
+}
+
+static
+void
+jetbin_addblob(struct jetbin_context *ctx, const void *x, size_t len)
+{
+	if (ctx->allocated) {
+		JBASSERT(ctx->pos + len < ctx->max);
+		memcpy(ctx->buf + ctx->pos, x, len);
+		ctx->pos += len;
+	}
+	else {
+		ctx->max += len;
+	}
+}
+
+static
+void
+jetbin_addsize(struct jetbin_context *ctx, size_t sz)
+{
+	jetbin_addblob(ctx, &sz, sizeof(sz));
+}
+
+static
+void
+jetbin_addstring(struct jetbin_context *ctx, const char *s)
+{
+	size_t len;
+
+	len = strlen(s);
+
+	if (len <= UCHAR_MAX) {
+		jetbin_addch(ctx, 's');
+		jetbin_addch(ctx, (unsigned char)len);
+	}
+	else {
+		jetbin_addch(ctx, 'S');
+		jetbin_addsize(ctx, len);
+	}
+	jetbin_addblob(ctx, s, len);
+}
+
+static
+jetval *
+jetbin_finish(struct jetbin_context *ctx)
+{
+	jetval *ret;
+	int sverrno;
+
+	ret = jetval_blob(ctx->buf, ctx->pos);
+	if (ret == NULL) {
+		sverrno = errno;
+		free(ctx->buf);
+		errno = sverrno;
+		return NULL;
+	}
+	return ret;
+}
+
+////////////////////////////////////////////////////////////
+// per-type functions
+
+static
+void
+jetbin_inspect_bool(void *x, bool val)
+{
+	struct jetbin_context *ctx = x;
+
+	jetbin_addch(ctx, val ? 'T' : 'F');
+}
+
+static
+void
+jetbin_inspect_int(void *x, intmax_t val)
+{
+	struct jetbin_context *ctx = x;
+
+	if (val >= INT_MIN && val <= INT_MAX) {
+		int ival = (int)val;
+
+		jetbin_addch(ctx, 'i');
+		jetbin_addblob(ctx, &ival, sizeof(ival));
+	}
+	else {
+		jetbin_addch(ctx, 'I');
+		jetbin_addblob(ctx, &val, sizeof(val));
+	}
+}
+
+static
+void
+jetbin_inspect_uint(void *x, uintmax_t val)
+{
+	struct jetbin_context *ctx = x;
+
+	if (val <= UINT_MAX) {
+		unsigned uval = (unsigned)val;
+
+		jetbin_addch(ctx, 'u');
+		jetbin_addblob(ctx, &uval, sizeof(uval));
+	}
+	else {
+		jetbin_addch(ctx, 'U');
+		jetbin_addblob(ctx, &val, sizeof(val));
+	}
+}
+
+static
+void
+jetbin_inspect_double(void *x, double val)
+{
+	struct jetbin_context *ctx = x;
+
+	jetbin_addch(ctx, 'D');
+	jetbin_addblob(ctx, &val, sizeof(val));
+}
+
+static
+void
+jetbin_inspect_string(void *x, const char *s)
+{
+	struct jetbin_context *ctx = x;
+
+	jetbin_addstring(ctx, s);
+}
+
+static
+void
+jetbin_inspect_blob(void *x, const void *data, size_t len)
+{
+	struct jetbin_context *ctx = x;
+
+	if (len < UCHAR_MAX) {
+		jetbin_addch(ctx, 'b');
+		jetbin_addch(ctx, (unsigned char)len);
+	}
+	else {
+		jetbin_addch(ctx, 'B');
+		jetbin_addsize(ctx, len);
+	}
+	jetbin_addblob(ctx, data, len);
+}
+
+static
+void
+jetbin_inspect_array(void *x, const jetval *array)
+{
+	struct jetbin_context *ctx = x;
+
+	if (ctx->depthchange > 0) {
+		jetbin_addblob(ctx, "AB", 2);
+	}
+	if (ctx->depthchange < 0) {
+		jetbin_addblob(ctx, "AE", 2);
+	}
+}
+
+static
+void
+jetbin_inspect_dict(void *x, const jetval *dict)
+{
+	struct jetbin_context *ctx = x;
+
+	if (ctx->depthchange > 0) {
+		jetbin_addblob(ctx, "DB", 2);
+	}
+	if (ctx->depthchange < 0) {
+		jetbin_addblob(ctx, "DE", 2);
+	}
+}
+
+static const jetval_inspector jetbin_inspector = {
+	jetbin_inspect_bool,
+	jetbin_inspect_int,
+	jetbin_inspect_uint,
+	jetbin_inspect_double,
+	jetbin_inspect_string,
+	jetbin_inspect_blob,
+	jetbin_inspect_array,
+	jetbin_inspect_dict,
+};
+
+////////////////////////////////////////////////////////////
+// driver
+
+static
+void
+jetbin_traversal(void *x, const char *key, const jetval *jv, int depthchange)
+{
+	struct jetbin_context *ctx = x;
+	ctx->depthchange = depthchange;
+
+	if (key != NULL) {
+		jetbin_addch(ctx, 'K');
+		jetbin_addstring(ctx, key);
+	}
+
+	jetval_inspect(jv, x, &jetbin_inspector);
+}
+
+jetval *
+jetval_to_blob(const jetval *jv)
+{
+	struct jetbin_context ctx;
+
+	jetbin_init(&ctx);
+
+	jetbin_addblob(&ctx, "JET-BIN!", 8);
+	jetval_traverse(jv, &ctx, jetbin_traversal);
+
+	if (jetbin_allocate(&ctx) < 0) {
+		return NULL;
+	}
+
+	jetbin_addblob(&ctx, "JET-BIN!", 8);
+	jetval_traverse(jv, &ctx, jetbin_traversal);
+
+	return jetbin_finish(&ctx);
+}
Index: othersrc/external/bsd/jetlib/lib/libjet/jettotext.c
diff -u /dev/null othersrc/external/bsd/jetlib/lib/libjet/jettotext.c:1.1
--- /dev/null	Thu Feb  6 04:57:02 2014
+++ othersrc/external/bsd/jetlib/lib/libjet/jettotext.c	Thu Feb  6 04:57:02 2014
@@ -0,0 +1,299 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include "jetlib.h"
+
+////////////////////////////////////////////////////////////
+// assertions
+
+#define JTASSERT(x) ((x) ? (void)0 : jettext_badassert(#x, __FILE__, __LINE__))
+
+static
+void
+jettext_badassert(const char *expr, const char *file, int line)
+{
+	warnx("jetlib assertion failure: %s, at %s:%d", expr, file, line);
+	abort();
+}
+
+////////////////////////////////////////////////////////////
+// support functions
+
+struct jettext_context {
+	bool allocated;
+	char *buf;
+	size_t pos, max;
+
+	int depthchange;
+};
+
+static
+void
+jettext_init(struct jettext_context *ctx)
+{
+	ctx->allocated = false;
+	ctx->buf = NULL;
+	ctx->pos = 0;
+	ctx->max = 0;
+	ctx->depthchange = 0;
+}
+
+static
+int
+jettext_allocate(struct jettext_context *ctx)
+{
+	JTASSERT(ctx->allocated == false);
+	JTASSERT(ctx->max > 0);
+
+	/* make room for a null terminator */
+	ctx->max++;
+
+	ctx->buf = malloc(ctx->max);
+	if (ctx->buf == NULL) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static
+void
+jettext_addch(struct jettext_context *ctx, unsigned char ch)
+{
+	if (ctx->allocated) {
+		JTASSERT(ctx->pos + 1 < ctx->max);
+		ctx->buf[ctx->pos] = ch;
+		ctx->pos++;
+	}
+	else {
+		ctx->max++;
+	}
+}
+
+static
+void
+jettext_addstring(struct jettext_context *ctx, const char *s)
+{
+	size_t len;
+
+	len = strlen(s);
+	if (ctx->allocated) {
+		JTASSERT(ctx->pos + len < ctx->max);
+		strcpy(ctx->buf + ctx->pos, s);
+		ctx->pos += len;
+	}
+	else {
+		ctx->max += len;
+	}
+}
+
+static
+char *
+jettext_finish(struct jettext_context *ctx)
+{
+	/* null terminate */
+	ctx->buf[ctx->pos] = 0;
+	return ctx->buf;
+}
+
+static
+void
+jettext_encodestring(struct jettext_context *ctx, const char *s)
+{
+	size_t i;
+
+	for (i=0; s[i]; i++) {
+		if (*s == '&') {
+			jettext_addstring(ctx, "&amp;");
+		}
+		else if (*s == '<') {
+			jettext_addstring(ctx, "&lt;");
+		}
+		else if (*s == '>') {
+			jettext_addstring(ctx, "&gt;");
+		}
+		else {
+			jettext_addch(ctx, s[i]);
+		}
+	}
+}
+
+////////////////////////////////////////////////////////////
+// per-type functions
+
+static
+void
+jettext_inspect_bool(void *x, bool val)
+{
+	struct jettext_context *ctx = x;
+
+	jettext_addstring(ctx, "<bool>");
+	jettext_addstring(ctx, val ? "true" : "false");
+	jettext_addstring(ctx, "</bool>\n");
+}
+
+static
+void
+jettext_inspect_int(void *x, intmax_t val)
+{
+	struct jettext_context *ctx = x;
+	char tmp[sizeof(uintmax_t)*(CHAR_BIT/4)+1 + 10/*slop*/];
+	uintmax_t uval;
+	const char *sign;
+
+	if (val < 0) {
+		/* avoid overflow in case val is INTMAX_MIN */
+		uval = ((uintmax_t) -(val+1)) + 1;
+		sign = "-";
+	}
+	else {
+		uval = (uintmax_t) val;
+		sign = "";
+	}
+
+	snprintf(tmp, sizeof(tmp), "%jx", uval);
+
+	jettext_addstring(ctx, "<int>");
+	jettext_addstring(ctx, sign);
+	jettext_addstring(ctx, tmp);
+	jettext_addstring(ctx, "</int>\n");
+}
+
+static
+void
+jettext_inspect_uint(void *x, uintmax_t val)
+{
+	struct jettext_context *ctx = x;
+	char tmp[sizeof(uintmax_t)*(CHAR_BIT/4)+1 + 10/*slop*/];
+
+	snprintf(tmp, sizeof(tmp), "%jx", val);
+
+	jettext_addstring(ctx, "<uint>");
+	jettext_addstring(ctx, tmp);
+	jettext_addstring(ctx, "</uint>\n");
+}
+
+static
+void
+jettext_inspect_double(void *x, double val)
+{
+	struct jettext_context *ctx = x;
+	char tmp[256];
+
+	/* XXX is there a way to print a float that doesn't lose precision? */
+	snprintf(tmp, sizeof(tmp), "%.128e", val);
+
+	jettext_addstring(ctx, "<double>");
+	jettext_addstring(ctx, tmp);
+	jettext_addstring(ctx, "</double>\n");
+}
+
+static
+void
+jettext_inspect_string(void *x, const char *s)
+{
+	struct jettext_context *ctx = x;
+
+	jettext_addstring(ctx, "<string>");
+	jettext_encodestring(ctx, s);
+	jettext_addstring(ctx, "</string>\n");
+}
+
+static
+void
+jettext_inspect_blob(void *x, const void *data, size_t len)
+{
+	struct jettext_context *ctx = x;
+	const unsigned char *udata = data;
+	char tmp[4];
+	size_t i;
+
+	jettext_addstring(ctx, "<blob>");
+	for (i=0; i<len; i++) {
+		snprintf(tmp, sizeof(tmp), "%02x", udata[i]);
+		jettext_addstring(ctx, tmp);
+	}
+	jettext_addstring(ctx, "</blob>\n");
+}
+
+static
+void
+jettext_inspect_array(void *x, const jetval *array)
+{
+	struct jettext_context *ctx = x;
+
+	if (ctx->depthchange > 0) {
+		jettext_addstring(ctx, "<array>\n");
+	}
+	if (ctx->depthchange < 0) {
+		jettext_addstring(ctx, "</array>\n");
+	}
+}
+
+static
+void
+jettext_inspect_dict(void *x, const jetval *dict)
+{
+	struct jettext_context *ctx = x;
+
+	if (ctx->depthchange > 0) {
+		jettext_addstring(ctx, "<dict>\n");
+	}
+	if (ctx->depthchange < 0) {
+		jettext_addstring(ctx, "</dict>\n");
+	}
+}
+
+static const jetval_inspector jettext_inspector = {
+	jettext_inspect_bool,
+	jettext_inspect_int,
+	jettext_inspect_uint,
+	jettext_inspect_double,
+	jettext_inspect_string,
+	jettext_inspect_blob,
+	jettext_inspect_array,
+	jettext_inspect_dict,
+};
+
+////////////////////////////////////////////////////////////
+// driver
+
+static
+void
+jettext_traversal(void *x, const char *key, const jetval *jv, int depthchange)
+{
+	struct jettext_context *ctx = x;
+	ctx->depthchange = depthchange;
+
+	if (key != NULL) {
+		jettext_addstring(ctx, "<key>");
+		jettext_encodestring(ctx, key);
+		jettext_addstring(ctx, "</key>\n");
+	}
+
+	jetval_inspect(jv, x, &jettext_inspector);
+}
+
+char *
+jetval_to_text(const jetval *jv)
+{
+	struct jettext_context ctx;
+
+	jettext_init(&ctx);
+
+	jettext_addstring(&ctx, "<jet>\n");
+	jetval_traverse(jv, &ctx, jettext_traversal);
+	jettext_addstring(&ctx, "</jet>\n");
+
+	if (jettext_allocate(&ctx) < 0) {
+		return NULL;
+	}
+
+	jettext_addstring(&ctx, "<jet>\n");
+	jetval_traverse(jv, &ctx, jettext_traversal);
+	jettext_addstring(&ctx, "</jet>\n");
+
+	return jettext_finish(&ctx);
+}

Reply via email to