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