xref: /unit/src/nxt_conf.c (revision 1174)
1106Svbart@nginx.com 
2106Svbart@nginx.com /*
3106Svbart@nginx.com  * Copyright (C) Igor Sysoev
4106Svbart@nginx.com  * Copyright (C) Valentin V. Bartenev
5106Svbart@nginx.com  * Copyright (C) NGINX, Inc.
6106Svbart@nginx.com  */
7106Svbart@nginx.com 
8106Svbart@nginx.com #include <nxt_main.h>
9106Svbart@nginx.com #include <nxt_conf.h>
10106Svbart@nginx.com #if 0
11106Svbart@nginx.com #include <math.h>
12106Svbart@nginx.com #include <float.h>
13106Svbart@nginx.com #endif
14106Svbart@nginx.com 
15106Svbart@nginx.com 
16106Svbart@nginx.com #define NXT_CONF_MAX_SHORT_STRING  14
17172Svbart@nginx.com #define NXT_CONF_MAX_STRING        NXT_INT32_T_MAX
18106Svbart@nginx.com 
19*1174Svbart@nginx.com #define NXT_CONF_MAX_TOKEN_LEN     256
20*1174Svbart@nginx.com 
21106Svbart@nginx.com 
22106Svbart@nginx.com typedef enum {
23116Svbart@nginx.com     NXT_CONF_VALUE_NULL = 0,
24116Svbart@nginx.com     NXT_CONF_VALUE_BOOLEAN,
25116Svbart@nginx.com     NXT_CONF_VALUE_INTEGER,
26116Svbart@nginx.com     NXT_CONF_VALUE_NUMBER,
27116Svbart@nginx.com     NXT_CONF_VALUE_SHORT_STRING,
28116Svbart@nginx.com     NXT_CONF_VALUE_STRING,
29116Svbart@nginx.com     NXT_CONF_VALUE_ARRAY,
30116Svbart@nginx.com     NXT_CONF_VALUE_OBJECT,
31116Svbart@nginx.com } nxt_conf_value_type_t;
32106Svbart@nginx.com 
33106Svbart@nginx.com 
34106Svbart@nginx.com typedef enum {
35106Svbart@nginx.com     NXT_CONF_OP_PASS = 0,
36106Svbart@nginx.com     NXT_CONF_OP_CREATE,
37106Svbart@nginx.com     NXT_CONF_OP_REPLACE,
38106Svbart@nginx.com     NXT_CONF_OP_DELETE,
39106Svbart@nginx.com } nxt_conf_op_action_t;
40106Svbart@nginx.com 
41106Svbart@nginx.com 
42106Svbart@nginx.com typedef struct nxt_conf_array_s   nxt_conf_array_t;
43106Svbart@nginx.com typedef struct nxt_conf_object_s  nxt_conf_object_t;
44106Svbart@nginx.com 
45106Svbart@nginx.com 
46180Smax.romanov@nginx.com struct nxt_conf_value_s {
47187Smax.romanov@nginx.com     union {
48171Svbart@nginx.com         uint8_t               boolean;  /* 1 bit. */
49106Svbart@nginx.com         int64_t               integer;
50106Svbart@nginx.com         double                number;
51173Svbart@nginx.com 
52173Svbart@nginx.com         struct {
53208Svbart@nginx.com             u_char            start[NXT_CONF_MAX_SHORT_STRING];
54173Svbart@nginx.com             uint8_t           length;
55173Svbart@nginx.com         } str;
56172Svbart@nginx.com 
57187Smax.romanov@nginx.com         struct {
58172Svbart@nginx.com             u_char            *start;
59172Svbart@nginx.com             uint32_t          length;
60187Smax.romanov@nginx.com         } nxt_packed string;
61172Svbart@nginx.com 
62106Svbart@nginx.com         nxt_conf_array_t      *array;
63106Svbart@nginx.com         nxt_conf_object_t     *object;
64187Smax.romanov@nginx.com     } nxt_packed u;
65106Svbart@nginx.com 
66171Svbart@nginx.com     uint8_t                   type;  /* 3 bits. */
67180Smax.romanov@nginx.com } nxt_aligned(8);
68106Svbart@nginx.com 
69106Svbart@nginx.com 
70106Svbart@nginx.com struct nxt_conf_array_s {
71106Svbart@nginx.com     nxt_uint_t                count;
72106Svbart@nginx.com     nxt_conf_value_t          elements[];
73106Svbart@nginx.com };
74106Svbart@nginx.com 
75106Svbart@nginx.com 
76106Svbart@nginx.com typedef struct {
77106Svbart@nginx.com     nxt_conf_value_t          name;
78106Svbart@nginx.com     nxt_conf_value_t          value;
79106Svbart@nginx.com } nxt_conf_object_member_t;
80106Svbart@nginx.com 
81106Svbart@nginx.com 
82106Svbart@nginx.com struct nxt_conf_object_s {
83106Svbart@nginx.com     nxt_uint_t                count;
84106Svbart@nginx.com     nxt_conf_object_member_t  members[];
85106Svbart@nginx.com };
86106Svbart@nginx.com 
87106Svbart@nginx.com 
88106Svbart@nginx.com struct nxt_conf_op_s {
89106Svbart@nginx.com     uint32_t                  index;
90106Svbart@nginx.com     uint32_t                  action;  /* nxt_conf_op_action_t */
91106Svbart@nginx.com     void                      *ctx;
92106Svbart@nginx.com };
93106Svbart@nginx.com 
94106Svbart@nginx.com 
95*1174Svbart@nginx.com typedef struct {
96*1174Svbart@nginx.com     u_char                    *start;
97*1174Svbart@nginx.com     u_char                    *end;
98*1174Svbart@nginx.com     nxt_bool_t                last;
99*1174Svbart@nginx.com     u_char                    buf[NXT_CONF_MAX_TOKEN_LEN];
100*1174Svbart@nginx.com } nxt_conf_path_parse_t;
101*1174Svbart@nginx.com 
102*1174Svbart@nginx.com 
103*1174Svbart@nginx.com static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse,
104*1174Svbart@nginx.com     nxt_str_t *token);
105*1174Svbart@nginx.com 
106106Svbart@nginx.com static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end);
107106Svbart@nginx.com static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
108208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
109106Svbart@nginx.com static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
110208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
111106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
112106Svbart@nginx.com     nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
113106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
114106Svbart@nginx.com     void *data);
115106Svbart@nginx.com static void *nxt_conf_object_hash_alloc(void *data, size_t size);
116106Svbart@nginx.com static void nxt_conf_object_hash_free(void *data, void *p);
117106Svbart@nginx.com static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
118208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
119106Svbart@nginx.com static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value,
120208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
121106Svbart@nginx.com static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value,
122208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
123208Svbart@nginx.com static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
124208Svbart@nginx.com     const char *detail);
125106Svbart@nginx.com 
126106Svbart@nginx.com static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
127106Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
1281048Svbart@nginx.com static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op,
1291048Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
130106Svbart@nginx.com static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op,
131106Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
132106Svbart@nginx.com 
133106Svbart@nginx.com static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value);
134106Svbart@nginx.com static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value);
135106Svbart@nginx.com static size_t nxt_conf_json_string_length(nxt_conf_value_t *value);
136106Svbart@nginx.com static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value);
137106Svbart@nginx.com static size_t nxt_conf_json_array_length(nxt_conf_value_t *value,
138106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
139106Svbart@nginx.com static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
140106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
141106Svbart@nginx.com static size_t nxt_conf_json_object_length(nxt_conf_value_t *value,
142106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
143106Svbart@nginx.com static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
144106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
145106Svbart@nginx.com 
146106Svbart@nginx.com static size_t nxt_conf_json_escape_length(u_char *p, size_t size);
147106Svbart@nginx.com static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
148106Svbart@nginx.com 
149106Svbart@nginx.com 
150106Svbart@nginx.com #define nxt_conf_json_newline(p)                                              \
151106Svbart@nginx.com     ((p)[0] = '\r', (p)[1] = '\n', (p) + 2)
152106Svbart@nginx.com 
153106Svbart@nginx.com 
154106Svbart@nginx.com nxt_inline u_char *
155106Svbart@nginx.com nxt_conf_json_indentation(u_char *p, uint32_t level)
156106Svbart@nginx.com {
157106Svbart@nginx.com     while (level) {
158106Svbart@nginx.com         *p++ = '\t';
159106Svbart@nginx.com         level--;
160106Svbart@nginx.com     }
161106Svbart@nginx.com 
162106Svbart@nginx.com     return p;
163106Svbart@nginx.com }
164106Svbart@nginx.com 
165106Svbart@nginx.com 
166121Svbart@nginx.com void
167106Svbart@nginx.com nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
168106Svbart@nginx.com {
169116Svbart@nginx.com     if (value->type == NXT_CONF_VALUE_SHORT_STRING) {
170173Svbart@nginx.com         str->length = value->u.str.length;
171173Svbart@nginx.com         str->start = value->u.str.start;
172106Svbart@nginx.com 
173106Svbart@nginx.com     } else {
174172Svbart@nginx.com         str->length = value->u.string.length;
175172Svbart@nginx.com         str->start = value->u.string.start;
176106Svbart@nginx.com     }
177106Svbart@nginx.com }
178106Svbart@nginx.com 
179106Svbart@nginx.com 
180773Svbart@nginx.com void
181773Svbart@nginx.com nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str)
182773Svbart@nginx.com {
183773Svbart@nginx.com     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
184773Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
185773Svbart@nginx.com         value->u.string.length = str->length;
186773Svbart@nginx.com         value->u.string.start = str->start;
187773Svbart@nginx.com 
188773Svbart@nginx.com     } else {
189773Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
190773Svbart@nginx.com         value->u.str.length = str->length;
191773Svbart@nginx.com 
192773Svbart@nginx.com         nxt_memcpy(value->u.str.start, str->start, str->length);
193773Svbart@nginx.com     }
194773Svbart@nginx.com }
195773Svbart@nginx.com 
196773Svbart@nginx.com 
197774Svbart@nginx.com nxt_int_t
198774Svbart@nginx.com nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str)
199774Svbart@nginx.com {
200774Svbart@nginx.com     nxt_str_t  tmp, *ptr;
201774Svbart@nginx.com 
202774Svbart@nginx.com     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
203774Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
204774Svbart@nginx.com 
205774Svbart@nginx.com         ptr = nxt_str_dup(mp, &tmp, str);
206774Svbart@nginx.com         if (nxt_slow_path(ptr == NULL)) {
207774Svbart@nginx.com             return NXT_ERROR;
208774Svbart@nginx.com         }
209774Svbart@nginx.com 
210774Svbart@nginx.com         value->u.string.length = tmp.length;
211774Svbart@nginx.com         value->u.string.start = tmp.start;
212774Svbart@nginx.com 
213774Svbart@nginx.com     } else {
214774Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
215774Svbart@nginx.com         value->u.str.length = str->length;
216774Svbart@nginx.com 
217774Svbart@nginx.com         nxt_memcpy(value->u.str.start, str->start, str->length);
218774Svbart@nginx.com     }
219774Svbart@nginx.com 
220774Svbart@nginx.com     return NXT_OK;
221774Svbart@nginx.com }
222774Svbart@nginx.com 
223774Svbart@nginx.com 
224507Smax.romanov@nginx.com int64_t
225507Smax.romanov@nginx.com nxt_conf_get_integer(nxt_conf_value_t *value)
226507Smax.romanov@nginx.com {
227507Smax.romanov@nginx.com     return value->u.integer;
228507Smax.romanov@nginx.com }
229507Smax.romanov@nginx.com 
230507Smax.romanov@nginx.com 
231116Svbart@nginx.com nxt_uint_t
232121Svbart@nginx.com nxt_conf_object_members_count(nxt_conf_value_t *value)
233121Svbart@nginx.com {
234121Svbart@nginx.com     return value->u.object->count;
235121Svbart@nginx.com }
236121Svbart@nginx.com 
237121Svbart@nginx.com 
238121Svbart@nginx.com nxt_conf_value_t *
239121Svbart@nginx.com nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count)
240121Svbart@nginx.com {
241121Svbart@nginx.com     size_t            size;
242121Svbart@nginx.com     nxt_conf_value_t  *value;
243121Svbart@nginx.com 
244121Svbart@nginx.com     size = sizeof(nxt_conf_value_t)
245121Svbart@nginx.com            + sizeof(nxt_conf_object_t)
246121Svbart@nginx.com            + count * sizeof(nxt_conf_object_member_t);
247121Svbart@nginx.com 
248121Svbart@nginx.com     value = nxt_mp_get(mp, size);
249121Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
250121Svbart@nginx.com         return NULL;
251121Svbart@nginx.com     }
252121Svbart@nginx.com 
253121Svbart@nginx.com     value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
254121Svbart@nginx.com     value->u.object->count = count;
255121Svbart@nginx.com 
256121Svbart@nginx.com     value->type = NXT_CONF_VALUE_OBJECT;
257121Svbart@nginx.com 
258121Svbart@nginx.com     return value;
259121Svbart@nginx.com }
260121Svbart@nginx.com 
261121Svbart@nginx.com 
262208Svbart@nginx.com void
263208Svbart@nginx.com nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
264172Svbart@nginx.com     nxt_conf_value_t *value, uint32_t index)
265121Svbart@nginx.com {
266121Svbart@nginx.com     nxt_conf_object_member_t  *member;
267121Svbart@nginx.com 
268121Svbart@nginx.com     member = &object->u.object->members[index];
269773Svbart@nginx.com 
270773Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
271121Svbart@nginx.com 
272121Svbart@nginx.com     member->value = *value;
273208Svbart@nginx.com }
274208Svbart@nginx.com 
275208Svbart@nginx.com 
276208Svbart@nginx.com void
277208Svbart@nginx.com nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
278208Svbart@nginx.com     nxt_str_t *value, uint32_t index)
279208Svbart@nginx.com {
280208Svbart@nginx.com     nxt_conf_object_member_t  *member;
281208Svbart@nginx.com 
282208Svbart@nginx.com     member = &object->u.object->members[index];
283773Svbart@nginx.com 
284773Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
285773Svbart@nginx.com 
286773Svbart@nginx.com     nxt_conf_set_string(&member->value, value);
287208Svbart@nginx.com }
288208Svbart@nginx.com 
289208Svbart@nginx.com 
290774Svbart@nginx.com nxt_int_t
291774Svbart@nginx.com nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp,
292774Svbart@nginx.com     nxt_str_t *name, nxt_str_t *value, uint32_t index)
293774Svbart@nginx.com {
294774Svbart@nginx.com     nxt_conf_object_member_t  *member;
295774Svbart@nginx.com 
296774Svbart@nginx.com     member = &object->u.object->members[index];
297774Svbart@nginx.com 
298774Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
299774Svbart@nginx.com 
300774Svbart@nginx.com     return nxt_conf_set_string_dup(&member->value, mp, value);
301774Svbart@nginx.com }
302774Svbart@nginx.com 
303774Svbart@nginx.com 
304208Svbart@nginx.com void
305208Svbart@nginx.com nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
306208Svbart@nginx.com     int64_t value, uint32_t index)
307208Svbart@nginx.com {
308208Svbart@nginx.com     nxt_conf_object_member_t  *member;
309208Svbart@nginx.com 
310208Svbart@nginx.com     member = &object->u.object->members[index];
311773Svbart@nginx.com 
312773Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
313208Svbart@nginx.com 
314208Svbart@nginx.com     member->value.u.integer = value;
315208Svbart@nginx.com     member->value.type = NXT_CONF_VALUE_INTEGER;
316121Svbart@nginx.com }
317121Svbart@nginx.com 
318121Svbart@nginx.com 
319774Svbart@nginx.com void
320774Svbart@nginx.com nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name,
321774Svbart@nginx.com     uint32_t index)
322774Svbart@nginx.com {
323774Svbart@nginx.com     nxt_conf_object_member_t  *member;
324774Svbart@nginx.com 
325774Svbart@nginx.com     member = &object->u.object->members[index];
326774Svbart@nginx.com 
327774Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
328774Svbart@nginx.com 
329774Svbart@nginx.com     member->value.type = NXT_CONF_VALUE_NULL;
330774Svbart@nginx.com }
331774Svbart@nginx.com 
332774Svbart@nginx.com 
333774Svbart@nginx.com nxt_conf_value_t *
334774Svbart@nginx.com nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count)
335774Svbart@nginx.com {
336774Svbart@nginx.com     size_t            size;
337774Svbart@nginx.com     nxt_conf_value_t  *value;
338774Svbart@nginx.com 
339774Svbart@nginx.com     size = sizeof(nxt_conf_value_t)
340774Svbart@nginx.com            + sizeof(nxt_conf_array_t)
341774Svbart@nginx.com            + count * sizeof(nxt_conf_value_t);
342774Svbart@nginx.com 
343774Svbart@nginx.com     value = nxt_mp_get(mp, size);
344774Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
345774Svbart@nginx.com         return NULL;
346774Svbart@nginx.com     }
347774Svbart@nginx.com 
348774Svbart@nginx.com     value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
349774Svbart@nginx.com     value->u.array->count = count;
350774Svbart@nginx.com 
351774Svbart@nginx.com     value->type = NXT_CONF_VALUE_ARRAY;
352774Svbart@nginx.com 
353774Svbart@nginx.com     return value;
354774Svbart@nginx.com }
355774Svbart@nginx.com 
356774Svbart@nginx.com 
357774Svbart@nginx.com void
358774Svbart@nginx.com nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
359774Svbart@nginx.com     nxt_conf_value_t *value)
360774Svbart@nginx.com {
361774Svbart@nginx.com     array->u.array->elements[index] = *value;
362774Svbart@nginx.com }
363774Svbart@nginx.com 
364774Svbart@nginx.com 
365774Svbart@nginx.com nxt_int_t
366774Svbart@nginx.com nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
367774Svbart@nginx.com     nxt_uint_t index, nxt_str_t *value)
368774Svbart@nginx.com {
369774Svbart@nginx.com     nxt_conf_value_t  *element;
370774Svbart@nginx.com 
371774Svbart@nginx.com     element = &array->u.array->elements[index];
372774Svbart@nginx.com 
373774Svbart@nginx.com     return nxt_conf_set_string_dup(element, mp, value);
374774Svbart@nginx.com }
375774Svbart@nginx.com 
376774Svbart@nginx.com 
377121Svbart@nginx.com nxt_uint_t
378961Sigor@sysoev.ru nxt_conf_array_elements_count(nxt_conf_value_t *value)
379961Sigor@sysoev.ru {
380961Sigor@sysoev.ru     return value->u.array->count;
381961Sigor@sysoev.ru }
382961Sigor@sysoev.ru 
383961Sigor@sysoev.ru 
384961Sigor@sysoev.ru nxt_uint_t
385116Svbart@nginx.com nxt_conf_type(nxt_conf_value_t *value)
386116Svbart@nginx.com {
387116Svbart@nginx.com     switch (value->type) {
388116Svbart@nginx.com 
389116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
390116Svbart@nginx.com         return NXT_CONF_NULL;
391116Svbart@nginx.com 
392116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
393116Svbart@nginx.com         return NXT_CONF_BOOLEAN;
394116Svbart@nginx.com 
395116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
396116Svbart@nginx.com         return NXT_CONF_INTEGER;
397116Svbart@nginx.com 
398116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
399116Svbart@nginx.com         return NXT_CONF_NUMBER;
400116Svbart@nginx.com 
401116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
402116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
403116Svbart@nginx.com         return NXT_CONF_STRING;
404116Svbart@nginx.com 
405116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
406116Svbart@nginx.com         return NXT_CONF_ARRAY;
407116Svbart@nginx.com 
408116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
409116Svbart@nginx.com         return NXT_CONF_OBJECT;
410116Svbart@nginx.com     }
411116Svbart@nginx.com 
412116Svbart@nginx.com     nxt_unreachable();
413116Svbart@nginx.com 
414116Svbart@nginx.com     return 0;
415116Svbart@nginx.com }
416116Svbart@nginx.com 
417116Svbart@nginx.com 
418106Svbart@nginx.com nxt_conf_value_t *
419106Svbart@nginx.com nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path)
420106Svbart@nginx.com {
421106Svbart@nginx.com     nxt_str_t              token;
422*1174Svbart@nginx.com     nxt_int_t              ret, index;
423106Svbart@nginx.com     nxt_conf_path_parse_t  parse;
424106Svbart@nginx.com 
425106Svbart@nginx.com     parse.start = path->start;
426106Svbart@nginx.com     parse.end = path->start + path->length;
427106Svbart@nginx.com     parse.last = 0;
428106Svbart@nginx.com 
429106Svbart@nginx.com     do {
430*1174Svbart@nginx.com         ret = nxt_conf_path_next_token(&parse, &token);
431*1174Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
432*1174Svbart@nginx.com             return NULL;
433*1174Svbart@nginx.com         }
434106Svbart@nginx.com 
435106Svbart@nginx.com         if (token.length == 0) {
436106Svbart@nginx.com 
437106Svbart@nginx.com             if (parse.last) {
438106Svbart@nginx.com                 break;
439106Svbart@nginx.com             }
440106Svbart@nginx.com 
441106Svbart@nginx.com             return NULL;
442106Svbart@nginx.com         }
443106Svbart@nginx.com 
444775Svbart@nginx.com         switch (value->type) {
445775Svbart@nginx.com 
446775Svbart@nginx.com         case NXT_CONF_VALUE_OBJECT:
447775Svbart@nginx.com             value = nxt_conf_get_object_member(value, &token, NULL);
448775Svbart@nginx.com             break;
449775Svbart@nginx.com 
450775Svbart@nginx.com         case NXT_CONF_VALUE_ARRAY:
451775Svbart@nginx.com             index = nxt_int_parse(token.start, token.length);
452775Svbart@nginx.com 
453775Svbart@nginx.com             if (index < 0 || index > NXT_INT32_T_MAX) {
454775Svbart@nginx.com                 return NULL;
455775Svbart@nginx.com             }
456775Svbart@nginx.com 
457775Svbart@nginx.com             value = nxt_conf_get_array_element(value, index);
458775Svbart@nginx.com             break;
459775Svbart@nginx.com 
460775Svbart@nginx.com         default:
461775Svbart@nginx.com             return NULL;
462775Svbart@nginx.com         }
463106Svbart@nginx.com 
464106Svbart@nginx.com         if (value == NULL) {
465106Svbart@nginx.com             return NULL;
466106Svbart@nginx.com         }
467106Svbart@nginx.com 
468106Svbart@nginx.com     } while (parse.last == 0);
469106Svbart@nginx.com 
470106Svbart@nginx.com     return value;
471106Svbart@nginx.com }
472106Svbart@nginx.com 
473106Svbart@nginx.com 
474*1174Svbart@nginx.com static nxt_int_t
475106Svbart@nginx.com nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token)
476106Svbart@nginx.com {
477*1174Svbart@nginx.com     u_char  *p, *start, *end;
478*1174Svbart@nginx.com     size_t  length;
479*1174Svbart@nginx.com 
480*1174Svbart@nginx.com     start = parse->start + 1;
481*1174Svbart@nginx.com 
482*1174Svbart@nginx.com     p = start;
483*1174Svbart@nginx.com 
484*1174Svbart@nginx.com     while (p < parse->end && *p != '/') {
485106Svbart@nginx.com         p++;
486106Svbart@nginx.com     }
487106Svbart@nginx.com 
488106Svbart@nginx.com     parse->start = p;
489*1174Svbart@nginx.com     parse->last = (p >= parse->end);
490*1174Svbart@nginx.com 
491*1174Svbart@nginx.com     length = p - start;
492*1174Svbart@nginx.com 
493*1174Svbart@nginx.com     if (nxt_slow_path(length > NXT_CONF_MAX_TOKEN_LEN)) {
494*1174Svbart@nginx.com         return NXT_ERROR;
495*1174Svbart@nginx.com     }
496*1174Svbart@nginx.com 
497*1174Svbart@nginx.com     end = nxt_decode_uri(parse->buf, start, length);
498*1174Svbart@nginx.com     if (nxt_slow_path(end == NULL)) {
499*1174Svbart@nginx.com         return NXT_ERROR;
500*1174Svbart@nginx.com     }
501*1174Svbart@nginx.com 
502*1174Svbart@nginx.com     token->length = end - parse->buf;
503*1174Svbart@nginx.com     token->start = parse->buf;
504*1174Svbart@nginx.com 
505*1174Svbart@nginx.com     return NXT_OK;
506106Svbart@nginx.com }
507106Svbart@nginx.com 
508106Svbart@nginx.com 
509106Svbart@nginx.com nxt_conf_value_t *
510106Svbart@nginx.com nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name,
511106Svbart@nginx.com     uint32_t *index)
512106Svbart@nginx.com {
513106Svbart@nginx.com     nxt_str_t                 str;
514106Svbart@nginx.com     nxt_uint_t                n;
515106Svbart@nginx.com     nxt_conf_object_t         *object;
516106Svbart@nginx.com     nxt_conf_object_member_t  *member;
517106Svbart@nginx.com 
518116Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_OBJECT) {
519106Svbart@nginx.com         return NULL;
520106Svbart@nginx.com     }
521106Svbart@nginx.com 
522106Svbart@nginx.com     object = value->u.object;
523106Svbart@nginx.com 
524106Svbart@nginx.com     for (n = 0; n < object->count; n++) {
525106Svbart@nginx.com         member = &object->members[n];
526106Svbart@nginx.com 
527106Svbart@nginx.com         nxt_conf_get_string(&member->name, &str);
528106Svbart@nginx.com 
529106Svbart@nginx.com         if (nxt_strstr_eq(&str, name)) {
530106Svbart@nginx.com 
531106Svbart@nginx.com             if (index != NULL) {
532106Svbart@nginx.com                 *index = n;
533106Svbart@nginx.com             }
534106Svbart@nginx.com 
535106Svbart@nginx.com             return &member->value;
536106Svbart@nginx.com         }
537106Svbart@nginx.com     }
538106Svbart@nginx.com 
539106Svbart@nginx.com     return NULL;
540106Svbart@nginx.com }
541106Svbart@nginx.com 
542106Svbart@nginx.com 
543106Svbart@nginx.com nxt_int_t
544213Svbart@nginx.com nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map,
545213Svbart@nginx.com     nxt_uint_t n, void *data)
546106Svbart@nginx.com {
547213Svbart@nginx.com     nxt_str_t         str, *s;
548106Svbart@nginx.com     nxt_uint_t        i;
549106Svbart@nginx.com     nxt_conf_value_t  *v;
550106Svbart@nginx.com 
551106Svbart@nginx.com     union {
552111Sigor@sysoev.ru         uint8_t     ui8;
553111Sigor@sysoev.ru         int32_t     i32;
554111Sigor@sysoev.ru         int64_t     i64;
555839Svbart@nginx.com         int         i;
556111Sigor@sysoev.ru         ssize_t     size;
557111Sigor@sysoev.ru         off_t       off;
558111Sigor@sysoev.ru         nxt_msec_t  msec;
559111Sigor@sysoev.ru         double      dbl;
560111Sigor@sysoev.ru         nxt_str_t   str;
561213Svbart@nginx.com         char        *cstrz;
562111Sigor@sysoev.ru         void        *v;
563106Svbart@nginx.com     } *ptr;
564106Svbart@nginx.com 
565136Svbart@nginx.com     for (i = 0; i < n; i++) {
566106Svbart@nginx.com 
567106Svbart@nginx.com         v = nxt_conf_get_object_member(value, &map[i].name, NULL);
568106Svbart@nginx.com 
569116Svbart@nginx.com         if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
570106Svbart@nginx.com             continue;
571106Svbart@nginx.com         }
572106Svbart@nginx.com 
573106Svbart@nginx.com         ptr = nxt_pointer_to(data, map[i].offset);
574106Svbart@nginx.com 
575106Svbart@nginx.com         switch (map[i].type) {
576106Svbart@nginx.com 
577106Svbart@nginx.com         case NXT_CONF_MAP_INT8:
578106Svbart@nginx.com 
579136Svbart@nginx.com             if (v->type == NXT_CONF_VALUE_BOOLEAN) {
580136Svbart@nginx.com                 ptr->ui8 = v->u.boolean;
581106Svbart@nginx.com             }
582106Svbart@nginx.com 
583106Svbart@nginx.com             break;
584106Svbart@nginx.com 
585106Svbart@nginx.com         case NXT_CONF_MAP_INT32:
586106Svbart@nginx.com         case NXT_CONF_MAP_INT64:
587106Svbart@nginx.com         case NXT_CONF_MAP_INT:
588106Svbart@nginx.com         case NXT_CONF_MAP_SIZE:
589106Svbart@nginx.com         case NXT_CONF_MAP_OFF:
590111Sigor@sysoev.ru         case NXT_CONF_MAP_MSEC:
591106Svbart@nginx.com 
592116Svbart@nginx.com             if (v->type != NXT_CONF_VALUE_INTEGER) {
593136Svbart@nginx.com                 break;
594106Svbart@nginx.com             }
595106Svbart@nginx.com 
596106Svbart@nginx.com             switch (map[i].type) {
597106Svbart@nginx.com 
598106Svbart@nginx.com             case NXT_CONF_MAP_INT32:
599120Svbart@nginx.com                 ptr->i32 = v->u.integer;
600106Svbart@nginx.com                 break;
601106Svbart@nginx.com 
602106Svbart@nginx.com             case NXT_CONF_MAP_INT64:
603106Svbart@nginx.com                 ptr->i64 = v->u.integer;
604106Svbart@nginx.com                 break;
605106Svbart@nginx.com 
606106Svbart@nginx.com             case NXT_CONF_MAP_INT:
607106Svbart@nginx.com                 ptr->i = v->u.integer;
608106Svbart@nginx.com                 break;
609106Svbart@nginx.com 
610106Svbart@nginx.com             case NXT_CONF_MAP_SIZE:
611106Svbart@nginx.com                 ptr->size = v->u.integer;
612106Svbart@nginx.com                 break;
613106Svbart@nginx.com 
614106Svbart@nginx.com             case NXT_CONF_MAP_OFF:
615106Svbart@nginx.com                 ptr->off = v->u.integer;
616106Svbart@nginx.com                 break;
617106Svbart@nginx.com 
618111Sigor@sysoev.ru             case NXT_CONF_MAP_MSEC:
619318Smax.romanov@nginx.com                 ptr->msec = v->u.integer * 1000;
620111Sigor@sysoev.ru                 break;
621111Sigor@sysoev.ru 
622106Svbart@nginx.com             default:
623106Svbart@nginx.com                 nxt_unreachable();
624106Svbart@nginx.com             }
625106Svbart@nginx.com 
626106Svbart@nginx.com             break;
627106Svbart@nginx.com 
628106Svbart@nginx.com         case NXT_CONF_MAP_DOUBLE:
629106Svbart@nginx.com 
630116Svbart@nginx.com             if (v->type == NXT_CONF_VALUE_NUMBER) {
631106Svbart@nginx.com                 ptr->dbl = v->u.number;
632106Svbart@nginx.com 
633116Svbart@nginx.com             } else if (v->type == NXT_CONF_VALUE_INTEGER) {
634106Svbart@nginx.com                 ptr->dbl = v->u.integer;
635106Svbart@nginx.com 
636106Svbart@nginx.com             }
637106Svbart@nginx.com 
638106Svbart@nginx.com             break;
639106Svbart@nginx.com 
640106Svbart@nginx.com         case NXT_CONF_MAP_STR:
641213Svbart@nginx.com         case NXT_CONF_MAP_STR_COPY:
642213Svbart@nginx.com         case NXT_CONF_MAP_CSTRZ:
643213Svbart@nginx.com 
644213Svbart@nginx.com             if (v->type != NXT_CONF_VALUE_SHORT_STRING
645213Svbart@nginx.com                 && v->type != NXT_CONF_VALUE_STRING)
646106Svbart@nginx.com             {
647213Svbart@nginx.com                 break;
648213Svbart@nginx.com             }
649213Svbart@nginx.com 
650213Svbart@nginx.com             nxt_conf_get_string(v, &str);
651213Svbart@nginx.com 
652213Svbart@nginx.com             switch (map[i].type) {
653213Svbart@nginx.com 
654213Svbart@nginx.com             case NXT_CONF_MAP_STR:
655213Svbart@nginx.com                 ptr->str = str;
656213Svbart@nginx.com                 break;
657213Svbart@nginx.com 
658213Svbart@nginx.com             case NXT_CONF_MAP_STR_COPY:
659213Svbart@nginx.com 
660213Svbart@nginx.com                 s = nxt_str_dup(mp, &ptr->str, &str);
661213Svbart@nginx.com 
662213Svbart@nginx.com                 if (nxt_slow_path(s == NULL)) {
663213Svbart@nginx.com                     return NXT_ERROR;
664213Svbart@nginx.com                 }
665213Svbart@nginx.com 
666213Svbart@nginx.com                 break;
667213Svbart@nginx.com 
668213Svbart@nginx.com             case NXT_CONF_MAP_CSTRZ:
669213Svbart@nginx.com 
670213Svbart@nginx.com                 ptr->cstrz = nxt_str_cstrz(mp, &str);
671213Svbart@nginx.com 
672213Svbart@nginx.com                 if (nxt_slow_path(ptr->cstrz == NULL)) {
673213Svbart@nginx.com                     return NXT_ERROR;
674213Svbart@nginx.com                 }
675213Svbart@nginx.com 
676213Svbart@nginx.com                 break;
677213Svbart@nginx.com 
678213Svbart@nginx.com             default:
679213Svbart@nginx.com                 nxt_unreachable();
680106Svbart@nginx.com             }
681106Svbart@nginx.com 
682106Svbart@nginx.com             break;
683106Svbart@nginx.com 
684106Svbart@nginx.com         case NXT_CONF_MAP_PTR:
685106Svbart@nginx.com 
686106Svbart@nginx.com             ptr->v = v;
687106Svbart@nginx.com 
688106Svbart@nginx.com             break;
689106Svbart@nginx.com         }
690106Svbart@nginx.com     }
691106Svbart@nginx.com 
692106Svbart@nginx.com     return NXT_OK;
693106Svbart@nginx.com }
694106Svbart@nginx.com 
695106Svbart@nginx.com 
696106Svbart@nginx.com nxt_conf_value_t *
697106Svbart@nginx.com nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name,
698106Svbart@nginx.com     uint32_t *next)
699106Svbart@nginx.com {
700106Svbart@nginx.com     uint32_t                  n;
701106Svbart@nginx.com     nxt_conf_object_t         *object;
702106Svbart@nginx.com     nxt_conf_object_member_t  *member;
703106Svbart@nginx.com 
704116Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_OBJECT) {
705106Svbart@nginx.com         return NULL;
706106Svbart@nginx.com     }
707106Svbart@nginx.com 
708106Svbart@nginx.com     n = *next;
709106Svbart@nginx.com     object = value->u.object;
710106Svbart@nginx.com 
711106Svbart@nginx.com     if (n >= object->count) {
712106Svbart@nginx.com         return NULL;
713106Svbart@nginx.com     }
714106Svbart@nginx.com 
715106Svbart@nginx.com     member = &object->members[n];
716106Svbart@nginx.com     *next = n + 1;
717106Svbart@nginx.com 
718106Svbart@nginx.com     nxt_conf_get_string(&member->name, name);
719106Svbart@nginx.com 
720106Svbart@nginx.com     return &member->value;
721106Svbart@nginx.com }
722106Svbart@nginx.com 
723106Svbart@nginx.com 
724214Svbart@nginx.com nxt_conf_value_t *
725214Svbart@nginx.com nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index)
726214Svbart@nginx.com {
727214Svbart@nginx.com     nxt_conf_array_t  *array;
728214Svbart@nginx.com 
729214Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_ARRAY) {
730214Svbart@nginx.com         return NULL;
731214Svbart@nginx.com     }
732214Svbart@nginx.com 
733214Svbart@nginx.com     array = value->u.array;
734214Svbart@nginx.com 
735214Svbart@nginx.com     if (index >= array->count) {
736214Svbart@nginx.com         return NULL;
737214Svbart@nginx.com     }
738214Svbart@nginx.com 
739214Svbart@nginx.com     return &array->elements[index];
740214Svbart@nginx.com }
741214Svbart@nginx.com 
742214Svbart@nginx.com 
743962Sigor@sysoev.ru void
744962Sigor@sysoev.ru nxt_conf_array_qsort(nxt_conf_value_t *value,
745962Sigor@sysoev.ru     int (*compare)(const void *, const void *))
746962Sigor@sysoev.ru {
747962Sigor@sysoev.ru     nxt_conf_array_t  *array;
748962Sigor@sysoev.ru 
749962Sigor@sysoev.ru     if (value->type != NXT_CONF_VALUE_ARRAY) {
750962Sigor@sysoev.ru         return;
751962Sigor@sysoev.ru     }
752962Sigor@sysoev.ru 
753962Sigor@sysoev.ru     array = value->u.array;
754962Sigor@sysoev.ru 
755962Sigor@sysoev.ru     nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare);
756962Sigor@sysoev.ru }
757962Sigor@sysoev.ru 
758962Sigor@sysoev.ru 
7591049Svbart@nginx.com nxt_conf_op_ret_t
760106Svbart@nginx.com nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
7611049Svbart@nginx.com     nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add)
762106Svbart@nginx.com {
763106Svbart@nginx.com     nxt_str_t                 token;
764*1174Svbart@nginx.com     nxt_int_t                 ret, index;
765106Svbart@nginx.com     nxt_conf_op_t             *op, **parent;
7661047Svbart@nginx.com     nxt_conf_value_t          *node;
767106Svbart@nginx.com     nxt_conf_path_parse_t     parse;
768106Svbart@nginx.com     nxt_conf_object_member_t  *member;
769106Svbart@nginx.com 
770106Svbart@nginx.com     parse.start = path->start;
771106Svbart@nginx.com     parse.end = path->start + path->length;
772106Svbart@nginx.com     parse.last = 0;
773106Svbart@nginx.com 
774106Svbart@nginx.com     parent = ops;
775106Svbart@nginx.com 
776106Svbart@nginx.com     for ( ;; ) {
777106Svbart@nginx.com         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
778106Svbart@nginx.com         if (nxt_slow_path(op == NULL)) {
7791049Svbart@nginx.com             return NXT_CONF_OP_ERROR;
780106Svbart@nginx.com         }
781106Svbart@nginx.com 
782106Svbart@nginx.com         *parent = op;
783106Svbart@nginx.com         parent = (nxt_conf_op_t **) &op->ctx;
784106Svbart@nginx.com 
785*1174Svbart@nginx.com         ret = nxt_conf_path_next_token(&parse, &token);
786*1174Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
787*1174Svbart@nginx.com             return NXT_CONF_OP_ERROR;
788*1174Svbart@nginx.com         }
789106Svbart@nginx.com 
7901048Svbart@nginx.com         switch (root->type) {
7911048Svbart@nginx.com 
7921048Svbart@nginx.com         case NXT_CONF_VALUE_OBJECT:
7931048Svbart@nginx.com             node = nxt_conf_get_object_member(root, &token, &op->index);
7941048Svbart@nginx.com             break;
7951048Svbart@nginx.com 
7961048Svbart@nginx.com         case NXT_CONF_VALUE_ARRAY:
7971048Svbart@nginx.com             index = nxt_int_parse(token.start, token.length);
7981048Svbart@nginx.com 
7991048Svbart@nginx.com             if (index < 0 || index > NXT_INT32_T_MAX) {
8001049Svbart@nginx.com                 return NXT_CONF_OP_NOT_FOUND;
8011048Svbart@nginx.com             }
8021048Svbart@nginx.com 
8031048Svbart@nginx.com             op->index = index;
8041048Svbart@nginx.com 
8051048Svbart@nginx.com             node = nxt_conf_get_array_element(root, index);
8061048Svbart@nginx.com             break;
8071048Svbart@nginx.com 
8081048Svbart@nginx.com         default:
8091048Svbart@nginx.com             node = NULL;
8101048Svbart@nginx.com         }
811106Svbart@nginx.com 
812106Svbart@nginx.com         if (parse.last) {
813106Svbart@nginx.com             break;
814106Svbart@nginx.com         }
815106Svbart@nginx.com 
8161047Svbart@nginx.com         if (node == NULL) {
8171049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
818106Svbart@nginx.com         }
819106Svbart@nginx.com 
820106Svbart@nginx.com         op->action = NXT_CONF_OP_PASS;
8211047Svbart@nginx.com         root = node;
822106Svbart@nginx.com     }
823106Svbart@nginx.com 
824106Svbart@nginx.com     if (value == NULL) {
825106Svbart@nginx.com 
8261047Svbart@nginx.com         if (node == NULL) {
8271049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
828106Svbart@nginx.com         }
829106Svbart@nginx.com 
830106Svbart@nginx.com         op->action = NXT_CONF_OP_DELETE;
831106Svbart@nginx.com 
8321049Svbart@nginx.com         return NXT_CONF_OP_OK;
8331049Svbart@nginx.com     }
8341049Svbart@nginx.com 
8351049Svbart@nginx.com     if (add) {
8361049Svbart@nginx.com         if (node == NULL) {
8371049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
8381049Svbart@nginx.com         }
8391049Svbart@nginx.com 
8401049Svbart@nginx.com         if (node->type != NXT_CONF_VALUE_ARRAY) {
8411049Svbart@nginx.com             return NXT_CONF_OP_NOT_ALLOWED;
8421049Svbart@nginx.com         }
8431049Svbart@nginx.com 
8441049Svbart@nginx.com         op->action = NXT_CONF_OP_PASS;
8451049Svbart@nginx.com 
8461049Svbart@nginx.com         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
8471049Svbart@nginx.com         if (nxt_slow_path(op == NULL)) {
8481049Svbart@nginx.com             return NXT_CONF_OP_ERROR;
8491049Svbart@nginx.com         }
8501049Svbart@nginx.com 
8511049Svbart@nginx.com         *parent = op;
8521049Svbart@nginx.com 
8531049Svbart@nginx.com         op->index = node->u.array->count;
8541049Svbart@nginx.com         op->action = NXT_CONF_OP_CREATE;
8551049Svbart@nginx.com         op->ctx = value;
8561049Svbart@nginx.com 
8571049Svbart@nginx.com         return NXT_CONF_OP_OK;
858106Svbart@nginx.com     }
859106Svbart@nginx.com 
8601048Svbart@nginx.com     if (node != NULL) {
8611048Svbart@nginx.com         op->action = NXT_CONF_OP_REPLACE;
8621048Svbart@nginx.com         op->ctx = value;
8631048Svbart@nginx.com 
8641049Svbart@nginx.com         return NXT_CONF_OP_OK;
8651048Svbart@nginx.com     }
8661048Svbart@nginx.com 
8671048Svbart@nginx.com     op->action = NXT_CONF_OP_CREATE;
8681048Svbart@nginx.com 
8691048Svbart@nginx.com     if (root->type == NXT_CONF_VALUE_ARRAY) {
8701048Svbart@nginx.com         if (op->index > root->u.array->count) {
8711049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
8721048Svbart@nginx.com         }
8731048Svbart@nginx.com 
8741048Svbart@nginx.com         op->ctx = value;
8751048Svbart@nginx.com 
8761048Svbart@nginx.com     } else {
877106Svbart@nginx.com         member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t));
878106Svbart@nginx.com         if (nxt_slow_path(member == NULL)) {
8791049Svbart@nginx.com             return NXT_CONF_OP_ERROR;
880106Svbart@nginx.com         }
881106Svbart@nginx.com 
882*1174Svbart@nginx.com         ret = nxt_conf_set_string_dup(&member->name, mp, &token);
883*1174Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
884*1174Svbart@nginx.com             return NXT_CONF_OP_ERROR;
885*1174Svbart@nginx.com         }
886106Svbart@nginx.com 
887106Svbart@nginx.com         member->value = *value;
888106Svbart@nginx.com 
8891047Svbart@nginx.com         op->index = root->u.object->count;
890106Svbart@nginx.com         op->ctx = member;
891106Svbart@nginx.com     }
892106Svbart@nginx.com 
8931049Svbart@nginx.com     return NXT_CONF_OP_OK;
894106Svbart@nginx.com }
895106Svbart@nginx.com 
896106Svbart@nginx.com 
897106Svbart@nginx.com nxt_conf_value_t *
898106Svbart@nginx.com nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value)
899106Svbart@nginx.com {
900106Svbart@nginx.com     nxt_int_t         rc;
901106Svbart@nginx.com     nxt_conf_value_t  *copy;
902106Svbart@nginx.com 
903106Svbart@nginx.com     copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
904106Svbart@nginx.com     if (nxt_slow_path(copy == NULL)) {
905106Svbart@nginx.com         return NULL;
906106Svbart@nginx.com     }
907106Svbart@nginx.com 
908106Svbart@nginx.com     rc = nxt_conf_copy_value(mp, op, copy, value);
909106Svbart@nginx.com 
910106Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
911106Svbart@nginx.com         return NULL;
912106Svbart@nginx.com     }
913106Svbart@nginx.com 
914106Svbart@nginx.com     return copy;
915106Svbart@nginx.com }
916106Svbart@nginx.com 
917106Svbart@nginx.com 
918106Svbart@nginx.com static nxt_int_t
919106Svbart@nginx.com nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
920106Svbart@nginx.com     nxt_conf_value_t *src)
921106Svbart@nginx.com {
9221048Svbart@nginx.com     if (op != NULL
9231048Svbart@nginx.com         && src->type != NXT_CONF_VALUE_ARRAY
9241048Svbart@nginx.com         && src->type != NXT_CONF_VALUE_OBJECT)
9251048Svbart@nginx.com     {
926106Svbart@nginx.com         return NXT_ERROR;
927106Svbart@nginx.com     }
928106Svbart@nginx.com 
929106Svbart@nginx.com     switch (src->type) {
930106Svbart@nginx.com 
931116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
932106Svbart@nginx.com 
933172Svbart@nginx.com         dst->u.string.start = nxt_mp_nget(mp, src->u.string.length);
934172Svbart@nginx.com         if (nxt_slow_path(dst->u.string.start == NULL)) {
935106Svbart@nginx.com             return NXT_ERROR;
936106Svbart@nginx.com         }
937106Svbart@nginx.com 
938172Svbart@nginx.com         nxt_memcpy(dst->u.string.start, src->u.string.start,
939172Svbart@nginx.com                    src->u.string.length);
940172Svbart@nginx.com 
941172Svbart@nginx.com         dst->u.string.length = src->u.string.length;
942172Svbart@nginx.com 
943106Svbart@nginx.com         break;
944106Svbart@nginx.com 
945116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
9461048Svbart@nginx.com         return nxt_conf_copy_array(mp, op, dst, src);
947106Svbart@nginx.com 
948116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
949106Svbart@nginx.com         return nxt_conf_copy_object(mp, op, dst, src);
950106Svbart@nginx.com 
951106Svbart@nginx.com     default:
952106Svbart@nginx.com         dst->u = src->u;
953106Svbart@nginx.com     }
954106Svbart@nginx.com 
9551048Svbart@nginx.com     dst->type = src->type;
9561048Svbart@nginx.com 
9571048Svbart@nginx.com     return NXT_OK;
9581048Svbart@nginx.com }
9591048Svbart@nginx.com 
9601048Svbart@nginx.com 
9611048Svbart@nginx.com static nxt_int_t
9621048Svbart@nginx.com nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
9631048Svbart@nginx.com     nxt_conf_value_t *src)
9641048Svbart@nginx.com {
9651048Svbart@nginx.com     size_t            size;
9661048Svbart@nginx.com     nxt_int_t         rc;
9671048Svbart@nginx.com     nxt_uint_t        s, d, count, index;
9681048Svbart@nginx.com     nxt_conf_op_t     *pass_op;
9691048Svbart@nginx.com     nxt_conf_value_t  *value;
9701048Svbart@nginx.com 
9711048Svbart@nginx.com     count = src->u.array->count;
9721048Svbart@nginx.com 
9731048Svbart@nginx.com     if (op != NULL) {
9741048Svbart@nginx.com         if (op->action == NXT_CONF_OP_CREATE) {
9751048Svbart@nginx.com             count++;
9761048Svbart@nginx.com 
9771048Svbart@nginx.com         } else if (op->action == NXT_CONF_OP_DELETE) {
9781048Svbart@nginx.com             count--;
9791048Svbart@nginx.com         }
9801048Svbart@nginx.com     }
9811048Svbart@nginx.com 
9821048Svbart@nginx.com     size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t);
9831048Svbart@nginx.com 
9841048Svbart@nginx.com     dst->u.array = nxt_mp_get(mp, size);
9851048Svbart@nginx.com     if (nxt_slow_path(dst->u.array == NULL)) {
9861048Svbart@nginx.com         return NXT_ERROR;
9871048Svbart@nginx.com     }
9881048Svbart@nginx.com 
9891048Svbart@nginx.com     dst->u.array->count = count;
9901048Svbart@nginx.com 
9911048Svbart@nginx.com     s = 0;
9921048Svbart@nginx.com     d = 0;
9931048Svbart@nginx.com 
9941048Svbart@nginx.com     pass_op = NULL;
9951048Svbart@nginx.com 
9961048Svbart@nginx.com     /*
9971048Svbart@nginx.com      * This initialization is needed only to
9981048Svbart@nginx.com      * suppress a warning on GCC 4.8 and older.
9991048Svbart@nginx.com      */
10001048Svbart@nginx.com     index = 0;
10011048Svbart@nginx.com 
10021048Svbart@nginx.com     do {
10031048Svbart@nginx.com         if (pass_op == NULL) {
10041048Svbart@nginx.com             index = (op == NULL) ? src->u.array->count : op->index;
10051048Svbart@nginx.com         }
10061048Svbart@nginx.com 
10071048Svbart@nginx.com         while (s != index) {
10081048Svbart@nginx.com             rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d],
10091048Svbart@nginx.com                                                   &src->u.array->elements[s]);
10101048Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
10111048Svbart@nginx.com                 return NXT_ERROR;
10121048Svbart@nginx.com             }
10131048Svbart@nginx.com 
10141048Svbart@nginx.com             s++;
10151048Svbart@nginx.com             d++;
10161048Svbart@nginx.com         }
10171048Svbart@nginx.com 
10181048Svbart@nginx.com         if (pass_op != NULL) {
10191048Svbart@nginx.com             pass_op = NULL;
10201048Svbart@nginx.com             continue;
10211048Svbart@nginx.com         }
10221048Svbart@nginx.com 
10231048Svbart@nginx.com         if (op != NULL) {
10241048Svbart@nginx.com             switch (op->action) {
10251048Svbart@nginx.com             case NXT_CONF_OP_PASS:
10261048Svbart@nginx.com                 pass_op = op->ctx;
10271048Svbart@nginx.com                 index++;
10281048Svbart@nginx.com                 break;
10291048Svbart@nginx.com 
10301048Svbart@nginx.com             case NXT_CONF_OP_CREATE:
10311048Svbart@nginx.com                 value = op->ctx;
10321048Svbart@nginx.com                 dst->u.array->elements[d] = *value;
10331048Svbart@nginx.com 
10341048Svbart@nginx.com                 d++;
10351048Svbart@nginx.com                 break;
10361048Svbart@nginx.com 
10371048Svbart@nginx.com             case NXT_CONF_OP_REPLACE:
10381048Svbart@nginx.com                 value = op->ctx;
10391048Svbart@nginx.com                 dst->u.array->elements[d] = *value;
10401048Svbart@nginx.com 
10411048Svbart@nginx.com                 s++;
10421048Svbart@nginx.com                 d++;
10431048Svbart@nginx.com                 break;
10441048Svbart@nginx.com 
10451048Svbart@nginx.com             case NXT_CONF_OP_DELETE:
10461048Svbart@nginx.com                 s++;
10471048Svbart@nginx.com                 break;
10481048Svbart@nginx.com             }
10491048Svbart@nginx.com 
10501048Svbart@nginx.com             op = NULL;
10511048Svbart@nginx.com         }
10521048Svbart@nginx.com 
10531048Svbart@nginx.com     } while (d != count);
10541048Svbart@nginx.com 
10551048Svbart@nginx.com     dst->type = src->type;
10561048Svbart@nginx.com 
1057106Svbart@nginx.com     return NXT_OK;
1058106Svbart@nginx.com }
1059106Svbart@nginx.com 
1060106Svbart@nginx.com 
1061106Svbart@nginx.com static nxt_int_t
1062106Svbart@nginx.com nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
1063106Svbart@nginx.com     nxt_conf_value_t *src)
1064106Svbart@nginx.com {
1065106Svbart@nginx.com     size_t                    size;
1066106Svbart@nginx.com     nxt_int_t                 rc;
1067106Svbart@nginx.com     nxt_uint_t                s, d, count, index;
1068106Svbart@nginx.com     nxt_conf_op_t             *pass_op;
1069106Svbart@nginx.com     nxt_conf_value_t          *value;
1070106Svbart@nginx.com     nxt_conf_object_member_t  *member;
1071106Svbart@nginx.com 
1072106Svbart@nginx.com     count = src->u.object->count;
1073106Svbart@nginx.com 
1074106Svbart@nginx.com     if (op != NULL) {
1075106Svbart@nginx.com         if (op->action == NXT_CONF_OP_CREATE) {
1076106Svbart@nginx.com             count++;
1077106Svbart@nginx.com 
1078106Svbart@nginx.com         } else if (op->action == NXT_CONF_OP_DELETE) {
1079106Svbart@nginx.com             count--;
1080106Svbart@nginx.com         }
1081106Svbart@nginx.com     }
1082106Svbart@nginx.com 
1083106Svbart@nginx.com     size = sizeof(nxt_conf_object_t)
1084106Svbart@nginx.com            + count * sizeof(nxt_conf_object_member_t);
1085106Svbart@nginx.com 
1086106Svbart@nginx.com     dst->u.object = nxt_mp_get(mp, size);
1087106Svbart@nginx.com     if (nxt_slow_path(dst->u.object == NULL)) {
1088106Svbart@nginx.com         return NXT_ERROR;
1089106Svbart@nginx.com     }
1090106Svbart@nginx.com 
1091106Svbart@nginx.com     dst->u.object->count = count;
1092106Svbart@nginx.com 
1093106Svbart@nginx.com     s = 0;
1094106Svbart@nginx.com     d = 0;
1095106Svbart@nginx.com 
1096106Svbart@nginx.com     pass_op = NULL;
1097106Svbart@nginx.com 
1098106Svbart@nginx.com     /*
1099106Svbart@nginx.com      * This initialization is needed only to
1100106Svbart@nginx.com      * suppress a warning on GCC 4.8 and older.
1101106Svbart@nginx.com      */
1102106Svbart@nginx.com     index = 0;
1103106Svbart@nginx.com 
1104106Svbart@nginx.com     do {
1105106Svbart@nginx.com         if (pass_op == NULL) {
11061047Svbart@nginx.com             index = (op == NULL) ? src->u.object->count : op->index;
1107106Svbart@nginx.com         }
1108106Svbart@nginx.com 
1109106Svbart@nginx.com         while (s != index) {
1110106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, NULL,
1111106Svbart@nginx.com                                      &dst->u.object->members[d].name,
1112106Svbart@nginx.com                                      &src->u.object->members[s].name);
1113106Svbart@nginx.com 
1114106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
1115106Svbart@nginx.com                 return NXT_ERROR;
1116106Svbart@nginx.com             }
1117106Svbart@nginx.com 
1118106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, pass_op,
1119106Svbart@nginx.com                                      &dst->u.object->members[d].value,
1120106Svbart@nginx.com                                      &src->u.object->members[s].value);
1121106Svbart@nginx.com 
1122106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
1123106Svbart@nginx.com                 return NXT_ERROR;
1124106Svbart@nginx.com             }
1125106Svbart@nginx.com 
1126106Svbart@nginx.com             s++;
1127106Svbart@nginx.com             d++;
1128106Svbart@nginx.com         }
1129106Svbart@nginx.com 
1130106Svbart@nginx.com         if (pass_op != NULL) {
1131106Svbart@nginx.com             pass_op = NULL;
1132106Svbart@nginx.com             continue;
1133106Svbart@nginx.com         }
1134106Svbart@nginx.com 
1135106Svbart@nginx.com         if (op != NULL) {
1136106Svbart@nginx.com             switch (op->action) {
1137106Svbart@nginx.com             case NXT_CONF_OP_PASS:
1138106Svbart@nginx.com                 pass_op = op->ctx;
1139106Svbart@nginx.com                 index++;
1140106Svbart@nginx.com                 break;
1141106Svbart@nginx.com 
1142106Svbart@nginx.com             case NXT_CONF_OP_CREATE:
1143106Svbart@nginx.com                 member = op->ctx;
1144106Svbart@nginx.com 
1145106Svbart@nginx.com                 rc = nxt_conf_copy_value(mp, NULL,
1146106Svbart@nginx.com                                          &dst->u.object->members[d].name,
1147106Svbart@nginx.com                                          &member->name);
1148106Svbart@nginx.com 
1149106Svbart@nginx.com                 if (nxt_slow_path(rc != NXT_OK)) {
1150106Svbart@nginx.com                     return NXT_ERROR;
1151106Svbart@nginx.com                 }
1152106Svbart@nginx.com 
1153106Svbart@nginx.com                 dst->u.object->members[d].value = member->value;
1154106Svbart@nginx.com 
1155106Svbart@nginx.com                 d++;
1156106Svbart@nginx.com                 break;
1157106Svbart@nginx.com 
1158106Svbart@nginx.com             case NXT_CONF_OP_REPLACE:
1159106Svbart@nginx.com                 rc = nxt_conf_copy_value(mp, NULL,
1160106Svbart@nginx.com                                          &dst->u.object->members[d].name,
1161106Svbart@nginx.com                                          &src->u.object->members[s].name);
1162106Svbart@nginx.com 
1163106Svbart@nginx.com                 if (nxt_slow_path(rc != NXT_OK)) {
1164106Svbart@nginx.com                     return NXT_ERROR;
1165106Svbart@nginx.com                 }
1166106Svbart@nginx.com 
1167106Svbart@nginx.com                 value = op->ctx;
1168106Svbart@nginx.com 
1169106Svbart@nginx.com                 dst->u.object->members[d].value = *value;
1170106Svbart@nginx.com 
1171106Svbart@nginx.com                 s++;
1172106Svbart@nginx.com                 d++;
1173106Svbart@nginx.com                 break;
1174106Svbart@nginx.com 
1175106Svbart@nginx.com             case NXT_CONF_OP_DELETE:
1176106Svbart@nginx.com                 s++;
1177106Svbart@nginx.com                 break;
1178106Svbart@nginx.com             }
1179106Svbart@nginx.com 
11801046Svbart@nginx.com             op = NULL;
1181106Svbart@nginx.com         }
1182106Svbart@nginx.com 
1183106Svbart@nginx.com     } while (d != count);
1184106Svbart@nginx.com 
1185106Svbart@nginx.com     dst->type = src->type;
1186106Svbart@nginx.com 
1187106Svbart@nginx.com     return NXT_OK;
1188106Svbart@nginx.com }
1189106Svbart@nginx.com 
1190106Svbart@nginx.com 
1191106Svbart@nginx.com nxt_conf_value_t *
1192208Svbart@nginx.com nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
1193208Svbart@nginx.com     nxt_conf_json_error_t *error)
1194106Svbart@nginx.com {
1195106Svbart@nginx.com     u_char            *p;
1196106Svbart@nginx.com     nxt_conf_value_t  *value;
1197106Svbart@nginx.com 
1198106Svbart@nginx.com     value = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
1199106Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
1200106Svbart@nginx.com         return NULL;
1201106Svbart@nginx.com     }
1202106Svbart@nginx.com 
1203106Svbart@nginx.com     p = nxt_conf_json_skip_space(start, end);
1204106Svbart@nginx.com 
1205106Svbart@nginx.com     if (nxt_slow_path(p == end)) {
1206208Svbart@nginx.com 
1207208Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
1208311Snick@nginx.com             "An empty JSON payload isn't allowed.  It must be either a literal "
1209311Snick@nginx.com             "(null, true, or false), a number, a string (in double quotes "
1210311Snick@nginx.com             "\"\"), an array (with brackets []), or an object (with braces {})."
1211208Svbart@nginx.com         );
1212208Svbart@nginx.com 
1213106Svbart@nginx.com         return NULL;
1214106Svbart@nginx.com     }
1215106Svbart@nginx.com 
1216208Svbart@nginx.com     p = nxt_conf_json_parse_value(mp, value, p, end, error);
1217106Svbart@nginx.com 
1218106Svbart@nginx.com     if (nxt_slow_path(p == NULL)) {
1219106Svbart@nginx.com         return NULL;
1220106Svbart@nginx.com     }
1221106Svbart@nginx.com 
1222106Svbart@nginx.com     p = nxt_conf_json_skip_space(p, end);
1223106Svbart@nginx.com 
1224106Svbart@nginx.com     if (nxt_slow_path(p != end)) {
1225208Svbart@nginx.com 
1226208Svbart@nginx.com         nxt_conf_json_parse_error(error, p,
1227311Snick@nginx.com             "Unexpected character after the end of a valid JSON value."
1228208Svbart@nginx.com         );
1229208Svbart@nginx.com 
1230106Svbart@nginx.com         return NULL;
1231106Svbart@nginx.com     }
1232106Svbart@nginx.com 
1233106Svbart@nginx.com     return value;
1234106Svbart@nginx.com }
1235106Svbart@nginx.com 
1236106Svbart@nginx.com 
1237106Svbart@nginx.com static u_char *
1238106Svbart@nginx.com nxt_conf_json_skip_space(u_char *start, u_char *end)
1239106Svbart@nginx.com {
1240106Svbart@nginx.com     u_char  *p;
1241106Svbart@nginx.com 
1242106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1243106Svbart@nginx.com 
1244106Svbart@nginx.com         switch (*p) {
1245106Svbart@nginx.com         case ' ':
1246106Svbart@nginx.com         case '\t':
1247106Svbart@nginx.com         case '\r':
1248106Svbart@nginx.com         case '\n':
1249106Svbart@nginx.com             continue;
1250106Svbart@nginx.com         }
1251106Svbart@nginx.com 
1252106Svbart@nginx.com         break;
1253106Svbart@nginx.com     }
1254106Svbart@nginx.com 
1255106Svbart@nginx.com     return p;
1256106Svbart@nginx.com }
1257106Svbart@nginx.com 
1258106Svbart@nginx.com 
1259106Svbart@nginx.com static u_char *
1260106Svbart@nginx.com nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1261208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1262106Svbart@nginx.com {
1263208Svbart@nginx.com     u_char  ch, *p;
1264106Svbart@nginx.com 
1265106Svbart@nginx.com     ch = *start;
1266106Svbart@nginx.com 
1267106Svbart@nginx.com     switch (ch) {
1268106Svbart@nginx.com     case '{':
1269208Svbart@nginx.com         return nxt_conf_json_parse_object(mp, value, start, end, error);
1270106Svbart@nginx.com 
1271106Svbart@nginx.com     case '[':
1272208Svbart@nginx.com         return nxt_conf_json_parse_array(mp, value, start, end, error);
1273106Svbart@nginx.com 
1274106Svbart@nginx.com     case '"':
1275208Svbart@nginx.com         return nxt_conf_json_parse_string(mp, value, start, end, error);
1276106Svbart@nginx.com 
1277106Svbart@nginx.com     case 't':
1278106Svbart@nginx.com         if (nxt_fast_path(end - start >= 4
1279106Svbart@nginx.com                           && nxt_memcmp(start, "true", 4) == 0))
1280106Svbart@nginx.com         {
1281106Svbart@nginx.com             value->u.boolean = 1;
1282116Svbart@nginx.com             value->type = NXT_CONF_VALUE_BOOLEAN;
1283106Svbart@nginx.com 
1284106Svbart@nginx.com             return start + 4;
1285106Svbart@nginx.com         }
1286106Svbart@nginx.com 
1287208Svbart@nginx.com         goto error;
1288106Svbart@nginx.com 
1289106Svbart@nginx.com     case 'f':
1290106Svbart@nginx.com         if (nxt_fast_path(end - start >= 5
1291106Svbart@nginx.com                           && nxt_memcmp(start, "false", 5) == 0))
1292106Svbart@nginx.com         {
1293106Svbart@nginx.com             value->u.boolean = 0;
1294116Svbart@nginx.com             value->type = NXT_CONF_VALUE_BOOLEAN;
1295106Svbart@nginx.com 
1296106Svbart@nginx.com             return start + 5;
1297106Svbart@nginx.com         }
1298106Svbart@nginx.com 
1299208Svbart@nginx.com         goto error;
1300106Svbart@nginx.com 
1301106Svbart@nginx.com     case 'n':
1302106Svbart@nginx.com         if (nxt_fast_path(end - start >= 4
1303106Svbart@nginx.com                           && nxt_memcmp(start, "null", 4) == 0))
1304106Svbart@nginx.com         {
1305116Svbart@nginx.com             value->type = NXT_CONF_VALUE_NULL;
1306106Svbart@nginx.com             return start + 4;
1307106Svbart@nginx.com         }
1308106Svbart@nginx.com 
1309208Svbart@nginx.com         goto error;
1310208Svbart@nginx.com 
1311208Svbart@nginx.com     case '-':
1312208Svbart@nginx.com         if (nxt_fast_path(end - start > 1)) {
1313208Svbart@nginx.com             ch = start[1];
1314208Svbart@nginx.com             break;
1315208Svbart@nginx.com         }
1316208Svbart@nginx.com 
1317208Svbart@nginx.com         goto error;
1318106Svbart@nginx.com     }
1319106Svbart@nginx.com 
1320208Svbart@nginx.com     if (nxt_fast_path((ch - '0') <= 9)) {
1321208Svbart@nginx.com         p = nxt_conf_json_parse_number(mp, value, start, end, error);
1322208Svbart@nginx.com 
1323383Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1324383Svbart@nginx.com             return NULL;
1325383Svbart@nginx.com         }
1326383Svbart@nginx.com 
1327208Svbart@nginx.com         if (p == end) {
1328208Svbart@nginx.com             return end;
1329208Svbart@nginx.com         }
1330208Svbart@nginx.com 
1331208Svbart@nginx.com         switch (*p) {
1332208Svbart@nginx.com         case ' ':
1333208Svbart@nginx.com         case '\t':
1334208Svbart@nginx.com         case '\r':
1335208Svbart@nginx.com         case '\n':
1336208Svbart@nginx.com         case ',':
1337208Svbart@nginx.com         case '}':
1338208Svbart@nginx.com         case ']':
1339208Svbart@nginx.com         case '{':
1340208Svbart@nginx.com         case '[':
1341208Svbart@nginx.com         case '"':
1342208Svbart@nginx.com             return p;
1343208Svbart@nginx.com         }
1344106Svbart@nginx.com     }
1345106Svbart@nginx.com 
1346208Svbart@nginx.com error:
1347208Svbart@nginx.com 
1348208Svbart@nginx.com     nxt_conf_json_parse_error(error, start,
1349311Snick@nginx.com         "A valid JSON value is expected here.  It must be either a literal "
1350311Snick@nginx.com         "(null, true, or false), a number, a string (in double quotes \"\"), "
1351311Snick@nginx.com         "an array (with brackets []), or an object (with braces {})."
1352208Svbart@nginx.com     );
1353208Svbart@nginx.com 
1354106Svbart@nginx.com     return NULL;
1355106Svbart@nginx.com }
1356106Svbart@nginx.com 
1357106Svbart@nginx.com 
1358106Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_conf_object_hash_proto
1359106Svbart@nginx.com     nxt_aligned(64) =
1360106Svbart@nginx.com {
1361106Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
1362106Svbart@nginx.com     nxt_conf_object_hash_test,
1363106Svbart@nginx.com     nxt_conf_object_hash_alloc,
1364106Svbart@nginx.com     nxt_conf_object_hash_free,
1365106Svbart@nginx.com };
1366106Svbart@nginx.com 
1367106Svbart@nginx.com 
1368106Svbart@nginx.com static u_char *
1369106Svbart@nginx.com nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1370208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1371106Svbart@nginx.com {
1372208Svbart@nginx.com     u_char                    *p, *name;
1373106Svbart@nginx.com     nxt_mp_t                  *mp_temp;
1374106Svbart@nginx.com     nxt_int_t                 rc;
1375106Svbart@nginx.com     nxt_uint_t                count;
1376106Svbart@nginx.com     nxt_lvlhsh_t              hash;
1377106Svbart@nginx.com     nxt_lvlhsh_each_t         lhe;
1378106Svbart@nginx.com     nxt_conf_object_t         *object;
1379106Svbart@nginx.com     nxt_conf_object_member_t  *member, *element;
1380106Svbart@nginx.com 
1381106Svbart@nginx.com     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1382106Svbart@nginx.com     if (nxt_slow_path(mp_temp == NULL)) {
1383106Svbart@nginx.com         return NULL;
1384106Svbart@nginx.com     }
1385106Svbart@nginx.com 
1386106Svbart@nginx.com     nxt_lvlhsh_init(&hash);
1387106Svbart@nginx.com 
1388106Svbart@nginx.com     count = 0;
1389130Svbart@nginx.com     p = start;
1390130Svbart@nginx.com 
1391130Svbart@nginx.com     for ( ;; ) {
1392130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1393130Svbart@nginx.com 
1394130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1395208Svbart@nginx.com 
1396208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1397311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object without "
1398311Snick@nginx.com                 "a closing brace (})."
1399208Svbart@nginx.com             );
1400208Svbart@nginx.com 
1401130Svbart@nginx.com             goto error;
1402130Svbart@nginx.com         }
1403130Svbart@nginx.com 
1404130Svbart@nginx.com         if (*p != '"') {
1405130Svbart@nginx.com             if (nxt_fast_path(*p == '}')) {
1406106Svbart@nginx.com                 break;
1407106Svbart@nginx.com             }
1408106Svbart@nginx.com 
1409208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1410208Svbart@nginx.com                 "A double quote (\") is expected here.  There must be a valid "
1411208Svbart@nginx.com                 "JSON object member starts with a name, which is a string "
1412208Svbart@nginx.com                 "enclosed in double quotes."
1413208Svbart@nginx.com             );
1414208Svbart@nginx.com 
1415130Svbart@nginx.com             goto error;
1416130Svbart@nginx.com         }
1417130Svbart@nginx.com 
1418208Svbart@nginx.com         name = p;
1419208Svbart@nginx.com 
1420130Svbart@nginx.com         count++;
1421130Svbart@nginx.com 
1422130Svbart@nginx.com         member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
1423130Svbart@nginx.com         if (nxt_slow_path(member == NULL)) {
1424130Svbart@nginx.com             goto error;
1425130Svbart@nginx.com         }
1426130Svbart@nginx.com 
1427208Svbart@nginx.com         p = nxt_conf_json_parse_string(mp, &member->name, p, end, error);
1428130Svbart@nginx.com 
1429130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1430130Svbart@nginx.com             goto error;
1431130Svbart@nginx.com         }
1432130Svbart@nginx.com 
1433130Svbart@nginx.com         rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
1434130Svbart@nginx.com 
1435130Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1436208Svbart@nginx.com 
1437208Svbart@nginx.com             if (rc == NXT_DECLINED) {
1438208Svbart@nginx.com                 nxt_conf_json_parse_error(error, name,
1439208Svbart@nginx.com                     "Duplicate object member.  All JSON object members must "
1440208Svbart@nginx.com                     "have unique names."
1441208Svbart@nginx.com                 );
1442208Svbart@nginx.com             }
1443208Svbart@nginx.com 
1444130Svbart@nginx.com             goto error;
1445130Svbart@nginx.com         }
1446130Svbart@nginx.com 
1447130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1448130Svbart@nginx.com 
1449208Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1450208Svbart@nginx.com 
1451208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1452311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object member "
1453311Snick@nginx.com                 "without a value."
1454208Svbart@nginx.com             );
1455208Svbart@nginx.com 
1456208Svbart@nginx.com             goto error;
1457208Svbart@nginx.com         }
1458208Svbart@nginx.com 
1459208Svbart@nginx.com         if (nxt_slow_path(*p != ':')) {
1460208Svbart@nginx.com 
1461208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1462311Snick@nginx.com                 "A colon (:) is expected here.  There must be a colon after "
1463311Snick@nginx.com                 "a JSON member name."
1464208Svbart@nginx.com             );
1465208Svbart@nginx.com 
1466130Svbart@nginx.com             goto error;
1467130Svbart@nginx.com         }
1468130Svbart@nginx.com 
1469130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1470130Svbart@nginx.com 
1471130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1472208Svbart@nginx.com 
1473208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1474311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object member "
1475311Snick@nginx.com                 "without a value."
1476208Svbart@nginx.com             );
1477208Svbart@nginx.com 
1478130Svbart@nginx.com             goto error;
1479130Svbart@nginx.com         }
1480130Svbart@nginx.com 
1481208Svbart@nginx.com         p = nxt_conf_json_parse_value(mp, &member->value, p, end, error);
1482130Svbart@nginx.com 
1483130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1484130Svbart@nginx.com             goto error;
1485130Svbart@nginx.com         }
1486130Svbart@nginx.com 
1487130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1488130Svbart@nginx.com 
1489130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1490208Svbart@nginx.com 
1491208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1492311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object without "
1493311Snick@nginx.com                 "a closing brace (})."
1494208Svbart@nginx.com             );
1495208Svbart@nginx.com 
1496130Svbart@nginx.com             goto error;
1497130Svbart@nginx.com         }
1498130Svbart@nginx.com 
1499130Svbart@nginx.com         if (*p != ',') {
1500130Svbart@nginx.com             if (nxt_fast_path(*p == '}')) {
1501130Svbart@nginx.com                 break;
1502106Svbart@nginx.com             }
1503106Svbart@nginx.com 
1504208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1505311Snick@nginx.com                 "Either a closing brace (}) or a comma (,) is expected here.  "
1506311Snick@nginx.com                 "Each JSON object must be enclosed in braces and its members "
1507311Snick@nginx.com                 "must be separated by commas."
1508208Svbart@nginx.com             );
1509208Svbart@nginx.com 
1510130Svbart@nginx.com             goto error;
1511106Svbart@nginx.com         }
1512106Svbart@nginx.com     }
1513106Svbart@nginx.com 
1514106Svbart@nginx.com     object = nxt_mp_get(mp, sizeof(nxt_conf_object_t)
1515106Svbart@nginx.com                             + count * sizeof(nxt_conf_object_member_t));
1516106Svbart@nginx.com     if (nxt_slow_path(object == NULL)) {
1517106Svbart@nginx.com         goto error;
1518106Svbart@nginx.com     }
1519106Svbart@nginx.com 
1520106Svbart@nginx.com     value->u.object = object;
1521116Svbart@nginx.com     value->type = NXT_CONF_VALUE_OBJECT;
1522106Svbart@nginx.com 
1523106Svbart@nginx.com     object->count = count;
1524106Svbart@nginx.com     member = object->members;
1525106Svbart@nginx.com 
1526598Sigor@sysoev.ru     nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto);
1527106Svbart@nginx.com 
1528106Svbart@nginx.com     for ( ;; ) {
1529106Svbart@nginx.com         element = nxt_lvlhsh_each(&hash, &lhe);
1530106Svbart@nginx.com 
1531106Svbart@nginx.com         if (element == NULL) {
1532106Svbart@nginx.com             break;
1533106Svbart@nginx.com         }
1534106Svbart@nginx.com 
1535106Svbart@nginx.com         *member++ = *element;
1536106Svbart@nginx.com     }
1537106Svbart@nginx.com 
1538106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1539106Svbart@nginx.com 
1540106Svbart@nginx.com     return p + 1;
1541106Svbart@nginx.com 
1542106Svbart@nginx.com error:
1543106Svbart@nginx.com 
1544106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1545106Svbart@nginx.com     return NULL;
1546106Svbart@nginx.com }
1547106Svbart@nginx.com 
1548106Svbart@nginx.com 
1549106Svbart@nginx.com static nxt_int_t
1550106Svbart@nginx.com nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh,
1551106Svbart@nginx.com     nxt_conf_object_member_t *member)
1552106Svbart@nginx.com {
1553106Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1554106Svbart@nginx.com 
1555106Svbart@nginx.com     nxt_conf_get_string(&member->name, &lhq.key);
1556106Svbart@nginx.com 
1557106Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
1558106Svbart@nginx.com     lhq.replace = 0;
1559106Svbart@nginx.com     lhq.value = member;
1560106Svbart@nginx.com     lhq.proto = &nxt_conf_object_hash_proto;
1561106Svbart@nginx.com     lhq.pool = mp;
1562106Svbart@nginx.com 
1563106Svbart@nginx.com     return nxt_lvlhsh_insert(lvlhsh, &lhq);
1564106Svbart@nginx.com }
1565106Svbart@nginx.com 
1566106Svbart@nginx.com 
1567106Svbart@nginx.com static nxt_int_t
1568106Svbart@nginx.com nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1569106Svbart@nginx.com {
1570106Svbart@nginx.com     nxt_str_t                 str;
1571106Svbart@nginx.com     nxt_conf_object_member_t  *member;
1572106Svbart@nginx.com 
1573106Svbart@nginx.com     member = data;
1574106Svbart@nginx.com 
1575106Svbart@nginx.com     nxt_conf_get_string(&member->name, &str);
1576106Svbart@nginx.com 
1577208Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED;
1578106Svbart@nginx.com }
1579106Svbart@nginx.com 
1580106Svbart@nginx.com 
1581106Svbart@nginx.com static void *
1582106Svbart@nginx.com nxt_conf_object_hash_alloc(void *data, size_t size)
1583106Svbart@nginx.com {
1584106Svbart@nginx.com     return nxt_mp_align(data, size, size);
1585106Svbart@nginx.com }
1586106Svbart@nginx.com 
1587106Svbart@nginx.com 
1588106Svbart@nginx.com static void
1589106Svbart@nginx.com nxt_conf_object_hash_free(void *data, void *p)
1590106Svbart@nginx.com {
1591106Svbart@nginx.com     nxt_mp_free(data, p);
1592106Svbart@nginx.com }
1593106Svbart@nginx.com 
1594106Svbart@nginx.com 
1595106Svbart@nginx.com static u_char *
1596106Svbart@nginx.com nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1597208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1598106Svbart@nginx.com {
1599106Svbart@nginx.com     u_char            *p;
1600106Svbart@nginx.com     nxt_mp_t          *mp_temp;
1601106Svbart@nginx.com     nxt_uint_t        count;
1602106Svbart@nginx.com     nxt_list_t        *list;
1603106Svbart@nginx.com     nxt_conf_array_t  *array;
1604106Svbart@nginx.com     nxt_conf_value_t  *element;
1605106Svbart@nginx.com 
1606106Svbart@nginx.com     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1607106Svbart@nginx.com     if (nxt_slow_path(mp_temp == NULL)) {
1608106Svbart@nginx.com         return NULL;
1609106Svbart@nginx.com     }
1610106Svbart@nginx.com 
1611106Svbart@nginx.com     list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t));
1612106Svbart@nginx.com     if (nxt_slow_path(list == NULL)) {
1613106Svbart@nginx.com         goto error;
1614106Svbart@nginx.com     }
1615106Svbart@nginx.com 
1616106Svbart@nginx.com     count = 0;
1617130Svbart@nginx.com     p = start;
1618130Svbart@nginx.com 
1619130Svbart@nginx.com     for ( ;; ) {
1620130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1621130Svbart@nginx.com 
1622130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1623208Svbart@nginx.com 
1624208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1625311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an array without "
1626311Snick@nginx.com                 "a closing bracket (])."
1627208Svbart@nginx.com             );
1628208Svbart@nginx.com 
1629130Svbart@nginx.com             goto error;
1630130Svbart@nginx.com         }
1631130Svbart@nginx.com 
1632130Svbart@nginx.com         if (*p == ']') {
1633130Svbart@nginx.com             break;
1634130Svbart@nginx.com         }
1635130Svbart@nginx.com 
1636130Svbart@nginx.com         count++;
1637130Svbart@nginx.com 
1638130Svbart@nginx.com         element = nxt_list_add(list);
1639130Svbart@nginx.com         if (nxt_slow_path(element == NULL)) {
1640130Svbart@nginx.com             goto error;
1641130Svbart@nginx.com         }
1642130Svbart@nginx.com 
1643208Svbart@nginx.com         p = nxt_conf_json_parse_value(mp, element, p, end, error);
1644130Svbart@nginx.com 
1645130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1646130Svbart@nginx.com             goto error;
1647130Svbart@nginx.com         }
1648130Svbart@nginx.com 
1649130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1650130Svbart@nginx.com 
1651130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1652208Svbart@nginx.com 
1653208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1654311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an array without "
1655311Snick@nginx.com                 "a closing bracket (])."
1656208Svbart@nginx.com             );
1657208Svbart@nginx.com 
1658130Svbart@nginx.com             goto error;
1659130Svbart@nginx.com         }
1660130Svbart@nginx.com 
1661130Svbart@nginx.com         if (*p != ',') {
1662130Svbart@nginx.com             if (nxt_fast_path(*p == ']')) {
1663106Svbart@nginx.com                 break;
1664106Svbart@nginx.com             }
1665106Svbart@nginx.com 
1666208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1667311Snick@nginx.com                 "Either a closing bracket (]) or a comma (,) is expected "
1668311Snick@nginx.com                 "here.  Each array must be enclosed in brackets and its "
1669311Snick@nginx.com                 "members must be separated by commas."
1670208Svbart@nginx.com             );
1671208Svbart@nginx.com 
1672130Svbart@nginx.com             goto error;
1673106Svbart@nginx.com         }
1674106Svbart@nginx.com     }
1675106Svbart@nginx.com 
1676106Svbart@nginx.com     array = nxt_mp_get(mp, sizeof(nxt_conf_array_t)
1677106Svbart@nginx.com                            + count * sizeof(nxt_conf_value_t));
1678106Svbart@nginx.com     if (nxt_slow_path(array == NULL)) {
1679106Svbart@nginx.com         goto error;
1680106Svbart@nginx.com     }
1681106Svbart@nginx.com 
1682106Svbart@nginx.com     value->u.array = array;
1683116Svbart@nginx.com     value->type = NXT_CONF_VALUE_ARRAY;
1684106Svbart@nginx.com 
1685106Svbart@nginx.com     array->count = count;
1686106Svbart@nginx.com     element = array->elements;
1687106Svbart@nginx.com 
1688106Svbart@nginx.com     nxt_list_each(value, list) {
1689106Svbart@nginx.com         *element++ = *value;
1690106Svbart@nginx.com     } nxt_list_loop;
1691106Svbart@nginx.com 
1692106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1693106Svbart@nginx.com 
1694106Svbart@nginx.com     return p + 1;
1695106Svbart@nginx.com 
1696106Svbart@nginx.com error:
1697106Svbart@nginx.com 
1698106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1699106Svbart@nginx.com     return NULL;
1700106Svbart@nginx.com }
1701106Svbart@nginx.com 
1702106Svbart@nginx.com 
1703106Svbart@nginx.com static u_char *
1704106Svbart@nginx.com nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1705208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1706106Svbart@nginx.com {
1707106Svbart@nginx.com     u_char      *p, ch, *last, *s;
1708106Svbart@nginx.com     size_t      size, surplus;
1709106Svbart@nginx.com     uint32_t    utf, utf_high;
1710106Svbart@nginx.com     nxt_uint_t  i;
1711106Svbart@nginx.com     enum {
1712106Svbart@nginx.com         sw_usual = 0,
1713106Svbart@nginx.com         sw_escape,
1714106Svbart@nginx.com         sw_encoded1,
1715106Svbart@nginx.com         sw_encoded2,
1716106Svbart@nginx.com         sw_encoded3,
1717106Svbart@nginx.com         sw_encoded4,
1718106Svbart@nginx.com     } state;
1719106Svbart@nginx.com 
1720106Svbart@nginx.com     start++;
1721106Svbart@nginx.com 
1722106Svbart@nginx.com     state = 0;
1723106Svbart@nginx.com     surplus = 0;
1724106Svbart@nginx.com 
1725106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1726106Svbart@nginx.com         ch = *p;
1727106Svbart@nginx.com 
1728106Svbart@nginx.com         switch (state) {
1729106Svbart@nginx.com 
1730106Svbart@nginx.com         case sw_usual:
1731106Svbart@nginx.com 
1732106Svbart@nginx.com             if (ch == '"') {
1733106Svbart@nginx.com                 break;
1734106Svbart@nginx.com             }
1735106Svbart@nginx.com 
1736106Svbart@nginx.com             if (ch == '\\') {
1737106Svbart@nginx.com                 state = sw_escape;
1738106Svbart@nginx.com                 continue;
1739106Svbart@nginx.com             }
1740106Svbart@nginx.com 
1741106Svbart@nginx.com             if (nxt_fast_path(ch >= ' ')) {
1742106Svbart@nginx.com                 continue;
1743106Svbart@nginx.com             }
1744106Svbart@nginx.com 
1745208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1746311Snick@nginx.com                 "Unexpected character.  All control characters in a JSON "
1747311Snick@nginx.com                 "string must be escaped."
1748208Svbart@nginx.com             );
1749208Svbart@nginx.com 
1750106Svbart@nginx.com             return NULL;
1751106Svbart@nginx.com 
1752106Svbart@nginx.com         case sw_escape:
1753106Svbart@nginx.com 
1754106Svbart@nginx.com             switch (ch) {
1755106Svbart@nginx.com             case '"':
1756106Svbart@nginx.com             case '\\':
1757106Svbart@nginx.com             case '/':
1758106Svbart@nginx.com             case 'n':
1759106Svbart@nginx.com             case 'r':
1760106Svbart@nginx.com             case 't':
1761106Svbart@nginx.com             case 'b':
1762106Svbart@nginx.com             case 'f':
1763106Svbart@nginx.com                 surplus++;
1764106Svbart@nginx.com                 state = sw_usual;
1765106Svbart@nginx.com                 continue;
1766106Svbart@nginx.com 
1767106Svbart@nginx.com             case 'u':
1768106Svbart@nginx.com                 /*
1769106Svbart@nginx.com                  * Basic unicode 6 bytes "\uXXXX" in JSON
1770106Svbart@nginx.com                  * and up to 3 bytes in UTF-8.
1771106Svbart@nginx.com                  *
1772106Svbart@nginx.com                  * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON
1773106Svbart@nginx.com                  * and 3 or 4 bytes in UTF-8.
1774106Svbart@nginx.com                  */
1775106Svbart@nginx.com                 surplus += 3;
1776106Svbart@nginx.com                 state = sw_encoded1;
1777106Svbart@nginx.com                 continue;
1778106Svbart@nginx.com             }
1779106Svbart@nginx.com 
1780208Svbart@nginx.com             nxt_conf_json_parse_error(error, p - 1,
1781311Snick@nginx.com                 "Unexpected backslash.  A literal backslash in a JSON string "
1782311Snick@nginx.com                 "must be escaped with a second backslash (\\\\)."
1783208Svbart@nginx.com             );
1784208Svbart@nginx.com 
1785106Svbart@nginx.com             return NULL;
1786106Svbart@nginx.com 
1787106Svbart@nginx.com         case sw_encoded1:
1788106Svbart@nginx.com         case sw_encoded2:
1789106Svbart@nginx.com         case sw_encoded3:
1790106Svbart@nginx.com         case sw_encoded4:
1791106Svbart@nginx.com 
1792106Svbart@nginx.com             if (nxt_fast_path((ch >= '0' && ch <= '9')
1793202Svbart@nginx.com                               || (ch >= 'A' && ch <= 'F')
1794202Svbart@nginx.com                               || (ch >= 'a' && ch <= 'f')))
1795106Svbart@nginx.com             {
1796106Svbart@nginx.com                 state = (state == sw_encoded4) ? sw_usual : state + 1;
1797106Svbart@nginx.com                 continue;
1798106Svbart@nginx.com             }
1799106Svbart@nginx.com 
1800208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1801311Snick@nginx.com                 "Invalid escape sequence.  An escape sequence in a JSON "
1802311Snick@nginx.com                 "string must start with a backslash, followed by the lowercase "
1803311Snick@nginx.com                 "letter u, followed by four hexadecimal digits (\\uXXXX)."
1804208Svbart@nginx.com             );
1805208Svbart@nginx.com 
1806106Svbart@nginx.com             return NULL;
1807106Svbart@nginx.com         }
1808106Svbart@nginx.com 
1809106Svbart@nginx.com         break;
1810106Svbart@nginx.com     }
1811106Svbart@nginx.com 
1812106Svbart@nginx.com     if (nxt_slow_path(p == end)) {
1813208Svbart@nginx.com 
1814208Svbart@nginx.com         nxt_conf_json_parse_error(error, p,
1815311Snick@nginx.com             "Unexpected end of JSON payload.  There's a string without "
1816311Snick@nginx.com             "a final double quote (\")."
1817208Svbart@nginx.com         );
1818208Svbart@nginx.com 
1819106Svbart@nginx.com         return NULL;
1820106Svbart@nginx.com     }
1821106Svbart@nginx.com 
1822106Svbart@nginx.com     /* Points to the ending quote mark. */
1823106Svbart@nginx.com     last = p;
1824106Svbart@nginx.com 
1825106Svbart@nginx.com     size = last - start - surplus;
1826106Svbart@nginx.com 
1827106Svbart@nginx.com     if (size > NXT_CONF_MAX_SHORT_STRING) {
1828172Svbart@nginx.com 
1829172Svbart@nginx.com         if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
1830208Svbart@nginx.com 
1831208Svbart@nginx.com             nxt_conf_json_parse_error(error, start,
1832311Snick@nginx.com                 "The string is too long.  Such a long JSON string value "
1833311Snick@nginx.com                 "is not supported."
1834208Svbart@nginx.com             );
1835208Svbart@nginx.com 
1836106Svbart@nginx.com             return NULL;
1837106Svbart@nginx.com         }
1838106Svbart@nginx.com 
1839172Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
1840172Svbart@nginx.com 
1841172Svbart@nginx.com         value->u.string.start = nxt_mp_nget(mp, size);
1842172Svbart@nginx.com         if (nxt_slow_path(value->u.string.start == NULL)) {
1843172Svbart@nginx.com             return NULL;
1844172Svbart@nginx.com         }
1845172Svbart@nginx.com 
1846172Svbart@nginx.com         value->u.string.length = size;
1847172Svbart@nginx.com 
1848172Svbart@nginx.com         s = value->u.string.start;
1849106Svbart@nginx.com 
1850106Svbart@nginx.com     } else {
1851116Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
1852173Svbart@nginx.com         value->u.str.length = size;
1853173Svbart@nginx.com 
1854173Svbart@nginx.com         s = value->u.str.start;
1855106Svbart@nginx.com     }
1856106Svbart@nginx.com 
1857106Svbart@nginx.com     if (surplus == 0) {
1858106Svbart@nginx.com         nxt_memcpy(s, start, size);
1859106Svbart@nginx.com         return last + 1;
1860106Svbart@nginx.com     }
1861106Svbart@nginx.com 
1862106Svbart@nginx.com     p = start;
1863106Svbart@nginx.com 
1864106Svbart@nginx.com     do {
1865106Svbart@nginx.com         ch = *p++;
1866106Svbart@nginx.com 
1867106Svbart@nginx.com         if (ch != '\\') {
1868106Svbart@nginx.com             *s++ = ch;
1869106Svbart@nginx.com             continue;
1870106Svbart@nginx.com         }
1871106Svbart@nginx.com 
1872106Svbart@nginx.com         ch = *p++;
1873106Svbart@nginx.com 
1874106Svbart@nginx.com         switch (ch) {
1875106Svbart@nginx.com         case '"':
1876106Svbart@nginx.com         case '\\':
1877106Svbart@nginx.com         case '/':
1878106Svbart@nginx.com             *s++ = ch;
1879106Svbart@nginx.com             continue;
1880106Svbart@nginx.com 
1881106Svbart@nginx.com         case 'n':
1882106Svbart@nginx.com             *s++ = '\n';
1883106Svbart@nginx.com             continue;
1884106Svbart@nginx.com 
1885106Svbart@nginx.com         case 'r':
1886106Svbart@nginx.com             *s++ = '\r';
1887106Svbart@nginx.com             continue;
1888106Svbart@nginx.com 
1889106Svbart@nginx.com         case 't':
1890106Svbart@nginx.com             *s++ = '\t';
1891106Svbart@nginx.com             continue;
1892106Svbart@nginx.com 
1893106Svbart@nginx.com         case 'b':
1894106Svbart@nginx.com             *s++ = '\b';
1895106Svbart@nginx.com             continue;
1896106Svbart@nginx.com 
1897106Svbart@nginx.com         case 'f':
1898106Svbart@nginx.com             *s++ = '\f';
1899106Svbart@nginx.com             continue;
1900106Svbart@nginx.com         }
1901106Svbart@nginx.com 
1902106Svbart@nginx.com         utf = 0;
1903106Svbart@nginx.com         utf_high = 0;
1904106Svbart@nginx.com 
1905106Svbart@nginx.com         for ( ;; ) {
1906106Svbart@nginx.com             for (i = 0; i < 4; i++) {
1907202Svbart@nginx.com                 utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A')
1908202Svbart@nginx.com                                                 : p[i] - '0');
1909106Svbart@nginx.com             }
1910106Svbart@nginx.com 
1911106Svbart@nginx.com             p += 4;
1912106Svbart@nginx.com 
1913207Svbart@nginx.com             if (utf_high != 0) {
1914611Svbart@nginx.com                 if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) {
1915208Svbart@nginx.com 
1916208Svbart@nginx.com                     nxt_conf_json_parse_error(error, p - 12,
1917311Snick@nginx.com                         "Invalid JSON encoding sequence.  This 12-byte "
1918311Snick@nginx.com                         "sequence composes an illegal UTF-16 surrogate pair."
1919208Svbart@nginx.com                     );
1920208Svbart@nginx.com 
1921207Svbart@nginx.com                     return NULL;
1922207Svbart@nginx.com                 }
1923207Svbart@nginx.com 
1924611Svbart@nginx.com                 utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000;
1925207Svbart@nginx.com 
1926106Svbart@nginx.com                 break;
1927106Svbart@nginx.com             }
1928106Svbart@nginx.com 
1929611Svbart@nginx.com             if (utf < 0xD800 || utf > 0xDFFF) {
1930106Svbart@nginx.com                 break;
1931106Svbart@nginx.com             }
1932106Svbart@nginx.com 
1933611Svbart@nginx.com             if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') {
1934208Svbart@nginx.com 
1935208Svbart@nginx.com                 nxt_conf_json_parse_error(error, p - 6,
1936311Snick@nginx.com                     "Invalid JSON encoding sequence.  This 6-byte sequence "
1937311Snick@nginx.com                     "does not represent a valid UTF character."
1938208Svbart@nginx.com                 );
1939208Svbart@nginx.com 
1940207Svbart@nginx.com                 return NULL;
1941207Svbart@nginx.com             }
1942207Svbart@nginx.com 
1943106Svbart@nginx.com             p += 2;
1944207Svbart@nginx.com 
1945207Svbart@nginx.com             utf_high = utf;
1946207Svbart@nginx.com             utf = 0;
1947106Svbart@nginx.com         }
1948106Svbart@nginx.com 
1949106Svbart@nginx.com         s = nxt_utf8_encode(s, utf);
1950106Svbart@nginx.com 
1951106Svbart@nginx.com     } while (p != last);
1952106Svbart@nginx.com 
1953106Svbart@nginx.com     if (size > NXT_CONF_MAX_SHORT_STRING) {
1954172Svbart@nginx.com         value->u.string.length = s - value->u.string.start;
1955106Svbart@nginx.com 
1956106Svbart@nginx.com     } else {
1957173Svbart@nginx.com         value->u.str.length = s - value->u.str.start;
1958106Svbart@nginx.com     }
1959106Svbart@nginx.com 
1960106Svbart@nginx.com     return last + 1;
1961106Svbart@nginx.com }
1962106Svbart@nginx.com 
1963106Svbart@nginx.com 
1964106Svbart@nginx.com static u_char *
1965106Svbart@nginx.com nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1966208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1967106Svbart@nginx.com {
1968106Svbart@nginx.com     u_char     *p, ch;
1969106Svbart@nginx.com     uint64_t   integer;
1970106Svbart@nginx.com     nxt_int_t  sign;
1971106Svbart@nginx.com #if 0
1972106Svbart@nginx.com     uint64_t   frac, power
1973106Svbart@nginx.com     nxt_int_t  e, negative;
1974106Svbart@nginx.com #endif
1975106Svbart@nginx.com 
1976106Svbart@nginx.com     static const uint64_t cutoff = NXT_INT64_T_MAX / 10;
1977106Svbart@nginx.com     static const uint64_t cutlim = NXT_INT64_T_MAX % 10;
1978106Svbart@nginx.com 
1979106Svbart@nginx.com     ch = *start;
1980106Svbart@nginx.com 
1981106Svbart@nginx.com     if (ch == '-') {
1982106Svbart@nginx.com         sign = -1;
1983106Svbart@nginx.com         start++;
1984106Svbart@nginx.com 
1985106Svbart@nginx.com     } else {
1986106Svbart@nginx.com         sign = 1;
1987106Svbart@nginx.com     }
1988106Svbart@nginx.com 
1989106Svbart@nginx.com     integer = 0;
1990106Svbart@nginx.com 
1991106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1992106Svbart@nginx.com         ch = *p;
1993106Svbart@nginx.com 
1994106Svbart@nginx.com         /* Values below '0' become >= 208. */
1995106Svbart@nginx.com         ch = ch - '0';
1996106Svbart@nginx.com 
1997106Svbart@nginx.com         if (ch > 9) {
1998106Svbart@nginx.com             break;
1999106Svbart@nginx.com         }
2000106Svbart@nginx.com 
2001106Svbart@nginx.com         if (nxt_slow_path(integer >= cutoff
2002106Svbart@nginx.com                           && (integer > cutoff || ch > cutlim)))
2003106Svbart@nginx.com         {
2004208Svbart@nginx.com             nxt_conf_json_parse_error(error, start,
2005311Snick@nginx.com                 "The integer is too large.  Such a large JSON integer value "
2006311Snick@nginx.com                 "is not supported."
2007208Svbart@nginx.com             );
2008208Svbart@nginx.com 
2009208Svbart@nginx.com             return NULL;
2010106Svbart@nginx.com         }
2011106Svbart@nginx.com 
2012106Svbart@nginx.com         integer = integer * 10 + ch;
2013106Svbart@nginx.com     }
2014106Svbart@nginx.com 
2015208Svbart@nginx.com     if (nxt_slow_path(p - start > 1 && *start == '0')) {
2016208Svbart@nginx.com 
2017208Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
2018311Snick@nginx.com             "The number is invalid.  Leading zeros are not allowed in JSON "
2019311Snick@nginx.com             "numbers."
2020208Svbart@nginx.com         );
2021208Svbart@nginx.com 
2022106Svbart@nginx.com         return NULL;
2023106Svbart@nginx.com     }
2024106Svbart@nginx.com 
2025106Svbart@nginx.com     if (ch != '.') {
2026116Svbart@nginx.com         value->type = NXT_CONF_VALUE_INTEGER;
2027106Svbart@nginx.com         value->u.integer = sign * integer;
2028106Svbart@nginx.com         return p;
2029106Svbart@nginx.com     }
2030106Svbart@nginx.com 
2031106Svbart@nginx.com #if 0
2032106Svbart@nginx.com     start = p + 1;
2033106Svbart@nginx.com 
2034106Svbart@nginx.com     frac = 0;
2035106Svbart@nginx.com     power = 1;
2036106Svbart@nginx.com 
2037106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
2038106Svbart@nginx.com         ch = *p;
2039106Svbart@nginx.com 
2040106Svbart@nginx.com         /* Values below '0' become >= 208. */
2041106Svbart@nginx.com         ch = ch - '0';
2042106Svbart@nginx.com 
2043106Svbart@nginx.com         if (ch > 9) {
2044106Svbart@nginx.com             break;
2045106Svbart@nginx.com         }
2046106Svbart@nginx.com 
2047106Svbart@nginx.com         if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim))
2048106Svbart@nginx.com                           || power > cutoff))
2049106Svbart@nginx.com         {
2050106Svbart@nginx.com             return NULL;
2051106Svbart@nginx.com         }
2052106Svbart@nginx.com 
2053106Svbart@nginx.com         frac = frac * 10 + ch;
2054106Svbart@nginx.com         power *= 10;
2055106Svbart@nginx.com     }
2056106Svbart@nginx.com 
2057106Svbart@nginx.com     if (nxt_slow_path(p == start)) {
2058106Svbart@nginx.com         return NULL;
2059106Svbart@nginx.com     }
2060106Svbart@nginx.com 
2061116Svbart@nginx.com     value->type = NXT_CONF_VALUE_NUMBER;
2062106Svbart@nginx.com     value->u.number = integer + (double) frac / power;
2063106Svbart@nginx.com 
2064106Svbart@nginx.com     value->u.number = copysign(value->u.number, sign);
2065106Svbart@nginx.com 
2066106Svbart@nginx.com     if (ch == 'e' || ch == 'E') {
2067106Svbart@nginx.com         start = p + 1;
2068106Svbart@nginx.com 
2069106Svbart@nginx.com         ch = *start;
2070106Svbart@nginx.com 
2071106Svbart@nginx.com         if (ch == '-' || ch == '+') {
2072106Svbart@nginx.com             start++;
2073106Svbart@nginx.com         }
2074106Svbart@nginx.com 
2075106Svbart@nginx.com         negative = (ch == '-') ? 1 : 0;
2076106Svbart@nginx.com         e = 0;
2077106Svbart@nginx.com 
2078106Svbart@nginx.com         for (p = start; nxt_fast_path(p != end); p++) {
2079106Svbart@nginx.com             ch = *p;
2080106Svbart@nginx.com 
2081106Svbart@nginx.com             /* Values below '0' become >= 208. */
2082106Svbart@nginx.com             ch = ch - '0';
2083106Svbart@nginx.com 
2084106Svbart@nginx.com             if (ch > 9) {
2085106Svbart@nginx.com                 break;
2086106Svbart@nginx.com             }
2087106Svbart@nginx.com 
2088106Svbart@nginx.com             e = e * 10 + ch;
2089106Svbart@nginx.com 
2090106Svbart@nginx.com             if (nxt_slow_path(e > DBL_MAX_10_EXP)) {
2091106Svbart@nginx.com                 return NULL;
2092106Svbart@nginx.com             }
2093106Svbart@nginx.com         }
2094106Svbart@nginx.com 
2095106Svbart@nginx.com         if (nxt_slow_path(p == start)) {
2096106Svbart@nginx.com             return NULL;
2097106Svbart@nginx.com         }
2098106Svbart@nginx.com 
2099106Svbart@nginx.com         if (negative) {
2100106Svbart@nginx.com             value->u.number /= exp10(e);
2101106Svbart@nginx.com 
2102106Svbart@nginx.com         } else {
2103106Svbart@nginx.com             value->u.number *= exp10(e);
2104106Svbart@nginx.com         }
2105106Svbart@nginx.com     }
2106106Svbart@nginx.com 
2107106Svbart@nginx.com     if (nxt_fast_path(isfinite(value->u.number))) {
2108106Svbart@nginx.com         return p;
2109106Svbart@nginx.com     }
2110208Svbart@nginx.com #else
2111208Svbart@nginx.com 
2112208Svbart@nginx.com     nxt_conf_json_parse_error(error, start,
2113311Snick@nginx.com         "The number is not an integer.  JSON numbers with decimals and "
2114311Snick@nginx.com         "exponents are not supported."
2115208Svbart@nginx.com     );
2116208Svbart@nginx.com 
2117106Svbart@nginx.com #endif
2118106Svbart@nginx.com 
2119106Svbart@nginx.com     return NULL;
2120106Svbart@nginx.com }
2121106Svbart@nginx.com 
2122106Svbart@nginx.com 
2123208Svbart@nginx.com static void
2124208Svbart@nginx.com nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
2125208Svbart@nginx.com     const char *detail)
2126208Svbart@nginx.com {
2127208Svbart@nginx.com     if (error == NULL) {
2128208Svbart@nginx.com         return;
2129208Svbart@nginx.com     }
2130208Svbart@nginx.com 
2131208Svbart@nginx.com     error->pos = pos;
2132208Svbart@nginx.com     error->detail = (u_char *) detail;
2133208Svbart@nginx.com }
2134208Svbart@nginx.com 
2135208Svbart@nginx.com 
2136106Svbart@nginx.com size_t
2137106Svbart@nginx.com nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
2138106Svbart@nginx.com {
2139106Svbart@nginx.com     switch (value->type) {
2140106Svbart@nginx.com 
2141116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
2142703Svbart@nginx.com         return nxt_length("null");
2143106Svbart@nginx.com 
2144116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
2145703Svbart@nginx.com         return value->u.boolean ? nxt_length("true") : nxt_length("false");
2146106Svbart@nginx.com 
2147116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
2148106Svbart@nginx.com         return nxt_conf_json_integer_length(value);
2149106Svbart@nginx.com 
2150116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
2151106Svbart@nginx.com         /* TODO */
2152106Svbart@nginx.com         return 0;
2153106Svbart@nginx.com 
2154116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
2155116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
2156106Svbart@nginx.com         return nxt_conf_json_string_length(value);
2157106Svbart@nginx.com 
2158116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
2159106Svbart@nginx.com         return nxt_conf_json_array_length(value, pretty);
2160106Svbart@nginx.com 
2161116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
2162106Svbart@nginx.com         return nxt_conf_json_object_length(value, pretty);
2163106Svbart@nginx.com     }
2164106Svbart@nginx.com 
2165106Svbart@nginx.com     nxt_unreachable();
2166106Svbart@nginx.com 
2167106Svbart@nginx.com     return 0;
2168106Svbart@nginx.com }
2169106Svbart@nginx.com 
2170106Svbart@nginx.com 
2171106Svbart@nginx.com u_char *
2172106Svbart@nginx.com nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
2173106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2174106Svbart@nginx.com {
2175106Svbart@nginx.com     switch (value->type) {
2176106Svbart@nginx.com 
2177116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
2178106Svbart@nginx.com         return nxt_cpymem(p, "null", 4);
2179106Svbart@nginx.com 
2180116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
2181106Svbart@nginx.com         return value->u.boolean ? nxt_cpymem(p, "true", 4)
2182106Svbart@nginx.com                                 : nxt_cpymem(p, "false", 5);
2183106Svbart@nginx.com 
2184116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
2185106Svbart@nginx.com         return nxt_conf_json_print_integer(p, value);
2186106Svbart@nginx.com 
2187116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
2188106Svbart@nginx.com         /* TODO */
2189106Svbart@nginx.com         return p;
2190106Svbart@nginx.com 
2191116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
2192116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
2193106Svbart@nginx.com         return nxt_conf_json_print_string(p, value);
2194106Svbart@nginx.com 
2195116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
2196106Svbart@nginx.com         return nxt_conf_json_print_array(p, value, pretty);
2197106Svbart@nginx.com 
2198116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
2199106Svbart@nginx.com         return nxt_conf_json_print_object(p, value, pretty);
2200106Svbart@nginx.com     }
2201106Svbart@nginx.com 
2202106Svbart@nginx.com     nxt_unreachable();
2203106Svbart@nginx.com 
2204106Svbart@nginx.com     return p;
2205106Svbart@nginx.com }
2206106Svbart@nginx.com 
2207106Svbart@nginx.com 
2208106Svbart@nginx.com static size_t
2209106Svbart@nginx.com nxt_conf_json_integer_length(nxt_conf_value_t *value)
2210106Svbart@nginx.com {
2211106Svbart@nginx.com     int64_t  num;
2212106Svbart@nginx.com 
2213106Svbart@nginx.com     num = llabs(value->u.integer);
2214106Svbart@nginx.com 
2215106Svbart@nginx.com     if (num <= 9999) {
2216703Svbart@nginx.com         return nxt_length("-9999");
2217106Svbart@nginx.com     }
2218106Svbart@nginx.com 
2219210Svbart@nginx.com     if (num <= 99999999999LL) {
2220703Svbart@nginx.com         return nxt_length("-99999999999");
2221106Svbart@nginx.com     }
2222106Svbart@nginx.com 
2223106Svbart@nginx.com     return NXT_INT64_T_LEN;
2224106Svbart@nginx.com }
2225106Svbart@nginx.com 
2226106Svbart@nginx.com 
2227106Svbart@nginx.com static u_char *
2228106Svbart@nginx.com nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value)
2229106Svbart@nginx.com {
2230106Svbart@nginx.com     return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer);
2231106Svbart@nginx.com }
2232106Svbart@nginx.com 
2233106Svbart@nginx.com 
2234106Svbart@nginx.com static size_t
2235106Svbart@nginx.com nxt_conf_json_string_length(nxt_conf_value_t *value)
2236106Svbart@nginx.com {
2237106Svbart@nginx.com     nxt_str_t  str;
2238106Svbart@nginx.com 
2239106Svbart@nginx.com     nxt_conf_get_string(value, &str);
2240106Svbart@nginx.com 
2241106Svbart@nginx.com     return 2 + nxt_conf_json_escape_length(str.start, str.length);
2242106Svbart@nginx.com }
2243106Svbart@nginx.com 
2244106Svbart@nginx.com 
2245106Svbart@nginx.com static u_char *
2246106Svbart@nginx.com nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value)
2247106Svbart@nginx.com {
2248106Svbart@nginx.com     nxt_str_t  str;
2249106Svbart@nginx.com 
2250106Svbart@nginx.com     nxt_conf_get_string(value, &str);
2251106Svbart@nginx.com 
2252106Svbart@nginx.com     *p++ = '"';
2253106Svbart@nginx.com 
2254106Svbart@nginx.com     p = nxt_conf_json_escape(p, str.start, str.length);
2255106Svbart@nginx.com 
2256106Svbart@nginx.com     *p++ = '"';
2257106Svbart@nginx.com 
2258106Svbart@nginx.com     return p;
2259106Svbart@nginx.com }
2260106Svbart@nginx.com 
2261106Svbart@nginx.com 
2262106Svbart@nginx.com static size_t
2263106Svbart@nginx.com nxt_conf_json_array_length(nxt_conf_value_t *value,
2264106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2265106Svbart@nginx.com {
2266106Svbart@nginx.com     size_t            len;
2267106Svbart@nginx.com     nxt_uint_t        n;
2268106Svbart@nginx.com     nxt_conf_array_t  *array;
2269106Svbart@nginx.com 
2270106Svbart@nginx.com     array = value->u.array;
2271106Svbart@nginx.com 
2272106Svbart@nginx.com     /* [] */
2273106Svbart@nginx.com     len = 2;
2274106Svbart@nginx.com 
2275106Svbart@nginx.com     if (pretty != NULL) {
2276106Svbart@nginx.com         pretty->level++;
2277106Svbart@nginx.com     }
2278106Svbart@nginx.com 
2279106Svbart@nginx.com     value = array->elements;
2280106Svbart@nginx.com 
2281106Svbart@nginx.com     for (n = 0; n < array->count; n++) {
2282106Svbart@nginx.com         len += nxt_conf_json_length(&value[n], pretty);
2283106Svbart@nginx.com 
2284106Svbart@nginx.com         if (pretty != NULL) {
2285106Svbart@nginx.com             /* Indentation and new line. */
2286106Svbart@nginx.com             len += pretty->level + 2;
2287106Svbart@nginx.com         }
2288106Svbart@nginx.com     }
2289106Svbart@nginx.com 
2290106Svbart@nginx.com     if (pretty != NULL) {
2291106Svbart@nginx.com         pretty->level--;
2292106Svbart@nginx.com 
2293106Svbart@nginx.com         if (n != 0) {
2294106Svbart@nginx.com             /* Indentation and new line. */
2295106Svbart@nginx.com             len += pretty->level + 2;
2296106Svbart@nginx.com         }
2297106Svbart@nginx.com     }
2298106Svbart@nginx.com 
2299106Svbart@nginx.com     /* Reserve space for "n" commas. */
2300106Svbart@nginx.com     return len + n;
2301106Svbart@nginx.com }
2302106Svbart@nginx.com 
2303106Svbart@nginx.com 
2304106Svbart@nginx.com static u_char *
2305106Svbart@nginx.com nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
2306106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2307106Svbart@nginx.com {
2308106Svbart@nginx.com     nxt_uint_t        n;
2309106Svbart@nginx.com     nxt_conf_array_t  *array;
2310106Svbart@nginx.com 
2311106Svbart@nginx.com     array = value->u.array;
2312106Svbart@nginx.com 
2313106Svbart@nginx.com     *p++ = '[';
2314106Svbart@nginx.com 
2315106Svbart@nginx.com     if (array->count != 0) {
2316106Svbart@nginx.com         value = array->elements;
2317106Svbart@nginx.com 
2318106Svbart@nginx.com         if (pretty != NULL) {
2319106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2320106Svbart@nginx.com 
2321106Svbart@nginx.com             pretty->level++;
2322106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2323106Svbart@nginx.com         }
2324106Svbart@nginx.com 
2325106Svbart@nginx.com         p = nxt_conf_json_print(p, &value[0], pretty);
2326106Svbart@nginx.com 
2327106Svbart@nginx.com         for (n = 1; n < array->count; n++) {
2328106Svbart@nginx.com             *p++ = ',';
2329106Svbart@nginx.com 
2330106Svbart@nginx.com             if (pretty != NULL) {
2331106Svbart@nginx.com                 p = nxt_conf_json_newline(p);
2332106Svbart@nginx.com                 p = nxt_conf_json_indentation(p, pretty->level);
2333106Svbart@nginx.com 
2334106Svbart@nginx.com                 pretty->more_space = 0;
2335106Svbart@nginx.com             }
2336106Svbart@nginx.com 
2337106Svbart@nginx.com             p = nxt_conf_json_print(p, &value[n], pretty);
2338106Svbart@nginx.com         }
2339106Svbart@nginx.com 
2340106Svbart@nginx.com         if (pretty != NULL) {
2341106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2342106Svbart@nginx.com 
2343106Svbart@nginx.com             pretty->level--;
2344106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2345106Svbart@nginx.com 
2346106Svbart@nginx.com             pretty->more_space = 1;
2347106Svbart@nginx.com         }
2348106Svbart@nginx.com     }
2349106Svbart@nginx.com 
2350106Svbart@nginx.com     *p++ = ']';
2351106Svbart@nginx.com 
2352106Svbart@nginx.com     return p;
2353106Svbart@nginx.com }
2354106Svbart@nginx.com 
2355106Svbart@nginx.com 
2356106Svbart@nginx.com static size_t
2357106Svbart@nginx.com nxt_conf_json_object_length(nxt_conf_value_t *value,
2358106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2359106Svbart@nginx.com {
2360106Svbart@nginx.com     size_t                    len;
2361106Svbart@nginx.com     nxt_uint_t                n;
2362106Svbart@nginx.com     nxt_conf_object_t         *object;
2363106Svbart@nginx.com     nxt_conf_object_member_t  *member;
2364106Svbart@nginx.com 
2365106Svbart@nginx.com     object = value->u.object;
2366106Svbart@nginx.com 
2367106Svbart@nginx.com     /* {} */
2368106Svbart@nginx.com     len = 2;
2369106Svbart@nginx.com 
2370106Svbart@nginx.com     if (pretty != NULL) {
2371106Svbart@nginx.com         pretty->level++;
2372106Svbart@nginx.com     }
2373106Svbart@nginx.com 
2374106Svbart@nginx.com     member = object->members;
2375106Svbart@nginx.com 
2376106Svbart@nginx.com     for (n = 0; n < object->count; n++) {
2377106Svbart@nginx.com         len += nxt_conf_json_string_length(&member[n].name) + 1
2378106Svbart@nginx.com                + nxt_conf_json_length(&member[n].value, pretty) + 1;
2379106Svbart@nginx.com 
2380106Svbart@nginx.com         if (pretty != NULL) {
2381106Svbart@nginx.com             /*
2382106Svbart@nginx.com              * Indentation, space after ":", new line, and possible
2383106Svbart@nginx.com              * additional empty line between non-empty objects.
2384106Svbart@nginx.com              */
2385106Svbart@nginx.com             len += pretty->level + 1 + 2 + 2;
2386106Svbart@nginx.com         }
2387106Svbart@nginx.com     }
2388106Svbart@nginx.com 
2389106Svbart@nginx.com     if (pretty != NULL) {
2390106Svbart@nginx.com         pretty->level--;
2391106Svbart@nginx.com 
2392106Svbart@nginx.com         /* Indentation and new line. */
2393106Svbart@nginx.com         len += pretty->level + 2;
2394106Svbart@nginx.com     }
2395106Svbart@nginx.com 
2396106Svbart@nginx.com     return len;
2397106Svbart@nginx.com }
2398106Svbart@nginx.com 
2399106Svbart@nginx.com 
2400106Svbart@nginx.com static u_char *
2401106Svbart@nginx.com nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
2402106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2403106Svbart@nginx.com {
2404106Svbart@nginx.com     nxt_uint_t                n;
2405106Svbart@nginx.com     nxt_conf_object_t         *object;
2406106Svbart@nginx.com     nxt_conf_object_member_t  *member;
2407106Svbart@nginx.com 
2408106Svbart@nginx.com     object = value->u.object;
2409106Svbart@nginx.com 
2410106Svbart@nginx.com     *p++ = '{';
2411106Svbart@nginx.com 
2412106Svbart@nginx.com     if (object->count != 0) {
2413106Svbart@nginx.com 
2414106Svbart@nginx.com         if (pretty != NULL) {
2415106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2416106Svbart@nginx.com             pretty->level++;
2417106Svbart@nginx.com         }
2418106Svbart@nginx.com 
2419106Svbart@nginx.com         member = object->members;
2420106Svbart@nginx.com 
2421106Svbart@nginx.com         n = 0;
2422106Svbart@nginx.com 
2423106Svbart@nginx.com         for ( ;; ) {
2424106Svbart@nginx.com             if (pretty != NULL) {
2425106Svbart@nginx.com                 p = nxt_conf_json_indentation(p, pretty->level);
2426106Svbart@nginx.com             }
2427106Svbart@nginx.com 
2428106Svbart@nginx.com             p = nxt_conf_json_print_string(p, &member[n].name);
2429106Svbart@nginx.com 
2430106Svbart@nginx.com             *p++ = ':';
2431106Svbart@nginx.com 
2432106Svbart@nginx.com             if (pretty != NULL) {
2433106Svbart@nginx.com                 *p++ = ' ';
2434106Svbart@nginx.com             }
2435106Svbart@nginx.com 
2436106Svbart@nginx.com             p = nxt_conf_json_print(p, &member[n].value, pretty);
2437106Svbart@nginx.com 
2438106Svbart@nginx.com             n++;
2439106Svbart@nginx.com 
2440106Svbart@nginx.com             if (n == object->count) {
2441106Svbart@nginx.com                 break;
2442106Svbart@nginx.com             }
2443106Svbart@nginx.com 
2444106Svbart@nginx.com             *p++ = ',';
2445106Svbart@nginx.com 
2446106Svbart@nginx.com             if (pretty != NULL) {
2447106Svbart@nginx.com                 p = nxt_conf_json_newline(p);
2448106Svbart@nginx.com 
2449106Svbart@nginx.com                 if (pretty->more_space) {
2450106Svbart@nginx.com                     pretty->more_space = 0;
2451106Svbart@nginx.com                     p = nxt_conf_json_newline(p);
2452106Svbart@nginx.com                 }
2453106Svbart@nginx.com             }
2454106Svbart@nginx.com         }
2455106Svbart@nginx.com 
2456106Svbart@nginx.com         if (pretty != NULL) {
2457106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2458106Svbart@nginx.com 
2459106Svbart@nginx.com             pretty->level--;
2460106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2461106Svbart@nginx.com 
2462106Svbart@nginx.com             pretty->more_space = 1;
2463106Svbart@nginx.com         }
2464106Svbart@nginx.com     }
2465106Svbart@nginx.com 
2466106Svbart@nginx.com     *p++ = '}';
2467106Svbart@nginx.com 
2468106Svbart@nginx.com     return p;
2469106Svbart@nginx.com }
2470106Svbart@nginx.com 
2471106Svbart@nginx.com 
2472106Svbart@nginx.com static size_t
2473106Svbart@nginx.com nxt_conf_json_escape_length(u_char *p, size_t size)
2474106Svbart@nginx.com {
2475106Svbart@nginx.com     u_char  ch;
2476106Svbart@nginx.com     size_t  len;
2477106Svbart@nginx.com 
2478106Svbart@nginx.com     len = size;
2479106Svbart@nginx.com 
2480106Svbart@nginx.com     while (size) {
2481106Svbart@nginx.com         ch = *p++;
2482106Svbart@nginx.com 
2483106Svbart@nginx.com         if (ch == '\\' || ch == '"') {
2484106Svbart@nginx.com             len++;
2485106Svbart@nginx.com 
2486611Svbart@nginx.com         } else if (ch <= 0x1F) {
2487106Svbart@nginx.com 
2488106Svbart@nginx.com             switch (ch) {
2489106Svbart@nginx.com             case '\n':
2490106Svbart@nginx.com             case '\r':
2491106Svbart@nginx.com             case '\t':
2492106Svbart@nginx.com             case '\b':
2493106Svbart@nginx.com             case '\f':
2494106Svbart@nginx.com                 len++;
2495106Svbart@nginx.com                 break;
2496106Svbart@nginx.com 
2497106Svbart@nginx.com             default:
2498106Svbart@nginx.com                 len += sizeof("\\u001F") - 2;
2499106Svbart@nginx.com             }
2500106Svbart@nginx.com         }
2501106Svbart@nginx.com 
2502106Svbart@nginx.com         size--;
2503106Svbart@nginx.com     }
2504106Svbart@nginx.com 
2505106Svbart@nginx.com     return len;
2506106Svbart@nginx.com }
2507106Svbart@nginx.com 
2508106Svbart@nginx.com 
2509106Svbart@nginx.com static u_char *
2510106Svbart@nginx.com nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
2511106Svbart@nginx.com {
2512106Svbart@nginx.com     u_char  ch;
2513106Svbart@nginx.com 
2514106Svbart@nginx.com     while (size) {
2515106Svbart@nginx.com         ch = *src++;
2516106Svbart@nginx.com 
2517611Svbart@nginx.com         if (ch > 0x1F) {
2518106Svbart@nginx.com 
2519106Svbart@nginx.com             if (ch == '\\' || ch == '"') {
2520106Svbart@nginx.com                 *dst++ = '\\';
2521106Svbart@nginx.com             }
2522106Svbart@nginx.com 
2523106Svbart@nginx.com             *dst++ = ch;
2524106Svbart@nginx.com 
2525106Svbart@nginx.com         } else {
2526106Svbart@nginx.com             *dst++ = '\\';
2527106Svbart@nginx.com 
2528106Svbart@nginx.com             switch (ch) {
2529106Svbart@nginx.com             case '\n':
2530106Svbart@nginx.com                 *dst++ = 'n';
2531106Svbart@nginx.com                 break;
2532106Svbart@nginx.com 
2533106Svbart@nginx.com             case '\r':
2534106Svbart@nginx.com                 *dst++ = 'r';
2535106Svbart@nginx.com                 break;
2536106Svbart@nginx.com 
2537106Svbart@nginx.com             case '\t':
2538106Svbart@nginx.com                 *dst++ = 't';
2539106Svbart@nginx.com                 break;
2540106Svbart@nginx.com 
2541106Svbart@nginx.com             case '\b':
2542106Svbart@nginx.com                 *dst++ = 'b';
2543106Svbart@nginx.com                 break;
2544106Svbart@nginx.com 
2545106Svbart@nginx.com             case '\f':
2546106Svbart@nginx.com                 *dst++ = 'f';
2547106Svbart@nginx.com                 break;
2548106Svbart@nginx.com 
2549106Svbart@nginx.com             default:
2550106Svbart@nginx.com                 *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
2551106Svbart@nginx.com                 *dst++ = '0' + (ch >> 4);
2552106Svbart@nginx.com 
2553611Svbart@nginx.com                 ch &= 0xF;
2554106Svbart@nginx.com 
2555106Svbart@nginx.com                 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
2556106Svbart@nginx.com             }
2557106Svbart@nginx.com         }
2558106Svbart@nginx.com 
2559106Svbart@nginx.com         size--;
2560106Svbart@nginx.com     }
2561106Svbart@nginx.com 
2562106Svbart@nginx.com     return dst;
2563106Svbart@nginx.com }
2564208Svbart@nginx.com 
2565208Svbart@nginx.com 
2566208Svbart@nginx.com void
2567208Svbart@nginx.com nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line,
2568208Svbart@nginx.com     nxt_uint_t *column)
2569208Svbart@nginx.com {
2570208Svbart@nginx.com     u_char      *p;
2571208Svbart@nginx.com     ssize_t     symbols;
2572208Svbart@nginx.com     nxt_uint_t  lines;
2573208Svbart@nginx.com 
2574208Svbart@nginx.com     lines = 1;
2575208Svbart@nginx.com 
2576208Svbart@nginx.com     for (p = start; p != pos; p++) {
2577208Svbart@nginx.com 
2578208Svbart@nginx.com         if (*p != '\n') {
2579208Svbart@nginx.com             continue;
2580208Svbart@nginx.com         }
2581208Svbart@nginx.com 
2582208Svbart@nginx.com         lines++;
2583208Svbart@nginx.com         start = p + 1;
2584208Svbart@nginx.com     }
2585208Svbart@nginx.com 
2586208Svbart@nginx.com     symbols = nxt_utf8_length(start, p - start);
2587208Svbart@nginx.com 
2588208Svbart@nginx.com     if (symbols != -1) {
2589208Svbart@nginx.com         *line = lines;
2590208Svbart@nginx.com         *column = 1 + symbols;
2591208Svbart@nginx.com     }
2592208Svbart@nginx.com }
2593