1*36589d6bSRobert Mustacchi /*
2*36589d6bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*36589d6bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*36589d6bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*36589d6bSRobert Mustacchi  * 1.0 of the CDDL.
6*36589d6bSRobert Mustacchi  *
7*36589d6bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*36589d6bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*36589d6bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*36589d6bSRobert Mustacchi  */
11*36589d6bSRobert Mustacchi 
12*36589d6bSRobert Mustacchi /*
13*36589d6bSRobert Mustacchi  * Copyright 2015 Joyent, Inc.
14*36589d6bSRobert Mustacchi  */
15*36589d6bSRobert Mustacchi 
16*36589d6bSRobert Mustacchi #include <stdio.h>
17*36589d6bSRobert Mustacchi #include <stdlib.h>
18*36589d6bSRobert Mustacchi #include <ctype.h>
19*36589d6bSRobert Mustacchi #include <strings.h>
20*36589d6bSRobert Mustacchi #include <errno.h>
21*36589d6bSRobert Mustacchi #include <libnvpair.h>
22*36589d6bSRobert Mustacchi #include <sys/ccompile.h>
23*36589d6bSRobert Mustacchi 
24*36589d6bSRobert Mustacchi #include "libvarpd_files_json.h"
25*36589d6bSRobert Mustacchi 
26*36589d6bSRobert Mustacchi typedef enum json_type {
27*36589d6bSRobert Mustacchi 	JSON_TYPE_NOTHING = 0,
28*36589d6bSRobert Mustacchi 	JSON_TYPE_STRING = 1,
29*36589d6bSRobert Mustacchi 	JSON_TYPE_INTEGER,
30*36589d6bSRobert Mustacchi 	JSON_TYPE_DOUBLE,
31*36589d6bSRobert Mustacchi 	JSON_TYPE_BOOLEAN,
32*36589d6bSRobert Mustacchi 	JSON_TYPE_NULL,
33*36589d6bSRobert Mustacchi 	JSON_TYPE_OBJECT,
34*36589d6bSRobert Mustacchi 	JSON_TYPE_ARRAY
35*36589d6bSRobert Mustacchi } json_type_t;
36*36589d6bSRobert Mustacchi 
37*36589d6bSRobert Mustacchi typedef enum parse_state {
38*36589d6bSRobert Mustacchi 	PARSE_ERROR = -1,
39*36589d6bSRobert Mustacchi 	PARSE_DONE = 0,
40*36589d6bSRobert Mustacchi 	PARSE_REST,
41*36589d6bSRobert Mustacchi 	PARSE_OBJECT,
42*36589d6bSRobert Mustacchi 	PARSE_KEY_STRING,
43*36589d6bSRobert Mustacchi 	PARSE_COLON,
44*36589d6bSRobert Mustacchi 	PARSE_STRING,
45*36589d6bSRobert Mustacchi 	PARSE_OBJECT_COMMA,
46*36589d6bSRobert Mustacchi 	PARSE_ARRAY,
47*36589d6bSRobert Mustacchi 	PARSE_BAREWORD,
48*36589d6bSRobert Mustacchi 	PARSE_NUMBER,
49*36589d6bSRobert Mustacchi 	PARSE_ARRAY_VALUE,
50*36589d6bSRobert Mustacchi 	PARSE_ARRAY_COMMA
51*36589d6bSRobert Mustacchi } parse_state_t;
52*36589d6bSRobert Mustacchi 
53*36589d6bSRobert Mustacchi #define	JSON_MARKER		".__json_"
54*36589d6bSRobert Mustacchi #define	JSON_MARKER_ARRAY	JSON_MARKER "array"
55*36589d6bSRobert Mustacchi 
56*36589d6bSRobert Mustacchi typedef struct parse_frame {
57*36589d6bSRobert Mustacchi 	parse_state_t pf_ps;
58*36589d6bSRobert Mustacchi 	nvlist_t *pf_nvl;
59*36589d6bSRobert Mustacchi 
60*36589d6bSRobert Mustacchi 	char *pf_key;
61*36589d6bSRobert Mustacchi 	void *pf_value;
62*36589d6bSRobert Mustacchi 	json_type_t pf_value_type;
63*36589d6bSRobert Mustacchi 	int pf_array_index;
64*36589d6bSRobert Mustacchi 
65*36589d6bSRobert Mustacchi 	struct parse_frame *pf_next;
66*36589d6bSRobert Mustacchi } parse_frame_t;
67*36589d6bSRobert Mustacchi 
68*36589d6bSRobert Mustacchi typedef struct state {
69*36589d6bSRobert Mustacchi 	const char *s_in;
70*36589d6bSRobert Mustacchi 	unsigned long s_pos;
71*36589d6bSRobert Mustacchi 	unsigned long s_len;
72*36589d6bSRobert Mustacchi 
73*36589d6bSRobert Mustacchi 	parse_frame_t *s_top;
74*36589d6bSRobert Mustacchi 
75*36589d6bSRobert Mustacchi 	nvlist_parse_json_flags_t s_flags;
76*36589d6bSRobert Mustacchi 
77*36589d6bSRobert Mustacchi 	/*
78*36589d6bSRobert Mustacchi 	 * This string buffer is used for temporary storage by the
79*36589d6bSRobert Mustacchi 	 * "collect_*()" family of functions.
80*36589d6bSRobert Mustacchi 	 */
81*36589d6bSRobert Mustacchi 	custr_t *s_collect;
82*36589d6bSRobert Mustacchi 
83*36589d6bSRobert Mustacchi 	int s_errno;
84*36589d6bSRobert Mustacchi 	custr_t *s_errstr;
85*36589d6bSRobert Mustacchi } state_t;
86*36589d6bSRobert Mustacchi 
87*36589d6bSRobert Mustacchi typedef void (*parse_handler_t)(state_t *);
88*36589d6bSRobert Mustacchi 
89*36589d6bSRobert Mustacchi static void
movestate(state_t * s,parse_state_t ps)90*36589d6bSRobert Mustacchi movestate(state_t *s, parse_state_t ps)
91*36589d6bSRobert Mustacchi {
92*36589d6bSRobert Mustacchi 	if (s->s_flags & NVJSON_DEBUG) {
93*36589d6bSRobert Mustacchi 		(void) fprintf(stderr, "nvjson: move state %d -> %d\n",
94*36589d6bSRobert Mustacchi 		    s->s_top->pf_ps, ps);
95*36589d6bSRobert Mustacchi 	}
96*36589d6bSRobert Mustacchi 	s->s_top->pf_ps = ps;
97*36589d6bSRobert Mustacchi }
98*36589d6bSRobert Mustacchi 
99*36589d6bSRobert Mustacchi static void
posterror(state_t * s,int erno,const char * error)100*36589d6bSRobert Mustacchi posterror(state_t *s, int erno, const char *error)
101*36589d6bSRobert Mustacchi {
102*36589d6bSRobert Mustacchi 	/*
103*36589d6bSRobert Mustacchi 	 * If the caller wants error messages printed to stderr, do that
104*36589d6bSRobert Mustacchi 	 * first.
105*36589d6bSRobert Mustacchi 	 */
106*36589d6bSRobert Mustacchi 	if (s->s_flags & NVJSON_ERRORS_TO_STDERR) {
107*36589d6bSRobert Mustacchi 		(void) fprintf(stderr, "nvjson error (pos %ld, errno %d): %s\n",
108*36589d6bSRobert Mustacchi 		    s->s_pos, erno, error);
109*36589d6bSRobert Mustacchi 	}
110*36589d6bSRobert Mustacchi 
111*36589d6bSRobert Mustacchi 	/*
112*36589d6bSRobert Mustacchi 	 * Try and store the error message for the caller.  This may fail if
113*36589d6bSRobert Mustacchi 	 * the error was related to memory pressure, and that condition still
114*36589d6bSRobert Mustacchi 	 * exists.
115*36589d6bSRobert Mustacchi 	 */
116*36589d6bSRobert Mustacchi 	s->s_errno = erno;
117*36589d6bSRobert Mustacchi 	if (s->s_errstr != NULL) {
118*36589d6bSRobert Mustacchi 		(void) custr_append(s->s_errstr, error);
119*36589d6bSRobert Mustacchi 	}
120*36589d6bSRobert Mustacchi 
121*36589d6bSRobert Mustacchi 	movestate(s, PARSE_ERROR);
122*36589d6bSRobert Mustacchi }
123*36589d6bSRobert Mustacchi 
124*36589d6bSRobert Mustacchi static int
pushstate(state_t * s,parse_state_t ps,parse_state_t retps)125*36589d6bSRobert Mustacchi pushstate(state_t *s, parse_state_t ps, parse_state_t retps)
126*36589d6bSRobert Mustacchi {
127*36589d6bSRobert Mustacchi 	parse_frame_t *n;
128*36589d6bSRobert Mustacchi 
129*36589d6bSRobert Mustacchi 	if (s->s_flags & NVJSON_DEBUG) {
130*36589d6bSRobert Mustacchi 		(void) fprintf(stderr, "nvjson: push state %d -> %d (ret %d)\n",
131*36589d6bSRobert Mustacchi 		    s->s_top->pf_ps, ps, retps);
132*36589d6bSRobert Mustacchi 	}
133*36589d6bSRobert Mustacchi 
134*36589d6bSRobert Mustacchi 	if ((n = calloc(1, sizeof (*n))) == NULL) {
135*36589d6bSRobert Mustacchi 		posterror(s, errno, "pushstate calloc failure");
136*36589d6bSRobert Mustacchi 		return (-1);
137*36589d6bSRobert Mustacchi 	}
138*36589d6bSRobert Mustacchi 
139*36589d6bSRobert Mustacchi 	/*
140*36589d6bSRobert Mustacchi 	 * Store the state we'll return to when popping this
141*36589d6bSRobert Mustacchi 	 * frame:
142*36589d6bSRobert Mustacchi 	 */
143*36589d6bSRobert Mustacchi 	s->s_top->pf_ps = retps;
144*36589d6bSRobert Mustacchi 
145*36589d6bSRobert Mustacchi 	/*
146*36589d6bSRobert Mustacchi 	 * Store the initial state for the new frame, and
147*36589d6bSRobert Mustacchi 	 * put it on top of the stack:
148*36589d6bSRobert Mustacchi 	 */
149*36589d6bSRobert Mustacchi 	n->pf_ps = ps;
150*36589d6bSRobert Mustacchi 	n->pf_value_type = JSON_TYPE_NOTHING;
151*36589d6bSRobert Mustacchi 
152*36589d6bSRobert Mustacchi 	n->pf_next = s->s_top;
153*36589d6bSRobert Mustacchi 	s->s_top = n;
154*36589d6bSRobert Mustacchi 
155*36589d6bSRobert Mustacchi 	return (0);
156*36589d6bSRobert Mustacchi }
157*36589d6bSRobert Mustacchi 
158*36589d6bSRobert Mustacchi static char
popchar(state_t * s)159*36589d6bSRobert Mustacchi popchar(state_t *s)
160*36589d6bSRobert Mustacchi {
161*36589d6bSRobert Mustacchi 	if (s->s_pos > s->s_len) {
162*36589d6bSRobert Mustacchi 		return (0);
163*36589d6bSRobert Mustacchi 	}
164*36589d6bSRobert Mustacchi 	return (s->s_in[s->s_pos++]);
165*36589d6bSRobert Mustacchi }
166*36589d6bSRobert Mustacchi 
167*36589d6bSRobert Mustacchi static char
peekchar(state_t * s)168*36589d6bSRobert Mustacchi peekchar(state_t *s)
169*36589d6bSRobert Mustacchi {
170*36589d6bSRobert Mustacchi 	if (s->s_pos > s->s_len) {
171*36589d6bSRobert Mustacchi 		return (0);
172*36589d6bSRobert Mustacchi 	}
173*36589d6bSRobert Mustacchi 	return (s->s_in[s->s_pos]);
174*36589d6bSRobert Mustacchi }
175*36589d6bSRobert Mustacchi 
176*36589d6bSRobert Mustacchi static void
discard_whitespace(state_t * s)177*36589d6bSRobert Mustacchi discard_whitespace(state_t *s)
178*36589d6bSRobert Mustacchi {
179*36589d6bSRobert Mustacchi 	while (isspace(peekchar(s))) {
180*36589d6bSRobert Mustacchi 		(void) popchar(s);
181*36589d6bSRobert Mustacchi 	}
182*36589d6bSRobert Mustacchi }
183*36589d6bSRobert Mustacchi 
184*36589d6bSRobert Mustacchi static char *escape_pairs[] = {
185*36589d6bSRobert Mustacchi 	"\"\"", "\\\\", "//", "b\b", "f\f", "n\n", "r\r", "t\t", NULL
186*36589d6bSRobert Mustacchi };
187*36589d6bSRobert Mustacchi 
188*36589d6bSRobert Mustacchi static char
collect_string_escape(state_t * s)189*36589d6bSRobert Mustacchi collect_string_escape(state_t *s)
190*36589d6bSRobert Mustacchi {
191*36589d6bSRobert Mustacchi 	int i;
192*36589d6bSRobert Mustacchi 	char c = popchar(s);
193*36589d6bSRobert Mustacchi 
194*36589d6bSRobert Mustacchi 	if (c == '\0') {
195*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "EOF mid-escape sequence");
196*36589d6bSRobert Mustacchi 		return (-1);
197*36589d6bSRobert Mustacchi 	}
198*36589d6bSRobert Mustacchi 
199*36589d6bSRobert Mustacchi 	/*
200*36589d6bSRobert Mustacchi 	 * Handle four-digit Unicode escapes up to and including \u007f.
201*36589d6bSRobert Mustacchi 	 * Strings that cannot be represented as 7-bit clean ASCII are not
202*36589d6bSRobert Mustacchi 	 * currently supported.
203*36589d6bSRobert Mustacchi 	 */
204*36589d6bSRobert Mustacchi 	if (c == 'u') {
205*36589d6bSRobert Mustacchi 		int res;
206*36589d6bSRobert Mustacchi 		int ndigs = 0;
207*36589d6bSRobert Mustacchi 		char digs[5];
208*36589d6bSRobert Mustacchi 
209*36589d6bSRobert Mustacchi 		/*
210*36589d6bSRobert Mustacchi 		 * Deal with 4-digit unicode escape.
211*36589d6bSRobert Mustacchi 		 */
212*36589d6bSRobert Mustacchi 		while (ndigs < 4) {
213*36589d6bSRobert Mustacchi 			if ((digs[ndigs++] = popchar(s)) == '\0') {
214*36589d6bSRobert Mustacchi 				posterror(s, EPROTO, "EOF mid-escape "
215*36589d6bSRobert Mustacchi 				    "sequence");
216*36589d6bSRobert Mustacchi 				return (-1);
217*36589d6bSRobert Mustacchi 			}
218*36589d6bSRobert Mustacchi 		}
219*36589d6bSRobert Mustacchi 		digs[4] = '\0';
220*36589d6bSRobert Mustacchi 		if ((res = atoi(digs)) > 127) {
221*36589d6bSRobert Mustacchi 			posterror(s, EPROTO, "unicode escape above 0x7f");
222*36589d6bSRobert Mustacchi 			return (-1);
223*36589d6bSRobert Mustacchi 		}
224*36589d6bSRobert Mustacchi 
225*36589d6bSRobert Mustacchi 		if (custr_appendc(s->s_collect, res) != 0) {
226*36589d6bSRobert Mustacchi 			posterror(s, errno, "custr_appendc failure");
227*36589d6bSRobert Mustacchi 			return (-1);
228*36589d6bSRobert Mustacchi 		}
229*36589d6bSRobert Mustacchi 		return (0);
230*36589d6bSRobert Mustacchi 	}
231*36589d6bSRobert Mustacchi 
232*36589d6bSRobert Mustacchi 	/*
233*36589d6bSRobert Mustacchi 	 * See if this is a C-style escape character we recognise.
234*36589d6bSRobert Mustacchi 	 */
235*36589d6bSRobert Mustacchi 	for (i = 0; escape_pairs[i] != NULL; i++) {
236*36589d6bSRobert Mustacchi 		char *ep = escape_pairs[i];
237*36589d6bSRobert Mustacchi 		if (ep[0] == c) {
238*36589d6bSRobert Mustacchi 			if (custr_appendc(s->s_collect, ep[1]) != 0) {
239*36589d6bSRobert Mustacchi 				posterror(s, errno, "custr_appendc failure");
240*36589d6bSRobert Mustacchi 				return (-1);
241*36589d6bSRobert Mustacchi 			}
242*36589d6bSRobert Mustacchi 			return (0);
243*36589d6bSRobert Mustacchi 		}
244*36589d6bSRobert Mustacchi 	}
245*36589d6bSRobert Mustacchi 
246*36589d6bSRobert Mustacchi 	posterror(s, EPROTO, "unrecognised escape sequence");
247*36589d6bSRobert Mustacchi 	return (-1);
248*36589d6bSRobert Mustacchi }
249*36589d6bSRobert Mustacchi 
250*36589d6bSRobert Mustacchi static int
collect_string(state_t * s)251*36589d6bSRobert Mustacchi collect_string(state_t *s)
252*36589d6bSRobert Mustacchi {
253*36589d6bSRobert Mustacchi 	custr_reset(s->s_collect);
254*36589d6bSRobert Mustacchi 
255*36589d6bSRobert Mustacchi 	for (;;) {
256*36589d6bSRobert Mustacchi 		char c;
257*36589d6bSRobert Mustacchi 
258*36589d6bSRobert Mustacchi 		switch (c = popchar(s)) {
259*36589d6bSRobert Mustacchi 		case '"':
260*36589d6bSRobert Mustacchi 			/*
261*36589d6bSRobert Mustacchi 			 * Legal End of String.
262*36589d6bSRobert Mustacchi 			 */
263*36589d6bSRobert Mustacchi 			return (0);
264*36589d6bSRobert Mustacchi 
265*36589d6bSRobert Mustacchi 		case '\0':
266*36589d6bSRobert Mustacchi 			posterror(s, EPROTO, "EOF mid-string");
267*36589d6bSRobert Mustacchi 			return (-1);
268*36589d6bSRobert Mustacchi 
269*36589d6bSRobert Mustacchi 		case '\\':
270*36589d6bSRobert Mustacchi 			/*
271*36589d6bSRobert Mustacchi 			 * Escape Characters and Sequences.
272*36589d6bSRobert Mustacchi 			 */
273*36589d6bSRobert Mustacchi 			if (collect_string_escape(s) != 0) {
274*36589d6bSRobert Mustacchi 				return (-1);
275*36589d6bSRobert Mustacchi 			}
276*36589d6bSRobert Mustacchi 			break;
277*36589d6bSRobert Mustacchi 
278*36589d6bSRobert Mustacchi 		default:
279*36589d6bSRobert Mustacchi 			if (custr_appendc(s->s_collect, c) != 0) {
280*36589d6bSRobert Mustacchi 				posterror(s, errno, "custr_appendc failure");
281*36589d6bSRobert Mustacchi 				return (-1);
282*36589d6bSRobert Mustacchi 			}
283*36589d6bSRobert Mustacchi 			break;
284*36589d6bSRobert Mustacchi 		}
285*36589d6bSRobert Mustacchi 	}
286*36589d6bSRobert Mustacchi }
287*36589d6bSRobert Mustacchi 
288*36589d6bSRobert Mustacchi static int
collect_bareword(state_t * s)289*36589d6bSRobert Mustacchi collect_bareword(state_t *s)
290*36589d6bSRobert Mustacchi {
291*36589d6bSRobert Mustacchi 	custr_reset(s->s_collect);
292*36589d6bSRobert Mustacchi 
293*36589d6bSRobert Mustacchi 	for (;;) {
294*36589d6bSRobert Mustacchi 		if (!islower(peekchar(s))) {
295*36589d6bSRobert Mustacchi 			return (0);
296*36589d6bSRobert Mustacchi 		}
297*36589d6bSRobert Mustacchi 
298*36589d6bSRobert Mustacchi 		if (custr_appendc(s->s_collect, popchar(s)) != 0) {
299*36589d6bSRobert Mustacchi 			posterror(s, errno, "custr_appendc failure");
300*36589d6bSRobert Mustacchi 			return (-1);
301*36589d6bSRobert Mustacchi 		}
302*36589d6bSRobert Mustacchi 	}
303*36589d6bSRobert Mustacchi }
304*36589d6bSRobert Mustacchi 
305*36589d6bSRobert Mustacchi static void
hdlr_bareword(state_t * s)306*36589d6bSRobert Mustacchi hdlr_bareword(state_t *s)
307*36589d6bSRobert Mustacchi {
308*36589d6bSRobert Mustacchi 	const char *str;
309*36589d6bSRobert Mustacchi 
310*36589d6bSRobert Mustacchi 	if (collect_bareword(s) != 0) {
311*36589d6bSRobert Mustacchi 		return;
312*36589d6bSRobert Mustacchi 	}
313*36589d6bSRobert Mustacchi 
314*36589d6bSRobert Mustacchi 	str = custr_cstr(s->s_collect);
315*36589d6bSRobert Mustacchi 	if (strcmp(str, "true") == 0) {
316*36589d6bSRobert Mustacchi 		s->s_top->pf_value_type = JSON_TYPE_BOOLEAN;
317*36589d6bSRobert Mustacchi 		s->s_top->pf_value = (void *)B_TRUE;
318*36589d6bSRobert Mustacchi 	} else if (strcmp(str, "false") == 0) {
319*36589d6bSRobert Mustacchi 		s->s_top->pf_value_type = JSON_TYPE_BOOLEAN;
320*36589d6bSRobert Mustacchi 		s->s_top->pf_value = (void *)B_FALSE;
321*36589d6bSRobert Mustacchi 	} else if (strcmp(str, "null") == 0) {
322*36589d6bSRobert Mustacchi 		s->s_top->pf_value_type = JSON_TYPE_NULL;
323*36589d6bSRobert Mustacchi 	} else {
324*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "expected 'true', 'false' or 'null'");
325*36589d6bSRobert Mustacchi 		return;
326*36589d6bSRobert Mustacchi 	}
327*36589d6bSRobert Mustacchi 
328*36589d6bSRobert Mustacchi 	movestate(s, PARSE_DONE);
329*36589d6bSRobert Mustacchi }
330*36589d6bSRobert Mustacchi 
331*36589d6bSRobert Mustacchi /* ARGSUSED */
332*36589d6bSRobert Mustacchi static int
collect_number(state_t * s,boolean_t * isint,int32_t * result,double * fresult __unused)333*36589d6bSRobert Mustacchi collect_number(state_t *s, boolean_t *isint, int32_t *result,
334*36589d6bSRobert Mustacchi     double *fresult __unused)
335*36589d6bSRobert Mustacchi {
336*36589d6bSRobert Mustacchi 	boolean_t neg = B_FALSE;
337*36589d6bSRobert Mustacchi 	int t;
338*36589d6bSRobert Mustacchi 
339*36589d6bSRobert Mustacchi 	custr_reset(s->s_collect);
340*36589d6bSRobert Mustacchi 
341*36589d6bSRobert Mustacchi 	if (peekchar(s) == '-') {
342*36589d6bSRobert Mustacchi 		neg = B_TRUE;
343*36589d6bSRobert Mustacchi 		(void) popchar(s);
344*36589d6bSRobert Mustacchi 	}
345*36589d6bSRobert Mustacchi 	/*
346*36589d6bSRobert Mustacchi 	 * Read the 'int' portion:
347*36589d6bSRobert Mustacchi 	 */
348*36589d6bSRobert Mustacchi 	if (!isdigit(peekchar(s))) {
349*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "malformed number: expected digit (0-9)");
350*36589d6bSRobert Mustacchi 		return (-1);
351*36589d6bSRobert Mustacchi 	}
352*36589d6bSRobert Mustacchi 	for (;;) {
353*36589d6bSRobert Mustacchi 		if (!isdigit(peekchar(s))) {
354*36589d6bSRobert Mustacchi 			break;
355*36589d6bSRobert Mustacchi 		}
356*36589d6bSRobert Mustacchi 		if (custr_appendc(s->s_collect, popchar(s)) != 0) {
357*36589d6bSRobert Mustacchi 			posterror(s, errno, "custr_append failure");
358*36589d6bSRobert Mustacchi 			return (-1);
359*36589d6bSRobert Mustacchi 		}
360*36589d6bSRobert Mustacchi 	}
361*36589d6bSRobert Mustacchi 	if (peekchar(s) == '.' || peekchar(s) == 'e' || peekchar(s) == 'E') {
362*36589d6bSRobert Mustacchi 		posterror(s, ENOTSUP, "do not yet support FRACs or EXPs");
363*36589d6bSRobert Mustacchi 		return (-1);
364*36589d6bSRobert Mustacchi 	}
365*36589d6bSRobert Mustacchi 
366*36589d6bSRobert Mustacchi 	t = atoi(custr_cstr(s->s_collect));
367*36589d6bSRobert Mustacchi 
368*36589d6bSRobert Mustacchi 	*isint = B_TRUE;
369*36589d6bSRobert Mustacchi 	*result = (neg == B_TRUE) ? (-t) : t;
370*36589d6bSRobert Mustacchi 	return (0);
371*36589d6bSRobert Mustacchi }
372*36589d6bSRobert Mustacchi 
373*36589d6bSRobert Mustacchi static void
hdlr_number(state_t * s)374*36589d6bSRobert Mustacchi hdlr_number(state_t *s)
375*36589d6bSRobert Mustacchi {
376*36589d6bSRobert Mustacchi 	boolean_t isint;
377*36589d6bSRobert Mustacchi 	int32_t result;
378*36589d6bSRobert Mustacchi 	double fresult;
379*36589d6bSRobert Mustacchi 
380*36589d6bSRobert Mustacchi 	if (collect_number(s, &isint, &result, &fresult) != 0) {
381*36589d6bSRobert Mustacchi 		return;
382*36589d6bSRobert Mustacchi 	}
383*36589d6bSRobert Mustacchi 
384*36589d6bSRobert Mustacchi 	if (isint == B_TRUE) {
385*36589d6bSRobert Mustacchi 		s->s_top->pf_value = (void *)(uintptr_t)result;
386*36589d6bSRobert Mustacchi 		s->s_top->pf_value_type = JSON_TYPE_INTEGER;
387*36589d6bSRobert Mustacchi 	} else {
388*36589d6bSRobert Mustacchi 		s->s_top->pf_value = malloc(sizeof (fresult));
389*36589d6bSRobert Mustacchi 		bcopy(&fresult, s->s_top->pf_value, sizeof (fresult));
390*36589d6bSRobert Mustacchi 		s->s_top->pf_value_type = JSON_TYPE_DOUBLE;
391*36589d6bSRobert Mustacchi 	}
392*36589d6bSRobert Mustacchi 
393*36589d6bSRobert Mustacchi 	movestate(s, PARSE_DONE);
394*36589d6bSRobert Mustacchi }
395*36589d6bSRobert Mustacchi 
396*36589d6bSRobert Mustacchi static void
hdlr_rest(state_t * s)397*36589d6bSRobert Mustacchi hdlr_rest(state_t *s)
398*36589d6bSRobert Mustacchi {
399*36589d6bSRobert Mustacchi 	char c;
400*36589d6bSRobert Mustacchi 	discard_whitespace(s);
401*36589d6bSRobert Mustacchi 	c = popchar(s);
402*36589d6bSRobert Mustacchi 	switch (c) {
403*36589d6bSRobert Mustacchi 	case '{':
404*36589d6bSRobert Mustacchi 		movestate(s, PARSE_OBJECT);
405*36589d6bSRobert Mustacchi 		return;
406*36589d6bSRobert Mustacchi 
407*36589d6bSRobert Mustacchi 	case '[':
408*36589d6bSRobert Mustacchi 		movestate(s, PARSE_ARRAY);
409*36589d6bSRobert Mustacchi 		return;
410*36589d6bSRobert Mustacchi 
411*36589d6bSRobert Mustacchi 	default:
412*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "EOF before object or array");
413*36589d6bSRobert Mustacchi 		return;
414*36589d6bSRobert Mustacchi 	}
415*36589d6bSRobert Mustacchi }
416*36589d6bSRobert Mustacchi 
417*36589d6bSRobert Mustacchi static int
add_empty_child(state_t * s)418*36589d6bSRobert Mustacchi add_empty_child(state_t *s)
419*36589d6bSRobert Mustacchi {
420*36589d6bSRobert Mustacchi 	/*
421*36589d6bSRobert Mustacchi 	 * Here, we create an empty nvlist to represent this object
422*36589d6bSRobert Mustacchi 	 * or array:
423*36589d6bSRobert Mustacchi 	 */
424*36589d6bSRobert Mustacchi 	nvlist_t *empty;
425*36589d6bSRobert Mustacchi 	if (nvlist_alloc(&empty, NV_UNIQUE_NAME, 0) != 0) {
426*36589d6bSRobert Mustacchi 		posterror(s, errno, "nvlist_alloc failure");
427*36589d6bSRobert Mustacchi 		return (-1);
428*36589d6bSRobert Mustacchi 	}
429*36589d6bSRobert Mustacchi 	if (s->s_top->pf_next != NULL) {
430*36589d6bSRobert Mustacchi 		/*
431*36589d6bSRobert Mustacchi 		 * If we're a child of the frame above, we store ourselves in
432*36589d6bSRobert Mustacchi 		 * that frame's nvlist:
433*36589d6bSRobert Mustacchi 		 */
434*36589d6bSRobert Mustacchi 		nvlist_t *nvl = s->s_top->pf_next->pf_nvl;
435*36589d6bSRobert Mustacchi 		char *key = s->s_top->pf_next->pf_key;
436*36589d6bSRobert Mustacchi 
437*36589d6bSRobert Mustacchi 		if (nvlist_add_nvlist(nvl, key, empty) != 0) {
438*36589d6bSRobert Mustacchi 			posterror(s, errno, "nvlist_add_nvlist failure");
439*36589d6bSRobert Mustacchi 			nvlist_free(empty);
440*36589d6bSRobert Mustacchi 			return (-1);
441*36589d6bSRobert Mustacchi 		}
442*36589d6bSRobert Mustacchi 		nvlist_free(empty);
443*36589d6bSRobert Mustacchi 		if (nvlist_lookup_nvlist(nvl, key, &empty) != 0) {
444*36589d6bSRobert Mustacchi 			posterror(s, errno, "nvlist_lookup_nvlist failure");
445*36589d6bSRobert Mustacchi 			return (-1);
446*36589d6bSRobert Mustacchi 		}
447*36589d6bSRobert Mustacchi 	}
448*36589d6bSRobert Mustacchi 	s->s_top->pf_nvl = empty;
449*36589d6bSRobert Mustacchi 	return (0);
450*36589d6bSRobert Mustacchi }
451*36589d6bSRobert Mustacchi 
452*36589d6bSRobert Mustacchi static int
decorate_array(state_t * s)453*36589d6bSRobert Mustacchi decorate_array(state_t *s)
454*36589d6bSRobert Mustacchi {
455*36589d6bSRobert Mustacchi 	int idx = s->s_top->pf_array_index;
456*36589d6bSRobert Mustacchi 	/*
457*36589d6bSRobert Mustacchi 	 * When we are done creating an array, we store a 'length'
458*36589d6bSRobert Mustacchi 	 * property on it, as well as an internal-use marker value.
459*36589d6bSRobert Mustacchi 	 */
460*36589d6bSRobert Mustacchi 	if (nvlist_add_boolean(s->s_top->pf_nvl, JSON_MARKER_ARRAY) != 0 ||
461*36589d6bSRobert Mustacchi 	    nvlist_add_uint32(s->s_top->pf_nvl, "length", idx) != 0) {
462*36589d6bSRobert Mustacchi 		posterror(s, errno, "nvlist_add failure");
463*36589d6bSRobert Mustacchi 		return (-1);
464*36589d6bSRobert Mustacchi 	}
465*36589d6bSRobert Mustacchi 
466*36589d6bSRobert Mustacchi 	return (0);
467*36589d6bSRobert Mustacchi }
468*36589d6bSRobert Mustacchi 
469*36589d6bSRobert Mustacchi static void
hdlr_array(state_t * s)470*36589d6bSRobert Mustacchi hdlr_array(state_t *s)
471*36589d6bSRobert Mustacchi {
472*36589d6bSRobert Mustacchi 	s->s_top->pf_value_type = JSON_TYPE_ARRAY;
473*36589d6bSRobert Mustacchi 
474*36589d6bSRobert Mustacchi 	if (add_empty_child(s) != 0) {
475*36589d6bSRobert Mustacchi 		return;
476*36589d6bSRobert Mustacchi 	}
477*36589d6bSRobert Mustacchi 
478*36589d6bSRobert Mustacchi 	discard_whitespace(s);
479*36589d6bSRobert Mustacchi 
480*36589d6bSRobert Mustacchi 	switch (peekchar(s)) {
481*36589d6bSRobert Mustacchi 	case ']':
482*36589d6bSRobert Mustacchi 		(void) popchar(s);
483*36589d6bSRobert Mustacchi 
484*36589d6bSRobert Mustacchi 		if (decorate_array(s) != 0) {
485*36589d6bSRobert Mustacchi 			return;
486*36589d6bSRobert Mustacchi 		}
487*36589d6bSRobert Mustacchi 
488*36589d6bSRobert Mustacchi 		movestate(s, PARSE_DONE);
489*36589d6bSRobert Mustacchi 		return;
490*36589d6bSRobert Mustacchi 
491*36589d6bSRobert Mustacchi 	default:
492*36589d6bSRobert Mustacchi 		movestate(s, PARSE_ARRAY_VALUE);
493*36589d6bSRobert Mustacchi 		return;
494*36589d6bSRobert Mustacchi 	}
495*36589d6bSRobert Mustacchi }
496*36589d6bSRobert Mustacchi 
497*36589d6bSRobert Mustacchi static void
hdlr_array_comma(state_t * s)498*36589d6bSRobert Mustacchi hdlr_array_comma(state_t *s)
499*36589d6bSRobert Mustacchi {
500*36589d6bSRobert Mustacchi 	discard_whitespace(s);
501*36589d6bSRobert Mustacchi 
502*36589d6bSRobert Mustacchi 	switch (popchar(s)) {
503*36589d6bSRobert Mustacchi 	case ']':
504*36589d6bSRobert Mustacchi 		if (decorate_array(s) != 0) {
505*36589d6bSRobert Mustacchi 			return;
506*36589d6bSRobert Mustacchi 		}
507*36589d6bSRobert Mustacchi 
508*36589d6bSRobert Mustacchi 		movestate(s, PARSE_DONE);
509*36589d6bSRobert Mustacchi 		return;
510*36589d6bSRobert Mustacchi 	case ',':
511*36589d6bSRobert Mustacchi 		movestate(s, PARSE_ARRAY_VALUE);
512*36589d6bSRobert Mustacchi 		return;
513*36589d6bSRobert Mustacchi 	default:
514*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "expected ',' or ']'");
515*36589d6bSRobert Mustacchi 		return;
516*36589d6bSRobert Mustacchi 	}
517*36589d6bSRobert Mustacchi }
518*36589d6bSRobert Mustacchi 
519*36589d6bSRobert Mustacchi static void
hdlr_array_value(state_t * s)520*36589d6bSRobert Mustacchi hdlr_array_value(state_t *s)
521*36589d6bSRobert Mustacchi {
522*36589d6bSRobert Mustacchi 	char c;
523*36589d6bSRobert Mustacchi 
524*36589d6bSRobert Mustacchi 	/*
525*36589d6bSRobert Mustacchi 	 * Generate keyname from the next array index:
526*36589d6bSRobert Mustacchi 	 */
527*36589d6bSRobert Mustacchi 	if (s->s_top->pf_key != NULL) {
528*36589d6bSRobert Mustacchi 		(void) fprintf(stderr, "pf_key not null! was %s\n",
529*36589d6bSRobert Mustacchi 		    s->s_top->pf_key);
530*36589d6bSRobert Mustacchi 		abort();
531*36589d6bSRobert Mustacchi 	}
532*36589d6bSRobert Mustacchi 
533*36589d6bSRobert Mustacchi 	if (asprintf(&s->s_top->pf_key, "%d", s->s_top->pf_array_index++) < 0) {
534*36589d6bSRobert Mustacchi 		posterror(s, errno, "asprintf failure");
535*36589d6bSRobert Mustacchi 		return;
536*36589d6bSRobert Mustacchi 	}
537*36589d6bSRobert Mustacchi 
538*36589d6bSRobert Mustacchi 	discard_whitespace(s);
539*36589d6bSRobert Mustacchi 
540*36589d6bSRobert Mustacchi 	/*
541*36589d6bSRobert Mustacchi 	 * Select which type handler we need for the next value:
542*36589d6bSRobert Mustacchi 	 */
543*36589d6bSRobert Mustacchi 	switch (c = peekchar(s)) {
544*36589d6bSRobert Mustacchi 	case '"':
545*36589d6bSRobert Mustacchi 		(void) popchar(s);
546*36589d6bSRobert Mustacchi 		(void) pushstate(s, PARSE_STRING, PARSE_ARRAY_COMMA);
547*36589d6bSRobert Mustacchi 		return;
548*36589d6bSRobert Mustacchi 
549*36589d6bSRobert Mustacchi 	case '{':
550*36589d6bSRobert Mustacchi 		(void) popchar(s);
551*36589d6bSRobert Mustacchi 		(void) pushstate(s, PARSE_OBJECT, PARSE_ARRAY_COMMA);
552*36589d6bSRobert Mustacchi 		return;
553*36589d6bSRobert Mustacchi 
554*36589d6bSRobert Mustacchi 	case '[':
555*36589d6bSRobert Mustacchi 		(void) popchar(s);
556*36589d6bSRobert Mustacchi 		(void) pushstate(s, PARSE_ARRAY, PARSE_ARRAY_COMMA);
557*36589d6bSRobert Mustacchi 		return;
558*36589d6bSRobert Mustacchi 
559*36589d6bSRobert Mustacchi 	default:
560*36589d6bSRobert Mustacchi 		if (islower(c)) {
561*36589d6bSRobert Mustacchi 			(void) pushstate(s, PARSE_BAREWORD,
562*36589d6bSRobert Mustacchi 			    PARSE_ARRAY_COMMA);
563*36589d6bSRobert Mustacchi 			return;
564*36589d6bSRobert Mustacchi 		} else if (c == '-' || isdigit(c)) {
565*36589d6bSRobert Mustacchi 			(void) pushstate(s, PARSE_NUMBER, PARSE_ARRAY_COMMA);
566*36589d6bSRobert Mustacchi 			return;
567*36589d6bSRobert Mustacchi 		} else {
568*36589d6bSRobert Mustacchi 			posterror(s, EPROTO, "unexpected character at start "
569*36589d6bSRobert Mustacchi 			    "of value");
570*36589d6bSRobert Mustacchi 			return;
571*36589d6bSRobert Mustacchi 		}
572*36589d6bSRobert Mustacchi 	}
573*36589d6bSRobert Mustacchi }
574*36589d6bSRobert Mustacchi 
575*36589d6bSRobert Mustacchi static void
hdlr_object(state_t * s)576*36589d6bSRobert Mustacchi hdlr_object(state_t *s)
577*36589d6bSRobert Mustacchi {
578*36589d6bSRobert Mustacchi 	s->s_top->pf_value_type = JSON_TYPE_OBJECT;
579*36589d6bSRobert Mustacchi 
580*36589d6bSRobert Mustacchi 	if (add_empty_child(s) != 0) {
581*36589d6bSRobert Mustacchi 		return;
582*36589d6bSRobert Mustacchi 	}
583*36589d6bSRobert Mustacchi 
584*36589d6bSRobert Mustacchi 	discard_whitespace(s);
585*36589d6bSRobert Mustacchi 
586*36589d6bSRobert Mustacchi 	switch (popchar(s)) {
587*36589d6bSRobert Mustacchi 	case '}':
588*36589d6bSRobert Mustacchi 		movestate(s, PARSE_DONE);
589*36589d6bSRobert Mustacchi 		return;
590*36589d6bSRobert Mustacchi 
591*36589d6bSRobert Mustacchi 	case '"':
592*36589d6bSRobert Mustacchi 		movestate(s, PARSE_KEY_STRING);
593*36589d6bSRobert Mustacchi 		return;
594*36589d6bSRobert Mustacchi 
595*36589d6bSRobert Mustacchi 	default:
596*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "expected key or '}'");
597*36589d6bSRobert Mustacchi 		return;
598*36589d6bSRobert Mustacchi 	}
599*36589d6bSRobert Mustacchi }
600*36589d6bSRobert Mustacchi 
601*36589d6bSRobert Mustacchi static void
hdlr_key_string(state_t * s)602*36589d6bSRobert Mustacchi hdlr_key_string(state_t *s)
603*36589d6bSRobert Mustacchi {
604*36589d6bSRobert Mustacchi 	if (collect_string(s) != 0) {
605*36589d6bSRobert Mustacchi 		return;
606*36589d6bSRobert Mustacchi 	}
607*36589d6bSRobert Mustacchi 
608*36589d6bSRobert Mustacchi 	/*
609*36589d6bSRobert Mustacchi 	 * Record the key name of the next value.
610*36589d6bSRobert Mustacchi 	 */
611*36589d6bSRobert Mustacchi 	if ((s->s_top->pf_key = strdup(custr_cstr(s->s_collect))) == NULL) {
612*36589d6bSRobert Mustacchi 		posterror(s, errno, "strdup failure");
613*36589d6bSRobert Mustacchi 		return;
614*36589d6bSRobert Mustacchi 	}
615*36589d6bSRobert Mustacchi 
616*36589d6bSRobert Mustacchi 	movestate(s, PARSE_COLON);
617*36589d6bSRobert Mustacchi }
618*36589d6bSRobert Mustacchi 
619*36589d6bSRobert Mustacchi static void
hdlr_colon(state_t * s)620*36589d6bSRobert Mustacchi hdlr_colon(state_t *s)
621*36589d6bSRobert Mustacchi {
622*36589d6bSRobert Mustacchi 	char c;
623*36589d6bSRobert Mustacchi 	discard_whitespace(s);
624*36589d6bSRobert Mustacchi 
625*36589d6bSRobert Mustacchi 	if ((c = popchar(s)) != ':') {
626*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "expected ':'");
627*36589d6bSRobert Mustacchi 		return;
628*36589d6bSRobert Mustacchi 	}
629*36589d6bSRobert Mustacchi 
630*36589d6bSRobert Mustacchi 	discard_whitespace(s);
631*36589d6bSRobert Mustacchi 
632*36589d6bSRobert Mustacchi 	/*
633*36589d6bSRobert Mustacchi 	 * Select which type handler we need for the value after the colon:
634*36589d6bSRobert Mustacchi 	 */
635*36589d6bSRobert Mustacchi 	switch (c = peekchar(s)) {
636*36589d6bSRobert Mustacchi 	case '"':
637*36589d6bSRobert Mustacchi 		(void) popchar(s);
638*36589d6bSRobert Mustacchi 		(void) pushstate(s, PARSE_STRING, PARSE_OBJECT_COMMA);
639*36589d6bSRobert Mustacchi 		return;
640*36589d6bSRobert Mustacchi 
641*36589d6bSRobert Mustacchi 	case '{':
642*36589d6bSRobert Mustacchi 		(void) popchar(s);
643*36589d6bSRobert Mustacchi 		(void) pushstate(s, PARSE_OBJECT, PARSE_OBJECT_COMMA);
644*36589d6bSRobert Mustacchi 		return;
645*36589d6bSRobert Mustacchi 
646*36589d6bSRobert Mustacchi 	case '[':
647*36589d6bSRobert Mustacchi 		(void) popchar(s);
648*36589d6bSRobert Mustacchi 		(void) pushstate(s, PARSE_ARRAY, PARSE_OBJECT_COMMA);
649*36589d6bSRobert Mustacchi 		return;
650*36589d6bSRobert Mustacchi 
651*36589d6bSRobert Mustacchi 	default:
652*36589d6bSRobert Mustacchi 		if (islower(c)) {
653*36589d6bSRobert Mustacchi 			(void) pushstate(s, PARSE_BAREWORD, PARSE_OBJECT_COMMA);
654*36589d6bSRobert Mustacchi 			return;
655*36589d6bSRobert Mustacchi 		} else if (c == '-' || isdigit(c)) {
656*36589d6bSRobert Mustacchi 			(void) pushstate(s, PARSE_NUMBER, PARSE_OBJECT_COMMA);
657*36589d6bSRobert Mustacchi 			return;
658*36589d6bSRobert Mustacchi 		} else {
659*36589d6bSRobert Mustacchi 			(void) posterror(s, EPROTO, "unexpected character at "
660*36589d6bSRobert Mustacchi 			    "start of value");
661*36589d6bSRobert Mustacchi 			return;
662*36589d6bSRobert Mustacchi 		}
663*36589d6bSRobert Mustacchi 	}
664*36589d6bSRobert Mustacchi }
665*36589d6bSRobert Mustacchi 
666*36589d6bSRobert Mustacchi static void
hdlr_object_comma(state_t * s)667*36589d6bSRobert Mustacchi hdlr_object_comma(state_t *s)
668*36589d6bSRobert Mustacchi {
669*36589d6bSRobert Mustacchi 	discard_whitespace(s);
670*36589d6bSRobert Mustacchi 
671*36589d6bSRobert Mustacchi 	switch (popchar(s)) {
672*36589d6bSRobert Mustacchi 	case '}':
673*36589d6bSRobert Mustacchi 		movestate(s, PARSE_DONE);
674*36589d6bSRobert Mustacchi 		return;
675*36589d6bSRobert Mustacchi 
676*36589d6bSRobert Mustacchi 	case ',':
677*36589d6bSRobert Mustacchi 		discard_whitespace(s);
678*36589d6bSRobert Mustacchi 		if (popchar(s) != '"') {
679*36589d6bSRobert Mustacchi 			posterror(s, EPROTO, "expected '\"'");
680*36589d6bSRobert Mustacchi 			return;
681*36589d6bSRobert Mustacchi 		}
682*36589d6bSRobert Mustacchi 		movestate(s, PARSE_KEY_STRING);
683*36589d6bSRobert Mustacchi 		return;
684*36589d6bSRobert Mustacchi 
685*36589d6bSRobert Mustacchi 	default:
686*36589d6bSRobert Mustacchi 		posterror(s, EPROTO, "expected ',' or '}'");
687*36589d6bSRobert Mustacchi 		return;
688*36589d6bSRobert Mustacchi 	}
689*36589d6bSRobert Mustacchi }
690*36589d6bSRobert Mustacchi 
691*36589d6bSRobert Mustacchi static void
hdlr_string(state_t * s)692*36589d6bSRobert Mustacchi hdlr_string(state_t *s)
693*36589d6bSRobert Mustacchi {
694*36589d6bSRobert Mustacchi 	if (collect_string(s) != 0) {
695*36589d6bSRobert Mustacchi 		return;
696*36589d6bSRobert Mustacchi 	}
697*36589d6bSRobert Mustacchi 
698*36589d6bSRobert Mustacchi 	s->s_top->pf_value_type = JSON_TYPE_STRING;
699*36589d6bSRobert Mustacchi 	if ((s->s_top->pf_value = strdup(custr_cstr(s->s_collect))) == NULL) {
700*36589d6bSRobert Mustacchi 		posterror(s, errno, "strdup failure");
701*36589d6bSRobert Mustacchi 		return;
702*36589d6bSRobert Mustacchi 	}
703*36589d6bSRobert Mustacchi 
704*36589d6bSRobert Mustacchi 	movestate(s, PARSE_DONE);
705*36589d6bSRobert Mustacchi }
706*36589d6bSRobert Mustacchi 
707*36589d6bSRobert Mustacchi static int
store_value(state_t * s)708*36589d6bSRobert Mustacchi store_value(state_t *s)
709*36589d6bSRobert Mustacchi {
710*36589d6bSRobert Mustacchi 	nvlist_t *targ = s->s_top->pf_next->pf_nvl;
711*36589d6bSRobert Mustacchi 	char *key = s->s_top->pf_next->pf_key;
712*36589d6bSRobert Mustacchi 	json_type_t type = s->s_top->pf_value_type;
713*36589d6bSRobert Mustacchi 	int ret = 0;
714*36589d6bSRobert Mustacchi 
715*36589d6bSRobert Mustacchi 	switch (type) {
716*36589d6bSRobert Mustacchi 	case JSON_TYPE_STRING:
717*36589d6bSRobert Mustacchi 		if (nvlist_add_string(targ, key, s->s_top->pf_value) != 0) {
718*36589d6bSRobert Mustacchi 			posterror(s, errno, "nvlist_add_string failure");
719*36589d6bSRobert Mustacchi 			ret = -1;
720*36589d6bSRobert Mustacchi 		}
721*36589d6bSRobert Mustacchi 		free(s->s_top->pf_value);
722*36589d6bSRobert Mustacchi 		break;
723*36589d6bSRobert Mustacchi 
724*36589d6bSRobert Mustacchi 	case JSON_TYPE_BOOLEAN:
725*36589d6bSRobert Mustacchi 		if (nvlist_add_boolean_value(targ, key,
726*36589d6bSRobert Mustacchi 		    (boolean_t)s->s_top->pf_value) != 0) {
727*36589d6bSRobert Mustacchi 			posterror(s, errno, "nvlist_add_boolean_value "
728*36589d6bSRobert Mustacchi 			    "failure");
729*36589d6bSRobert Mustacchi 			ret = -1;
730*36589d6bSRobert Mustacchi 		}
731*36589d6bSRobert Mustacchi 		break;
732*36589d6bSRobert Mustacchi 
733*36589d6bSRobert Mustacchi 	case JSON_TYPE_NULL:
734*36589d6bSRobert Mustacchi 		if (nvlist_add_boolean(targ, key) != 0) {
735*36589d6bSRobert Mustacchi 			posterror(s, errno, "nvlist_add_boolean failure");
736*36589d6bSRobert Mustacchi 			ret = -1;
737*36589d6bSRobert Mustacchi 		}
738*36589d6bSRobert Mustacchi 		break;
739*36589d6bSRobert Mustacchi 
740*36589d6bSRobert Mustacchi 	case JSON_TYPE_INTEGER:
741*36589d6bSRobert Mustacchi 		if (nvlist_add_int32(targ, key,
742*36589d6bSRobert Mustacchi 		    (int32_t)(uintptr_t)s->s_top->pf_value) != 0) {
743*36589d6bSRobert Mustacchi 			posterror(s, errno, "nvlist_add_int32 failure");
744*36589d6bSRobert Mustacchi 			ret = -1;
745*36589d6bSRobert Mustacchi 		}
746*36589d6bSRobert Mustacchi 		break;
747*36589d6bSRobert Mustacchi 
748*36589d6bSRobert Mustacchi 	case JSON_TYPE_ARRAY:
749*36589d6bSRobert Mustacchi 	case JSON_TYPE_OBJECT:
750*36589d6bSRobert Mustacchi 		/*
751*36589d6bSRobert Mustacchi 		 * Objects and arrays are already 'stored' in their target
752*36589d6bSRobert Mustacchi 		 * nvlist on creation. See: hdlr_object, hdlr_array.
753*36589d6bSRobert Mustacchi 		 */
754*36589d6bSRobert Mustacchi 		break;
755*36589d6bSRobert Mustacchi 
756*36589d6bSRobert Mustacchi 	default:
757*36589d6bSRobert Mustacchi 		(void) fprintf(stderr, "ERROR: could not store unknown "
758*36589d6bSRobert Mustacchi 		    "type %d\n", type);
759*36589d6bSRobert Mustacchi 		abort();
760*36589d6bSRobert Mustacchi 	}
761*36589d6bSRobert Mustacchi 
762*36589d6bSRobert Mustacchi 	s->s_top->pf_value = NULL;
763*36589d6bSRobert Mustacchi 	free(s->s_top->pf_next->pf_key);
764*36589d6bSRobert Mustacchi 	s->s_top->pf_next->pf_key = NULL;
765*36589d6bSRobert Mustacchi 	return (ret);
766*36589d6bSRobert Mustacchi }
767*36589d6bSRobert Mustacchi 
768*36589d6bSRobert Mustacchi static parse_frame_t *
parse_frame_free(parse_frame_t * pf,boolean_t free_nvl)769*36589d6bSRobert Mustacchi parse_frame_free(parse_frame_t *pf, boolean_t free_nvl)
770*36589d6bSRobert Mustacchi {
771*36589d6bSRobert Mustacchi 	parse_frame_t *next = pf->pf_next;
772*36589d6bSRobert Mustacchi 	if (pf->pf_key != NULL) {
773*36589d6bSRobert Mustacchi 		free(pf->pf_key);
774*36589d6bSRobert Mustacchi 	}
775*36589d6bSRobert Mustacchi 	if (pf->pf_value != NULL) {
776*36589d6bSRobert Mustacchi 		abort();
777*36589d6bSRobert Mustacchi 	}
778*36589d6bSRobert Mustacchi 	if (free_nvl && pf->pf_nvl != NULL) {
779*36589d6bSRobert Mustacchi 		nvlist_free(pf->pf_nvl);
780*36589d6bSRobert Mustacchi 	}
781*36589d6bSRobert Mustacchi 	free(pf);
782*36589d6bSRobert Mustacchi 	return (next);
783*36589d6bSRobert Mustacchi }
784*36589d6bSRobert Mustacchi 
785*36589d6bSRobert Mustacchi static parse_handler_t hdlrs[] = {
786*36589d6bSRobert Mustacchi 	NULL,				/* PARSE_DONE */
787*36589d6bSRobert Mustacchi 	hdlr_rest,			/* PARSE_REST */
788*36589d6bSRobert Mustacchi 	hdlr_object,			/* PARSE_OBJECT */
789*36589d6bSRobert Mustacchi 	hdlr_key_string,		/* PARSE_KEY_STRING */
790*36589d6bSRobert Mustacchi 	hdlr_colon,			/* PARSE_COLON */
791*36589d6bSRobert Mustacchi 	hdlr_string,			/* PARSE_STRING */
792*36589d6bSRobert Mustacchi 	hdlr_object_comma,		/* PARSE_OBJECT_COMMA */
793*36589d6bSRobert Mustacchi 	hdlr_array,			/* PARSE_ARRAY */
794*36589d6bSRobert Mustacchi 	hdlr_bareword,			/* PARSE_BAREWORD */
795*36589d6bSRobert Mustacchi 	hdlr_number,			/* PARSE_NUMBER */
796*36589d6bSRobert Mustacchi 	hdlr_array_value,		/* PARSE_ARRAY_VALUE */
797*36589d6bSRobert Mustacchi 	hdlr_array_comma		/* PARSE_ARRAY_COMMA */
798*36589d6bSRobert Mustacchi };
799*36589d6bSRobert Mustacchi #define	NUM_PARSE_HANDLERS	(int)(sizeof (hdlrs) / sizeof (hdlrs[0]))
800*36589d6bSRobert Mustacchi 
801*36589d6bSRobert Mustacchi int
nvlist_parse_json(const char * buf,size_t buflen,nvlist_t ** nvlp,nvlist_parse_json_flags_t flag,nvlist_parse_json_error_t * errout)802*36589d6bSRobert Mustacchi nvlist_parse_json(const char *buf, size_t buflen, nvlist_t **nvlp,
803*36589d6bSRobert Mustacchi     nvlist_parse_json_flags_t flag, nvlist_parse_json_error_t *errout)
804*36589d6bSRobert Mustacchi {
805*36589d6bSRobert Mustacchi 	state_t s;
806*36589d6bSRobert Mustacchi 
807*36589d6bSRobert Mustacchi 	/*
808*36589d6bSRobert Mustacchi 	 * Check for valid flags:
809*36589d6bSRobert Mustacchi 	 */
810*36589d6bSRobert Mustacchi 	if ((flag & NVJSON_FORCE_INTEGER) && (flag & NVJSON_FORCE_DOUBLE)) {
811*36589d6bSRobert Mustacchi 		errno = EINVAL;
812*36589d6bSRobert Mustacchi 		return (-1);
813*36589d6bSRobert Mustacchi 	}
814*36589d6bSRobert Mustacchi 	if ((flag & ~NVJSON_ALL) != 0) {
815*36589d6bSRobert Mustacchi 		errno = EINVAL;
816*36589d6bSRobert Mustacchi 		return (-1);
817*36589d6bSRobert Mustacchi 	}
818*36589d6bSRobert Mustacchi 
819*36589d6bSRobert Mustacchi 	/*
820*36589d6bSRobert Mustacchi 	 * Initialise parsing state structure:
821*36589d6bSRobert Mustacchi 	 */
822*36589d6bSRobert Mustacchi 	bzero(&s, sizeof (s));
823*36589d6bSRobert Mustacchi 	s.s_in = buf;
824*36589d6bSRobert Mustacchi 	s.s_pos = 0;
825*36589d6bSRobert Mustacchi 	s.s_len = buflen;
826*36589d6bSRobert Mustacchi 	s.s_flags = flag;
827*36589d6bSRobert Mustacchi 
828*36589d6bSRobert Mustacchi 	/*
829*36589d6bSRobert Mustacchi 	 * Allocate the collect buffer string.
830*36589d6bSRobert Mustacchi 	 */
831*36589d6bSRobert Mustacchi 	if (custr_alloc(&s.s_collect) != 0) {
832*36589d6bSRobert Mustacchi 		s.s_errno = errno;
833*36589d6bSRobert Mustacchi 		if (errout != NULL) {
834*36589d6bSRobert Mustacchi 			(void) snprintf(errout->nje_message,
835*36589d6bSRobert Mustacchi 			    sizeof (errout->nje_message),
836*36589d6bSRobert Mustacchi 			    "custr alloc failure: %s",
837*36589d6bSRobert Mustacchi 			    strerror(errno));
838*36589d6bSRobert Mustacchi 		}
839*36589d6bSRobert Mustacchi 		goto out;
840*36589d6bSRobert Mustacchi 	}
841*36589d6bSRobert Mustacchi 
842*36589d6bSRobert Mustacchi 	/*
843*36589d6bSRobert Mustacchi 	 * If the caller has requested error information, allocate the error
844*36589d6bSRobert Mustacchi 	 * string now.
845*36589d6bSRobert Mustacchi 	 */
846*36589d6bSRobert Mustacchi 	if (errout != NULL) {
847*36589d6bSRobert Mustacchi 		if (custr_alloc_buf(&s.s_errstr, errout->nje_message,
848*36589d6bSRobert Mustacchi 		    sizeof (errout->nje_message)) != 0) {
849*36589d6bSRobert Mustacchi 			s.s_errno = errno;
850*36589d6bSRobert Mustacchi 			(void) snprintf(errout->nje_message,
851*36589d6bSRobert Mustacchi 			    sizeof (errout->nje_message),
852*36589d6bSRobert Mustacchi 			    "custr alloc failure: %s",
853*36589d6bSRobert Mustacchi 			    strerror(errno));
854*36589d6bSRobert Mustacchi 			goto out;
855*36589d6bSRobert Mustacchi 		}
856*36589d6bSRobert Mustacchi 		custr_reset(s.s_errstr);
857*36589d6bSRobert Mustacchi 	}
858*36589d6bSRobert Mustacchi 
859*36589d6bSRobert Mustacchi 	/*
860*36589d6bSRobert Mustacchi 	 * Allocate top-most stack frame:
861*36589d6bSRobert Mustacchi 	 */
862*36589d6bSRobert Mustacchi 	if ((s.s_top = calloc(1, sizeof (*s.s_top))) == NULL) {
863*36589d6bSRobert Mustacchi 		s.s_errno = errno;
864*36589d6bSRobert Mustacchi 		goto out;
865*36589d6bSRobert Mustacchi 	}
866*36589d6bSRobert Mustacchi 
867*36589d6bSRobert Mustacchi 	s.s_top->pf_ps = PARSE_REST;
868*36589d6bSRobert Mustacchi 	for (;;) {
869*36589d6bSRobert Mustacchi 		if (s.s_top->pf_ps < 0) {
870*36589d6bSRobert Mustacchi 			/*
871*36589d6bSRobert Mustacchi 			 * The parser reported an error.
872*36589d6bSRobert Mustacchi 			 */
873*36589d6bSRobert Mustacchi 			goto out;
874*36589d6bSRobert Mustacchi 		}
875*36589d6bSRobert Mustacchi 
876*36589d6bSRobert Mustacchi 		if (s.s_top->pf_ps == PARSE_DONE) {
877*36589d6bSRobert Mustacchi 			if (s.s_top->pf_next == NULL) {
878*36589d6bSRobert Mustacchi 				/*
879*36589d6bSRobert Mustacchi 				 * Last frame, so we're really
880*36589d6bSRobert Mustacchi 				 * done.
881*36589d6bSRobert Mustacchi 				 */
882*36589d6bSRobert Mustacchi 				*nvlp = s.s_top->pf_nvl;
883*36589d6bSRobert Mustacchi 				goto out;
884*36589d6bSRobert Mustacchi 			} else {
885*36589d6bSRobert Mustacchi 				/*
886*36589d6bSRobert Mustacchi 				 * Otherwise, pop a frame and continue in
887*36589d6bSRobert Mustacchi 				 * previous state.  Copy out the value we
888*36589d6bSRobert Mustacchi 				 * created in the old frame:
889*36589d6bSRobert Mustacchi 				 */
890*36589d6bSRobert Mustacchi 				if (store_value(&s) != 0) {
891*36589d6bSRobert Mustacchi 					goto out;
892*36589d6bSRobert Mustacchi 				}
893*36589d6bSRobert Mustacchi 
894*36589d6bSRobert Mustacchi 				/*
895*36589d6bSRobert Mustacchi 				 * Free old frame:
896*36589d6bSRobert Mustacchi 				 */
897*36589d6bSRobert Mustacchi 				s.s_top = parse_frame_free(s.s_top, B_FALSE);
898*36589d6bSRobert Mustacchi 			}
899*36589d6bSRobert Mustacchi 		}
900*36589d6bSRobert Mustacchi 
901*36589d6bSRobert Mustacchi 		/*
902*36589d6bSRobert Mustacchi 		 * Dispatch to parser handler routine for this state:
903*36589d6bSRobert Mustacchi 		 */
904*36589d6bSRobert Mustacchi 		if (s.s_top->pf_ps >= NUM_PARSE_HANDLERS ||
905*36589d6bSRobert Mustacchi 		    hdlrs[s.s_top->pf_ps] == NULL) {
906*36589d6bSRobert Mustacchi 			(void) fprintf(stderr, "no handler for state %d\n",
907*36589d6bSRobert Mustacchi 			    s.s_top->pf_ps);
908*36589d6bSRobert Mustacchi 			abort();
909*36589d6bSRobert Mustacchi 		}
910*36589d6bSRobert Mustacchi 		hdlrs[s.s_top->pf_ps](&s);
911*36589d6bSRobert Mustacchi 	}
912*36589d6bSRobert Mustacchi 
913*36589d6bSRobert Mustacchi out:
914*36589d6bSRobert Mustacchi 	if (errout != NULL) {
915*36589d6bSRobert Mustacchi 		/*
916*36589d6bSRobert Mustacchi 		 * Copy out error number and parse position.  The custr_t for
917*36589d6bSRobert Mustacchi 		 * the error message was backed by the buffer in the error
918*36589d6bSRobert Mustacchi 		 * object, so no copying is required.
919*36589d6bSRobert Mustacchi 		 */
920*36589d6bSRobert Mustacchi 		errout->nje_errno = s.s_errno;
921*36589d6bSRobert Mustacchi 		errout->nje_pos = s.s_pos;
922*36589d6bSRobert Mustacchi 	}
923*36589d6bSRobert Mustacchi 
924*36589d6bSRobert Mustacchi 	/*
925*36589d6bSRobert Mustacchi 	 * Free resources:
926*36589d6bSRobert Mustacchi 	 */
927*36589d6bSRobert Mustacchi 	while (s.s_top != NULL) {
928*36589d6bSRobert Mustacchi 		s.s_top = parse_frame_free(s.s_top, s.s_errno == 0 ? B_FALSE :
929*36589d6bSRobert Mustacchi 		    B_TRUE);
930*36589d6bSRobert Mustacchi 	}
931*36589d6bSRobert Mustacchi 	custr_free(s.s_collect);
932*36589d6bSRobert Mustacchi 	custr_free(s.s_errstr);
933*36589d6bSRobert Mustacchi 
934*36589d6bSRobert Mustacchi 	errno = s.s_errno;
935*36589d6bSRobert Mustacchi 	return (s.s_errno == 0 ? 0 : -1);
936*36589d6bSRobert Mustacchi }
937