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