--- libelwix/src/json.c	2017/11/24 09:53:53	1.1.2.1
+++ libelwix/src/json.c	2017/11/30 13:46:27	1.2
@@ -3,7 +3,7 @@
 *  by Michael Pounov <misho@elwix.org>
 *
 * $Author: misho $
-* $Id: json.c,v 1.1.2.1 2017/11/24 09:53:53 misho Exp $
+* $Id: json.c,v 1.2 2017/11/30 13:46:27 misho Exp $
 *
 **************************************************************************
 The ELWIX and AITNET software is distributed under the following
@@ -46,3 +46,940 @@ SUCH DAMAGE.
 #include "global.h"
 
 
+/* JSON error strings */
+const char *jerrstr[] = {
+	"No error",
+	"Not enough tokens were provided",
+	"Invalid character",
+	"JSON string isn't full",
+	"Invalid parameter", 
+	NULL
+};
+
+
+/*
+ * json_init() - Initialize JSON handler
+ *
+ * @json = JSON handler, if there is NULL then dynamically will be allocated
+ * @jstrict = JSON strict mode, when we select strict mode every unquoted value is error
+ * return: =NULL error or !=NULL ready for use JSON handler and should be free with json_free()
+ */
+json_t *
+json_init(json_t * __restrict json, int jstrict)
+{
+	json_t *j = json;
+
+	if (!j) {
+		j = e_malloc(sizeof(json_t));
+		if (!j) {
+			LOGERR;
+			return NULL;
+		}
+	}
+
+	memset(j, 0, sizeof(json_t));
+	j->h_parent = -1;
+	j->h_strict = jstrict;
+
+	/* handler is dynamically allocated! */
+	if (!json)
+		j->h_alloc = j;
+
+	return j;
+}
+
+/*
+ * json_free() - Free JSON handler
+ *
+ * @json = JSON handler
+ * return: none
+ */
+void
+json_free(json_t * __restrict json)
+{
+	if (json) {
+		if (json->h_alloc)
+			e_free(json);
+		else
+			memset(json, 0, sizeof(json_t));
+	}
+}
+
+static jtok_t *
+json_gettoken(json_t * __restrict json, jtok_t * __restrict jtoks, u_int toksnum)
+{
+	jtok_t *tok;
+
+	assert(json || !(!jtoks && toksnum));
+
+	if (json->h_next >= toksnum) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		return NULL;
+	} else
+		tok = &jtoks[json->h_next];
+	tok->tok_idx = json->h_next++;
+	tok->tok_start = tok->tok_end = tok->tok_parent = -1;
+	tok->tok_size = 0;
+
+	return tok;
+}
+
+inline void
+json_filltoken(jtok_t * __restrict tok, jtype_t type, long start, long end, long parent)
+{
+	assert(tok);
+
+	tok->tok_type = type;
+	tok->tok_start = start;
+	tok->tok_end = end;
+	tok->tok_parent = parent;
+	tok->tok_size = 0;
+}
+
+static int
+json_parse_string(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
+{
+	jtok_t	*tok;
+	u_long pos;
+	char ch;
+	register int i;
+
+	assert(json || jstr || !(!jtoks && toksnum));
+
+	for (pos = json->h_pos++; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
+		ch = jstr[json->h_pos];
+
+		if (ch == '\"') {
+			if (!jtoks)
+				return 0;
+			if (!(tok = json_gettoken(json, jtoks, toksnum))) {
+				json->h_pos = pos;
+				return -1;
+			} else
+				json_filltoken(tok, J_STRING, pos + 1, json->h_pos, json->h_parent);
+			return 0;
+		}
+
+		if (ch == '\\' && json->h_pos + 1 < jlen) {
+			switch (jstr[++json->h_pos]) {
+				case '\"':
+				case '/':
+				case '\\':
+				case 'b':
+				case 'f':
+				case 'r':
+				case 'n':
+				case 't':
+					/* Allowed escaped symbols */
+					break;
+				case 'u':
+					/* Allows escaped symbol \uXXXX */
+					json->h_pos++;
+					for (i = 0; i < 4 && json->h_pos < jlen && jstr[json->h_pos]; i++, json->h_pos++) {
+						/* If it isn't a hex character we have an error */
+						if (!((jstr[json->h_pos] >= 48 && jstr[json->h_pos] <= 57) || /* 0-9 */
+								(jstr[json->h_pos] >= 65 && jstr[json->h_pos] <= 70) || /* A-F */
+								(jstr[json->h_pos] >= 97 && jstr[json->h_pos] <= 102))) { /* a-f */
+							json->h_pos = pos;
+							elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+							return -1;
+						}
+					}
+					json->h_pos--;
+					break;
+				default:
+					/* Unexpected symbol */
+					json->h_pos = pos;
+					elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+					return -1;
+			}
+		}
+	}
+
+	json->h_pos = pos;
+	elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
+	return -1;
+}
+
+static int
+json_parse_value(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
+{
+	jtok_t	*tok;
+	u_long pos;
+
+	assert(json || jstr || !(!jtoks && toksnum));
+
+	for (pos = json->h_pos; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
+		switch (jstr[json->h_pos]) {
+			case ':':
+				if (json->h_strict)
+					goto found;
+				break;
+			case '\t':
+			case '\r':
+			case '\n':
+			case ' ':
+			case ',':
+			case ']':
+			case '}':
+				goto found;
+		}
+		if (jstr[json->h_pos] < 32 || jstr[json->h_pos] > 127) {
+			json->h_pos = pos;
+			elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+			return -1;
+		}
+	}
+
+	if (json->h_strict) {
+		json->h_pos = pos;
+		elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
+		return -1;
+	}
+found:
+	if (jtoks) {
+		if (!(tok = json_gettoken(json, jtoks, toksnum))) {
+			json->h_pos = pos;
+			return -1;
+		} else
+			json_filltoken(tok, J_VALUE, pos, json->h_pos, json->h_parent);
+	}
+
+	json->h_pos--;
+	return 0;
+}
+
+/*
+ * json_parse() - Parse JSON string
+ *
+ * @json = JSON handler
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @jtoks = Token array
+ * @toksnum = Token array size, return number of allocated tokens in array
+ * return: -1 error or number of found tokens 
+ */
+u_int
+json_parse(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
+{
+	register int i;
+	register u_int cx;
+	jtype_t type;
+	jtok_t *tok;
+	char ch;
+
+	if (!json || !jstr || (!jtoks && toksnum)) {
+		elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
+		return (u_int) -1;
+	}
+
+	for (cx = json->h_next; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
+		switch ((ch = jstr[json->h_pos])) {
+			case '{':
+			case '[':
+				cx++;	/* start new object/array token */
+				if (!jtoks)
+					break;
+
+				tok = json_gettoken(json, jtoks, toksnum);
+				if (!tok)
+					return (u_int) -1;
+				if (json->h_parent != -1) {
+					jtoks[json->h_parent].tok_size++;
+					tok->tok_parent = json->h_parent;
+				}
+				tok->tok_type = (ch == '{' ? J_OBJECT : J_ARRAY);
+				tok->tok_start = json->h_pos;
+				json->h_parent = json->h_next - 1;
+				break;
+			case '}':
+			case ']':
+				if (!jtoks)
+					break;
+
+				if (json->h_next < 1) {
+					elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+					return (u_int) -1;
+				}
+
+				type = (ch == '}' ? J_OBJECT : J_ARRAY);
+				tok = &jtoks[json->h_next - 1];
+				while (42) {
+					if (tok->tok_start != -1 && tok->tok_end == -1) {
+						if (tok->tok_type != type) {
+							elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+							return (u_int) -1;
+						}
+						tok->tok_end = json->h_pos + 1;
+						json->h_parent = tok->tok_parent;
+						break;
+					}
+					if (tok->tok_parent == -1) {
+						if (tok->tok_type != type || json->h_parent == -1) {
+							elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+							return (u_int) -1;
+						}
+						break;
+					}
+					tok = &jtoks[tok->tok_parent];
+				}
+				break;
+			case '\"':
+				if (json_parse_string(json, jstr, jlen, jtoks, toksnum) == -1)
+					return (u_int) -1;
+				cx++;	/* start new string token */
+				if (jtoks && json->h_parent != -1)
+					jtoks[json->h_parent].tok_size++;
+				break;
+			case '\t':
+			case '\r':
+			case '\n':
+			case ' ':
+				/* whitespace, skip */
+				break;
+			case ':':
+				json->h_parent = json->h_next - 1;
+				break;
+			case ',':
+				if (jtoks && json->h_parent != -1 && 
+						jtoks[json->h_parent].tok_type != J_OBJECT && 
+						jtoks[json->h_parent].tok_type != J_ARRAY)
+					json->h_parent = jtoks[json->h_parent].tok_parent;
+				break;
+			case '-':
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+			case 't':
+			case 'f':
+			case 'n':
+				if (json->h_strict) {
+					if (jtoks && json->h_parent != -1) {
+						/* they must not be keys of the object */
+						if (jtoks[json->h_parent].tok_type == J_OBJECT || 
+								(jtoks[json->h_parent].tok_type == J_STRING && 
+								 jtoks[json->h_parent].tok_size)) {
+							elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+							return (u_int) -1;
+						}
+					}
+
+					if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
+						return (u_int) -1;
+					cx++;	/* start new value token */
+					if (jtoks && json->h_parent != -1)
+						jtoks[json->h_parent].tok_size++;
+					break;
+				}
+			default:
+				if (json->h_strict) {
+					elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
+					return (u_int) -1;
+				}
+
+				if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
+					return (u_int) -1;
+				cx++;	/* start new value token */
+				if (jtoks && json->h_parent != -1)
+					jtoks[json->h_parent].tok_size++;
+				break;
+		}
+	}
+
+	if (jtoks) {
+		for (i = json->h_next - 1; i >= 0; i--) {
+			/* unmatched opened object or array */
+			if (jtoks[i].tok_start != -1 && jtoks[i].tok_end == -1) {
+				elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
+				return (u_int) -1;
+			}
+		}
+	} else
+		cx++;	/* increment needed tokens number for termination empty token */
+
+	return cx;
+}
+
+/*
+ * json_token2val() - Return token to AIT variable
+ *
+ * @jstr = JSON string
+ * @tok = Token for convert
+ * @return =NULL error or !=NULL allocated variable, after use should be ait_freeVar()
+ */
+ait_val_t *
+json_token2val(const char *jstr, jtok_t * __restrict tok)
+{
+	ait_val_t *v = NULL;
+
+	if (!jstr || !tok)
+		return NULL;
+
+	v = ait_allocVar();
+	if (!v)
+		return NULL;
+
+	AIT_SET_STRSIZ(v, json_toklen(tok));
+	strncpy(AIT_GET_STR(v), json_tokstr(jstr, tok), AIT_LEN(v) - 1);
+
+	return v;
+}
+
+/*
+ * json_token2str() - Return token to string
+ *
+ * @jstr = JSON string
+ * @tok = Token for convert
+ * @return =NULL error or !=NULL allocated str, after use should be e_free()
+ */
+char *
+json_token2str(const char *jstr, jtok_t * __restrict tok)
+{
+	char *str = NULL;
+	size_t len;
+
+	if (!jstr || !tok)
+		return NULL;
+
+	len = json_toklen(tok);
+	str = e_malloc(len + 1);
+	if (!str)
+		return NULL;
+	else {
+		strncpy(str, json_tokstr(jstr, tok), len);
+		str[len] = 0;
+	}
+
+	return str;
+}
+
+/*
+ * json_token2num() - Return token to numeric
+ *
+ * @jstr = JSON string
+ * @tok = Token for convert
+ * @return number
+ */
+long
+json_token2num(const char *jstr, jtok_t * __restrict tok)
+{
+	long ret = 0;
+	char *str;
+
+	str = json_token2str(jstr, tok);
+	if (!str)
+		return 0;
+
+	ret = strtol(str, NULL, 0);
+	e_free(str);
+	return ret;
+}
+
+/*
+ * json_findbykey() - Find data by key
+ *
+ * @jstr = JSON string
+ * @key = Search key
+ * @toks = Parsed tokens
+ * @toksnum = Number of parsed tokens
+ * return: =NULL error or !=NULL data token found 
+ */
+jtok_t *
+json_findbykey(const char *jstr, const char *key, jtok_t * __restrict toks, int toksnum)
+{
+	jtok_t *tok = NULL;
+	register int i;
+	int klen;
+
+	if (!jstr || !key || !toks)
+		return NULL;
+	else
+		klen = strlen(key);
+
+	for (i = 1; i < toksnum; i++) {
+		if (toks[i].tok_type == J_STRING && 
+				klen == toks[i].tok_end - toks[i].tok_start && 
+				!strncmp(jstr + toks[i].tok_start, key, klen)) {
+			tok = toks + i + 1;
+			break;
+		}
+	}
+
+	return tok;
+}
+
+/*
+ * json_token2array() - Convert token to string array
+ *
+ * @jstr = JSON string
+ * @tok = Token for convert
+ * return: =NULL error or !=NULL allocated array with string variables, 
+ * 		after use should be ait_freeVars()
+ */
+array_t *
+json_token2array(const char *jstr, jtok_t * __restrict tok)
+{
+	array_t *arr = NULL;
+	register int i;
+	int siz;
+	ait_val_t *v;
+	jtok_t *t;
+
+	if (!jstr || !tok)
+		return NULL;
+
+	siz = tok->tok_size;
+	if (!siz && json_toktype(tok) != J_ARRAY && json_toktype(tok) != J_OBJECT)
+		siz++;
+
+	arr = ait_allocVars(siz);
+	if (!arr)
+		return NULL;
+
+	if (tok->tok_type == J_STRING || tok->tok_type == J_VALUE) {
+		v = ait_getVars(&arr, 0);
+		AIT_SET_STRSIZ(v, json_toklen(tok) + 1);
+		json_tokstrcpy(AIT_GET_STR(v), jstr, tok);
+	} else if (tok->tok_type == J_ARRAY) {
+		for (i = 0; i < tok->tok_size; i++) {
+			t = &tok[i + 1];
+			v = ait_getVars(&arr, i);
+			AIT_SET_STRSIZ(v, json_toklen(t) + 1);
+			json_tokstrcpy(AIT_GET_STR(v), jstr, t);
+		}
+	} else if (tok->tok_type == J_OBJECT) {
+		for (i = 0; tok->tok_idx <= tok[i + 1].tok_parent; i++) {
+			t = &tok[i + 1];
+			v = ait_getVars(&arr, i);
+			AIT_SET_STRSIZ(v, json_toklen(t) + 1);
+			json_tokstrcpy(AIT_GET_STR(v), jstr, t);
+		}
+	} else {
+		elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
+		ait_freeVars(&arr);
+		return NULL;
+	}
+
+	return arr;
+}
+
+
+
+/*
+ * json_add_begin_object() - Adds begin of object {
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_begin_object(char * __restrict jstr, int jlen, int wspace)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+
+	if (wspace)
+		len = strlcat(jstr, "{ ", jlen);
+	else
+		len = strlcat(jstr, "{", jlen);
+
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_end_object() - Adds end of object }
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_end_object(char * __restrict jstr, int jlen, int wspace)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (wspace)
+		len = strlcat(jstr, " }", jlen);
+	else
+		len = strlcat(jstr, "}", jlen);
+
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_begin_array() - Adds begin of array [
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_begin_array(char * __restrict jstr, int jlen, int wspace)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (wspace)
+		len = strlcat(jstr, "[ ", jlen);
+	else
+		len = strlcat(jstr, "[", jlen);
+
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_end_array() - Adds end of array ]
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_end_array(char * __restrict jstr, int jlen, int wspace)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (wspace)
+		len = strlcat(jstr, " ]", jlen);
+	else
+		len = strlcat(jstr, "]", jlen);
+
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_char() - Adds character
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @ch = Character
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_char(char * __restrict jstr, int jlen, u_char ch)
+{
+	int len;
+
+	if (!jstr)
+		return -1;
+
+	len = strlen(jstr) + 1;
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		return -1;
+	} else {
+		jstr[len++] = (char) ch;
+		jstr[len] = 0;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_colon() - Adds key/value pair delimiter colon :
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_colon(char * __restrict jstr, int jlen, int wspace)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (wspace)
+		len = strlcat(jstr, ": ", jlen);
+	else
+		len = strlcat(jstr, ":", jlen);
+
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_comma() - Adds value delimiter comma ,
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_comma(char * __restrict jstr, int jlen, int wspace)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (wspace)
+		len = strlcat(jstr, ", ", jlen);
+	else
+		len = strlcat(jstr, ",", jlen);
+
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_string() - Adds string
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @unquot = Unquoted string
+ * @str = String, it can't be NULL
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_string(char * __restrict jstr, int jlen, int unquot, const char *str)
+{
+	int len;
+	size_t eos;
+
+	if (!jstr || !str)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (!unquot) {
+		len = strlcat(jstr, "\"", jlen);
+		if (len >= jlen) {
+			elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+			jstr[eos] = 0;
+			return -1;
+		}
+	}
+	len = strlcat(jstr, str, jlen);
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+	if (!unquot) {
+		len = strlcat(jstr, "\"", jlen);
+		if (len >= jlen) {
+			elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+			jstr[eos] = 0;
+			return -1;
+		}
+	}
+
+	return len;
+}
+
+/*
+ * json_add_value() - Adds value
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @unquot = Unquoted number
+ * @num = Number
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_value(char * __restrict jstr, int jlen, int unquot, long num)
+{
+	int len;
+	char wrk[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
+	size_t eos;
+
+	if (!jstr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (!unquot) {
+		len = strlcat(jstr, "\"", jlen);
+		if (len >= jlen) {
+			elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+			jstr[eos] = 0;
+			return -1;
+		}
+	}
+	snprintf(wrk, sizeof wrk, "%ld", num);
+	len = strlcat(jstr, wrk, jlen);
+	if (len >= jlen) {
+		elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+		jstr[eos] = 0;
+		return -1;
+	}
+	if (!unquot) {
+		len = strlcat(jstr, "\"", jlen);
+		if (len >= jlen) {
+			elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
+			jstr[eos] = 0;
+			return -1;
+		}
+	}
+
+	return len;
+}
+
+/*
+ * json_add_pair() - Adds key/value pair
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * @key = Key string
+ * @val = Value string
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_pair(char * __restrict jstr, int jlen, int wspace, const char *key, const char *val)
+{
+	int len = -1;
+	size_t eos;
+
+	if (!jstr || !key || !val)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (json_add_string(jstr, jlen, 0, key) == -1) {
+		jstr[eos] = 0;
+		return -1;
+	}
+	if (json_add_colon(jstr, jlen, wspace) == -1) {
+		jstr[eos] = 0;
+		return -1;
+	}
+	if ((len = json_add_string(jstr, jlen, 0, val)) == -1) {
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}
+
+/*
+ * json_add_array() - Adds array
+ *
+ * @jstr = JSON string
+ * @jlen = JSON string length
+ * @wspace = whitespace include
+ * @arr = Array with variables
+ * return: -1 error or !=-1 actual JSON string length
+ */
+int
+json_add_array(char * __restrict jstr, int jlen, int wspace, array_t * __restrict arr)
+{
+	int len = -1;
+	register int i;
+	ait_val_t *v;
+	size_t eos;
+
+	if (!jstr || !arr)
+		return -1;
+	else
+		eos = strlen(jstr);
+
+	if (json_add_begin_array(jstr, jlen, wspace) == -1) {
+		jstr[eos] = 0;
+		return -1;
+	}
+	for (i = 0; i < array_Size(arr); i++) {
+		v = array(arr, i, ait_val_t*);
+		if (v) {
+			if (AIT_TYPE(v) == string) {
+				if (json_add_string(jstr, jlen, 0, AIT_GET_STR(v)) == -1) {
+					jstr[eos] = 0;
+					return -1;
+				}
+			} else {
+				if (json_add_value(jstr, jlen, 0, AIT_GET_LIKE(v, long)) == -1) {
+					jstr[eos] = 0;
+					return -1;
+				}
+			}
+			if (i < array_Size(arr) - 1 && json_add_comma(jstr, jlen, wspace) == -1) {
+				jstr[eos] = 0;
+				return -1;
+			}
+		}
+	}
+	if ((len = json_add_end_array(jstr, jlen, wspace)) == -1) {
+		jstr[eos] = 0;
+		return -1;
+	}
+
+	return len;
+}