xref: /minix3/crypto/external/bsd/netpgp/dist/src/libmj/mj.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1*ebfedea0SLionel Sambuc /*-
2*ebfedea0SLionel Sambuc  * Copyright (c) 2010 Alistair Crooks <agc@NetBSD.org>
3*ebfedea0SLionel Sambuc  * All rights reserved.
4*ebfedea0SLionel Sambuc  *
5*ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
6*ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
7*ebfedea0SLionel Sambuc  * are met:
8*ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
9*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
10*ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
11*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
12*ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
13*ebfedea0SLionel Sambuc  *
14*ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*ebfedea0SLionel Sambuc  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*ebfedea0SLionel Sambuc  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*ebfedea0SLionel Sambuc  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*ebfedea0SLionel Sambuc  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*ebfedea0SLionel Sambuc  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*ebfedea0SLionel Sambuc  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*ebfedea0SLionel Sambuc  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*ebfedea0SLionel Sambuc  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*ebfedea0SLionel Sambuc  */
25*ebfedea0SLionel Sambuc #include <sys/types.h>
26*ebfedea0SLionel Sambuc 
27*ebfedea0SLionel Sambuc #include <inttypes.h>
28*ebfedea0SLionel Sambuc #include <regex.h>
29*ebfedea0SLionel Sambuc #include <stdarg.h>
30*ebfedea0SLionel Sambuc #include <stdio.h>
31*ebfedea0SLionel Sambuc #include <stdlib.h>
32*ebfedea0SLionel Sambuc #include <string.h>
33*ebfedea0SLionel Sambuc #include <unistd.h>
34*ebfedea0SLionel Sambuc 
35*ebfedea0SLionel Sambuc #include "mj.h"
36*ebfedea0SLionel Sambuc #include "defs.h"
37*ebfedea0SLionel Sambuc 
38*ebfedea0SLionel Sambuc /* save 'n' chars of 's' in malloc'd memory */
39*ebfedea0SLionel Sambuc static char *
strnsave(const char * s,int n,unsigned encoded)40*ebfedea0SLionel Sambuc strnsave(const char *s, int n, unsigned encoded)
41*ebfedea0SLionel Sambuc {
42*ebfedea0SLionel Sambuc 	char	*newc;
43*ebfedea0SLionel Sambuc 	char	*cp;
44*ebfedea0SLionel Sambuc 	int	 i;
45*ebfedea0SLionel Sambuc 
46*ebfedea0SLionel Sambuc 	if (n < 0) {
47*ebfedea0SLionel Sambuc 		n = (int)strlen(s);
48*ebfedea0SLionel Sambuc 	}
49*ebfedea0SLionel Sambuc 	NEWARRAY(char, cp, n + n + 1, "strnsave", return NULL);
50*ebfedea0SLionel Sambuc 	if (encoded) {
51*ebfedea0SLionel Sambuc 		newc = cp;
52*ebfedea0SLionel Sambuc 		for (i = 0 ; i < n ; i++) {
53*ebfedea0SLionel Sambuc 			if ((uint8_t)*s == 0xac) {
54*ebfedea0SLionel Sambuc 				*newc++ = (char)0xac;
55*ebfedea0SLionel Sambuc 				*newc++ = '1';
56*ebfedea0SLionel Sambuc 				s += 1;
57*ebfedea0SLionel Sambuc 			} else if (*s == '"') {
58*ebfedea0SLionel Sambuc 				*newc++ = (char)0xac;
59*ebfedea0SLionel Sambuc 				*newc++ = '2';
60*ebfedea0SLionel Sambuc 				s += 1;
61*ebfedea0SLionel Sambuc 			} else if (*s == 0x0) {
62*ebfedea0SLionel Sambuc 				*newc++ = (char)0xac;
63*ebfedea0SLionel Sambuc 				*newc++ = '0';
64*ebfedea0SLionel Sambuc 				s += 1;
65*ebfedea0SLionel Sambuc 			} else {
66*ebfedea0SLionel Sambuc 				*newc++ = *s++;
67*ebfedea0SLionel Sambuc 			}
68*ebfedea0SLionel Sambuc 		}
69*ebfedea0SLionel Sambuc 		*newc = 0x0;
70*ebfedea0SLionel Sambuc 	} else {
71*ebfedea0SLionel Sambuc 		(void) memcpy(cp, s, (unsigned)n);
72*ebfedea0SLionel Sambuc 		cp[n] = 0x0;
73*ebfedea0SLionel Sambuc 	}
74*ebfedea0SLionel Sambuc 	return cp;
75*ebfedea0SLionel Sambuc }
76*ebfedea0SLionel Sambuc 
77*ebfedea0SLionel Sambuc /* look in an object for the item */
78*ebfedea0SLionel Sambuc static int
findentry(mj_t * atom,const char * name,const unsigned from,const unsigned incr)79*ebfedea0SLionel Sambuc findentry(mj_t *atom, const char *name, const unsigned from, const unsigned incr)
80*ebfedea0SLionel Sambuc {
81*ebfedea0SLionel Sambuc 	unsigned	i;
82*ebfedea0SLionel Sambuc 
83*ebfedea0SLionel Sambuc 	for (i = from ; i < atom->c ; i += incr) {
84*ebfedea0SLionel Sambuc 		if (strcmp(name, atom->value.v[i].value.s) == 0) {
85*ebfedea0SLionel Sambuc 			return i;
86*ebfedea0SLionel Sambuc 		}
87*ebfedea0SLionel Sambuc 	}
88*ebfedea0SLionel Sambuc 	return -1;
89*ebfedea0SLionel Sambuc }
90*ebfedea0SLionel Sambuc 
91*ebfedea0SLionel Sambuc /* create a real number */
92*ebfedea0SLionel Sambuc static void
create_number(mj_t * atom,double d)93*ebfedea0SLionel Sambuc create_number(mj_t *atom, double d)
94*ebfedea0SLionel Sambuc {
95*ebfedea0SLionel Sambuc 	char	number[128];
96*ebfedea0SLionel Sambuc 
97*ebfedea0SLionel Sambuc 	atom->type = MJ_NUMBER;
98*ebfedea0SLionel Sambuc 	atom->c = snprintf(number, sizeof(number), "%g", d);
99*ebfedea0SLionel Sambuc 	atom->value.s = strnsave(number, (int)atom->c, MJ_HUMAN);
100*ebfedea0SLionel Sambuc }
101*ebfedea0SLionel Sambuc 
102*ebfedea0SLionel Sambuc /* create an integer */
103*ebfedea0SLionel Sambuc static void
create_integer(mj_t * atom,int64_t i)104*ebfedea0SLionel Sambuc create_integer(mj_t *atom, int64_t i)
105*ebfedea0SLionel Sambuc {
106*ebfedea0SLionel Sambuc 	char	number[128];
107*ebfedea0SLionel Sambuc 
108*ebfedea0SLionel Sambuc 	atom->type = MJ_NUMBER;
109*ebfedea0SLionel Sambuc 	atom->c = snprintf(number, sizeof(number), "%" PRIi64, i);
110*ebfedea0SLionel Sambuc 	atom->value.s = strnsave(number, (int)atom->c, MJ_HUMAN);
111*ebfedea0SLionel Sambuc }
112*ebfedea0SLionel Sambuc 
113*ebfedea0SLionel Sambuc /* create a string */
114*ebfedea0SLionel Sambuc static void
create_string(mj_t * atom,const char * s,ssize_t len)115*ebfedea0SLionel Sambuc create_string(mj_t *atom, const char *s, ssize_t len)
116*ebfedea0SLionel Sambuc {
117*ebfedea0SLionel Sambuc 	atom->type = MJ_STRING;
118*ebfedea0SLionel Sambuc 	atom->value.s = strnsave(s, (int)len, MJ_JSON_ENCODE);
119*ebfedea0SLionel Sambuc 	atom->c = (unsigned)strlen(atom->value.s);
120*ebfedea0SLionel Sambuc }
121*ebfedea0SLionel Sambuc 
122*ebfedea0SLionel Sambuc #define MJ_OPEN_BRACKET		(MJ_OBJECT + 1)		/* 8 */
123*ebfedea0SLionel Sambuc #define MJ_CLOSE_BRACKET	(MJ_OPEN_BRACKET + 1)	/* 9 */
124*ebfedea0SLionel Sambuc #define MJ_OPEN_BRACE		(MJ_CLOSE_BRACKET + 1)	/* 10 */
125*ebfedea0SLionel Sambuc #define MJ_CLOSE_BRACE		(MJ_OPEN_BRACE + 1)	/* 11 */
126*ebfedea0SLionel Sambuc #define MJ_COLON		(MJ_CLOSE_BRACE + 1)	/* 12 */
127*ebfedea0SLionel Sambuc #define MJ_COMMA		(MJ_COLON + 1)		/* 13 */
128*ebfedea0SLionel Sambuc 
129*ebfedea0SLionel Sambuc /* return the token type, and start and finish locations in string */
130*ebfedea0SLionel Sambuc static int
gettok(const char * s,int * from,int * to,int * tok)131*ebfedea0SLionel Sambuc gettok(const char *s, int *from, int *to, int *tok)
132*ebfedea0SLionel Sambuc {
133*ebfedea0SLionel Sambuc 	static regex_t	tokregex;
134*ebfedea0SLionel Sambuc 	regmatch_t	matches[15];
135*ebfedea0SLionel Sambuc 	static int	compiled;
136*ebfedea0SLionel Sambuc 
137*ebfedea0SLionel Sambuc 	if (!compiled) {
138*ebfedea0SLionel Sambuc 		compiled = 1;
139*ebfedea0SLionel Sambuc 		(void) regcomp(&tokregex,
140*ebfedea0SLionel Sambuc 			"[ \t\r\n]*(([+-]?[0-9]{1,21}(\\.[0-9]*)?([eE][-+][0-9]+)?)|"
141*ebfedea0SLionel Sambuc 			"(\"([^\"]|\\\\.)*\")|(null)|(false)|(true)|([][{}:,]))",
142*ebfedea0SLionel Sambuc 			REG_EXTENDED);
143*ebfedea0SLionel Sambuc 	}
144*ebfedea0SLionel Sambuc 	if (regexec(&tokregex, &s[*from = *to], 15, matches, 0) != 0) {
145*ebfedea0SLionel Sambuc 		return *tok = -1;
146*ebfedea0SLionel Sambuc 	}
147*ebfedea0SLionel Sambuc 	*to = *from + (int)(matches[1].rm_eo);
148*ebfedea0SLionel Sambuc 	*tok = (matches[2].rm_so >= 0) ? MJ_NUMBER :
149*ebfedea0SLionel Sambuc 		(matches[5].rm_so >= 0) ? MJ_STRING :
150*ebfedea0SLionel Sambuc 		(matches[7].rm_so >= 0) ? MJ_NULL :
151*ebfedea0SLionel Sambuc 		(matches[8].rm_so >= 0) ? MJ_FALSE :
152*ebfedea0SLionel Sambuc 		(matches[9].rm_so >= 0) ? MJ_TRUE :
153*ebfedea0SLionel Sambuc 		(matches[10].rm_so < 0) ? -1 :
154*ebfedea0SLionel Sambuc 			(s[*from + (int)(matches[10].rm_so)] == '[') ? MJ_OPEN_BRACKET :
155*ebfedea0SLionel Sambuc 			(s[*from + (int)(matches[10].rm_so)] == ']') ? MJ_CLOSE_BRACKET :
156*ebfedea0SLionel Sambuc 			(s[*from + (int)(matches[10].rm_so)] == '{') ? MJ_OPEN_BRACE :
157*ebfedea0SLionel Sambuc 			(s[*from + (int)(matches[10].rm_so)] == '}') ? MJ_CLOSE_BRACE :
158*ebfedea0SLionel Sambuc 			(s[*from + (int)(matches[10].rm_so)] == ':') ? MJ_COLON :
159*ebfedea0SLionel Sambuc 				MJ_COMMA;
160*ebfedea0SLionel Sambuc 	*from += (int)(matches[1].rm_so);
161*ebfedea0SLionel Sambuc 	return *tok;
162*ebfedea0SLionel Sambuc }
163*ebfedea0SLionel Sambuc 
164*ebfedea0SLionel Sambuc /* minor function used to indent a JSON field */
165*ebfedea0SLionel Sambuc static void
indent(FILE * fp,unsigned depth,const char * trailer)166*ebfedea0SLionel Sambuc indent(FILE *fp, unsigned depth, const char *trailer)
167*ebfedea0SLionel Sambuc {
168*ebfedea0SLionel Sambuc 	unsigned	i;
169*ebfedea0SLionel Sambuc 
170*ebfedea0SLionel Sambuc 	for (i = 0 ; i < depth ; i++) {
171*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "    ");
172*ebfedea0SLionel Sambuc 	}
173*ebfedea0SLionel Sambuc 	if (trailer) {
174*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "%s", trailer);
175*ebfedea0SLionel Sambuc 	}
176*ebfedea0SLionel Sambuc }
177*ebfedea0SLionel Sambuc 
178*ebfedea0SLionel Sambuc /***************************************************************************/
179*ebfedea0SLionel Sambuc 
180*ebfedea0SLionel Sambuc /* return the number of entries in the array */
181*ebfedea0SLionel Sambuc int
mj_arraycount(mj_t * atom)182*ebfedea0SLionel Sambuc mj_arraycount(mj_t *atom)
183*ebfedea0SLionel Sambuc {
184*ebfedea0SLionel Sambuc 	return atom->c;
185*ebfedea0SLionel Sambuc }
186*ebfedea0SLionel Sambuc 
187*ebfedea0SLionel Sambuc /* create a new JSON node */
188*ebfedea0SLionel Sambuc int
mj_create(mj_t * atom,const char * type,...)189*ebfedea0SLionel Sambuc mj_create(mj_t *atom, const char *type, ...)
190*ebfedea0SLionel Sambuc {
191*ebfedea0SLionel Sambuc 	va_list	 args;
192*ebfedea0SLionel Sambuc 	ssize_t	 len;
193*ebfedea0SLionel Sambuc 	char	*s;
194*ebfedea0SLionel Sambuc 
195*ebfedea0SLionel Sambuc 	if (strcmp(type, "false") == 0) {
196*ebfedea0SLionel Sambuc 		atom->type = MJ_FALSE;
197*ebfedea0SLionel Sambuc 		atom->c = 0;
198*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "true") == 0) {
199*ebfedea0SLionel Sambuc 		atom->type = MJ_TRUE;
200*ebfedea0SLionel Sambuc 		atom->c = 1;
201*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "null") == 0) {
202*ebfedea0SLionel Sambuc 		atom->type = MJ_NULL;
203*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "number") == 0) {
204*ebfedea0SLionel Sambuc 		va_start(args, type);
205*ebfedea0SLionel Sambuc 		create_number(atom, (double)va_arg(args, double));
206*ebfedea0SLionel Sambuc 		va_end(args);
207*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "integer") == 0) {
208*ebfedea0SLionel Sambuc 		va_start(args, type);
209*ebfedea0SLionel Sambuc 		create_integer(atom, (int64_t)va_arg(args, int64_t));
210*ebfedea0SLionel Sambuc 		va_end(args);
211*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "string") == 0) {
212*ebfedea0SLionel Sambuc 		va_start(args, type);
213*ebfedea0SLionel Sambuc 		s = (char *)va_arg(args, char *);
214*ebfedea0SLionel Sambuc 		len = (size_t)va_arg(args, size_t);
215*ebfedea0SLionel Sambuc 		va_end(args);
216*ebfedea0SLionel Sambuc 		create_string(atom, s, len);
217*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "array") == 0) {
218*ebfedea0SLionel Sambuc 		atom->type = MJ_ARRAY;
219*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "object") == 0) {
220*ebfedea0SLionel Sambuc 		atom->type = MJ_OBJECT;
221*ebfedea0SLionel Sambuc 	} else {
222*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "weird type '%s'\n", type);
223*ebfedea0SLionel Sambuc 		return 0;
224*ebfedea0SLionel Sambuc 	}
225*ebfedea0SLionel Sambuc 	return 1;
226*ebfedea0SLionel Sambuc }
227*ebfedea0SLionel Sambuc 
228*ebfedea0SLionel Sambuc /* put a JSON tree into a text string */
229*ebfedea0SLionel Sambuc int
mj_snprint(char * buf,size_t size,mj_t * atom,int encoded)230*ebfedea0SLionel Sambuc mj_snprint(char *buf, size_t size, mj_t *atom, int encoded)
231*ebfedea0SLionel Sambuc {
232*ebfedea0SLionel Sambuc 	unsigned	 i;
233*ebfedea0SLionel Sambuc 	char		*s;
234*ebfedea0SLionel Sambuc 	char		*bp;
235*ebfedea0SLionel Sambuc 	int		 cc;
236*ebfedea0SLionel Sambuc 
237*ebfedea0SLionel Sambuc 	switch(atom->type) {
238*ebfedea0SLionel Sambuc 	case MJ_NULL:
239*ebfedea0SLionel Sambuc 		return snprintf(buf, size, "null");
240*ebfedea0SLionel Sambuc 	case MJ_FALSE:
241*ebfedea0SLionel Sambuc 		return snprintf(buf, size, "false");
242*ebfedea0SLionel Sambuc 	case MJ_TRUE:
243*ebfedea0SLionel Sambuc 		return snprintf(buf, size, "true");
244*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
245*ebfedea0SLionel Sambuc 		return snprintf(buf, size, "%s", atom->value.s);
246*ebfedea0SLionel Sambuc 	case MJ_STRING:
247*ebfedea0SLionel Sambuc 		if (encoded) {
248*ebfedea0SLionel Sambuc 			return snprintf(buf, size, "\"%s\"", atom->value.s);
249*ebfedea0SLionel Sambuc 		}
250*ebfedea0SLionel Sambuc 		for (bp = buf, *bp++ = '"', s = atom->value.s ;
251*ebfedea0SLionel Sambuc 		     (size_t)(bp - buf) < size && (unsigned)(s - atom->value.s) < atom->c ; ) {
252*ebfedea0SLionel Sambuc 			if ((uint8_t)*s == 0xac) {
253*ebfedea0SLionel Sambuc 				switch(s[1]) {
254*ebfedea0SLionel Sambuc 				case '0':
255*ebfedea0SLionel Sambuc 					*bp++ = 0x0;
256*ebfedea0SLionel Sambuc 					s += 2;
257*ebfedea0SLionel Sambuc 					break;
258*ebfedea0SLionel Sambuc 				case '1':
259*ebfedea0SLionel Sambuc 					*bp++ = (char)0xac;
260*ebfedea0SLionel Sambuc 					s += 2;
261*ebfedea0SLionel Sambuc 					break;
262*ebfedea0SLionel Sambuc 				case '2':
263*ebfedea0SLionel Sambuc 					*bp++ = '"';
264*ebfedea0SLionel Sambuc 					s += 2;
265*ebfedea0SLionel Sambuc 					break;
266*ebfedea0SLionel Sambuc 				default:
267*ebfedea0SLionel Sambuc 					(void) fprintf(stderr, "unrecognised character '%02x'\n", (uint8_t)s[1]);
268*ebfedea0SLionel Sambuc 					s += 1;
269*ebfedea0SLionel Sambuc 					break;
270*ebfedea0SLionel Sambuc 				}
271*ebfedea0SLionel Sambuc 			} else {
272*ebfedea0SLionel Sambuc 				*bp++ = *s++;
273*ebfedea0SLionel Sambuc 			}
274*ebfedea0SLionel Sambuc 		}
275*ebfedea0SLionel Sambuc 		*bp++ = '"';
276*ebfedea0SLionel Sambuc 		*bp = 0x0;
277*ebfedea0SLionel Sambuc 		return (int)(bp - buf) - 1;
278*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
279*ebfedea0SLionel Sambuc 		cc = snprintf(buf, size, "[ ");
280*ebfedea0SLionel Sambuc 		for (i = 0 ; i < atom->c ; i++) {
281*ebfedea0SLionel Sambuc 			cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i], encoded);
282*ebfedea0SLionel Sambuc 			if (i < atom->c - 1) {
283*ebfedea0SLionel Sambuc 				cc += snprintf(&buf[cc], size - cc, ", ");
284*ebfedea0SLionel Sambuc 			}
285*ebfedea0SLionel Sambuc 		}
286*ebfedea0SLionel Sambuc 		return cc + snprintf(&buf[cc], size - cc, "]\n");
287*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
288*ebfedea0SLionel Sambuc 		cc = snprintf(buf, size, "{ ");
289*ebfedea0SLionel Sambuc 		for (i = 0 ; i < atom->c ; i += 2) {
290*ebfedea0SLionel Sambuc 			cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i], encoded);
291*ebfedea0SLionel Sambuc 			cc += snprintf(&buf[cc], size - cc, ":");
292*ebfedea0SLionel Sambuc 			cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i + 1], encoded);
293*ebfedea0SLionel Sambuc 			if (i + 1 < atom->c - 1) {
294*ebfedea0SLionel Sambuc 				cc += snprintf(&buf[cc], size - cc, ", ");
295*ebfedea0SLionel Sambuc 			}
296*ebfedea0SLionel Sambuc 		}
297*ebfedea0SLionel Sambuc 		return cc + snprintf(&buf[cc], size - cc, "}\n");
298*ebfedea0SLionel Sambuc 	default:
299*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "mj_snprint: weird type %d\n", atom->type);
300*ebfedea0SLionel Sambuc 		return 0;
301*ebfedea0SLionel Sambuc 	}
302*ebfedea0SLionel Sambuc }
303*ebfedea0SLionel Sambuc 
304*ebfedea0SLionel Sambuc /* allocate and print the atom */
305*ebfedea0SLionel Sambuc int
mj_asprint(char ** buf,mj_t * atom,int encoded)306*ebfedea0SLionel Sambuc mj_asprint(char **buf, mj_t *atom, int encoded)
307*ebfedea0SLionel Sambuc {
308*ebfedea0SLionel Sambuc 	int	 size;
309*ebfedea0SLionel Sambuc 
310*ebfedea0SLionel Sambuc 	size = mj_string_size(atom);
311*ebfedea0SLionel Sambuc 	if ((*buf = calloc(1, (unsigned)(size + 1))) == NULL) {
312*ebfedea0SLionel Sambuc 		return -1;
313*ebfedea0SLionel Sambuc 	}
314*ebfedea0SLionel Sambuc 	return mj_snprint(*buf, (unsigned)(size + 1), atom, encoded) + 1;
315*ebfedea0SLionel Sambuc }
316*ebfedea0SLionel Sambuc 
317*ebfedea0SLionel Sambuc /* read into a JSON tree from a string */
318*ebfedea0SLionel Sambuc int
mj_parse(mj_t * atom,const char * s,int * from,int * to,int * tok)319*ebfedea0SLionel Sambuc mj_parse(mj_t *atom, const char *s, int *from, int *to, int *tok)
320*ebfedea0SLionel Sambuc {
321*ebfedea0SLionel Sambuc 	int	i;
322*ebfedea0SLionel Sambuc 
323*ebfedea0SLionel Sambuc 	switch(atom->type = *tok = gettok(s, from, to, tok)) {
324*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
325*ebfedea0SLionel Sambuc 		atom->value.s = strnsave(&s[*from], *to - *from, MJ_JSON_ENCODE);
326*ebfedea0SLionel Sambuc 		atom->c = atom->size = (unsigned)strlen(atom->value.s);
327*ebfedea0SLionel Sambuc 		return gettok(s, from, to, tok);
328*ebfedea0SLionel Sambuc 	case MJ_STRING:
329*ebfedea0SLionel Sambuc 		atom->value.s = strnsave(&s[*from + 1], *to - *from - 2, MJ_HUMAN);
330*ebfedea0SLionel Sambuc 		atom->c = atom->size = (unsigned)strlen(atom->value.s);
331*ebfedea0SLionel Sambuc 		return gettok(s, from, to, tok);
332*ebfedea0SLionel Sambuc 	case MJ_NULL:
333*ebfedea0SLionel Sambuc 	case MJ_FALSE:
334*ebfedea0SLionel Sambuc 	case MJ_TRUE:
335*ebfedea0SLionel Sambuc 		atom->c = (unsigned)*to;
336*ebfedea0SLionel Sambuc 		return gettok(s, from, to, tok);
337*ebfedea0SLionel Sambuc 	case MJ_OPEN_BRACKET:
338*ebfedea0SLionel Sambuc 		mj_create(atom, "array");
339*ebfedea0SLionel Sambuc 		ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0);
340*ebfedea0SLionel Sambuc 		while (mj_parse(&atom->value.v[atom->c++], s, from, to, tok) >= 0 && *tok != MJ_CLOSE_BRACKET) {
341*ebfedea0SLionel Sambuc 			if (*tok != MJ_COMMA) {
342*ebfedea0SLionel Sambuc 				(void) fprintf(stderr, "1. expected comma (got %d) at '%s'\n", *tok, &s[*from]);
343*ebfedea0SLionel Sambuc 				break;
344*ebfedea0SLionel Sambuc 			}
345*ebfedea0SLionel Sambuc 			ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0);
346*ebfedea0SLionel Sambuc 		}
347*ebfedea0SLionel Sambuc 		return gettok(s, from, to, tok);
348*ebfedea0SLionel Sambuc 	case MJ_OPEN_BRACE:
349*ebfedea0SLionel Sambuc 		mj_create(atom, "object");
350*ebfedea0SLionel Sambuc 		ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0);
351*ebfedea0SLionel Sambuc 		for (i = 0 ; mj_parse(&atom->value.v[atom->c++], s, from, to, tok) >= 0 && *tok != MJ_CLOSE_BRACE ; i++) {
352*ebfedea0SLionel Sambuc 			if (((i % 2) == 0 && *tok != MJ_COLON) || ((i % 2) == 1 && *tok != MJ_COMMA)) {
353*ebfedea0SLionel Sambuc 				(void) fprintf(stderr, "2. expected comma (got %d) at '%s'\n", *tok, &s[*from]);
354*ebfedea0SLionel Sambuc 				break;
355*ebfedea0SLionel Sambuc 			}
356*ebfedea0SLionel Sambuc 			ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0);
357*ebfedea0SLionel Sambuc 		}
358*ebfedea0SLionel Sambuc 		return gettok(s, from, to, tok);
359*ebfedea0SLionel Sambuc 	default:
360*ebfedea0SLionel Sambuc 		return *tok;
361*ebfedea0SLionel Sambuc 	}
362*ebfedea0SLionel Sambuc }
363*ebfedea0SLionel Sambuc 
364*ebfedea0SLionel Sambuc /* return the index of the item which corresponds to the name in the array */
365*ebfedea0SLionel Sambuc int
mj_object_find(mj_t * atom,const char * name,const unsigned from,const unsigned incr)366*ebfedea0SLionel Sambuc mj_object_find(mj_t *atom, const char *name, const unsigned from, const unsigned incr)
367*ebfedea0SLionel Sambuc {
368*ebfedea0SLionel Sambuc 	return findentry(atom, name, from, incr);
369*ebfedea0SLionel Sambuc }
370*ebfedea0SLionel Sambuc 
371*ebfedea0SLionel Sambuc /* find an atom in a composite mj JSON node */
372*ebfedea0SLionel Sambuc mj_t *
mj_get_atom(mj_t * atom,...)373*ebfedea0SLionel Sambuc mj_get_atom(mj_t *atom, ...)
374*ebfedea0SLionel Sambuc {
375*ebfedea0SLionel Sambuc 	unsigned	 i;
376*ebfedea0SLionel Sambuc 	va_list		 args;
377*ebfedea0SLionel Sambuc 	char		*name;
378*ebfedea0SLionel Sambuc 	int		 n;
379*ebfedea0SLionel Sambuc 
380*ebfedea0SLionel Sambuc 	switch(atom->type) {
381*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
382*ebfedea0SLionel Sambuc 		va_start(args, atom);
383*ebfedea0SLionel Sambuc 		i = va_arg(args, int);
384*ebfedea0SLionel Sambuc 		va_end(args);
385*ebfedea0SLionel Sambuc 		return (i < atom->c) ? &atom->value.v[i] : NULL;
386*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
387*ebfedea0SLionel Sambuc 		va_start(args, atom);
388*ebfedea0SLionel Sambuc 		name = va_arg(args, char *);
389*ebfedea0SLionel Sambuc 		va_end(args);
390*ebfedea0SLionel Sambuc 		return ((n = findentry(atom, name, 0, 2)) >= 0) ? &atom->value.v[n + 1] : NULL;
391*ebfedea0SLionel Sambuc 	default:
392*ebfedea0SLionel Sambuc 		return NULL;
393*ebfedea0SLionel Sambuc 	}
394*ebfedea0SLionel Sambuc }
395*ebfedea0SLionel Sambuc 
396*ebfedea0SLionel Sambuc /* perform a deep copy on an mj JSON atom */
397*ebfedea0SLionel Sambuc int
mj_deepcopy(mj_t * dst,mj_t * src)398*ebfedea0SLionel Sambuc mj_deepcopy(mj_t *dst, mj_t *src)
399*ebfedea0SLionel Sambuc {
400*ebfedea0SLionel Sambuc 	unsigned	i;
401*ebfedea0SLionel Sambuc 
402*ebfedea0SLionel Sambuc 	switch(src->type) {
403*ebfedea0SLionel Sambuc 	case MJ_FALSE:
404*ebfedea0SLionel Sambuc 	case MJ_TRUE:
405*ebfedea0SLionel Sambuc 	case MJ_NULL:
406*ebfedea0SLionel Sambuc 		(void) memcpy(dst, src, sizeof(*dst));
407*ebfedea0SLionel Sambuc 		return 1;
408*ebfedea0SLionel Sambuc 	case MJ_STRING:
409*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
410*ebfedea0SLionel Sambuc 		(void) memcpy(dst, src, sizeof(*dst));
411*ebfedea0SLionel Sambuc 		dst->value.s = strnsave(src->value.s, -1, MJ_HUMAN);
412*ebfedea0SLionel Sambuc 		dst->c = dst->size = (unsigned)strlen(dst->value.s);
413*ebfedea0SLionel Sambuc 		return 1;
414*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
415*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
416*ebfedea0SLionel Sambuc 		(void) memcpy(dst, src, sizeof(*dst));
417*ebfedea0SLionel Sambuc 		NEWARRAY(mj_t, dst->value.v, dst->size, "mj_deepcopy()", return 0);
418*ebfedea0SLionel Sambuc 		for (i = 0 ; i < src->c ; i++) {
419*ebfedea0SLionel Sambuc 			if (!mj_deepcopy(&dst->value.v[i], &src->value.v[i])) {
420*ebfedea0SLionel Sambuc 				return 0;
421*ebfedea0SLionel Sambuc 			}
422*ebfedea0SLionel Sambuc 		}
423*ebfedea0SLionel Sambuc 		return 1;
424*ebfedea0SLionel Sambuc 	default:
425*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "weird type '%d'\n", src->type);
426*ebfedea0SLionel Sambuc 		return 0;
427*ebfedea0SLionel Sambuc 	}
428*ebfedea0SLionel Sambuc }
429*ebfedea0SLionel Sambuc 
430*ebfedea0SLionel Sambuc /* do a deep delete on the object */
431*ebfedea0SLionel Sambuc void
mj_delete(mj_t * atom)432*ebfedea0SLionel Sambuc mj_delete(mj_t *atom)
433*ebfedea0SLionel Sambuc {
434*ebfedea0SLionel Sambuc 	unsigned	i;
435*ebfedea0SLionel Sambuc 
436*ebfedea0SLionel Sambuc 	switch(atom->type) {
437*ebfedea0SLionel Sambuc 	case MJ_STRING:
438*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
439*ebfedea0SLionel Sambuc 		free(atom->value.s);
440*ebfedea0SLionel Sambuc 		break;
441*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
442*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
443*ebfedea0SLionel Sambuc 		for (i = 0 ; i < atom->c ; i++) {
444*ebfedea0SLionel Sambuc 			mj_delete(&atom->value.v[i]);
445*ebfedea0SLionel Sambuc 		}
446*ebfedea0SLionel Sambuc 		/* XXX - agc - causing problems? free(atom->value.v); */
447*ebfedea0SLionel Sambuc 		break;
448*ebfedea0SLionel Sambuc 	default:
449*ebfedea0SLionel Sambuc 		break;
450*ebfedea0SLionel Sambuc 	}
451*ebfedea0SLionel Sambuc }
452*ebfedea0SLionel Sambuc 
453*ebfedea0SLionel Sambuc /* return the string size needed for the textual output of the JSON node */
454*ebfedea0SLionel Sambuc int
mj_string_size(mj_t * atom)455*ebfedea0SLionel Sambuc mj_string_size(mj_t *atom)
456*ebfedea0SLionel Sambuc {
457*ebfedea0SLionel Sambuc 	unsigned	i;
458*ebfedea0SLionel Sambuc 	int		cc;
459*ebfedea0SLionel Sambuc 
460*ebfedea0SLionel Sambuc 	switch(atom->type) {
461*ebfedea0SLionel Sambuc 	case MJ_NULL:
462*ebfedea0SLionel Sambuc 	case MJ_TRUE:
463*ebfedea0SLionel Sambuc 		return 4;
464*ebfedea0SLionel Sambuc 	case MJ_FALSE:
465*ebfedea0SLionel Sambuc 		return 5;
466*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
467*ebfedea0SLionel Sambuc 		return atom->c;
468*ebfedea0SLionel Sambuc 	case MJ_STRING:
469*ebfedea0SLionel Sambuc 		return atom->c + 2;
470*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
471*ebfedea0SLionel Sambuc 		for (cc = 2, i = 0 ; i < atom->c ; i++) {
472*ebfedea0SLionel Sambuc 			cc += mj_string_size(&atom->value.v[i]);
473*ebfedea0SLionel Sambuc 			if (i < atom->c - 1) {
474*ebfedea0SLionel Sambuc 				cc += 2;
475*ebfedea0SLionel Sambuc 			}
476*ebfedea0SLionel Sambuc 		}
477*ebfedea0SLionel Sambuc 		return cc + 1 + 1;
478*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
479*ebfedea0SLionel Sambuc 		for (cc = 2, i = 0 ; i < atom->c ; i += 2) {
480*ebfedea0SLionel Sambuc 			cc += mj_string_size(&atom->value.v[i]) + 1 + mj_string_size(&atom->value.v[i + 1]);
481*ebfedea0SLionel Sambuc 			if (i + 1 < atom->c - 1) {
482*ebfedea0SLionel Sambuc 				cc += 2;
483*ebfedea0SLionel Sambuc 			}
484*ebfedea0SLionel Sambuc 		}
485*ebfedea0SLionel Sambuc 		return cc + 1 + 1;
486*ebfedea0SLionel Sambuc 	default:
487*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "mj_string_size: weird type %d\n", atom->type);
488*ebfedea0SLionel Sambuc 		return 0;
489*ebfedea0SLionel Sambuc 	}
490*ebfedea0SLionel Sambuc }
491*ebfedea0SLionel Sambuc 
492*ebfedea0SLionel Sambuc /* create a new atom, and append it to the array or object */
493*ebfedea0SLionel Sambuc int
mj_append(mj_t * atom,const char * type,...)494*ebfedea0SLionel Sambuc mj_append(mj_t *atom, const char *type, ...)
495*ebfedea0SLionel Sambuc {
496*ebfedea0SLionel Sambuc 	va_list	 args;
497*ebfedea0SLionel Sambuc 	ssize_t	 len;
498*ebfedea0SLionel Sambuc 	char	*s;
499*ebfedea0SLionel Sambuc 
500*ebfedea0SLionel Sambuc 	if (atom->type != MJ_ARRAY && atom->type != MJ_OBJECT) {
501*ebfedea0SLionel Sambuc 		return 0;
502*ebfedea0SLionel Sambuc 	}
503*ebfedea0SLionel Sambuc 	ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_append()", return 0);
504*ebfedea0SLionel Sambuc 	va_start(args, type);
505*ebfedea0SLionel Sambuc 	if (strcmp(type, "string") == 0) {
506*ebfedea0SLionel Sambuc 		s = (char *)va_arg(args, char *);
507*ebfedea0SLionel Sambuc 		len = (ssize_t)va_arg(args, ssize_t);
508*ebfedea0SLionel Sambuc 		create_string(&atom->value.v[atom->c++], s, len);
509*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "integer") == 0) {
510*ebfedea0SLionel Sambuc 		create_integer(&atom->value.v[atom->c++], (int64_t)va_arg(args, int64_t));
511*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "object") == 0 || strcmp(type, "array") == 0) {
512*ebfedea0SLionel Sambuc 		mj_deepcopy(&atom->value.v[atom->c++], (mj_t *)va_arg(args, mj_t *));
513*ebfedea0SLionel Sambuc 	} else {
514*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "mj_append: weird type '%s'\n", type);
515*ebfedea0SLionel Sambuc 	}
516*ebfedea0SLionel Sambuc 	va_end(args);
517*ebfedea0SLionel Sambuc 	return 1;
518*ebfedea0SLionel Sambuc }
519*ebfedea0SLionel Sambuc 
520*ebfedea0SLionel Sambuc /* append a field to an object */
521*ebfedea0SLionel Sambuc int
mj_append_field(mj_t * atom,const char * name,const char * type,...)522*ebfedea0SLionel Sambuc mj_append_field(mj_t *atom, const char *name, const char *type, ...)
523*ebfedea0SLionel Sambuc {
524*ebfedea0SLionel Sambuc 	va_list	 args;
525*ebfedea0SLionel Sambuc 	ssize_t	 len;
526*ebfedea0SLionel Sambuc 	char	*s;
527*ebfedea0SLionel Sambuc 
528*ebfedea0SLionel Sambuc 	if (atom->type != MJ_OBJECT) {
529*ebfedea0SLionel Sambuc 		return 0;
530*ebfedea0SLionel Sambuc 	}
531*ebfedea0SLionel Sambuc 	mj_append(atom, "string", name, -1);
532*ebfedea0SLionel Sambuc 	ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_append_field()", return 0);
533*ebfedea0SLionel Sambuc 	va_start(args, type);
534*ebfedea0SLionel Sambuc 	if (strcmp(type, "string") == 0) {
535*ebfedea0SLionel Sambuc 		s = (char *)va_arg(args, char *);
536*ebfedea0SLionel Sambuc 		len = (ssize_t)va_arg(args, ssize_t);
537*ebfedea0SLionel Sambuc 		create_string(&atom->value.v[atom->c++], s, len);
538*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "integer") == 0) {
539*ebfedea0SLionel Sambuc 		create_integer(&atom->value.v[atom->c++], (int64_t)va_arg(args, int64_t));
540*ebfedea0SLionel Sambuc 	} else if (strcmp(type, "object") == 0 || strcmp(type, "array") == 0) {
541*ebfedea0SLionel Sambuc 		mj_deepcopy(&atom->value.v[atom->c++], (mj_t *)va_arg(args, mj_t *));
542*ebfedea0SLionel Sambuc 	} else {
543*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "mj_append_field: weird type '%s'\n", type);
544*ebfedea0SLionel Sambuc 	}
545*ebfedea0SLionel Sambuc 	va_end(args);
546*ebfedea0SLionel Sambuc 	return 1;
547*ebfedea0SLionel Sambuc }
548*ebfedea0SLionel Sambuc 
549*ebfedea0SLionel Sambuc /* make sure a JSON object is politically correct */
550*ebfedea0SLionel Sambuc int
mj_lint(mj_t * obj)551*ebfedea0SLionel Sambuc mj_lint(mj_t *obj)
552*ebfedea0SLionel Sambuc {
553*ebfedea0SLionel Sambuc 	unsigned	i;
554*ebfedea0SLionel Sambuc 	int		ret;
555*ebfedea0SLionel Sambuc 
556*ebfedea0SLionel Sambuc 	switch(obj->type) {
557*ebfedea0SLionel Sambuc 	case MJ_NULL:
558*ebfedea0SLionel Sambuc 	case MJ_FALSE:
559*ebfedea0SLionel Sambuc 	case MJ_TRUE:
560*ebfedea0SLionel Sambuc 		if (obj->value.s != NULL) {
561*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "null/false/true: non zero string\n");
562*ebfedea0SLionel Sambuc 			return 0;
563*ebfedea0SLionel Sambuc 		}
564*ebfedea0SLionel Sambuc 		return 1;
565*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
566*ebfedea0SLionel Sambuc 	case MJ_STRING:
567*ebfedea0SLionel Sambuc 		if (obj->c > obj->size) {
568*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "string/number lint c (%u) > size (%u)\n", obj->c, obj->size);
569*ebfedea0SLionel Sambuc 			return 0;
570*ebfedea0SLionel Sambuc 		}
571*ebfedea0SLionel Sambuc 		return 1;
572*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
573*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
574*ebfedea0SLionel Sambuc 		if (obj->c > obj->size) {
575*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "array/object lint c (%u) > size (%u)\n", obj->c, obj->size);
576*ebfedea0SLionel Sambuc 			return 0;
577*ebfedea0SLionel Sambuc 		}
578*ebfedea0SLionel Sambuc 		for (ret = 1, i = 0 ; i < obj->c ; i++) {
579*ebfedea0SLionel Sambuc 			if (!mj_lint(&obj->value.v[i])) {
580*ebfedea0SLionel Sambuc 				(void) fprintf(stderr, "array/object lint found at %d of %p\n", i, obj);
581*ebfedea0SLionel Sambuc 				ret = 0;
582*ebfedea0SLionel Sambuc 			}
583*ebfedea0SLionel Sambuc 		}
584*ebfedea0SLionel Sambuc 		return ret;
585*ebfedea0SLionel Sambuc 	default:
586*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "problem type %d in %p\n", obj->type, obj);
587*ebfedea0SLionel Sambuc 		return 0;
588*ebfedea0SLionel Sambuc 	}
589*ebfedea0SLionel Sambuc }
590*ebfedea0SLionel Sambuc 
591*ebfedea0SLionel Sambuc /* pretty-print a JSON struct - can be called recursively */
592*ebfedea0SLionel Sambuc int
mj_pretty(mj_t * mj,void * vp,unsigned depth,const char * trailer)593*ebfedea0SLionel Sambuc mj_pretty(mj_t *mj, void *vp, unsigned depth, const char *trailer)
594*ebfedea0SLionel Sambuc {
595*ebfedea0SLionel Sambuc 	unsigned	 i;
596*ebfedea0SLionel Sambuc 	FILE		*fp;
597*ebfedea0SLionel Sambuc 	char		*s;
598*ebfedea0SLionel Sambuc 
599*ebfedea0SLionel Sambuc 	fp = (FILE *)vp;
600*ebfedea0SLionel Sambuc 	switch(mj->type) {
601*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
602*ebfedea0SLionel Sambuc 	case MJ_TRUE:
603*ebfedea0SLionel Sambuc 	case MJ_FALSE:
604*ebfedea0SLionel Sambuc 	case MJ_NULL:
605*ebfedea0SLionel Sambuc 		indent(fp, depth, mj->value.s);
606*ebfedea0SLionel Sambuc 		break;
607*ebfedea0SLionel Sambuc 	case MJ_STRING:
608*ebfedea0SLionel Sambuc 		indent(fp, depth, NULL);
609*ebfedea0SLionel Sambuc 		mj_asprint(&s, mj, MJ_HUMAN);
610*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "\"%s\"", s);
611*ebfedea0SLionel Sambuc 		free(s);
612*ebfedea0SLionel Sambuc 		break;
613*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
614*ebfedea0SLionel Sambuc 		indent(fp, depth, "[\n");
615*ebfedea0SLionel Sambuc 		for (i = 0 ; i < mj->c ; i++) {
616*ebfedea0SLionel Sambuc 			mj_pretty(&mj->value.v[i], fp, depth + 1, (i < mj->c - 1) ? ",\n" : "\n");
617*ebfedea0SLionel Sambuc 		}
618*ebfedea0SLionel Sambuc 		indent(fp, depth, "]");
619*ebfedea0SLionel Sambuc 		break;
620*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
621*ebfedea0SLionel Sambuc 		indent(fp, depth, "{\n");
622*ebfedea0SLionel Sambuc 		for (i = 0 ; i < mj->c ; i += 2) {
623*ebfedea0SLionel Sambuc 			mj_pretty(&mj->value.v[i], fp, depth + 1, " : ");
624*ebfedea0SLionel Sambuc 			mj_pretty(&mj->value.v[i + 1], fp, 0, (i < mj->c - 2) ? ",\n" : "\n");
625*ebfedea0SLionel Sambuc 		}
626*ebfedea0SLionel Sambuc 		indent(fp, depth, "}");
627*ebfedea0SLionel Sambuc 		break;
628*ebfedea0SLionel Sambuc 	}
629*ebfedea0SLionel Sambuc 	indent(fp, 0, trailer);
630*ebfedea0SLionel Sambuc 	return 1;
631*ebfedea0SLionel Sambuc }
632*ebfedea0SLionel Sambuc 
633*ebfedea0SLionel Sambuc /* show the contents of the simple atom as a string representation */
634*ebfedea0SLionel Sambuc const char *
mj_string_rep(mj_t * atom)635*ebfedea0SLionel Sambuc mj_string_rep(mj_t *atom)
636*ebfedea0SLionel Sambuc {
637*ebfedea0SLionel Sambuc 	if (atom == NULL) {
638*ebfedea0SLionel Sambuc 		return 0;
639*ebfedea0SLionel Sambuc 	}
640*ebfedea0SLionel Sambuc 	switch(atom->type) {
641*ebfedea0SLionel Sambuc 	case MJ_STRING:
642*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
643*ebfedea0SLionel Sambuc 		return atom->value.s;
644*ebfedea0SLionel Sambuc 	case MJ_NULL:
645*ebfedea0SLionel Sambuc 		return "null";
646*ebfedea0SLionel Sambuc 	case MJ_FALSE:
647*ebfedea0SLionel Sambuc 		return "false";
648*ebfedea0SLionel Sambuc 	case MJ_TRUE:
649*ebfedea0SLionel Sambuc 		return "true";
650*ebfedea0SLionel Sambuc 	default:
651*ebfedea0SLionel Sambuc 		return NULL;
652*ebfedea0SLionel Sambuc 	}
653*ebfedea0SLionel Sambuc }
654