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