xref: /unit/src/nxt_conf.c (revision 507)
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 
19106Svbart@nginx.com 
20106Svbart@nginx.com typedef enum {
21116Svbart@nginx.com     NXT_CONF_VALUE_NULL = 0,
22116Svbart@nginx.com     NXT_CONF_VALUE_BOOLEAN,
23116Svbart@nginx.com     NXT_CONF_VALUE_INTEGER,
24116Svbart@nginx.com     NXT_CONF_VALUE_NUMBER,
25116Svbart@nginx.com     NXT_CONF_VALUE_SHORT_STRING,
26116Svbart@nginx.com     NXT_CONF_VALUE_STRING,
27116Svbart@nginx.com     NXT_CONF_VALUE_ARRAY,
28116Svbart@nginx.com     NXT_CONF_VALUE_OBJECT,
29116Svbart@nginx.com } nxt_conf_value_type_t;
30106Svbart@nginx.com 
31106Svbart@nginx.com 
32106Svbart@nginx.com typedef enum {
33106Svbart@nginx.com     NXT_CONF_OP_PASS = 0,
34106Svbart@nginx.com     NXT_CONF_OP_CREATE,
35106Svbart@nginx.com     NXT_CONF_OP_REPLACE,
36106Svbart@nginx.com     NXT_CONF_OP_DELETE,
37106Svbart@nginx.com } nxt_conf_op_action_t;
38106Svbart@nginx.com 
39106Svbart@nginx.com 
40106Svbart@nginx.com typedef struct nxt_conf_array_s   nxt_conf_array_t;
41106Svbart@nginx.com typedef struct nxt_conf_object_s  nxt_conf_object_t;
42106Svbart@nginx.com 
43106Svbart@nginx.com 
44180Smax.romanov@nginx.com struct nxt_conf_value_s {
45187Smax.romanov@nginx.com     union {
46171Svbart@nginx.com         uint8_t               boolean;  /* 1 bit. */
47106Svbart@nginx.com         int64_t               integer;
48106Svbart@nginx.com         double                number;
49173Svbart@nginx.com 
50173Svbart@nginx.com         struct {
51208Svbart@nginx.com             u_char            start[NXT_CONF_MAX_SHORT_STRING];
52173Svbart@nginx.com             uint8_t           length;
53173Svbart@nginx.com         } str;
54172Svbart@nginx.com 
55187Smax.romanov@nginx.com         struct {
56172Svbart@nginx.com             u_char            *start;
57172Svbart@nginx.com             uint32_t          length;
58187Smax.romanov@nginx.com         } nxt_packed string;
59172Svbart@nginx.com 
60106Svbart@nginx.com         nxt_conf_array_t      *array;
61106Svbart@nginx.com         nxt_conf_object_t     *object;
62187Smax.romanov@nginx.com     } nxt_packed u;
63106Svbart@nginx.com 
64171Svbart@nginx.com     uint8_t                   type;  /* 3 bits. */
65180Smax.romanov@nginx.com } nxt_aligned(8);
66106Svbart@nginx.com 
67106Svbart@nginx.com 
68106Svbart@nginx.com struct nxt_conf_array_s {
69106Svbart@nginx.com     nxt_uint_t                count;
70106Svbart@nginx.com     nxt_conf_value_t          elements[];
71106Svbart@nginx.com };
72106Svbart@nginx.com 
73106Svbart@nginx.com 
74106Svbart@nginx.com typedef struct {
75106Svbart@nginx.com     nxt_conf_value_t          name;
76106Svbart@nginx.com     nxt_conf_value_t          value;
77106Svbart@nginx.com } nxt_conf_object_member_t;
78106Svbart@nginx.com 
79106Svbart@nginx.com 
80106Svbart@nginx.com struct nxt_conf_object_s {
81106Svbart@nginx.com     nxt_uint_t                count;
82106Svbart@nginx.com     nxt_conf_object_member_t  members[];
83106Svbart@nginx.com };
84106Svbart@nginx.com 
85106Svbart@nginx.com 
86106Svbart@nginx.com struct nxt_conf_op_s {
87106Svbart@nginx.com     uint32_t                  index;
88106Svbart@nginx.com     uint32_t                  action;  /* nxt_conf_op_action_t */
89106Svbart@nginx.com     void                      *ctx;
90106Svbart@nginx.com     nxt_conf_op_t             *next;
91106Svbart@nginx.com };
92106Svbart@nginx.com 
93106Svbart@nginx.com 
94106Svbart@nginx.com static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end);
95106Svbart@nginx.com static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
96208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
97106Svbart@nginx.com static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
98208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
99106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
100106Svbart@nginx.com     nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
101106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
102106Svbart@nginx.com     void *data);
103106Svbart@nginx.com static void *nxt_conf_object_hash_alloc(void *data, size_t size);
104106Svbart@nginx.com static void nxt_conf_object_hash_free(void *data, void *p);
105106Svbart@nginx.com static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
106208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
107106Svbart@nginx.com static u_char *nxt_conf_json_parse_string(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_number(nxt_mp_t *mp, nxt_conf_value_t *value,
110208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
111208Svbart@nginx.com static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
112208Svbart@nginx.com     const char *detail);
113106Svbart@nginx.com 
114106Svbart@nginx.com static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
115106Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
116106Svbart@nginx.com static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op,
117106Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
118106Svbart@nginx.com 
119106Svbart@nginx.com static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value);
120106Svbart@nginx.com static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value);
121106Svbart@nginx.com static size_t nxt_conf_json_string_length(nxt_conf_value_t *value);
122106Svbart@nginx.com static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value);
123106Svbart@nginx.com static size_t nxt_conf_json_array_length(nxt_conf_value_t *value,
124106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
125106Svbart@nginx.com static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
126106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
127106Svbart@nginx.com static size_t nxt_conf_json_object_length(nxt_conf_value_t *value,
128106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
129106Svbart@nginx.com static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
130106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
131106Svbart@nginx.com 
132106Svbart@nginx.com static size_t nxt_conf_json_escape_length(u_char *p, size_t size);
133106Svbart@nginx.com static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
134106Svbart@nginx.com 
135106Svbart@nginx.com 
136106Svbart@nginx.com #define nxt_conf_json_newline(p)                                              \
137106Svbart@nginx.com     ((p)[0] = '\r', (p)[1] = '\n', (p) + 2)
138106Svbart@nginx.com 
139106Svbart@nginx.com 
140106Svbart@nginx.com nxt_inline u_char *
141106Svbart@nginx.com nxt_conf_json_indentation(u_char *p, uint32_t level)
142106Svbart@nginx.com {
143106Svbart@nginx.com     while (level) {
144106Svbart@nginx.com         *p++ = '\t';
145106Svbart@nginx.com         level--;
146106Svbart@nginx.com     }
147106Svbart@nginx.com 
148106Svbart@nginx.com     return p;
149106Svbart@nginx.com }
150106Svbart@nginx.com 
151106Svbart@nginx.com 
152121Svbart@nginx.com void
153106Svbart@nginx.com nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
154106Svbart@nginx.com {
155116Svbart@nginx.com     if (value->type == NXT_CONF_VALUE_SHORT_STRING) {
156173Svbart@nginx.com         str->length = value->u.str.length;
157173Svbart@nginx.com         str->start = value->u.str.start;
158106Svbart@nginx.com 
159106Svbart@nginx.com     } else {
160172Svbart@nginx.com         str->length = value->u.string.length;
161172Svbart@nginx.com         str->start = value->u.string.start;
162106Svbart@nginx.com     }
163106Svbart@nginx.com }
164106Svbart@nginx.com 
165106Svbart@nginx.com 
166*507Smax.romanov@nginx.com int64_t
167*507Smax.romanov@nginx.com nxt_conf_get_integer(nxt_conf_value_t *value)
168*507Smax.romanov@nginx.com {
169*507Smax.romanov@nginx.com     return value->u.integer;
170*507Smax.romanov@nginx.com }
171*507Smax.romanov@nginx.com 
172*507Smax.romanov@nginx.com 
173116Svbart@nginx.com nxt_uint_t
174121Svbart@nginx.com nxt_conf_object_members_count(nxt_conf_value_t *value)
175121Svbart@nginx.com {
176121Svbart@nginx.com     return value->u.object->count;
177121Svbart@nginx.com }
178121Svbart@nginx.com 
179121Svbart@nginx.com 
180121Svbart@nginx.com nxt_conf_value_t *
181121Svbart@nginx.com nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count)
182121Svbart@nginx.com {
183121Svbart@nginx.com     size_t            size;
184121Svbart@nginx.com     nxt_conf_value_t  *value;
185121Svbart@nginx.com 
186121Svbart@nginx.com     size = sizeof(nxt_conf_value_t)
187121Svbart@nginx.com            + sizeof(nxt_conf_object_t)
188121Svbart@nginx.com            + count * sizeof(nxt_conf_object_member_t);
189121Svbart@nginx.com 
190121Svbart@nginx.com     value = nxt_mp_get(mp, size);
191121Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
192121Svbart@nginx.com         return NULL;
193121Svbart@nginx.com     }
194121Svbart@nginx.com 
195121Svbart@nginx.com     value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
196121Svbart@nginx.com     value->u.object->count = count;
197121Svbart@nginx.com 
198121Svbart@nginx.com     value->type = NXT_CONF_VALUE_OBJECT;
199121Svbart@nginx.com 
200121Svbart@nginx.com     return value;
201121Svbart@nginx.com }
202121Svbart@nginx.com 
203121Svbart@nginx.com 
204208Svbart@nginx.com void
205208Svbart@nginx.com nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
206172Svbart@nginx.com     nxt_conf_value_t *value, uint32_t index)
207121Svbart@nginx.com {
208121Svbart@nginx.com     nxt_conf_value_t          *name_value;
209121Svbart@nginx.com     nxt_conf_object_member_t  *member;
210121Svbart@nginx.com 
211121Svbart@nginx.com     member = &object->u.object->members[index];
212121Svbart@nginx.com     name_value = &member->name;
213121Svbart@nginx.com 
214121Svbart@nginx.com     if (name->length > NXT_CONF_MAX_SHORT_STRING) {
215121Svbart@nginx.com         name_value->type = NXT_CONF_VALUE_STRING;
216172Svbart@nginx.com         name_value->u.string.length = name->length;
217172Svbart@nginx.com         name_value->u.string.start = name->start;
218121Svbart@nginx.com 
219121Svbart@nginx.com     } else {
220121Svbart@nginx.com         name_value->type = NXT_CONF_VALUE_SHORT_STRING;
221173Svbart@nginx.com         name_value->u.str.length = name->length;
222173Svbart@nginx.com 
223173Svbart@nginx.com         nxt_memcpy(name_value->u.str.start, name->start, name->length);
224121Svbart@nginx.com     }
225121Svbart@nginx.com 
226121Svbart@nginx.com     member->value = *value;
227208Svbart@nginx.com }
228208Svbart@nginx.com 
229208Svbart@nginx.com 
230208Svbart@nginx.com void
231208Svbart@nginx.com nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
232208Svbart@nginx.com     nxt_str_t *value, uint32_t index)
233208Svbart@nginx.com {
234208Svbart@nginx.com     nxt_conf_value_t          *set;
235208Svbart@nginx.com     nxt_conf_object_member_t  *member;
236208Svbart@nginx.com 
237208Svbart@nginx.com     member = &object->u.object->members[index];
238208Svbart@nginx.com     set = &member->name;
239208Svbart@nginx.com 
240208Svbart@nginx.com     if (name->length > NXT_CONF_MAX_SHORT_STRING) {
241208Svbart@nginx.com         set->type = NXT_CONF_VALUE_STRING;
242208Svbart@nginx.com         set->u.string.length = name->length;
243208Svbart@nginx.com         set->u.string.start = name->start;
244208Svbart@nginx.com 
245208Svbart@nginx.com     } else {
246208Svbart@nginx.com         set->type = NXT_CONF_VALUE_SHORT_STRING;
247208Svbart@nginx.com         set->u.str.length = name->length;
248208Svbart@nginx.com 
249208Svbart@nginx.com         nxt_memcpy(set->u.str.start, name->start, name->length);
250208Svbart@nginx.com     }
251208Svbart@nginx.com 
252208Svbart@nginx.com     set = &member->value;
253208Svbart@nginx.com 
254208Svbart@nginx.com     if (value->length > NXT_CONF_MAX_SHORT_STRING) {
255208Svbart@nginx.com         set->type = NXT_CONF_VALUE_STRING;
256208Svbart@nginx.com         set->u.string.length = value->length;
257208Svbart@nginx.com         set->u.string.start = value->start;
258208Svbart@nginx.com 
259208Svbart@nginx.com     } else {
260208Svbart@nginx.com         set->type = NXT_CONF_VALUE_SHORT_STRING;
261208Svbart@nginx.com         set->u.str.length = value->length;
262208Svbart@nginx.com 
263208Svbart@nginx.com         nxt_memcpy(set->u.str.start, value->start, value->length);
264208Svbart@nginx.com     }
265208Svbart@nginx.com }
266208Svbart@nginx.com 
267208Svbart@nginx.com 
268208Svbart@nginx.com void
269208Svbart@nginx.com nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
270208Svbart@nginx.com     int64_t value, uint32_t index)
271208Svbart@nginx.com {
272208Svbart@nginx.com     nxt_conf_value_t          *name_value;
273208Svbart@nginx.com     nxt_conf_object_member_t  *member;
274208Svbart@nginx.com 
275208Svbart@nginx.com     member = &object->u.object->members[index];
276208Svbart@nginx.com     name_value = &member->name;
277208Svbart@nginx.com 
278208Svbart@nginx.com     if (name->length > NXT_CONF_MAX_SHORT_STRING) {
279208Svbart@nginx.com         name_value->type = NXT_CONF_VALUE_STRING;
280208Svbart@nginx.com         name_value->u.string.length = name->length;
281208Svbart@nginx.com         name_value->u.string.start = name->start;
282208Svbart@nginx.com 
283208Svbart@nginx.com     } else {
284208Svbart@nginx.com         name_value->type = NXT_CONF_VALUE_SHORT_STRING;
285208Svbart@nginx.com         name_value->u.str.length = name->length;
286208Svbart@nginx.com 
287208Svbart@nginx.com         nxt_memcpy(name_value->u.str.start, name->start, name->length);
288208Svbart@nginx.com     }
289208Svbart@nginx.com 
290208Svbart@nginx.com     member->value.u.integer = value;
291208Svbart@nginx.com     member->value.type = NXT_CONF_VALUE_INTEGER;
292121Svbart@nginx.com }
293121Svbart@nginx.com 
294121Svbart@nginx.com 
295121Svbart@nginx.com nxt_uint_t
296116Svbart@nginx.com nxt_conf_type(nxt_conf_value_t *value)
297116Svbart@nginx.com {
298116Svbart@nginx.com     switch (value->type) {
299116Svbart@nginx.com 
300116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
301116Svbart@nginx.com         return NXT_CONF_NULL;
302116Svbart@nginx.com 
303116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
304116Svbart@nginx.com         return NXT_CONF_BOOLEAN;
305116Svbart@nginx.com 
306116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
307116Svbart@nginx.com         return NXT_CONF_INTEGER;
308116Svbart@nginx.com 
309116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
310116Svbart@nginx.com         return NXT_CONF_NUMBER;
311116Svbart@nginx.com 
312116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
313116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
314116Svbart@nginx.com         return NXT_CONF_STRING;
315116Svbart@nginx.com 
316116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
317116Svbart@nginx.com         return NXT_CONF_ARRAY;
318116Svbart@nginx.com 
319116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
320116Svbart@nginx.com         return NXT_CONF_OBJECT;
321116Svbart@nginx.com     }
322116Svbart@nginx.com 
323116Svbart@nginx.com     nxt_unreachable();
324116Svbart@nginx.com 
325116Svbart@nginx.com     return 0;
326116Svbart@nginx.com }
327116Svbart@nginx.com 
328116Svbart@nginx.com 
329106Svbart@nginx.com typedef struct {
330106Svbart@nginx.com     u_char      *start;
331106Svbart@nginx.com     u_char      *end;
332106Svbart@nginx.com     nxt_bool_t  last;
333106Svbart@nginx.com } nxt_conf_path_parse_t;
334106Svbart@nginx.com 
335106Svbart@nginx.com 
336106Svbart@nginx.com static void nxt_conf_path_next_token(nxt_conf_path_parse_t *parse,
337106Svbart@nginx.com     nxt_str_t *token);
338106Svbart@nginx.com 
339106Svbart@nginx.com 
340106Svbart@nginx.com nxt_conf_value_t *
341106Svbart@nginx.com nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path)
342106Svbart@nginx.com {
343106Svbart@nginx.com     nxt_str_t              token;
344106Svbart@nginx.com     nxt_conf_path_parse_t  parse;
345106Svbart@nginx.com 
346106Svbart@nginx.com     parse.start = path->start;
347106Svbart@nginx.com     parse.end = path->start + path->length;
348106Svbart@nginx.com     parse.last = 0;
349106Svbart@nginx.com 
350106Svbart@nginx.com     do {
351106Svbart@nginx.com         nxt_conf_path_next_token(&parse, &token);
352106Svbart@nginx.com 
353106Svbart@nginx.com         if (token.length == 0) {
354106Svbart@nginx.com 
355106Svbart@nginx.com             if (parse.last) {
356106Svbart@nginx.com                 break;
357106Svbart@nginx.com             }
358106Svbart@nginx.com 
359106Svbart@nginx.com             return NULL;
360106Svbart@nginx.com         }
361106Svbart@nginx.com 
362106Svbart@nginx.com         value = nxt_conf_get_object_member(value, &token, NULL);
363106Svbart@nginx.com 
364106Svbart@nginx.com         if (value == NULL) {
365106Svbart@nginx.com             return NULL;
366106Svbart@nginx.com         }
367106Svbart@nginx.com 
368106Svbart@nginx.com     } while (parse.last == 0);
369106Svbart@nginx.com 
370106Svbart@nginx.com     return value;
371106Svbart@nginx.com }
372106Svbart@nginx.com 
373106Svbart@nginx.com 
374106Svbart@nginx.com static void
375106Svbart@nginx.com nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token)
376106Svbart@nginx.com {
377106Svbart@nginx.com     u_char  *p, *end;
378106Svbart@nginx.com 
379106Svbart@nginx.com     end = parse->end;
380106Svbart@nginx.com     p = parse->start + 1;
381106Svbart@nginx.com 
382106Svbart@nginx.com     token->start = p;
383106Svbart@nginx.com 
384106Svbart@nginx.com     while (p < end && *p != '/') {
385106Svbart@nginx.com         p++;
386106Svbart@nginx.com     }
387106Svbart@nginx.com 
388106Svbart@nginx.com     parse->start = p;
389106Svbart@nginx.com     parse->last = (p >= end);
390106Svbart@nginx.com 
391106Svbart@nginx.com     token->length = p - token->start;
392106Svbart@nginx.com }
393106Svbart@nginx.com 
394106Svbart@nginx.com 
395106Svbart@nginx.com nxt_conf_value_t *
396106Svbart@nginx.com nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name,
397106Svbart@nginx.com     uint32_t *index)
398106Svbart@nginx.com {
399106Svbart@nginx.com     nxt_str_t                 str;
400106Svbart@nginx.com     nxt_uint_t                n;
401106Svbart@nginx.com     nxt_conf_object_t         *object;
402106Svbart@nginx.com     nxt_conf_object_member_t  *member;
403106Svbart@nginx.com 
404116Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_OBJECT) {
405106Svbart@nginx.com         return NULL;
406106Svbart@nginx.com     }
407106Svbart@nginx.com 
408106Svbart@nginx.com     object = value->u.object;
409106Svbart@nginx.com 
410106Svbart@nginx.com     for (n = 0; n < object->count; n++) {
411106Svbart@nginx.com         member = &object->members[n];
412106Svbart@nginx.com 
413106Svbart@nginx.com         nxt_conf_get_string(&member->name, &str);
414106Svbart@nginx.com 
415106Svbart@nginx.com         if (nxt_strstr_eq(&str, name)) {
416106Svbart@nginx.com 
417106Svbart@nginx.com             if (index != NULL) {
418106Svbart@nginx.com                 *index = n;
419106Svbart@nginx.com             }
420106Svbart@nginx.com 
421106Svbart@nginx.com             return &member->value;
422106Svbart@nginx.com         }
423106Svbart@nginx.com     }
424106Svbart@nginx.com 
425106Svbart@nginx.com     return NULL;
426106Svbart@nginx.com }
427106Svbart@nginx.com 
428106Svbart@nginx.com 
429106Svbart@nginx.com nxt_int_t
430213Svbart@nginx.com nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map,
431213Svbart@nginx.com     nxt_uint_t n, void *data)
432106Svbart@nginx.com {
433213Svbart@nginx.com     nxt_str_t         str, *s;
434106Svbart@nginx.com     nxt_uint_t        i;
435106Svbart@nginx.com     nxt_conf_value_t  *v;
436106Svbart@nginx.com 
437106Svbart@nginx.com     union {
438111Sigor@sysoev.ru         uint8_t     ui8;
439111Sigor@sysoev.ru         int32_t     i32;
440111Sigor@sysoev.ru         int64_t     i64;
441111Sigor@sysoev.ru         nxt_int_t   i;
442111Sigor@sysoev.ru         ssize_t     size;
443111Sigor@sysoev.ru         off_t       off;
444111Sigor@sysoev.ru         nxt_msec_t  msec;
445111Sigor@sysoev.ru         double      dbl;
446111Sigor@sysoev.ru         nxt_str_t   str;
447213Svbart@nginx.com         char        *cstrz;
448111Sigor@sysoev.ru         void        *v;
449106Svbart@nginx.com     } *ptr;
450106Svbart@nginx.com 
451136Svbart@nginx.com     for (i = 0; i < n; i++) {
452106Svbart@nginx.com 
453106Svbart@nginx.com         v = nxt_conf_get_object_member(value, &map[i].name, NULL);
454106Svbart@nginx.com 
455116Svbart@nginx.com         if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
456106Svbart@nginx.com             continue;
457106Svbart@nginx.com         }
458106Svbart@nginx.com 
459106Svbart@nginx.com         ptr = nxt_pointer_to(data, map[i].offset);
460106Svbart@nginx.com 
461106Svbart@nginx.com         switch (map[i].type) {
462106Svbart@nginx.com 
463106Svbart@nginx.com         case NXT_CONF_MAP_INT8:
464106Svbart@nginx.com 
465136Svbart@nginx.com             if (v->type == NXT_CONF_VALUE_BOOLEAN) {
466136Svbart@nginx.com                 ptr->ui8 = v->u.boolean;
467106Svbart@nginx.com             }
468106Svbart@nginx.com 
469106Svbart@nginx.com             break;
470106Svbart@nginx.com 
471106Svbart@nginx.com         case NXT_CONF_MAP_INT32:
472106Svbart@nginx.com         case NXT_CONF_MAP_INT64:
473106Svbart@nginx.com         case NXT_CONF_MAP_INT:
474106Svbart@nginx.com         case NXT_CONF_MAP_SIZE:
475106Svbart@nginx.com         case NXT_CONF_MAP_OFF:
476111Sigor@sysoev.ru         case NXT_CONF_MAP_MSEC:
477106Svbart@nginx.com 
478116Svbart@nginx.com             if (v->type != NXT_CONF_VALUE_INTEGER) {
479136Svbart@nginx.com                 break;
480106Svbart@nginx.com             }
481106Svbart@nginx.com 
482106Svbart@nginx.com             switch (map[i].type) {
483106Svbart@nginx.com 
484106Svbart@nginx.com             case NXT_CONF_MAP_INT32:
485120Svbart@nginx.com                 ptr->i32 = v->u.integer;
486106Svbart@nginx.com                 break;
487106Svbart@nginx.com 
488106Svbart@nginx.com             case NXT_CONF_MAP_INT64:
489106Svbart@nginx.com                 ptr->i64 = v->u.integer;
490106Svbart@nginx.com                 break;
491106Svbart@nginx.com 
492106Svbart@nginx.com             case NXT_CONF_MAP_INT:
493106Svbart@nginx.com                 ptr->i = v->u.integer;
494106Svbart@nginx.com                 break;
495106Svbart@nginx.com 
496106Svbart@nginx.com             case NXT_CONF_MAP_SIZE:
497106Svbart@nginx.com                 ptr->size = v->u.integer;
498106Svbart@nginx.com                 break;
499106Svbart@nginx.com 
500106Svbart@nginx.com             case NXT_CONF_MAP_OFF:
501106Svbart@nginx.com                 ptr->off = v->u.integer;
502106Svbart@nginx.com                 break;
503106Svbart@nginx.com 
504111Sigor@sysoev.ru             case NXT_CONF_MAP_MSEC:
505318Smax.romanov@nginx.com                 ptr->msec = v->u.integer * 1000;
506111Sigor@sysoev.ru                 break;
507111Sigor@sysoev.ru 
508106Svbart@nginx.com             default:
509106Svbart@nginx.com                 nxt_unreachable();
510106Svbart@nginx.com             }
511106Svbart@nginx.com 
512106Svbart@nginx.com             break;
513106Svbart@nginx.com 
514106Svbart@nginx.com         case NXT_CONF_MAP_DOUBLE:
515106Svbart@nginx.com 
516116Svbart@nginx.com             if (v->type == NXT_CONF_VALUE_NUMBER) {
517106Svbart@nginx.com                 ptr->dbl = v->u.number;
518106Svbart@nginx.com 
519116Svbart@nginx.com             } else if (v->type == NXT_CONF_VALUE_INTEGER) {
520106Svbart@nginx.com                 ptr->dbl = v->u.integer;
521106Svbart@nginx.com 
522106Svbart@nginx.com             }
523106Svbart@nginx.com 
524106Svbart@nginx.com             break;
525106Svbart@nginx.com 
526106Svbart@nginx.com         case NXT_CONF_MAP_STR:
527213Svbart@nginx.com         case NXT_CONF_MAP_STR_COPY:
528213Svbart@nginx.com         case NXT_CONF_MAP_CSTRZ:
529213Svbart@nginx.com 
530213Svbart@nginx.com             if (v->type != NXT_CONF_VALUE_SHORT_STRING
531213Svbart@nginx.com                 && v->type != NXT_CONF_VALUE_STRING)
532106Svbart@nginx.com             {
533213Svbart@nginx.com                 break;
534213Svbart@nginx.com             }
535213Svbart@nginx.com 
536213Svbart@nginx.com             nxt_conf_get_string(v, &str);
537213Svbart@nginx.com 
538213Svbart@nginx.com             switch (map[i].type) {
539213Svbart@nginx.com 
540213Svbart@nginx.com             case NXT_CONF_MAP_STR:
541213Svbart@nginx.com                 ptr->str = str;
542213Svbart@nginx.com                 break;
543213Svbart@nginx.com 
544213Svbart@nginx.com             case NXT_CONF_MAP_STR_COPY:
545213Svbart@nginx.com 
546213Svbart@nginx.com                 s = nxt_str_dup(mp, &ptr->str, &str);
547213Svbart@nginx.com 
548213Svbart@nginx.com                 if (nxt_slow_path(s == NULL)) {
549213Svbart@nginx.com                     return NXT_ERROR;
550213Svbart@nginx.com                 }
551213Svbart@nginx.com 
552213Svbart@nginx.com                 break;
553213Svbart@nginx.com 
554213Svbart@nginx.com             case NXT_CONF_MAP_CSTRZ:
555213Svbart@nginx.com 
556213Svbart@nginx.com                 ptr->cstrz = nxt_str_cstrz(mp, &str);
557213Svbart@nginx.com 
558213Svbart@nginx.com                 if (nxt_slow_path(ptr->cstrz == NULL)) {
559213Svbart@nginx.com                     return NXT_ERROR;
560213Svbart@nginx.com                 }
561213Svbart@nginx.com 
562213Svbart@nginx.com                 break;
563213Svbart@nginx.com 
564213Svbart@nginx.com             default:
565213Svbart@nginx.com                 nxt_unreachable();
566106Svbart@nginx.com             }
567106Svbart@nginx.com 
568106Svbart@nginx.com             break;
569106Svbart@nginx.com 
570106Svbart@nginx.com         case NXT_CONF_MAP_PTR:
571106Svbart@nginx.com 
572106Svbart@nginx.com             ptr->v = v;
573106Svbart@nginx.com 
574106Svbart@nginx.com             break;
575106Svbart@nginx.com         }
576106Svbart@nginx.com     }
577106Svbart@nginx.com 
578106Svbart@nginx.com     return NXT_OK;
579106Svbart@nginx.com }
580106Svbart@nginx.com 
581106Svbart@nginx.com 
582106Svbart@nginx.com nxt_conf_value_t *
583106Svbart@nginx.com nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name,
584106Svbart@nginx.com     uint32_t *next)
585106Svbart@nginx.com {
586106Svbart@nginx.com     uint32_t                  n;
587106Svbart@nginx.com     nxt_conf_object_t         *object;
588106Svbart@nginx.com     nxt_conf_object_member_t  *member;
589106Svbart@nginx.com 
590116Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_OBJECT) {
591106Svbart@nginx.com         return NULL;
592106Svbart@nginx.com     }
593106Svbart@nginx.com 
594106Svbart@nginx.com     n = *next;
595106Svbart@nginx.com     object = value->u.object;
596106Svbart@nginx.com 
597106Svbart@nginx.com     if (n >= object->count) {
598106Svbart@nginx.com         return NULL;
599106Svbart@nginx.com     }
600106Svbart@nginx.com 
601106Svbart@nginx.com     member = &object->members[n];
602106Svbart@nginx.com     *next = n + 1;
603106Svbart@nginx.com 
604106Svbart@nginx.com     nxt_conf_get_string(&member->name, name);
605106Svbart@nginx.com 
606106Svbart@nginx.com     return &member->value;
607106Svbart@nginx.com }
608106Svbart@nginx.com 
609106Svbart@nginx.com 
610214Svbart@nginx.com nxt_conf_value_t *
611214Svbart@nginx.com nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index)
612214Svbart@nginx.com {
613214Svbart@nginx.com     nxt_conf_array_t  *array;
614214Svbart@nginx.com 
615214Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_ARRAY) {
616214Svbart@nginx.com         return NULL;
617214Svbart@nginx.com     }
618214Svbart@nginx.com 
619214Svbart@nginx.com     array = value->u.array;
620214Svbart@nginx.com 
621214Svbart@nginx.com     if (index >= array->count) {
622214Svbart@nginx.com         return NULL;
623214Svbart@nginx.com     }
624214Svbart@nginx.com 
625214Svbart@nginx.com     return &array->elements[index];
626214Svbart@nginx.com }
627214Svbart@nginx.com 
628214Svbart@nginx.com 
629106Svbart@nginx.com nxt_int_t
630106Svbart@nginx.com nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
631106Svbart@nginx.com     nxt_str_t *path, nxt_conf_value_t *value)
632106Svbart@nginx.com {
633106Svbart@nginx.com     nxt_str_t                 token;
634106Svbart@nginx.com     nxt_conf_op_t             *op, **parent;
635106Svbart@nginx.com     nxt_conf_path_parse_t     parse;
636106Svbart@nginx.com     nxt_conf_object_member_t  *member;
637106Svbart@nginx.com 
638106Svbart@nginx.com     parse.start = path->start;
639106Svbart@nginx.com     parse.end = path->start + path->length;
640106Svbart@nginx.com     parse.last = 0;
641106Svbart@nginx.com 
642106Svbart@nginx.com     parent = ops;
643106Svbart@nginx.com 
644106Svbart@nginx.com     for ( ;; ) {
645106Svbart@nginx.com         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
646106Svbart@nginx.com         if (nxt_slow_path(op == NULL)) {
647106Svbart@nginx.com             return NXT_ERROR;
648106Svbart@nginx.com         }
649106Svbart@nginx.com 
650106Svbart@nginx.com         *parent = op;
651106Svbart@nginx.com         parent = (nxt_conf_op_t **) &op->ctx;
652106Svbart@nginx.com 
653106Svbart@nginx.com         nxt_conf_path_next_token(&parse, &token);
654106Svbart@nginx.com 
655106Svbart@nginx.com         root = nxt_conf_get_object_member(root, &token, &op->index);
656106Svbart@nginx.com 
657106Svbart@nginx.com         if (parse.last) {
658106Svbart@nginx.com             break;
659106Svbart@nginx.com         }
660106Svbart@nginx.com 
661106Svbart@nginx.com         if (root == NULL) {
662106Svbart@nginx.com             return NXT_DECLINED;
663106Svbart@nginx.com         }
664106Svbart@nginx.com 
665106Svbart@nginx.com         op->action = NXT_CONF_OP_PASS;
666106Svbart@nginx.com     }
667106Svbart@nginx.com 
668106Svbart@nginx.com     if (value == NULL) {
669106Svbart@nginx.com 
670106Svbart@nginx.com         if (root == NULL) {
671106Svbart@nginx.com             return NXT_DECLINED;
672106Svbart@nginx.com         }
673106Svbart@nginx.com 
674106Svbart@nginx.com         op->action = NXT_CONF_OP_DELETE;
675106Svbart@nginx.com 
676106Svbart@nginx.com         return NXT_OK;
677106Svbart@nginx.com     }
678106Svbart@nginx.com 
679106Svbart@nginx.com     if (root == NULL) {
680106Svbart@nginx.com 
681106Svbart@nginx.com         member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t));
682106Svbart@nginx.com         if (nxt_slow_path(member == NULL)) {
683106Svbart@nginx.com             return NXT_ERROR;
684106Svbart@nginx.com         }
685106Svbart@nginx.com 
686106Svbart@nginx.com         if (token.length > NXT_CONF_MAX_SHORT_STRING) {
687172Svbart@nginx.com             member->name.u.string.length = token.length;
688172Svbart@nginx.com             member->name.u.string.start = token.start;
689172Svbart@nginx.com 
690116Svbart@nginx.com             member->name.type = NXT_CONF_VALUE_STRING;
691106Svbart@nginx.com 
692106Svbart@nginx.com         } else {
693173Svbart@nginx.com             member->name.u.str.length = token.length;
694173Svbart@nginx.com             nxt_memcpy(member->name.u.str.start, token.start, token.length);
695106Svbart@nginx.com 
696116Svbart@nginx.com             member->name.type = NXT_CONF_VALUE_SHORT_STRING;
697106Svbart@nginx.com         }
698106Svbart@nginx.com 
699106Svbart@nginx.com         member->value = *value;
700106Svbart@nginx.com 
701106Svbart@nginx.com         op->action = NXT_CONF_OP_CREATE;
702106Svbart@nginx.com         op->ctx = member;
703106Svbart@nginx.com 
704106Svbart@nginx.com     } else {
705106Svbart@nginx.com         op->action = NXT_CONF_OP_REPLACE;
706106Svbart@nginx.com         op->ctx = value;
707106Svbart@nginx.com     }
708106Svbart@nginx.com 
709106Svbart@nginx.com     return NXT_OK;
710106Svbart@nginx.com }
711106Svbart@nginx.com 
712106Svbart@nginx.com 
713106Svbart@nginx.com nxt_conf_value_t *
714106Svbart@nginx.com nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value)
715106Svbart@nginx.com {
716106Svbart@nginx.com     nxt_int_t         rc;
717106Svbart@nginx.com     nxt_conf_value_t  *copy;
718106Svbart@nginx.com 
719106Svbart@nginx.com     copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
720106Svbart@nginx.com     if (nxt_slow_path(copy == NULL)) {
721106Svbart@nginx.com         return NULL;
722106Svbart@nginx.com     }
723106Svbart@nginx.com 
724106Svbart@nginx.com     rc = nxt_conf_copy_value(mp, op, copy, value);
725106Svbart@nginx.com 
726106Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
727106Svbart@nginx.com         return NULL;
728106Svbart@nginx.com     }
729106Svbart@nginx.com 
730106Svbart@nginx.com     return copy;
731106Svbart@nginx.com }
732106Svbart@nginx.com 
733106Svbart@nginx.com 
734106Svbart@nginx.com static nxt_int_t
735106Svbart@nginx.com nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
736106Svbart@nginx.com     nxt_conf_value_t *src)
737106Svbart@nginx.com {
738106Svbart@nginx.com     size_t      size;
739106Svbart@nginx.com     nxt_int_t   rc;
740106Svbart@nginx.com     nxt_uint_t  n;
741106Svbart@nginx.com 
742116Svbart@nginx.com     if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) {
743106Svbart@nginx.com         return NXT_ERROR;
744106Svbart@nginx.com     }
745106Svbart@nginx.com 
746106Svbart@nginx.com     dst->type = src->type;
747106Svbart@nginx.com 
748106Svbart@nginx.com     switch (src->type) {
749106Svbart@nginx.com 
750116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
751106Svbart@nginx.com 
752172Svbart@nginx.com         dst->u.string.start = nxt_mp_nget(mp, src->u.string.length);
753172Svbart@nginx.com         if (nxt_slow_path(dst->u.string.start == NULL)) {
754106Svbart@nginx.com             return NXT_ERROR;
755106Svbart@nginx.com         }
756106Svbart@nginx.com 
757172Svbart@nginx.com         nxt_memcpy(dst->u.string.start, src->u.string.start,
758172Svbart@nginx.com                    src->u.string.length);
759172Svbart@nginx.com 
760172Svbart@nginx.com         dst->u.string.length = src->u.string.length;
761172Svbart@nginx.com 
762106Svbart@nginx.com         break;
763106Svbart@nginx.com 
764116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
765106Svbart@nginx.com 
766106Svbart@nginx.com         size = sizeof(nxt_conf_array_t)
767106Svbart@nginx.com                + src->u.array->count * sizeof(nxt_conf_value_t);
768106Svbart@nginx.com 
769106Svbart@nginx.com         dst->u.array = nxt_mp_get(mp, size);
770106Svbart@nginx.com         if (nxt_slow_path(dst->u.array == NULL)) {
771106Svbart@nginx.com             return NXT_ERROR;
772106Svbart@nginx.com         }
773106Svbart@nginx.com 
774106Svbart@nginx.com         dst->u.array->count = src->u.array->count;
775106Svbart@nginx.com 
776106Svbart@nginx.com         for (n = 0; n < src->u.array->count; n++) {
777106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, NULL, &dst->u.array->elements[n],
778106Svbart@nginx.com                                                &src->u.array->elements[n]);
779106Svbart@nginx.com 
780106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
781106Svbart@nginx.com                 return NXT_ERROR;
782106Svbart@nginx.com             }
783106Svbart@nginx.com         }
784106Svbart@nginx.com 
785106Svbart@nginx.com         break;
786106Svbart@nginx.com 
787116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
788106Svbart@nginx.com         return nxt_conf_copy_object(mp, op, dst, src);
789106Svbart@nginx.com 
790106Svbart@nginx.com     default:
791106Svbart@nginx.com         dst->u = src->u;
792106Svbart@nginx.com     }
793106Svbart@nginx.com 
794106Svbart@nginx.com     return NXT_OK;
795106Svbart@nginx.com }
796106Svbart@nginx.com 
797106Svbart@nginx.com 
798106Svbart@nginx.com static nxt_int_t
799106Svbart@nginx.com nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
800106Svbart@nginx.com     nxt_conf_value_t *src)
801106Svbart@nginx.com {
802106Svbart@nginx.com     size_t                    size;
803106Svbart@nginx.com     nxt_int_t                 rc;
804106Svbart@nginx.com     nxt_uint_t                s, d, count, index;
805106Svbart@nginx.com     nxt_conf_op_t             *pass_op;
806106Svbart@nginx.com     nxt_conf_value_t          *value;
807106Svbart@nginx.com     nxt_conf_object_member_t  *member;
808106Svbart@nginx.com 
809106Svbart@nginx.com     count = src->u.object->count;
810106Svbart@nginx.com 
811106Svbart@nginx.com     if (op != NULL) {
812106Svbart@nginx.com         if (op->action == NXT_CONF_OP_CREATE) {
813106Svbart@nginx.com             count++;
814106Svbart@nginx.com 
815106Svbart@nginx.com         } else if (op->action == NXT_CONF_OP_DELETE) {
816106Svbart@nginx.com             count--;
817106Svbart@nginx.com         }
818106Svbart@nginx.com     }
819106Svbart@nginx.com 
820106Svbart@nginx.com     size = sizeof(nxt_conf_object_t)
821106Svbart@nginx.com            + count * sizeof(nxt_conf_object_member_t);
822106Svbart@nginx.com 
823106Svbart@nginx.com     dst->u.object = nxt_mp_get(mp, size);
824106Svbart@nginx.com     if (nxt_slow_path(dst->u.object == NULL)) {
825106Svbart@nginx.com         return NXT_ERROR;
826106Svbart@nginx.com     }
827106Svbart@nginx.com 
828106Svbart@nginx.com     dst->u.object->count = count;
829106Svbart@nginx.com 
830106Svbart@nginx.com     s = 0;
831106Svbart@nginx.com     d = 0;
832106Svbart@nginx.com 
833106Svbart@nginx.com     pass_op = NULL;
834106Svbart@nginx.com 
835106Svbart@nginx.com     /*
836106Svbart@nginx.com      * This initialization is needed only to
837106Svbart@nginx.com      * suppress a warning on GCC 4.8 and older.
838106Svbart@nginx.com      */
839106Svbart@nginx.com     index = 0;
840106Svbart@nginx.com 
841106Svbart@nginx.com     do {
842106Svbart@nginx.com         if (pass_op == NULL) {
843106Svbart@nginx.com             index = (op == NULL || op->action == NXT_CONF_OP_CREATE)
844106Svbart@nginx.com                     ? src->u.object->count
845106Svbart@nginx.com                     : op->index;
846106Svbart@nginx.com         }
847106Svbart@nginx.com 
848106Svbart@nginx.com         while (s != index) {
849106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, NULL,
850106Svbart@nginx.com                                      &dst->u.object->members[d].name,
851106Svbart@nginx.com                                      &src->u.object->members[s].name);
852106Svbart@nginx.com 
853106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
854106Svbart@nginx.com                 return NXT_ERROR;
855106Svbart@nginx.com             }
856106Svbart@nginx.com 
857106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, pass_op,
858106Svbart@nginx.com                                      &dst->u.object->members[d].value,
859106Svbart@nginx.com                                      &src->u.object->members[s].value);
860106Svbart@nginx.com 
861106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
862106Svbart@nginx.com                 return NXT_ERROR;
863106Svbart@nginx.com             }
864106Svbart@nginx.com 
865106Svbart@nginx.com             s++;
866106Svbart@nginx.com             d++;
867106Svbart@nginx.com         }
868106Svbart@nginx.com 
869106Svbart@nginx.com         if (pass_op != NULL) {
870106Svbart@nginx.com             pass_op = NULL;
871106Svbart@nginx.com             continue;
872106Svbart@nginx.com         }
873106Svbart@nginx.com 
874106Svbart@nginx.com         if (op != NULL) {
875106Svbart@nginx.com             switch (op->action) {
876106Svbart@nginx.com             case NXT_CONF_OP_PASS:
877106Svbart@nginx.com                 pass_op = op->ctx;
878106Svbart@nginx.com                 index++;
879106Svbart@nginx.com                 break;
880106Svbart@nginx.com 
881106Svbart@nginx.com             case NXT_CONF_OP_CREATE:
882106Svbart@nginx.com                 member = op->ctx;
883106Svbart@nginx.com 
884106Svbart@nginx.com                 rc = nxt_conf_copy_value(mp, NULL,
885106Svbart@nginx.com                                          &dst->u.object->members[d].name,
886106Svbart@nginx.com                                          &member->name);
887106Svbart@nginx.com 
888106Svbart@nginx.com                 if (nxt_slow_path(rc != NXT_OK)) {
889106Svbart@nginx.com                     return NXT_ERROR;
890106Svbart@nginx.com                 }
891106Svbart@nginx.com 
892106Svbart@nginx.com                 dst->u.object->members[d].value = member->value;
893106Svbart@nginx.com 
894106Svbart@nginx.com                 d++;
895106Svbart@nginx.com                 break;
896106Svbart@nginx.com 
897106Svbart@nginx.com             case NXT_CONF_OP_REPLACE:
898106Svbart@nginx.com                 rc = nxt_conf_copy_value(mp, NULL,
899106Svbart@nginx.com                                          &dst->u.object->members[d].name,
900106Svbart@nginx.com                                          &src->u.object->members[s].name);
901106Svbart@nginx.com 
902106Svbart@nginx.com                 if (nxt_slow_path(rc != NXT_OK)) {
903106Svbart@nginx.com                     return NXT_ERROR;
904106Svbart@nginx.com                 }
905106Svbart@nginx.com 
906106Svbart@nginx.com                 value = op->ctx;
907106Svbart@nginx.com 
908106Svbart@nginx.com                 dst->u.object->members[d].value = *value;
909106Svbart@nginx.com 
910106Svbart@nginx.com                 s++;
911106Svbart@nginx.com                 d++;
912106Svbart@nginx.com                 break;
913106Svbart@nginx.com 
914106Svbart@nginx.com             case NXT_CONF_OP_DELETE:
915106Svbart@nginx.com                 s++;
916106Svbart@nginx.com                 break;
917106Svbart@nginx.com             }
918106Svbart@nginx.com 
919106Svbart@nginx.com             op = op->next;
920106Svbart@nginx.com         }
921106Svbart@nginx.com 
922106Svbart@nginx.com     } while (d != count);
923106Svbart@nginx.com 
924106Svbart@nginx.com     dst->type = src->type;
925106Svbart@nginx.com 
926106Svbart@nginx.com     return NXT_OK;
927106Svbart@nginx.com }
928106Svbart@nginx.com 
929106Svbart@nginx.com 
930106Svbart@nginx.com nxt_conf_value_t *
931208Svbart@nginx.com nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
932208Svbart@nginx.com     nxt_conf_json_error_t *error)
933106Svbart@nginx.com {
934106Svbart@nginx.com     u_char            *p;
935106Svbart@nginx.com     nxt_conf_value_t  *value;
936106Svbart@nginx.com 
937106Svbart@nginx.com     value = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
938106Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
939106Svbart@nginx.com         return NULL;
940106Svbart@nginx.com     }
941106Svbart@nginx.com 
942106Svbart@nginx.com     p = nxt_conf_json_skip_space(start, end);
943106Svbart@nginx.com 
944106Svbart@nginx.com     if (nxt_slow_path(p == end)) {
945208Svbart@nginx.com 
946208Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
947311Snick@nginx.com             "An empty JSON payload isn't allowed.  It must be either a literal "
948311Snick@nginx.com             "(null, true, or false), a number, a string (in double quotes "
949311Snick@nginx.com             "\"\"), an array (with brackets []), or an object (with braces {})."
950208Svbart@nginx.com         );
951208Svbart@nginx.com 
952106Svbart@nginx.com         return NULL;
953106Svbart@nginx.com     }
954106Svbart@nginx.com 
955208Svbart@nginx.com     p = nxt_conf_json_parse_value(mp, value, p, end, error);
956106Svbart@nginx.com 
957106Svbart@nginx.com     if (nxt_slow_path(p == NULL)) {
958106Svbart@nginx.com         return NULL;
959106Svbart@nginx.com     }
960106Svbart@nginx.com 
961106Svbart@nginx.com     p = nxt_conf_json_skip_space(p, end);
962106Svbart@nginx.com 
963106Svbart@nginx.com     if (nxt_slow_path(p != end)) {
964208Svbart@nginx.com 
965208Svbart@nginx.com         nxt_conf_json_parse_error(error, p,
966311Snick@nginx.com             "Unexpected character after the end of a valid JSON value."
967208Svbart@nginx.com         );
968208Svbart@nginx.com 
969106Svbart@nginx.com         return NULL;
970106Svbart@nginx.com     }
971106Svbart@nginx.com 
972106Svbart@nginx.com     return value;
973106Svbart@nginx.com }
974106Svbart@nginx.com 
975106Svbart@nginx.com 
976106Svbart@nginx.com static u_char *
977106Svbart@nginx.com nxt_conf_json_skip_space(u_char *start, u_char *end)
978106Svbart@nginx.com {
979106Svbart@nginx.com     u_char  *p;
980106Svbart@nginx.com 
981106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
982106Svbart@nginx.com 
983106Svbart@nginx.com         switch (*p) {
984106Svbart@nginx.com         case ' ':
985106Svbart@nginx.com         case '\t':
986106Svbart@nginx.com         case '\r':
987106Svbart@nginx.com         case '\n':
988106Svbart@nginx.com             continue;
989106Svbart@nginx.com         }
990106Svbart@nginx.com 
991106Svbart@nginx.com         break;
992106Svbart@nginx.com     }
993106Svbart@nginx.com 
994106Svbart@nginx.com     return p;
995106Svbart@nginx.com }
996106Svbart@nginx.com 
997106Svbart@nginx.com 
998106Svbart@nginx.com static u_char *
999106Svbart@nginx.com nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1000208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1001106Svbart@nginx.com {
1002208Svbart@nginx.com     u_char  ch, *p;
1003106Svbart@nginx.com 
1004106Svbart@nginx.com     ch = *start;
1005106Svbart@nginx.com 
1006106Svbart@nginx.com     switch (ch) {
1007106Svbart@nginx.com     case '{':
1008208Svbart@nginx.com         return nxt_conf_json_parse_object(mp, value, start, end, error);
1009106Svbart@nginx.com 
1010106Svbart@nginx.com     case '[':
1011208Svbart@nginx.com         return nxt_conf_json_parse_array(mp, value, start, end, error);
1012106Svbart@nginx.com 
1013106Svbart@nginx.com     case '"':
1014208Svbart@nginx.com         return nxt_conf_json_parse_string(mp, value, start, end, error);
1015106Svbart@nginx.com 
1016106Svbart@nginx.com     case 't':
1017106Svbart@nginx.com         if (nxt_fast_path(end - start >= 4
1018106Svbart@nginx.com                           && nxt_memcmp(start, "true", 4) == 0))
1019106Svbart@nginx.com         {
1020106Svbart@nginx.com             value->u.boolean = 1;
1021116Svbart@nginx.com             value->type = NXT_CONF_VALUE_BOOLEAN;
1022106Svbart@nginx.com 
1023106Svbart@nginx.com             return start + 4;
1024106Svbart@nginx.com         }
1025106Svbart@nginx.com 
1026208Svbart@nginx.com         goto error;
1027106Svbart@nginx.com 
1028106Svbart@nginx.com     case 'f':
1029106Svbart@nginx.com         if (nxt_fast_path(end - start >= 5
1030106Svbart@nginx.com                           && nxt_memcmp(start, "false", 5) == 0))
1031106Svbart@nginx.com         {
1032106Svbart@nginx.com             value->u.boolean = 0;
1033116Svbart@nginx.com             value->type = NXT_CONF_VALUE_BOOLEAN;
1034106Svbart@nginx.com 
1035106Svbart@nginx.com             return start + 5;
1036106Svbart@nginx.com         }
1037106Svbart@nginx.com 
1038208Svbart@nginx.com         goto error;
1039106Svbart@nginx.com 
1040106Svbart@nginx.com     case 'n':
1041106Svbart@nginx.com         if (nxt_fast_path(end - start >= 4
1042106Svbart@nginx.com                           && nxt_memcmp(start, "null", 4) == 0))
1043106Svbart@nginx.com         {
1044116Svbart@nginx.com             value->type = NXT_CONF_VALUE_NULL;
1045106Svbart@nginx.com             return start + 4;
1046106Svbart@nginx.com         }
1047106Svbart@nginx.com 
1048208Svbart@nginx.com         goto error;
1049208Svbart@nginx.com 
1050208Svbart@nginx.com     case '-':
1051208Svbart@nginx.com         if (nxt_fast_path(end - start > 1)) {
1052208Svbart@nginx.com             ch = start[1];
1053208Svbart@nginx.com             break;
1054208Svbart@nginx.com         }
1055208Svbart@nginx.com 
1056208Svbart@nginx.com         goto error;
1057106Svbart@nginx.com     }
1058106Svbart@nginx.com 
1059208Svbart@nginx.com     if (nxt_fast_path((ch - '0') <= 9)) {
1060208Svbart@nginx.com         p = nxt_conf_json_parse_number(mp, value, start, end, error);
1061208Svbart@nginx.com 
1062383Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1063383Svbart@nginx.com             return NULL;
1064383Svbart@nginx.com         }
1065383Svbart@nginx.com 
1066208Svbart@nginx.com         if (p == end) {
1067208Svbart@nginx.com             return end;
1068208Svbart@nginx.com         }
1069208Svbart@nginx.com 
1070208Svbart@nginx.com         switch (*p) {
1071208Svbart@nginx.com         case ' ':
1072208Svbart@nginx.com         case '\t':
1073208Svbart@nginx.com         case '\r':
1074208Svbart@nginx.com         case '\n':
1075208Svbart@nginx.com         case ',':
1076208Svbart@nginx.com         case '}':
1077208Svbart@nginx.com         case ']':
1078208Svbart@nginx.com         case '{':
1079208Svbart@nginx.com         case '[':
1080208Svbart@nginx.com         case '"':
1081208Svbart@nginx.com             return p;
1082208Svbart@nginx.com         }
1083106Svbart@nginx.com     }
1084106Svbart@nginx.com 
1085208Svbart@nginx.com error:
1086208Svbart@nginx.com 
1087208Svbart@nginx.com     nxt_conf_json_parse_error(error, start,
1088311Snick@nginx.com         "A valid JSON value is expected here.  It must be either a literal "
1089311Snick@nginx.com         "(null, true, or false), a number, a string (in double quotes \"\"), "
1090311Snick@nginx.com         "an array (with brackets []), or an object (with braces {})."
1091208Svbart@nginx.com     );
1092208Svbart@nginx.com 
1093106Svbart@nginx.com     return NULL;
1094106Svbart@nginx.com }
1095106Svbart@nginx.com 
1096106Svbart@nginx.com 
1097106Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_conf_object_hash_proto
1098106Svbart@nginx.com     nxt_aligned(64) =
1099106Svbart@nginx.com {
1100106Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
1101106Svbart@nginx.com     nxt_conf_object_hash_test,
1102106Svbart@nginx.com     nxt_conf_object_hash_alloc,
1103106Svbart@nginx.com     nxt_conf_object_hash_free,
1104106Svbart@nginx.com };
1105106Svbart@nginx.com 
1106106Svbart@nginx.com 
1107106Svbart@nginx.com static u_char *
1108106Svbart@nginx.com nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1109208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1110106Svbart@nginx.com {
1111208Svbart@nginx.com     u_char                    *p, *name;
1112106Svbart@nginx.com     nxt_mp_t                  *mp_temp;
1113106Svbart@nginx.com     nxt_int_t                 rc;
1114106Svbart@nginx.com     nxt_uint_t                count;
1115106Svbart@nginx.com     nxt_lvlhsh_t              hash;
1116106Svbart@nginx.com     nxt_lvlhsh_each_t         lhe;
1117106Svbart@nginx.com     nxt_conf_object_t         *object;
1118106Svbart@nginx.com     nxt_conf_object_member_t  *member, *element;
1119106Svbart@nginx.com 
1120106Svbart@nginx.com     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1121106Svbart@nginx.com     if (nxt_slow_path(mp_temp == NULL)) {
1122106Svbart@nginx.com         return NULL;
1123106Svbart@nginx.com     }
1124106Svbart@nginx.com 
1125106Svbart@nginx.com     nxt_lvlhsh_init(&hash);
1126106Svbart@nginx.com 
1127106Svbart@nginx.com     count = 0;
1128130Svbart@nginx.com     p = start;
1129130Svbart@nginx.com 
1130130Svbart@nginx.com     for ( ;; ) {
1131130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1132130Svbart@nginx.com 
1133130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1134208Svbart@nginx.com 
1135208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1136311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object without "
1137311Snick@nginx.com                 "a closing brace (})."
1138208Svbart@nginx.com             );
1139208Svbart@nginx.com 
1140130Svbart@nginx.com             goto error;
1141130Svbart@nginx.com         }
1142130Svbart@nginx.com 
1143130Svbart@nginx.com         if (*p != '"') {
1144130Svbart@nginx.com             if (nxt_fast_path(*p == '}')) {
1145106Svbart@nginx.com                 break;
1146106Svbart@nginx.com             }
1147106Svbart@nginx.com 
1148208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1149208Svbart@nginx.com                 "A double quote (\") is expected here.  There must be a valid "
1150208Svbart@nginx.com                 "JSON object member starts with a name, which is a string "
1151208Svbart@nginx.com                 "enclosed in double quotes."
1152208Svbart@nginx.com             );
1153208Svbart@nginx.com 
1154130Svbart@nginx.com             goto error;
1155130Svbart@nginx.com         }
1156130Svbart@nginx.com 
1157208Svbart@nginx.com         name = p;
1158208Svbart@nginx.com 
1159130Svbart@nginx.com         count++;
1160130Svbart@nginx.com 
1161130Svbart@nginx.com         member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
1162130Svbart@nginx.com         if (nxt_slow_path(member == NULL)) {
1163130Svbart@nginx.com             goto error;
1164130Svbart@nginx.com         }
1165130Svbart@nginx.com 
1166208Svbart@nginx.com         p = nxt_conf_json_parse_string(mp, &member->name, p, end, error);
1167130Svbart@nginx.com 
1168130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1169130Svbart@nginx.com             goto error;
1170130Svbart@nginx.com         }
1171130Svbart@nginx.com 
1172130Svbart@nginx.com         rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
1173130Svbart@nginx.com 
1174130Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1175208Svbart@nginx.com 
1176208Svbart@nginx.com             if (rc == NXT_DECLINED) {
1177208Svbart@nginx.com                 nxt_conf_json_parse_error(error, name,
1178208Svbart@nginx.com                     "Duplicate object member.  All JSON object members must "
1179208Svbart@nginx.com                     "have unique names."
1180208Svbart@nginx.com                 );
1181208Svbart@nginx.com             }
1182208Svbart@nginx.com 
1183130Svbart@nginx.com             goto error;
1184130Svbart@nginx.com         }
1185130Svbart@nginx.com 
1186130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1187130Svbart@nginx.com 
1188208Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1189208Svbart@nginx.com 
1190208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1191311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object member "
1192311Snick@nginx.com                 "without a value."
1193208Svbart@nginx.com             );
1194208Svbart@nginx.com 
1195208Svbart@nginx.com             goto error;
1196208Svbart@nginx.com         }
1197208Svbart@nginx.com 
1198208Svbart@nginx.com         if (nxt_slow_path(*p != ':')) {
1199208Svbart@nginx.com 
1200208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1201311Snick@nginx.com                 "A colon (:) is expected here.  There must be a colon after "
1202311Snick@nginx.com                 "a JSON member name."
1203208Svbart@nginx.com             );
1204208Svbart@nginx.com 
1205130Svbart@nginx.com             goto error;
1206130Svbart@nginx.com         }
1207130Svbart@nginx.com 
1208130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1209130Svbart@nginx.com 
1210130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1211208Svbart@nginx.com 
1212208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1213311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object member "
1214311Snick@nginx.com                 "without a value."
1215208Svbart@nginx.com             );
1216208Svbart@nginx.com 
1217130Svbart@nginx.com             goto error;
1218130Svbart@nginx.com         }
1219130Svbart@nginx.com 
1220208Svbart@nginx.com         p = nxt_conf_json_parse_value(mp, &member->value, p, end, error);
1221130Svbart@nginx.com 
1222130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1223130Svbart@nginx.com             goto error;
1224130Svbart@nginx.com         }
1225130Svbart@nginx.com 
1226130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1227130Svbart@nginx.com 
1228130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1229208Svbart@nginx.com 
1230208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1231311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object without "
1232311Snick@nginx.com                 "a closing brace (})."
1233208Svbart@nginx.com             );
1234208Svbart@nginx.com 
1235130Svbart@nginx.com             goto error;
1236130Svbart@nginx.com         }
1237130Svbart@nginx.com 
1238130Svbart@nginx.com         if (*p != ',') {
1239130Svbart@nginx.com             if (nxt_fast_path(*p == '}')) {
1240130Svbart@nginx.com                 break;
1241106Svbart@nginx.com             }
1242106Svbart@nginx.com 
1243208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1244311Snick@nginx.com                 "Either a closing brace (}) or a comma (,) is expected here.  "
1245311Snick@nginx.com                 "Each JSON object must be enclosed in braces and its members "
1246311Snick@nginx.com                 "must be separated by commas."
1247208Svbart@nginx.com             );
1248208Svbart@nginx.com 
1249130Svbart@nginx.com             goto error;
1250106Svbart@nginx.com         }
1251106Svbart@nginx.com     }
1252106Svbart@nginx.com 
1253106Svbart@nginx.com     object = nxt_mp_get(mp, sizeof(nxt_conf_object_t)
1254106Svbart@nginx.com                             + count * sizeof(nxt_conf_object_member_t));
1255106Svbart@nginx.com     if (nxt_slow_path(object == NULL)) {
1256106Svbart@nginx.com         goto error;
1257106Svbart@nginx.com     }
1258106Svbart@nginx.com 
1259106Svbart@nginx.com     value->u.object = object;
1260116Svbart@nginx.com     value->type = NXT_CONF_VALUE_OBJECT;
1261106Svbart@nginx.com 
1262106Svbart@nginx.com     object->count = count;
1263106Svbart@nginx.com     member = object->members;
1264106Svbart@nginx.com 
1265106Svbart@nginx.com     nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t));
1266106Svbart@nginx.com     lhe.proto = &nxt_conf_object_hash_proto;
1267106Svbart@nginx.com 
1268106Svbart@nginx.com     for ( ;; ) {
1269106Svbart@nginx.com         element = nxt_lvlhsh_each(&hash, &lhe);
1270106Svbart@nginx.com 
1271106Svbart@nginx.com         if (element == NULL) {
1272106Svbart@nginx.com             break;
1273106Svbart@nginx.com         }
1274106Svbart@nginx.com 
1275106Svbart@nginx.com         *member++ = *element;
1276106Svbart@nginx.com     }
1277106Svbart@nginx.com 
1278106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1279106Svbart@nginx.com 
1280106Svbart@nginx.com     return p + 1;
1281106Svbart@nginx.com 
1282106Svbart@nginx.com error:
1283106Svbart@nginx.com 
1284106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1285106Svbart@nginx.com     return NULL;
1286106Svbart@nginx.com }
1287106Svbart@nginx.com 
1288106Svbart@nginx.com 
1289106Svbart@nginx.com static nxt_int_t
1290106Svbart@nginx.com nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh,
1291106Svbart@nginx.com     nxt_conf_object_member_t *member)
1292106Svbart@nginx.com {
1293106Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1294106Svbart@nginx.com 
1295106Svbart@nginx.com     nxt_conf_get_string(&member->name, &lhq.key);
1296106Svbart@nginx.com 
1297106Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
1298106Svbart@nginx.com     lhq.replace = 0;
1299106Svbart@nginx.com     lhq.value = member;
1300106Svbart@nginx.com     lhq.proto = &nxt_conf_object_hash_proto;
1301106Svbart@nginx.com     lhq.pool = mp;
1302106Svbart@nginx.com 
1303106Svbart@nginx.com     return nxt_lvlhsh_insert(lvlhsh, &lhq);
1304106Svbart@nginx.com }
1305106Svbart@nginx.com 
1306106Svbart@nginx.com 
1307106Svbart@nginx.com static nxt_int_t
1308106Svbart@nginx.com nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1309106Svbart@nginx.com {
1310106Svbart@nginx.com     nxt_str_t                 str;
1311106Svbart@nginx.com     nxt_conf_object_member_t  *member;
1312106Svbart@nginx.com 
1313106Svbart@nginx.com     member = data;
1314106Svbart@nginx.com 
1315106Svbart@nginx.com     nxt_conf_get_string(&member->name, &str);
1316106Svbart@nginx.com 
1317208Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED;
1318106Svbart@nginx.com }
1319106Svbart@nginx.com 
1320106Svbart@nginx.com 
1321106Svbart@nginx.com static void *
1322106Svbart@nginx.com nxt_conf_object_hash_alloc(void *data, size_t size)
1323106Svbart@nginx.com {
1324106Svbart@nginx.com     return nxt_mp_align(data, size, size);
1325106Svbart@nginx.com }
1326106Svbart@nginx.com 
1327106Svbart@nginx.com 
1328106Svbart@nginx.com static void
1329106Svbart@nginx.com nxt_conf_object_hash_free(void *data, void *p)
1330106Svbart@nginx.com {
1331106Svbart@nginx.com     nxt_mp_free(data, p);
1332106Svbart@nginx.com }
1333106Svbart@nginx.com 
1334106Svbart@nginx.com 
1335106Svbart@nginx.com static u_char *
1336106Svbart@nginx.com nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1337208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1338106Svbart@nginx.com {
1339106Svbart@nginx.com     u_char            *p;
1340106Svbart@nginx.com     nxt_mp_t          *mp_temp;
1341106Svbart@nginx.com     nxt_uint_t        count;
1342106Svbart@nginx.com     nxt_list_t        *list;
1343106Svbart@nginx.com     nxt_conf_array_t  *array;
1344106Svbart@nginx.com     nxt_conf_value_t  *element;
1345106Svbart@nginx.com 
1346106Svbart@nginx.com     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1347106Svbart@nginx.com     if (nxt_slow_path(mp_temp == NULL)) {
1348106Svbart@nginx.com         return NULL;
1349106Svbart@nginx.com     }
1350106Svbart@nginx.com 
1351106Svbart@nginx.com     list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t));
1352106Svbart@nginx.com     if (nxt_slow_path(list == NULL)) {
1353106Svbart@nginx.com         goto error;
1354106Svbart@nginx.com     }
1355106Svbart@nginx.com 
1356106Svbart@nginx.com     count = 0;
1357130Svbart@nginx.com     p = start;
1358130Svbart@nginx.com 
1359130Svbart@nginx.com     for ( ;; ) {
1360130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1361130Svbart@nginx.com 
1362130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1363208Svbart@nginx.com 
1364208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1365311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an array without "
1366311Snick@nginx.com                 "a closing bracket (])."
1367208Svbart@nginx.com             );
1368208Svbart@nginx.com 
1369130Svbart@nginx.com             goto error;
1370130Svbart@nginx.com         }
1371130Svbart@nginx.com 
1372130Svbart@nginx.com         if (*p == ']') {
1373130Svbart@nginx.com             break;
1374130Svbart@nginx.com         }
1375130Svbart@nginx.com 
1376130Svbart@nginx.com         count++;
1377130Svbart@nginx.com 
1378130Svbart@nginx.com         element = nxt_list_add(list);
1379130Svbart@nginx.com         if (nxt_slow_path(element == NULL)) {
1380130Svbart@nginx.com             goto error;
1381130Svbart@nginx.com         }
1382130Svbart@nginx.com 
1383208Svbart@nginx.com         p = nxt_conf_json_parse_value(mp, element, p, end, error);
1384130Svbart@nginx.com 
1385130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1386130Svbart@nginx.com             goto error;
1387130Svbart@nginx.com         }
1388130Svbart@nginx.com 
1389130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1390130Svbart@nginx.com 
1391130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1392208Svbart@nginx.com 
1393208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1394311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an array without "
1395311Snick@nginx.com                 "a closing bracket (])."
1396208Svbart@nginx.com             );
1397208Svbart@nginx.com 
1398130Svbart@nginx.com             goto error;
1399130Svbart@nginx.com         }
1400130Svbart@nginx.com 
1401130Svbart@nginx.com         if (*p != ',') {
1402130Svbart@nginx.com             if (nxt_fast_path(*p == ']')) {
1403106Svbart@nginx.com                 break;
1404106Svbart@nginx.com             }
1405106Svbart@nginx.com 
1406208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1407311Snick@nginx.com                 "Either a closing bracket (]) or a comma (,) is expected "
1408311Snick@nginx.com                 "here.  Each array must be enclosed in brackets and its "
1409311Snick@nginx.com                 "members must be separated by commas."
1410208Svbart@nginx.com             );
1411208Svbart@nginx.com 
1412130Svbart@nginx.com             goto error;
1413106Svbart@nginx.com         }
1414106Svbart@nginx.com     }
1415106Svbart@nginx.com 
1416106Svbart@nginx.com     array = nxt_mp_get(mp, sizeof(nxt_conf_array_t)
1417106Svbart@nginx.com                            + count * sizeof(nxt_conf_value_t));
1418106Svbart@nginx.com     if (nxt_slow_path(array == NULL)) {
1419106Svbart@nginx.com         goto error;
1420106Svbart@nginx.com     }
1421106Svbart@nginx.com 
1422106Svbart@nginx.com     value->u.array = array;
1423116Svbart@nginx.com     value->type = NXT_CONF_VALUE_ARRAY;
1424106Svbart@nginx.com 
1425106Svbart@nginx.com     array->count = count;
1426106Svbart@nginx.com     element = array->elements;
1427106Svbart@nginx.com 
1428106Svbart@nginx.com     nxt_list_each(value, list) {
1429106Svbart@nginx.com         *element++ = *value;
1430106Svbart@nginx.com     } nxt_list_loop;
1431106Svbart@nginx.com 
1432106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1433106Svbart@nginx.com 
1434106Svbart@nginx.com     return p + 1;
1435106Svbart@nginx.com 
1436106Svbart@nginx.com error:
1437106Svbart@nginx.com 
1438106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1439106Svbart@nginx.com     return NULL;
1440106Svbart@nginx.com }
1441106Svbart@nginx.com 
1442106Svbart@nginx.com 
1443106Svbart@nginx.com static u_char *
1444106Svbart@nginx.com nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1445208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1446106Svbart@nginx.com {
1447106Svbart@nginx.com     u_char      *p, ch, *last, *s;
1448106Svbart@nginx.com     size_t      size, surplus;
1449106Svbart@nginx.com     uint32_t    utf, utf_high;
1450106Svbart@nginx.com     nxt_uint_t  i;
1451106Svbart@nginx.com     enum {
1452106Svbart@nginx.com         sw_usual = 0,
1453106Svbart@nginx.com         sw_escape,
1454106Svbart@nginx.com         sw_encoded1,
1455106Svbart@nginx.com         sw_encoded2,
1456106Svbart@nginx.com         sw_encoded3,
1457106Svbart@nginx.com         sw_encoded4,
1458106Svbart@nginx.com     } state;
1459106Svbart@nginx.com 
1460106Svbart@nginx.com     start++;
1461106Svbart@nginx.com 
1462106Svbart@nginx.com     state = 0;
1463106Svbart@nginx.com     surplus = 0;
1464106Svbart@nginx.com 
1465106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1466106Svbart@nginx.com         ch = *p;
1467106Svbart@nginx.com 
1468106Svbart@nginx.com         switch (state) {
1469106Svbart@nginx.com 
1470106Svbart@nginx.com         case sw_usual:
1471106Svbart@nginx.com 
1472106Svbart@nginx.com             if (ch == '"') {
1473106Svbart@nginx.com                 break;
1474106Svbart@nginx.com             }
1475106Svbart@nginx.com 
1476106Svbart@nginx.com             if (ch == '\\') {
1477106Svbart@nginx.com                 state = sw_escape;
1478106Svbart@nginx.com                 continue;
1479106Svbart@nginx.com             }
1480106Svbart@nginx.com 
1481106Svbart@nginx.com             if (nxt_fast_path(ch >= ' ')) {
1482106Svbart@nginx.com                 continue;
1483106Svbart@nginx.com             }
1484106Svbart@nginx.com 
1485208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1486311Snick@nginx.com                 "Unexpected character.  All control characters in a JSON "
1487311Snick@nginx.com                 "string must be escaped."
1488208Svbart@nginx.com             );
1489208Svbart@nginx.com 
1490106Svbart@nginx.com             return NULL;
1491106Svbart@nginx.com 
1492106Svbart@nginx.com         case sw_escape:
1493106Svbart@nginx.com 
1494106Svbart@nginx.com             switch (ch) {
1495106Svbart@nginx.com             case '"':
1496106Svbart@nginx.com             case '\\':
1497106Svbart@nginx.com             case '/':
1498106Svbart@nginx.com             case 'n':
1499106Svbart@nginx.com             case 'r':
1500106Svbart@nginx.com             case 't':
1501106Svbart@nginx.com             case 'b':
1502106Svbart@nginx.com             case 'f':
1503106Svbart@nginx.com                 surplus++;
1504106Svbart@nginx.com                 state = sw_usual;
1505106Svbart@nginx.com                 continue;
1506106Svbart@nginx.com 
1507106Svbart@nginx.com             case 'u':
1508106Svbart@nginx.com                 /*
1509106Svbart@nginx.com                  * Basic unicode 6 bytes "\uXXXX" in JSON
1510106Svbart@nginx.com                  * and up to 3 bytes in UTF-8.
1511106Svbart@nginx.com                  *
1512106Svbart@nginx.com                  * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON
1513106Svbart@nginx.com                  * and 3 or 4 bytes in UTF-8.
1514106Svbart@nginx.com                  */
1515106Svbart@nginx.com                 surplus += 3;
1516106Svbart@nginx.com                 state = sw_encoded1;
1517106Svbart@nginx.com                 continue;
1518106Svbart@nginx.com             }
1519106Svbart@nginx.com 
1520208Svbart@nginx.com             nxt_conf_json_parse_error(error, p - 1,
1521311Snick@nginx.com                 "Unexpected backslash.  A literal backslash in a JSON string "
1522311Snick@nginx.com                 "must be escaped with a second backslash (\\\\)."
1523208Svbart@nginx.com             );
1524208Svbart@nginx.com 
1525106Svbart@nginx.com             return NULL;
1526106Svbart@nginx.com 
1527106Svbart@nginx.com         case sw_encoded1:
1528106Svbart@nginx.com         case sw_encoded2:
1529106Svbart@nginx.com         case sw_encoded3:
1530106Svbart@nginx.com         case sw_encoded4:
1531106Svbart@nginx.com 
1532106Svbart@nginx.com             if (nxt_fast_path((ch >= '0' && ch <= '9')
1533202Svbart@nginx.com                               || (ch >= 'A' && ch <= 'F')
1534202Svbart@nginx.com                               || (ch >= 'a' && ch <= 'f')))
1535106Svbart@nginx.com             {
1536106Svbart@nginx.com                 state = (state == sw_encoded4) ? sw_usual : state + 1;
1537106Svbart@nginx.com                 continue;
1538106Svbart@nginx.com             }
1539106Svbart@nginx.com 
1540208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1541311Snick@nginx.com                 "Invalid escape sequence.  An escape sequence in a JSON "
1542311Snick@nginx.com                 "string must start with a backslash, followed by the lowercase "
1543311Snick@nginx.com                 "letter u, followed by four hexadecimal digits (\\uXXXX)."
1544208Svbart@nginx.com             );
1545208Svbart@nginx.com 
1546106Svbart@nginx.com             return NULL;
1547106Svbart@nginx.com         }
1548106Svbart@nginx.com 
1549106Svbart@nginx.com         break;
1550106Svbart@nginx.com     }
1551106Svbart@nginx.com 
1552106Svbart@nginx.com     if (nxt_slow_path(p == end)) {
1553208Svbart@nginx.com 
1554208Svbart@nginx.com         nxt_conf_json_parse_error(error, p,
1555311Snick@nginx.com             "Unexpected end of JSON payload.  There's a string without "
1556311Snick@nginx.com             "a final double quote (\")."
1557208Svbart@nginx.com         );
1558208Svbart@nginx.com 
1559106Svbart@nginx.com         return NULL;
1560106Svbart@nginx.com     }
1561106Svbart@nginx.com 
1562106Svbart@nginx.com     /* Points to the ending quote mark. */
1563106Svbart@nginx.com     last = p;
1564106Svbart@nginx.com 
1565106Svbart@nginx.com     size = last - start - surplus;
1566106Svbart@nginx.com 
1567106Svbart@nginx.com     if (size > NXT_CONF_MAX_SHORT_STRING) {
1568172Svbart@nginx.com 
1569172Svbart@nginx.com         if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
1570208Svbart@nginx.com 
1571208Svbart@nginx.com             nxt_conf_json_parse_error(error, start,
1572311Snick@nginx.com                 "The string is too long.  Such a long JSON string value "
1573311Snick@nginx.com                 "is not supported."
1574208Svbart@nginx.com             );
1575208Svbart@nginx.com 
1576106Svbart@nginx.com             return NULL;
1577106Svbart@nginx.com         }
1578106Svbart@nginx.com 
1579172Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
1580172Svbart@nginx.com 
1581172Svbart@nginx.com         value->u.string.start = nxt_mp_nget(mp, size);
1582172Svbart@nginx.com         if (nxt_slow_path(value->u.string.start == NULL)) {
1583172Svbart@nginx.com             return NULL;
1584172Svbart@nginx.com         }
1585172Svbart@nginx.com 
1586172Svbart@nginx.com         value->u.string.length = size;
1587172Svbart@nginx.com 
1588172Svbart@nginx.com         s = value->u.string.start;
1589106Svbart@nginx.com 
1590106Svbart@nginx.com     } else {
1591116Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
1592173Svbart@nginx.com         value->u.str.length = size;
1593173Svbart@nginx.com 
1594173Svbart@nginx.com         s = value->u.str.start;
1595106Svbart@nginx.com     }
1596106Svbart@nginx.com 
1597106Svbart@nginx.com     if (surplus == 0) {
1598106Svbart@nginx.com         nxt_memcpy(s, start, size);
1599106Svbart@nginx.com         return last + 1;
1600106Svbart@nginx.com     }
1601106Svbart@nginx.com 
1602106Svbart@nginx.com     p = start;
1603106Svbart@nginx.com 
1604106Svbart@nginx.com     do {
1605106Svbart@nginx.com         ch = *p++;
1606106Svbart@nginx.com 
1607106Svbart@nginx.com         if (ch != '\\') {
1608106Svbart@nginx.com             *s++ = ch;
1609106Svbart@nginx.com             continue;
1610106Svbart@nginx.com         }
1611106Svbart@nginx.com 
1612106Svbart@nginx.com         ch = *p++;
1613106Svbart@nginx.com 
1614106Svbart@nginx.com         switch (ch) {
1615106Svbart@nginx.com         case '"':
1616106Svbart@nginx.com         case '\\':
1617106Svbart@nginx.com         case '/':
1618106Svbart@nginx.com             *s++ = ch;
1619106Svbart@nginx.com             continue;
1620106Svbart@nginx.com 
1621106Svbart@nginx.com         case 'n':
1622106Svbart@nginx.com             *s++ = '\n';
1623106Svbart@nginx.com             continue;
1624106Svbart@nginx.com 
1625106Svbart@nginx.com         case 'r':
1626106Svbart@nginx.com             *s++ = '\r';
1627106Svbart@nginx.com             continue;
1628106Svbart@nginx.com 
1629106Svbart@nginx.com         case 't':
1630106Svbart@nginx.com             *s++ = '\t';
1631106Svbart@nginx.com             continue;
1632106Svbart@nginx.com 
1633106Svbart@nginx.com         case 'b':
1634106Svbart@nginx.com             *s++ = '\b';
1635106Svbart@nginx.com             continue;
1636106Svbart@nginx.com 
1637106Svbart@nginx.com         case 'f':
1638106Svbart@nginx.com             *s++ = '\f';
1639106Svbart@nginx.com             continue;
1640106Svbart@nginx.com         }
1641106Svbart@nginx.com 
1642106Svbart@nginx.com         utf = 0;
1643106Svbart@nginx.com         utf_high = 0;
1644106Svbart@nginx.com 
1645106Svbart@nginx.com         for ( ;; ) {
1646106Svbart@nginx.com             for (i = 0; i < 4; i++) {
1647202Svbart@nginx.com                 utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A')
1648202Svbart@nginx.com                                                 : p[i] - '0');
1649106Svbart@nginx.com             }
1650106Svbart@nginx.com 
1651106Svbart@nginx.com             p += 4;
1652106Svbart@nginx.com 
1653207Svbart@nginx.com             if (utf_high != 0) {
1654207Svbart@nginx.com                 if (nxt_slow_path(utf < 0xdc00 || utf > 0xdfff)) {
1655208Svbart@nginx.com 
1656208Svbart@nginx.com                     nxt_conf_json_parse_error(error, p - 12,
1657311Snick@nginx.com                         "Invalid JSON encoding sequence.  This 12-byte "
1658311Snick@nginx.com                         "sequence composes an illegal UTF-16 surrogate pair."
1659208Svbart@nginx.com                     );
1660208Svbart@nginx.com 
1661207Svbart@nginx.com                     return NULL;
1662207Svbart@nginx.com                 }
1663207Svbart@nginx.com 
1664207Svbart@nginx.com                 utf = ((utf_high - 0xd800) << 10) + (utf - 0xdc00) + 0x10000;
1665207Svbart@nginx.com 
1666106Svbart@nginx.com                 break;
1667106Svbart@nginx.com             }
1668106Svbart@nginx.com 
1669207Svbart@nginx.com             if (utf < 0xd800 || utf > 0xdfff) {
1670106Svbart@nginx.com                 break;
1671106Svbart@nginx.com             }
1672106Svbart@nginx.com 
1673207Svbart@nginx.com             if (utf > 0xdbff || p[0] != '\\' || p[1] != 'u') {
1674208Svbart@nginx.com 
1675208Svbart@nginx.com                 nxt_conf_json_parse_error(error, p - 6,
1676311Snick@nginx.com                     "Invalid JSON encoding sequence.  This 6-byte sequence "
1677311Snick@nginx.com                     "does not represent a valid UTF character."
1678208Svbart@nginx.com                 );
1679208Svbart@nginx.com 
1680207Svbart@nginx.com                 return NULL;
1681207Svbart@nginx.com             }
1682207Svbart@nginx.com 
1683106Svbart@nginx.com             p += 2;
1684207Svbart@nginx.com 
1685207Svbart@nginx.com             utf_high = utf;
1686207Svbart@nginx.com             utf = 0;
1687106Svbart@nginx.com         }
1688106Svbart@nginx.com 
1689106Svbart@nginx.com         s = nxt_utf8_encode(s, utf);
1690106Svbart@nginx.com 
1691106Svbart@nginx.com     } while (p != last);
1692106Svbart@nginx.com 
1693106Svbart@nginx.com     if (size > NXT_CONF_MAX_SHORT_STRING) {
1694172Svbart@nginx.com         value->u.string.length = s - value->u.string.start;
1695106Svbart@nginx.com 
1696106Svbart@nginx.com     } else {
1697173Svbart@nginx.com         value->u.str.length = s - value->u.str.start;
1698106Svbart@nginx.com     }
1699106Svbart@nginx.com 
1700106Svbart@nginx.com     return last + 1;
1701106Svbart@nginx.com }
1702106Svbart@nginx.com 
1703106Svbart@nginx.com 
1704106Svbart@nginx.com static u_char *
1705106Svbart@nginx.com nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1706208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1707106Svbart@nginx.com {
1708106Svbart@nginx.com     u_char     *p, ch;
1709106Svbart@nginx.com     uint64_t   integer;
1710106Svbart@nginx.com     nxt_int_t  sign;
1711106Svbart@nginx.com #if 0
1712106Svbart@nginx.com     uint64_t   frac, power
1713106Svbart@nginx.com     nxt_int_t  e, negative;
1714106Svbart@nginx.com #endif
1715106Svbart@nginx.com 
1716106Svbart@nginx.com     static const uint64_t cutoff = NXT_INT64_T_MAX / 10;
1717106Svbart@nginx.com     static const uint64_t cutlim = NXT_INT64_T_MAX % 10;
1718106Svbart@nginx.com 
1719106Svbart@nginx.com     ch = *start;
1720106Svbart@nginx.com 
1721106Svbart@nginx.com     if (ch == '-') {
1722106Svbart@nginx.com         sign = -1;
1723106Svbart@nginx.com         start++;
1724106Svbart@nginx.com 
1725106Svbart@nginx.com     } else {
1726106Svbart@nginx.com         sign = 1;
1727106Svbart@nginx.com     }
1728106Svbart@nginx.com 
1729106Svbart@nginx.com     integer = 0;
1730106Svbart@nginx.com 
1731106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1732106Svbart@nginx.com         ch = *p;
1733106Svbart@nginx.com 
1734106Svbart@nginx.com         /* Values below '0' become >= 208. */
1735106Svbart@nginx.com         ch = ch - '0';
1736106Svbart@nginx.com 
1737106Svbart@nginx.com         if (ch > 9) {
1738106Svbart@nginx.com             break;
1739106Svbart@nginx.com         }
1740106Svbart@nginx.com 
1741106Svbart@nginx.com         if (nxt_slow_path(integer >= cutoff
1742106Svbart@nginx.com                           && (integer > cutoff || ch > cutlim)))
1743106Svbart@nginx.com         {
1744208Svbart@nginx.com             nxt_conf_json_parse_error(error, start,
1745311Snick@nginx.com                 "The integer is too large.  Such a large JSON integer value "
1746311Snick@nginx.com                 "is not supported."
1747208Svbart@nginx.com             );
1748208Svbart@nginx.com 
1749208Svbart@nginx.com             return NULL;
1750106Svbart@nginx.com         }
1751106Svbart@nginx.com 
1752106Svbart@nginx.com         integer = integer * 10 + ch;
1753106Svbart@nginx.com     }
1754106Svbart@nginx.com 
1755208Svbart@nginx.com     if (nxt_slow_path(p - start > 1 && *start == '0')) {
1756208Svbart@nginx.com 
1757208Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
1758311Snick@nginx.com             "The number is invalid.  Leading zeros are not allowed in JSON "
1759311Snick@nginx.com             "numbers."
1760208Svbart@nginx.com         );
1761208Svbart@nginx.com 
1762106Svbart@nginx.com         return NULL;
1763106Svbart@nginx.com     }
1764106Svbart@nginx.com 
1765106Svbart@nginx.com     if (ch != '.') {
1766116Svbart@nginx.com         value->type = NXT_CONF_VALUE_INTEGER;
1767106Svbart@nginx.com         value->u.integer = sign * integer;
1768106Svbart@nginx.com         return p;
1769106Svbart@nginx.com     }
1770106Svbart@nginx.com 
1771106Svbart@nginx.com #if 0
1772106Svbart@nginx.com     start = p + 1;
1773106Svbart@nginx.com 
1774106Svbart@nginx.com     frac = 0;
1775106Svbart@nginx.com     power = 1;
1776106Svbart@nginx.com 
1777106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1778106Svbart@nginx.com         ch = *p;
1779106Svbart@nginx.com 
1780106Svbart@nginx.com         /* Values below '0' become >= 208. */
1781106Svbart@nginx.com         ch = ch - '0';
1782106Svbart@nginx.com 
1783106Svbart@nginx.com         if (ch > 9) {
1784106Svbart@nginx.com             break;
1785106Svbart@nginx.com         }
1786106Svbart@nginx.com 
1787106Svbart@nginx.com         if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim))
1788106Svbart@nginx.com                           || power > cutoff))
1789106Svbart@nginx.com         {
1790106Svbart@nginx.com             return NULL;
1791106Svbart@nginx.com         }
1792106Svbart@nginx.com 
1793106Svbart@nginx.com         frac = frac * 10 + ch;
1794106Svbart@nginx.com         power *= 10;
1795106Svbart@nginx.com     }
1796106Svbart@nginx.com 
1797106Svbart@nginx.com     if (nxt_slow_path(p == start)) {
1798106Svbart@nginx.com         return NULL;
1799106Svbart@nginx.com     }
1800106Svbart@nginx.com 
1801116Svbart@nginx.com     value->type = NXT_CONF_VALUE_NUMBER;
1802106Svbart@nginx.com     value->u.number = integer + (double) frac / power;
1803106Svbart@nginx.com 
1804106Svbart@nginx.com     value->u.number = copysign(value->u.number, sign);
1805106Svbart@nginx.com 
1806106Svbart@nginx.com     if (ch == 'e' || ch == 'E') {
1807106Svbart@nginx.com         start = p + 1;
1808106Svbart@nginx.com 
1809106Svbart@nginx.com         ch = *start;
1810106Svbart@nginx.com 
1811106Svbart@nginx.com         if (ch == '-' || ch == '+') {
1812106Svbart@nginx.com             start++;
1813106Svbart@nginx.com         }
1814106Svbart@nginx.com 
1815106Svbart@nginx.com         negative = (ch == '-') ? 1 : 0;
1816106Svbart@nginx.com         e = 0;
1817106Svbart@nginx.com 
1818106Svbart@nginx.com         for (p = start; nxt_fast_path(p != end); p++) {
1819106Svbart@nginx.com             ch = *p;
1820106Svbart@nginx.com 
1821106Svbart@nginx.com             /* Values below '0' become >= 208. */
1822106Svbart@nginx.com             ch = ch - '0';
1823106Svbart@nginx.com 
1824106Svbart@nginx.com             if (ch > 9) {
1825106Svbart@nginx.com                 break;
1826106Svbart@nginx.com             }
1827106Svbart@nginx.com 
1828106Svbart@nginx.com             e = e * 10 + ch;
1829106Svbart@nginx.com 
1830106Svbart@nginx.com             if (nxt_slow_path(e > DBL_MAX_10_EXP)) {
1831106Svbart@nginx.com                 return NULL;
1832106Svbart@nginx.com             }
1833106Svbart@nginx.com         }
1834106Svbart@nginx.com 
1835106Svbart@nginx.com         if (nxt_slow_path(p == start)) {
1836106Svbart@nginx.com             return NULL;
1837106Svbart@nginx.com         }
1838106Svbart@nginx.com 
1839106Svbart@nginx.com         if (negative) {
1840106Svbart@nginx.com             value->u.number /= exp10(e);
1841106Svbart@nginx.com 
1842106Svbart@nginx.com         } else {
1843106Svbart@nginx.com             value->u.number *= exp10(e);
1844106Svbart@nginx.com         }
1845106Svbart@nginx.com     }
1846106Svbart@nginx.com 
1847106Svbart@nginx.com     if (nxt_fast_path(isfinite(value->u.number))) {
1848106Svbart@nginx.com         return p;
1849106Svbart@nginx.com     }
1850208Svbart@nginx.com #else
1851208Svbart@nginx.com 
1852208Svbart@nginx.com     nxt_conf_json_parse_error(error, start,
1853311Snick@nginx.com         "The number is not an integer.  JSON numbers with decimals and "
1854311Snick@nginx.com         "exponents are not supported."
1855208Svbart@nginx.com     );
1856208Svbart@nginx.com 
1857106Svbart@nginx.com #endif
1858106Svbart@nginx.com 
1859106Svbart@nginx.com     return NULL;
1860106Svbart@nginx.com }
1861106Svbart@nginx.com 
1862106Svbart@nginx.com 
1863208Svbart@nginx.com static void
1864208Svbart@nginx.com nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
1865208Svbart@nginx.com     const char *detail)
1866208Svbart@nginx.com {
1867208Svbart@nginx.com     if (error == NULL) {
1868208Svbart@nginx.com         return;
1869208Svbart@nginx.com     }
1870208Svbart@nginx.com 
1871208Svbart@nginx.com     error->pos = pos;
1872208Svbart@nginx.com     error->detail = (u_char *) detail;
1873208Svbart@nginx.com }
1874208Svbart@nginx.com 
1875208Svbart@nginx.com 
1876106Svbart@nginx.com size_t
1877106Svbart@nginx.com nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
1878106Svbart@nginx.com {
1879106Svbart@nginx.com     switch (value->type) {
1880106Svbart@nginx.com 
1881116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
1882106Svbart@nginx.com         return sizeof("null") - 1;
1883106Svbart@nginx.com 
1884116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
1885106Svbart@nginx.com         return value->u.boolean ? sizeof("true") - 1 : sizeof("false") - 1;
1886106Svbart@nginx.com 
1887116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
1888106Svbart@nginx.com         return nxt_conf_json_integer_length(value);
1889106Svbart@nginx.com 
1890116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
1891106Svbart@nginx.com         /* TODO */
1892106Svbart@nginx.com         return 0;
1893106Svbart@nginx.com 
1894116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
1895116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
1896106Svbart@nginx.com         return nxt_conf_json_string_length(value);
1897106Svbart@nginx.com 
1898116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
1899106Svbart@nginx.com         return nxt_conf_json_array_length(value, pretty);
1900106Svbart@nginx.com 
1901116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
1902106Svbart@nginx.com         return nxt_conf_json_object_length(value, pretty);
1903106Svbart@nginx.com     }
1904106Svbart@nginx.com 
1905106Svbart@nginx.com     nxt_unreachable();
1906106Svbart@nginx.com 
1907106Svbart@nginx.com     return 0;
1908106Svbart@nginx.com }
1909106Svbart@nginx.com 
1910106Svbart@nginx.com 
1911106Svbart@nginx.com u_char *
1912106Svbart@nginx.com nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
1913106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
1914106Svbart@nginx.com {
1915106Svbart@nginx.com     switch (value->type) {
1916106Svbart@nginx.com 
1917116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
1918106Svbart@nginx.com         return nxt_cpymem(p, "null", 4);
1919106Svbart@nginx.com 
1920116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
1921106Svbart@nginx.com         return value->u.boolean ? nxt_cpymem(p, "true", 4)
1922106Svbart@nginx.com                                 : nxt_cpymem(p, "false", 5);
1923106Svbart@nginx.com 
1924116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
1925106Svbart@nginx.com         return nxt_conf_json_print_integer(p, value);
1926106Svbart@nginx.com 
1927116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
1928106Svbart@nginx.com         /* TODO */
1929106Svbart@nginx.com         return p;
1930106Svbart@nginx.com 
1931116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
1932116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
1933106Svbart@nginx.com         return nxt_conf_json_print_string(p, value);
1934106Svbart@nginx.com 
1935116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
1936106Svbart@nginx.com         return nxt_conf_json_print_array(p, value, pretty);
1937106Svbart@nginx.com 
1938116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
1939106Svbart@nginx.com         return nxt_conf_json_print_object(p, value, pretty);
1940106Svbart@nginx.com     }
1941106Svbart@nginx.com 
1942106Svbart@nginx.com     nxt_unreachable();
1943106Svbart@nginx.com 
1944106Svbart@nginx.com     return p;
1945106Svbart@nginx.com }
1946106Svbart@nginx.com 
1947106Svbart@nginx.com 
1948106Svbart@nginx.com static size_t
1949106Svbart@nginx.com nxt_conf_json_integer_length(nxt_conf_value_t *value)
1950106Svbart@nginx.com {
1951106Svbart@nginx.com     int64_t  num;
1952106Svbart@nginx.com 
1953106Svbart@nginx.com     num = llabs(value->u.integer);
1954106Svbart@nginx.com 
1955106Svbart@nginx.com     if (num <= 9999) {
1956106Svbart@nginx.com         return sizeof("-9999") - 1;
1957106Svbart@nginx.com     }
1958106Svbart@nginx.com 
1959210Svbart@nginx.com     if (num <= 99999999999LL) {
1960106Svbart@nginx.com         return sizeof("-99999999999") - 1;
1961106Svbart@nginx.com     }
1962106Svbart@nginx.com 
1963106Svbart@nginx.com     return NXT_INT64_T_LEN;
1964106Svbart@nginx.com }
1965106Svbart@nginx.com 
1966106Svbart@nginx.com 
1967106Svbart@nginx.com static u_char *
1968106Svbart@nginx.com nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value)
1969106Svbart@nginx.com {
1970106Svbart@nginx.com     return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer);
1971106Svbart@nginx.com }
1972106Svbart@nginx.com 
1973106Svbart@nginx.com 
1974106Svbart@nginx.com static size_t
1975106Svbart@nginx.com nxt_conf_json_string_length(nxt_conf_value_t *value)
1976106Svbart@nginx.com {
1977106Svbart@nginx.com     nxt_str_t  str;
1978106Svbart@nginx.com 
1979106Svbart@nginx.com     nxt_conf_get_string(value, &str);
1980106Svbart@nginx.com 
1981106Svbart@nginx.com     return 2 + nxt_conf_json_escape_length(str.start, str.length);
1982106Svbart@nginx.com }
1983106Svbart@nginx.com 
1984106Svbart@nginx.com 
1985106Svbart@nginx.com static u_char *
1986106Svbart@nginx.com nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value)
1987106Svbart@nginx.com {
1988106Svbart@nginx.com     nxt_str_t  str;
1989106Svbart@nginx.com 
1990106Svbart@nginx.com     nxt_conf_get_string(value, &str);
1991106Svbart@nginx.com 
1992106Svbart@nginx.com     *p++ = '"';
1993106Svbart@nginx.com 
1994106Svbart@nginx.com     p = nxt_conf_json_escape(p, str.start, str.length);
1995106Svbart@nginx.com 
1996106Svbart@nginx.com     *p++ = '"';
1997106Svbart@nginx.com 
1998106Svbart@nginx.com     return p;
1999106Svbart@nginx.com }
2000106Svbart@nginx.com 
2001106Svbart@nginx.com 
2002106Svbart@nginx.com static size_t
2003106Svbart@nginx.com nxt_conf_json_array_length(nxt_conf_value_t *value,
2004106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2005106Svbart@nginx.com {
2006106Svbart@nginx.com     size_t            len;
2007106Svbart@nginx.com     nxt_uint_t        n;
2008106Svbart@nginx.com     nxt_conf_array_t  *array;
2009106Svbart@nginx.com 
2010106Svbart@nginx.com     array = value->u.array;
2011106Svbart@nginx.com 
2012106Svbart@nginx.com     /* [] */
2013106Svbart@nginx.com     len = 2;
2014106Svbart@nginx.com 
2015106Svbart@nginx.com     if (pretty != NULL) {
2016106Svbart@nginx.com         pretty->level++;
2017106Svbart@nginx.com     }
2018106Svbart@nginx.com 
2019106Svbart@nginx.com     value = array->elements;
2020106Svbart@nginx.com 
2021106Svbart@nginx.com     for (n = 0; n < array->count; n++) {
2022106Svbart@nginx.com         len += nxt_conf_json_length(&value[n], pretty);
2023106Svbart@nginx.com 
2024106Svbart@nginx.com         if (pretty != NULL) {
2025106Svbart@nginx.com             /* Indentation and new line. */
2026106Svbart@nginx.com             len += pretty->level + 2;
2027106Svbart@nginx.com         }
2028106Svbart@nginx.com     }
2029106Svbart@nginx.com 
2030106Svbart@nginx.com     if (pretty != NULL) {
2031106Svbart@nginx.com         pretty->level--;
2032106Svbart@nginx.com 
2033106Svbart@nginx.com         if (n != 0) {
2034106Svbart@nginx.com             /* Indentation and new line. */
2035106Svbart@nginx.com             len += pretty->level + 2;
2036106Svbart@nginx.com         }
2037106Svbart@nginx.com     }
2038106Svbart@nginx.com 
2039106Svbart@nginx.com     /* Reserve space for "n" commas. */
2040106Svbart@nginx.com     return len + n;
2041106Svbart@nginx.com }
2042106Svbart@nginx.com 
2043106Svbart@nginx.com 
2044106Svbart@nginx.com static u_char *
2045106Svbart@nginx.com nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
2046106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2047106Svbart@nginx.com {
2048106Svbart@nginx.com     nxt_uint_t        n;
2049106Svbart@nginx.com     nxt_conf_array_t  *array;
2050106Svbart@nginx.com 
2051106Svbart@nginx.com     array = value->u.array;
2052106Svbart@nginx.com 
2053106Svbart@nginx.com     *p++ = '[';
2054106Svbart@nginx.com 
2055106Svbart@nginx.com     if (array->count != 0) {
2056106Svbart@nginx.com         value = array->elements;
2057106Svbart@nginx.com 
2058106Svbart@nginx.com         if (pretty != NULL) {
2059106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2060106Svbart@nginx.com 
2061106Svbart@nginx.com             pretty->level++;
2062106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2063106Svbart@nginx.com         }
2064106Svbart@nginx.com 
2065106Svbart@nginx.com         p = nxt_conf_json_print(p, &value[0], pretty);
2066106Svbart@nginx.com 
2067106Svbart@nginx.com         for (n = 1; n < array->count; n++) {
2068106Svbart@nginx.com             *p++ = ',';
2069106Svbart@nginx.com 
2070106Svbart@nginx.com             if (pretty != NULL) {
2071106Svbart@nginx.com                 p = nxt_conf_json_newline(p);
2072106Svbart@nginx.com                 p = nxt_conf_json_indentation(p, pretty->level);
2073106Svbart@nginx.com 
2074106Svbart@nginx.com                 pretty->more_space = 0;
2075106Svbart@nginx.com             }
2076106Svbart@nginx.com 
2077106Svbart@nginx.com             p = nxt_conf_json_print(p, &value[n], pretty);
2078106Svbart@nginx.com         }
2079106Svbart@nginx.com 
2080106Svbart@nginx.com         if (pretty != NULL) {
2081106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2082106Svbart@nginx.com 
2083106Svbart@nginx.com             pretty->level--;
2084106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2085106Svbart@nginx.com 
2086106Svbart@nginx.com             pretty->more_space = 1;
2087106Svbart@nginx.com         }
2088106Svbart@nginx.com     }
2089106Svbart@nginx.com 
2090106Svbart@nginx.com     *p++ = ']';
2091106Svbart@nginx.com 
2092106Svbart@nginx.com     return p;
2093106Svbart@nginx.com }
2094106Svbart@nginx.com 
2095106Svbart@nginx.com 
2096106Svbart@nginx.com static size_t
2097106Svbart@nginx.com nxt_conf_json_object_length(nxt_conf_value_t *value,
2098106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2099106Svbart@nginx.com {
2100106Svbart@nginx.com     size_t                    len;
2101106Svbart@nginx.com     nxt_uint_t                n;
2102106Svbart@nginx.com     nxt_conf_object_t         *object;
2103106Svbart@nginx.com     nxt_conf_object_member_t  *member;
2104106Svbart@nginx.com 
2105106Svbart@nginx.com     object = value->u.object;
2106106Svbart@nginx.com 
2107106Svbart@nginx.com     /* {} */
2108106Svbart@nginx.com     len = 2;
2109106Svbart@nginx.com 
2110106Svbart@nginx.com     if (pretty != NULL) {
2111106Svbart@nginx.com         pretty->level++;
2112106Svbart@nginx.com     }
2113106Svbart@nginx.com 
2114106Svbart@nginx.com     member = object->members;
2115106Svbart@nginx.com 
2116106Svbart@nginx.com     for (n = 0; n < object->count; n++) {
2117106Svbart@nginx.com         len += nxt_conf_json_string_length(&member[n].name) + 1
2118106Svbart@nginx.com                + nxt_conf_json_length(&member[n].value, pretty) + 1;
2119106Svbart@nginx.com 
2120106Svbart@nginx.com         if (pretty != NULL) {
2121106Svbart@nginx.com             /*
2122106Svbart@nginx.com              * Indentation, space after ":", new line, and possible
2123106Svbart@nginx.com              * additional empty line between non-empty objects.
2124106Svbart@nginx.com              */
2125106Svbart@nginx.com             len += pretty->level + 1 + 2 + 2;
2126106Svbart@nginx.com         }
2127106Svbart@nginx.com     }
2128106Svbart@nginx.com 
2129106Svbart@nginx.com     if (pretty != NULL) {
2130106Svbart@nginx.com         pretty->level--;
2131106Svbart@nginx.com 
2132106Svbart@nginx.com         /* Indentation and new line. */
2133106Svbart@nginx.com         len += pretty->level + 2;
2134106Svbart@nginx.com     }
2135106Svbart@nginx.com 
2136106Svbart@nginx.com     return len;
2137106Svbart@nginx.com }
2138106Svbart@nginx.com 
2139106Svbart@nginx.com 
2140106Svbart@nginx.com static u_char *
2141106Svbart@nginx.com nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
2142106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2143106Svbart@nginx.com {
2144106Svbart@nginx.com     nxt_uint_t                n;
2145106Svbart@nginx.com     nxt_conf_object_t         *object;
2146106Svbart@nginx.com     nxt_conf_object_member_t  *member;
2147106Svbart@nginx.com 
2148106Svbart@nginx.com     object = value->u.object;
2149106Svbart@nginx.com 
2150106Svbart@nginx.com     *p++ = '{';
2151106Svbart@nginx.com 
2152106Svbart@nginx.com     if (object->count != 0) {
2153106Svbart@nginx.com 
2154106Svbart@nginx.com         if (pretty != NULL) {
2155106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2156106Svbart@nginx.com             pretty->level++;
2157106Svbart@nginx.com         }
2158106Svbart@nginx.com 
2159106Svbart@nginx.com         member = object->members;
2160106Svbart@nginx.com 
2161106Svbart@nginx.com         n = 0;
2162106Svbart@nginx.com 
2163106Svbart@nginx.com         for ( ;; ) {
2164106Svbart@nginx.com             if (pretty != NULL) {
2165106Svbart@nginx.com                 p = nxt_conf_json_indentation(p, pretty->level);
2166106Svbart@nginx.com             }
2167106Svbart@nginx.com 
2168106Svbart@nginx.com             p = nxt_conf_json_print_string(p, &member[n].name);
2169106Svbart@nginx.com 
2170106Svbart@nginx.com             *p++ = ':';
2171106Svbart@nginx.com 
2172106Svbart@nginx.com             if (pretty != NULL) {
2173106Svbart@nginx.com                 *p++ = ' ';
2174106Svbart@nginx.com             }
2175106Svbart@nginx.com 
2176106Svbart@nginx.com             p = nxt_conf_json_print(p, &member[n].value, pretty);
2177106Svbart@nginx.com 
2178106Svbart@nginx.com             n++;
2179106Svbart@nginx.com 
2180106Svbart@nginx.com             if (n == object->count) {
2181106Svbart@nginx.com                 break;
2182106Svbart@nginx.com             }
2183106Svbart@nginx.com 
2184106Svbart@nginx.com             *p++ = ',';
2185106Svbart@nginx.com 
2186106Svbart@nginx.com             if (pretty != NULL) {
2187106Svbart@nginx.com                 p = nxt_conf_json_newline(p);
2188106Svbart@nginx.com 
2189106Svbart@nginx.com                 if (pretty->more_space) {
2190106Svbart@nginx.com                     pretty->more_space = 0;
2191106Svbart@nginx.com                     p = nxt_conf_json_newline(p);
2192106Svbart@nginx.com                 }
2193106Svbart@nginx.com             }
2194106Svbart@nginx.com         }
2195106Svbart@nginx.com 
2196106Svbart@nginx.com         if (pretty != NULL) {
2197106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2198106Svbart@nginx.com 
2199106Svbart@nginx.com             pretty->level--;
2200106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2201106Svbart@nginx.com 
2202106Svbart@nginx.com             pretty->more_space = 1;
2203106Svbart@nginx.com         }
2204106Svbart@nginx.com     }
2205106Svbart@nginx.com 
2206106Svbart@nginx.com     *p++ = '}';
2207106Svbart@nginx.com 
2208106Svbart@nginx.com     return p;
2209106Svbart@nginx.com }
2210106Svbart@nginx.com 
2211106Svbart@nginx.com 
2212106Svbart@nginx.com static size_t
2213106Svbart@nginx.com nxt_conf_json_escape_length(u_char *p, size_t size)
2214106Svbart@nginx.com {
2215106Svbart@nginx.com     u_char  ch;
2216106Svbart@nginx.com     size_t  len;
2217106Svbart@nginx.com 
2218106Svbart@nginx.com     len = size;
2219106Svbart@nginx.com 
2220106Svbart@nginx.com     while (size) {
2221106Svbart@nginx.com         ch = *p++;
2222106Svbart@nginx.com 
2223106Svbart@nginx.com         if (ch == '\\' || ch == '"') {
2224106Svbart@nginx.com             len++;
2225106Svbart@nginx.com 
2226106Svbart@nginx.com         } else if (ch <= 0x1f) {
2227106Svbart@nginx.com 
2228106Svbart@nginx.com             switch (ch) {
2229106Svbart@nginx.com             case '\n':
2230106Svbart@nginx.com             case '\r':
2231106Svbart@nginx.com             case '\t':
2232106Svbart@nginx.com             case '\b':
2233106Svbart@nginx.com             case '\f':
2234106Svbart@nginx.com                 len++;
2235106Svbart@nginx.com                 break;
2236106Svbart@nginx.com 
2237106Svbart@nginx.com             default:
2238106Svbart@nginx.com                 len += sizeof("\\u001F") - 2;
2239106Svbart@nginx.com             }
2240106Svbart@nginx.com         }
2241106Svbart@nginx.com 
2242106Svbart@nginx.com         size--;
2243106Svbart@nginx.com     }
2244106Svbart@nginx.com 
2245106Svbart@nginx.com     return len;
2246106Svbart@nginx.com }
2247106Svbart@nginx.com 
2248106Svbart@nginx.com 
2249106Svbart@nginx.com static u_char *
2250106Svbart@nginx.com nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
2251106Svbart@nginx.com {
2252106Svbart@nginx.com     u_char  ch;
2253106Svbart@nginx.com 
2254106Svbart@nginx.com     while (size) {
2255106Svbart@nginx.com         ch = *src++;
2256106Svbart@nginx.com 
2257106Svbart@nginx.com         if (ch > 0x1f) {
2258106Svbart@nginx.com 
2259106Svbart@nginx.com             if (ch == '\\' || ch == '"') {
2260106Svbart@nginx.com                 *dst++ = '\\';
2261106Svbart@nginx.com             }
2262106Svbart@nginx.com 
2263106Svbart@nginx.com             *dst++ = ch;
2264106Svbart@nginx.com 
2265106Svbart@nginx.com         } else {
2266106Svbart@nginx.com             *dst++ = '\\';
2267106Svbart@nginx.com 
2268106Svbart@nginx.com             switch (ch) {
2269106Svbart@nginx.com             case '\n':
2270106Svbart@nginx.com                 *dst++ = 'n';
2271106Svbart@nginx.com                 break;
2272106Svbart@nginx.com 
2273106Svbart@nginx.com             case '\r':
2274106Svbart@nginx.com                 *dst++ = 'r';
2275106Svbart@nginx.com                 break;
2276106Svbart@nginx.com 
2277106Svbart@nginx.com             case '\t':
2278106Svbart@nginx.com                 *dst++ = 't';
2279106Svbart@nginx.com                 break;
2280106Svbart@nginx.com 
2281106Svbart@nginx.com             case '\b':
2282106Svbart@nginx.com                 *dst++ = 'b';
2283106Svbart@nginx.com                 break;
2284106Svbart@nginx.com 
2285106Svbart@nginx.com             case '\f':
2286106Svbart@nginx.com                 *dst++ = 'f';
2287106Svbart@nginx.com                 break;
2288106Svbart@nginx.com 
2289106Svbart@nginx.com             default:
2290106Svbart@nginx.com                 *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
2291106Svbart@nginx.com                 *dst++ = '0' + (ch >> 4);
2292106Svbart@nginx.com 
2293106Svbart@nginx.com                 ch &= 0xf;
2294106Svbart@nginx.com 
2295106Svbart@nginx.com                 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
2296106Svbart@nginx.com             }
2297106Svbart@nginx.com         }
2298106Svbart@nginx.com 
2299106Svbart@nginx.com         size--;
2300106Svbart@nginx.com     }
2301106Svbart@nginx.com 
2302106Svbart@nginx.com     return dst;
2303106Svbart@nginx.com }
2304208Svbart@nginx.com 
2305208Svbart@nginx.com 
2306208Svbart@nginx.com void
2307208Svbart@nginx.com nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line,
2308208Svbart@nginx.com     nxt_uint_t *column)
2309208Svbart@nginx.com {
2310208Svbart@nginx.com     u_char      *p;
2311208Svbart@nginx.com     ssize_t     symbols;
2312208Svbart@nginx.com     nxt_uint_t  lines;
2313208Svbart@nginx.com 
2314208Svbart@nginx.com     lines = 1;
2315208Svbart@nginx.com 
2316208Svbart@nginx.com     for (p = start; p != pos; p++) {
2317208Svbart@nginx.com 
2318208Svbart@nginx.com         if (*p != '\n') {
2319208Svbart@nginx.com             continue;
2320208Svbart@nginx.com         }
2321208Svbart@nginx.com 
2322208Svbart@nginx.com         lines++;
2323208Svbart@nginx.com         start = p + 1;
2324208Svbart@nginx.com     }
2325208Svbart@nginx.com 
2326208Svbart@nginx.com     symbols = nxt_utf8_length(start, p - start);
2327208Svbart@nginx.com 
2328208Svbart@nginx.com     if (symbols != -1) {
2329208Svbart@nginx.com         *line = lines;
2330208Svbart@nginx.com         *column = 1 + symbols;
2331208Svbart@nginx.com     }
2332208Svbart@nginx.com }
2333