xref: /unit/src/nxt_conf.c (revision 2632:77c672f9ba45)
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.
6*2632Salx@kernel.org  * Copyright 2024, Alejandro Colomar <alx@kernel.org>
7106Svbart@nginx.com  */
8106Svbart@nginx.com 
9106Svbart@nginx.com #include <nxt_main.h>
10106Svbart@nginx.com #include <nxt_conf.h>
111439Svbart@nginx.com 
121439Svbart@nginx.com #include <float.h>
13106Svbart@nginx.com #include <math.h>
14106Svbart@nginx.com 
15106Svbart@nginx.com 
16106Svbart@nginx.com #define NXT_CONF_MAX_SHORT_STRING  14
171439Svbart@nginx.com #define NXT_CONF_MAX_NUMBER_LEN    14
18172Svbart@nginx.com #define NXT_CONF_MAX_STRING        NXT_INT32_T_MAX
19106Svbart@nginx.com 
201174Svbart@nginx.com #define NXT_CONF_MAX_TOKEN_LEN     256
211174Svbart@nginx.com 
22106Svbart@nginx.com 
23106Svbart@nginx.com typedef enum {
24116Svbart@nginx.com     NXT_CONF_VALUE_NULL = 0,
25116Svbart@nginx.com     NXT_CONF_VALUE_BOOLEAN,
26116Svbart@nginx.com     NXT_CONF_VALUE_INTEGER,
27116Svbart@nginx.com     NXT_CONF_VALUE_NUMBER,
28116Svbart@nginx.com     NXT_CONF_VALUE_SHORT_STRING,
29116Svbart@nginx.com     NXT_CONF_VALUE_STRING,
30116Svbart@nginx.com     NXT_CONF_VALUE_ARRAY,
31116Svbart@nginx.com     NXT_CONF_VALUE_OBJECT,
32116Svbart@nginx.com } nxt_conf_value_type_t;
33106Svbart@nginx.com 
34106Svbart@nginx.com 
35106Svbart@nginx.com typedef enum {
36106Svbart@nginx.com     NXT_CONF_OP_PASS = 0,
37106Svbart@nginx.com     NXT_CONF_OP_CREATE,
38106Svbart@nginx.com     NXT_CONF_OP_REPLACE,
39106Svbart@nginx.com     NXT_CONF_OP_DELETE,
40106Svbart@nginx.com } nxt_conf_op_action_t;
41106Svbart@nginx.com 
42106Svbart@nginx.com 
43106Svbart@nginx.com typedef struct nxt_conf_array_s   nxt_conf_array_t;
44106Svbart@nginx.com typedef struct nxt_conf_object_s  nxt_conf_object_t;
45106Svbart@nginx.com 
46106Svbart@nginx.com 
47180Smax.romanov@nginx.com struct nxt_conf_value_s {
48187Smax.romanov@nginx.com     union {
49171Svbart@nginx.com         uint8_t               boolean;  /* 1 bit. */
502435Sa.clayton@nginx.com         u_char                number[NXT_CONF_MAX_NUMBER_LEN + 1];
51173Svbart@nginx.com 
52173Svbart@nginx.com         struct {
53208Svbart@nginx.com             u_char            start[NXT_CONF_MAX_SHORT_STRING];
54173Svbart@nginx.com             uint8_t           length;
55173Svbart@nginx.com         } str;
56172Svbart@nginx.com 
57187Smax.romanov@nginx.com         struct {
58172Svbart@nginx.com             u_char            *start;
59172Svbart@nginx.com             uint32_t          length;
60187Smax.romanov@nginx.com         } nxt_packed string;
61172Svbart@nginx.com 
62106Svbart@nginx.com         nxt_conf_array_t      *array;
63106Svbart@nginx.com         nxt_conf_object_t     *object;
64187Smax.romanov@nginx.com     } nxt_packed u;
65106Svbart@nginx.com 
66171Svbart@nginx.com     uint8_t                   type;  /* 3 bits. */
67180Smax.romanov@nginx.com } nxt_aligned(8);
68106Svbart@nginx.com 
69106Svbart@nginx.com 
70106Svbart@nginx.com struct nxt_conf_array_s {
71106Svbart@nginx.com     nxt_uint_t                count;
72106Svbart@nginx.com     nxt_conf_value_t          elements[];
73106Svbart@nginx.com };
74106Svbart@nginx.com 
75106Svbart@nginx.com 
76106Svbart@nginx.com typedef struct {
77106Svbart@nginx.com     nxt_conf_value_t          name;
78106Svbart@nginx.com     nxt_conf_value_t          value;
79106Svbart@nginx.com } nxt_conf_object_member_t;
80106Svbart@nginx.com 
81106Svbart@nginx.com 
82106Svbart@nginx.com struct nxt_conf_object_s {
83106Svbart@nginx.com     nxt_uint_t                count;
84106Svbart@nginx.com     nxt_conf_object_member_t  members[];
85106Svbart@nginx.com };
86106Svbart@nginx.com 
87106Svbart@nginx.com 
88106Svbart@nginx.com struct nxt_conf_op_s {
89106Svbart@nginx.com     uint32_t                  index;
90106Svbart@nginx.com     uint32_t                  action;  /* nxt_conf_op_action_t */
91106Svbart@nginx.com     void                      *ctx;
92106Svbart@nginx.com };
93106Svbart@nginx.com 
94106Svbart@nginx.com 
951174Svbart@nginx.com typedef struct {
961174Svbart@nginx.com     u_char                    *start;
971174Svbart@nginx.com     u_char                    *end;
981174Svbart@nginx.com     nxt_bool_t                last;
991174Svbart@nginx.com     u_char                    buf[NXT_CONF_MAX_TOKEN_LEN];
1001174Svbart@nginx.com } nxt_conf_path_parse_t;
1011174Svbart@nginx.com 
1021174Svbart@nginx.com 
1031174Svbart@nginx.com static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse,
1041174Svbart@nginx.com     nxt_str_t *token);
1051174Svbart@nginx.com 
1062139Sandrew@digital-domain.net static u_char *nxt_conf_json_skip_space(u_char *start, const u_char *end);
107106Svbart@nginx.com static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
108208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
109106Svbart@nginx.com static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
110208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
111106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
112106Svbart@nginx.com     nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
113106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
114106Svbart@nginx.com     void *data);
115106Svbart@nginx.com static void *nxt_conf_object_hash_alloc(void *data, size_t size);
116106Svbart@nginx.com static void nxt_conf_object_hash_free(void *data, void *p);
117106Svbart@nginx.com static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
118208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
119106Svbart@nginx.com static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value,
120208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
121106Svbart@nginx.com static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value,
122208Svbart@nginx.com     u_char *start, u_char *end, nxt_conf_json_error_t *error);
123208Svbart@nginx.com static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
124208Svbart@nginx.com     const char *detail);
125106Svbart@nginx.com 
126106Svbart@nginx.com static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
127106Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
1281048Svbart@nginx.com static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op,
1291048Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
130106Svbart@nginx.com static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op,
131106Svbart@nginx.com     nxt_conf_value_t *dst, nxt_conf_value_t *src);
132106Svbart@nginx.com 
133106Svbart@nginx.com static size_t nxt_conf_json_string_length(nxt_conf_value_t *value);
134106Svbart@nginx.com static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value);
135106Svbart@nginx.com static size_t nxt_conf_json_array_length(nxt_conf_value_t *value,
136106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
137106Svbart@nginx.com static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
138106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
139106Svbart@nginx.com static size_t nxt_conf_json_object_length(nxt_conf_value_t *value,
140106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
141106Svbart@nginx.com static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
142106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty);
143106Svbart@nginx.com 
144106Svbart@nginx.com static size_t nxt_conf_json_escape_length(u_char *p, size_t size);
145106Svbart@nginx.com static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
146106Svbart@nginx.com 
147106Svbart@nginx.com 
148106Svbart@nginx.com #define nxt_conf_json_newline(p)                                              \
149106Svbart@nginx.com     ((p)[0] = '\r', (p)[1] = '\n', (p) + 2)
150106Svbart@nginx.com 
151106Svbart@nginx.com 
152106Svbart@nginx.com nxt_inline u_char *
nxt_conf_json_indentation(u_char * p,uint32_t level)153106Svbart@nginx.com nxt_conf_json_indentation(u_char *p, uint32_t level)
154106Svbart@nginx.com {
155106Svbart@nginx.com     while (level) {
156106Svbart@nginx.com         *p++ = '\t';
157106Svbart@nginx.com         level--;
158106Svbart@nginx.com     }
159106Svbart@nginx.com 
160106Svbart@nginx.com     return p;
161106Svbart@nginx.com }
162106Svbart@nginx.com 
163106Svbart@nginx.com 
164121Svbart@nginx.com void
nxt_conf_get_string(nxt_conf_value_t * value,nxt_str_t * str)165106Svbart@nginx.com nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
166106Svbart@nginx.com {
167116Svbart@nginx.com     if (value->type == NXT_CONF_VALUE_SHORT_STRING) {
168173Svbart@nginx.com         str->length = value->u.str.length;
169173Svbart@nginx.com         str->start = value->u.str.start;
170106Svbart@nginx.com 
171106Svbart@nginx.com     } else {
172172Svbart@nginx.com         str->length = value->u.string.length;
173172Svbart@nginx.com         str->start = value->u.string.start;
174106Svbart@nginx.com     }
175106Svbart@nginx.com }
176106Svbart@nginx.com 
177106Svbart@nginx.com 
178*2632Salx@kernel.org nxt_str_t *
nxt_conf_get_string_dup(nxt_conf_value_t * value,nxt_mp_t * mp,nxt_str_t * str)179*2632Salx@kernel.org nxt_conf_get_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str)
180*2632Salx@kernel.org {
181*2632Salx@kernel.org     nxt_str_t  s;
182*2632Salx@kernel.org 
183*2632Salx@kernel.org     nxt_conf_get_string(value, &s);
184*2632Salx@kernel.org     return nxt_str_dup(mp, str, &s);
185*2632Salx@kernel.org }
186*2632Salx@kernel.org 
187*2632Salx@kernel.org 
188773Svbart@nginx.com void
nxt_conf_set_string(nxt_conf_value_t * value,nxt_str_t * str)189773Svbart@nginx.com nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str)
190773Svbart@nginx.com {
191773Svbart@nginx.com     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
192773Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
193773Svbart@nginx.com         value->u.string.length = str->length;
194773Svbart@nginx.com         value->u.string.start = str->start;
195773Svbart@nginx.com 
196773Svbart@nginx.com     } else {
197773Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
198773Svbart@nginx.com         value->u.str.length = str->length;
199773Svbart@nginx.com 
200773Svbart@nginx.com         nxt_memcpy(value->u.str.start, str->start, str->length);
201773Svbart@nginx.com     }
202773Svbart@nginx.com }
203773Svbart@nginx.com 
204773Svbart@nginx.com 
205774Svbart@nginx.com nxt_int_t
nxt_conf_set_string_dup(nxt_conf_value_t * value,nxt_mp_t * mp,const nxt_str_t * str)2062075Salx.manpages@gmail.com nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp,
2072075Salx.manpages@gmail.com     const nxt_str_t *str)
208774Svbart@nginx.com {
209774Svbart@nginx.com     nxt_str_t  tmp, *ptr;
210774Svbart@nginx.com 
211774Svbart@nginx.com     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
212774Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
213774Svbart@nginx.com 
214774Svbart@nginx.com         ptr = nxt_str_dup(mp, &tmp, str);
215774Svbart@nginx.com         if (nxt_slow_path(ptr == NULL)) {
216774Svbart@nginx.com             return NXT_ERROR;
217774Svbart@nginx.com         }
218774Svbart@nginx.com 
219774Svbart@nginx.com         value->u.string.length = tmp.length;
220774Svbart@nginx.com         value->u.string.start = tmp.start;
221774Svbart@nginx.com 
222774Svbart@nginx.com     } else {
223774Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
224774Svbart@nginx.com         value->u.str.length = str->length;
225774Svbart@nginx.com 
226774Svbart@nginx.com         nxt_memcpy(value->u.str.start, str->start, str->length);
227774Svbart@nginx.com     }
228774Svbart@nginx.com 
229774Svbart@nginx.com     return NXT_OK;
230774Svbart@nginx.com }
231774Svbart@nginx.com 
232774Svbart@nginx.com 
2331439Svbart@nginx.com double
nxt_conf_get_number(nxt_conf_value_t * value)2341439Svbart@nginx.com nxt_conf_get_number(nxt_conf_value_t *value)
235507Smax.romanov@nginx.com {
2361439Svbart@nginx.com     return nxt_strtod(value->u.number, NULL);
237507Smax.romanov@nginx.com }
238507Smax.romanov@nginx.com 
239507Smax.romanov@nginx.com 
2401236St.nateldemoura@f5.com uint8_t
nxt_conf_get_boolean(nxt_conf_value_t * value)2411236St.nateldemoura@f5.com nxt_conf_get_boolean(nxt_conf_value_t *value)
2421236St.nateldemoura@f5.com {
2431236St.nateldemoura@f5.com     return value->u.boolean;
2441236St.nateldemoura@f5.com }
2451236St.nateldemoura@f5.com 
2461236St.nateldemoura@f5.com 
247116Svbart@nginx.com nxt_uint_t
nxt_conf_object_members_count(nxt_conf_value_t * value)248121Svbart@nginx.com nxt_conf_object_members_count(nxt_conf_value_t *value)
249121Svbart@nginx.com {
250121Svbart@nginx.com     return value->u.object->count;
251121Svbart@nginx.com }
252121Svbart@nginx.com 
253121Svbart@nginx.com 
254121Svbart@nginx.com nxt_conf_value_t *
nxt_conf_create_object(nxt_mp_t * mp,nxt_uint_t count)255121Svbart@nginx.com nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count)
256121Svbart@nginx.com {
257121Svbart@nginx.com     size_t            size;
258121Svbart@nginx.com     nxt_conf_value_t  *value;
259121Svbart@nginx.com 
260121Svbart@nginx.com     size = sizeof(nxt_conf_value_t)
261121Svbart@nginx.com            + sizeof(nxt_conf_object_t)
262121Svbart@nginx.com            + count * sizeof(nxt_conf_object_member_t);
263121Svbart@nginx.com 
264121Svbart@nginx.com     value = nxt_mp_get(mp, size);
265121Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
266121Svbart@nginx.com         return NULL;
267121Svbart@nginx.com     }
268121Svbart@nginx.com 
269121Svbart@nginx.com     value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
270121Svbart@nginx.com     value->u.object->count = count;
271121Svbart@nginx.com 
272121Svbart@nginx.com     value->type = NXT_CONF_VALUE_OBJECT;
273121Svbart@nginx.com 
274121Svbart@nginx.com     return value;
275121Svbart@nginx.com }
276121Svbart@nginx.com 
277121Svbart@nginx.com 
278208Svbart@nginx.com void
nxt_conf_set_member(nxt_conf_value_t * object,nxt_str_t * name,const nxt_conf_value_t * value,uint32_t index)279208Svbart@nginx.com nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
2802139Sandrew@digital-domain.net     const nxt_conf_value_t *value, uint32_t index)
281121Svbart@nginx.com {
282121Svbart@nginx.com     nxt_conf_object_member_t  *member;
283121Svbart@nginx.com 
284121Svbart@nginx.com     member = &object->u.object->members[index];
285773Svbart@nginx.com 
286773Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
287121Svbart@nginx.com 
288121Svbart@nginx.com     member->value = *value;
289208Svbart@nginx.com }
290208Svbart@nginx.com 
291208Svbart@nginx.com 
2922185Svbart@nginx.com nxt_int_t
nxt_conf_set_member_dup(nxt_conf_value_t * object,nxt_mp_t * mp,nxt_str_t * name,nxt_conf_value_t * value,uint32_t index)2932185Svbart@nginx.com nxt_conf_set_member_dup(nxt_conf_value_t *object, nxt_mp_t *mp, nxt_str_t *name,
2942185Svbart@nginx.com     nxt_conf_value_t *value, uint32_t index)
2952185Svbart@nginx.com {
2962185Svbart@nginx.com     nxt_conf_object_member_t  *member;
2972185Svbart@nginx.com 
2982185Svbart@nginx.com     member = &object->u.object->members[index];
2992185Svbart@nginx.com 
3002185Svbart@nginx.com     member->value = *value;
3012185Svbart@nginx.com 
3022185Svbart@nginx.com     return nxt_conf_set_string_dup(&member->name, mp, name);
3032185Svbart@nginx.com }
3042185Svbart@nginx.com 
3052185Svbart@nginx.com 
306208Svbart@nginx.com void
nxt_conf_set_member_string(nxt_conf_value_t * object,nxt_str_t * name,nxt_str_t * value,uint32_t index)307208Svbart@nginx.com nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
308208Svbart@nginx.com     nxt_str_t *value, uint32_t index)
309208Svbart@nginx.com {
310208Svbart@nginx.com     nxt_conf_object_member_t  *member;
311208Svbart@nginx.com 
312208Svbart@nginx.com     member = &object->u.object->members[index];
313773Svbart@nginx.com 
314773Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
315773Svbart@nginx.com 
316773Svbart@nginx.com     nxt_conf_set_string(&member->value, value);
317208Svbart@nginx.com }
318208Svbart@nginx.com 
319208Svbart@nginx.com 
320774Svbart@nginx.com nxt_int_t
nxt_conf_set_member_string_dup(nxt_conf_value_t * object,nxt_mp_t * mp,nxt_str_t * name,nxt_str_t * value,uint32_t index)321774Svbart@nginx.com nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp,
322774Svbart@nginx.com     nxt_str_t *name, nxt_str_t *value, uint32_t index)
323774Svbart@nginx.com {
324774Svbart@nginx.com     nxt_conf_object_member_t  *member;
325774Svbart@nginx.com 
326774Svbart@nginx.com     member = &object->u.object->members[index];
327774Svbart@nginx.com 
328774Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
329774Svbart@nginx.com 
330774Svbart@nginx.com     return nxt_conf_set_string_dup(&member->value, mp, value);
331774Svbart@nginx.com }
332774Svbart@nginx.com 
333774Svbart@nginx.com 
334208Svbart@nginx.com void
nxt_conf_set_member_integer(nxt_conf_value_t * object,nxt_str_t * name,int64_t value,uint32_t index)335208Svbart@nginx.com nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
336208Svbart@nginx.com     int64_t value, uint32_t index)
337208Svbart@nginx.com {
3381439Svbart@nginx.com     u_char                    *p, *end;
339208Svbart@nginx.com     nxt_conf_object_member_t  *member;
340208Svbart@nginx.com 
341208Svbart@nginx.com     member = &object->u.object->members[index];
342773Svbart@nginx.com 
343773Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
344208Svbart@nginx.com 
3451439Svbart@nginx.com     p = member->value.u.number;
3461439Svbart@nginx.com     end = p + NXT_CONF_MAX_NUMBER_LEN;
3471439Svbart@nginx.com 
3481439Svbart@nginx.com     end = nxt_sprintf(p, end, "%L", value);
3491439Svbart@nginx.com     *end = '\0';
3501439Svbart@nginx.com 
351208Svbart@nginx.com     member->value.type = NXT_CONF_VALUE_INTEGER;
352121Svbart@nginx.com }
353121Svbart@nginx.com 
354121Svbart@nginx.com 
355774Svbart@nginx.com void
nxt_conf_set_member_null(nxt_conf_value_t * object,nxt_str_t * name,uint32_t index)356774Svbart@nginx.com nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name,
357774Svbart@nginx.com     uint32_t index)
358774Svbart@nginx.com {
359774Svbart@nginx.com     nxt_conf_object_member_t  *member;
360774Svbart@nginx.com 
361774Svbart@nginx.com     member = &object->u.object->members[index];
362774Svbart@nginx.com 
363774Svbart@nginx.com     nxt_conf_set_string(&member->name, name);
364774Svbart@nginx.com 
365774Svbart@nginx.com     member->value.type = NXT_CONF_VALUE_NULL;
366774Svbart@nginx.com }
367774Svbart@nginx.com 
368774Svbart@nginx.com 
369774Svbart@nginx.com nxt_conf_value_t *
nxt_conf_create_array(nxt_mp_t * mp,nxt_uint_t count)370774Svbart@nginx.com nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count)
371774Svbart@nginx.com {
372774Svbart@nginx.com     size_t            size;
373774Svbart@nginx.com     nxt_conf_value_t  *value;
374774Svbart@nginx.com 
375774Svbart@nginx.com     size = sizeof(nxt_conf_value_t)
376774Svbart@nginx.com            + sizeof(nxt_conf_array_t)
377774Svbart@nginx.com            + count * sizeof(nxt_conf_value_t);
378774Svbart@nginx.com 
379774Svbart@nginx.com     value = nxt_mp_get(mp, size);
380774Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
381774Svbart@nginx.com         return NULL;
382774Svbart@nginx.com     }
383774Svbart@nginx.com 
384774Svbart@nginx.com     value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
385774Svbart@nginx.com     value->u.array->count = count;
386774Svbart@nginx.com 
387774Svbart@nginx.com     value->type = NXT_CONF_VALUE_ARRAY;
388774Svbart@nginx.com 
389774Svbart@nginx.com     return value;
390774Svbart@nginx.com }
391774Svbart@nginx.com 
392774Svbart@nginx.com 
393774Svbart@nginx.com void
nxt_conf_set_element(nxt_conf_value_t * array,nxt_uint_t index,const nxt_conf_value_t * value)394774Svbart@nginx.com nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
3952139Sandrew@digital-domain.net     const nxt_conf_value_t *value)
396774Svbart@nginx.com {
397774Svbart@nginx.com     array->u.array->elements[index] = *value;
398774Svbart@nginx.com }
399774Svbart@nginx.com 
400774Svbart@nginx.com 
401774Svbart@nginx.com nxt_int_t
nxt_conf_set_element_string_dup(nxt_conf_value_t * array,nxt_mp_t * mp,nxt_uint_t index,nxt_str_t * value)402774Svbart@nginx.com nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
403774Svbart@nginx.com     nxt_uint_t index, nxt_str_t *value)
404774Svbart@nginx.com {
405774Svbart@nginx.com     nxt_conf_value_t  *element;
406774Svbart@nginx.com 
407774Svbart@nginx.com     element = &array->u.array->elements[index];
408774Svbart@nginx.com 
409774Svbart@nginx.com     return nxt_conf_set_string_dup(element, mp, value);
410774Svbart@nginx.com }
411774Svbart@nginx.com 
412774Svbart@nginx.com 
413121Svbart@nginx.com nxt_uint_t
nxt_conf_array_elements_count(nxt_conf_value_t * value)414961Sigor@sysoev.ru nxt_conf_array_elements_count(nxt_conf_value_t *value)
415961Sigor@sysoev.ru {
416961Sigor@sysoev.ru     return value->u.array->count;
417961Sigor@sysoev.ru }
418961Sigor@sysoev.ru 
419961Sigor@sysoev.ru 
420961Sigor@sysoev.ru nxt_uint_t
nxt_conf_array_elements_count_or_1(nxt_conf_value_t * value)4212076Salx.manpages@gmail.com nxt_conf_array_elements_count_or_1(nxt_conf_value_t *value)
4222076Salx.manpages@gmail.com {
4232076Salx.manpages@gmail.com     return (value->type == NXT_CONF_VALUE_ARRAY) ? value->u.array->count : 1;
4242076Salx.manpages@gmail.com }
4252076Salx.manpages@gmail.com 
4262076Salx.manpages@gmail.com 
4272076Salx.manpages@gmail.com nxt_uint_t
nxt_conf_type(nxt_conf_value_t * value)428116Svbart@nginx.com nxt_conf_type(nxt_conf_value_t *value)
429116Svbart@nginx.com {
430116Svbart@nginx.com     switch (value->type) {
431116Svbart@nginx.com 
432116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
433116Svbart@nginx.com         return NXT_CONF_NULL;
434116Svbart@nginx.com 
435116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
436116Svbart@nginx.com         return NXT_CONF_BOOLEAN;
437116Svbart@nginx.com 
438116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
439116Svbart@nginx.com         return NXT_CONF_INTEGER;
440116Svbart@nginx.com 
441116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
442116Svbart@nginx.com         return NXT_CONF_NUMBER;
443116Svbart@nginx.com 
444116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
445116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
446116Svbart@nginx.com         return NXT_CONF_STRING;
447116Svbart@nginx.com 
448116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
449116Svbart@nginx.com         return NXT_CONF_ARRAY;
450116Svbart@nginx.com 
451116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
452116Svbart@nginx.com         return NXT_CONF_OBJECT;
453116Svbart@nginx.com     }
454116Svbart@nginx.com 
455116Svbart@nginx.com     nxt_unreachable();
456116Svbart@nginx.com 
457116Svbart@nginx.com     return 0;
458116Svbart@nginx.com }
459116Svbart@nginx.com 
460116Svbart@nginx.com 
461106Svbart@nginx.com nxt_conf_value_t *
nxt_conf_get_path(nxt_conf_value_t * value,nxt_str_t * path)462106Svbart@nginx.com nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path)
463106Svbart@nginx.com {
464106Svbart@nginx.com     nxt_str_t              token;
4651174Svbart@nginx.com     nxt_int_t              ret, index;
466106Svbart@nginx.com     nxt_conf_path_parse_t  parse;
467106Svbart@nginx.com 
468106Svbart@nginx.com     parse.start = path->start;
469106Svbart@nginx.com     parse.end = path->start + path->length;
470106Svbart@nginx.com     parse.last = 0;
471106Svbart@nginx.com 
472106Svbart@nginx.com     do {
4731174Svbart@nginx.com         ret = nxt_conf_path_next_token(&parse, &token);
4741174Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
4751174Svbart@nginx.com             return NULL;
4761174Svbart@nginx.com         }
477106Svbart@nginx.com 
478106Svbart@nginx.com         if (token.length == 0) {
479106Svbart@nginx.com 
480106Svbart@nginx.com             if (parse.last) {
481106Svbart@nginx.com                 break;
482106Svbart@nginx.com             }
483106Svbart@nginx.com 
484106Svbart@nginx.com             return NULL;
485106Svbart@nginx.com         }
486106Svbart@nginx.com 
487775Svbart@nginx.com         switch (value->type) {
488775Svbart@nginx.com 
489775Svbart@nginx.com         case NXT_CONF_VALUE_OBJECT:
490775Svbart@nginx.com             value = nxt_conf_get_object_member(value, &token, NULL);
491775Svbart@nginx.com             break;
492775Svbart@nginx.com 
493775Svbart@nginx.com         case NXT_CONF_VALUE_ARRAY:
494775Svbart@nginx.com             index = nxt_int_parse(token.start, token.length);
495775Svbart@nginx.com 
496775Svbart@nginx.com             if (index < 0 || index > NXT_INT32_T_MAX) {
497775Svbart@nginx.com                 return NULL;
498775Svbart@nginx.com             }
499775Svbart@nginx.com 
500775Svbart@nginx.com             value = nxt_conf_get_array_element(value, index);
501775Svbart@nginx.com             break;
502775Svbart@nginx.com 
503775Svbart@nginx.com         default:
504775Svbart@nginx.com             return NULL;
505775Svbart@nginx.com         }
506106Svbart@nginx.com 
507106Svbart@nginx.com         if (value == NULL) {
508106Svbart@nginx.com             return NULL;
509106Svbart@nginx.com         }
510106Svbart@nginx.com 
511106Svbart@nginx.com     } while (parse.last == 0);
512106Svbart@nginx.com 
513106Svbart@nginx.com     return value;
514106Svbart@nginx.com }
515106Svbart@nginx.com 
516106Svbart@nginx.com 
5171174Svbart@nginx.com static nxt_int_t
nxt_conf_path_next_token(nxt_conf_path_parse_t * parse,nxt_str_t * token)518106Svbart@nginx.com nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token)
519106Svbart@nginx.com {
5201174Svbart@nginx.com     u_char  *p, *start, *end;
5211174Svbart@nginx.com     size_t  length;
5221174Svbart@nginx.com 
5231174Svbart@nginx.com     start = parse->start + 1;
5241174Svbart@nginx.com 
5251174Svbart@nginx.com     p = start;
5261174Svbart@nginx.com 
5271174Svbart@nginx.com     while (p < parse->end && *p != '/') {
528106Svbart@nginx.com         p++;
529106Svbart@nginx.com     }
530106Svbart@nginx.com 
531106Svbart@nginx.com     parse->start = p;
5321174Svbart@nginx.com     parse->last = (p >= parse->end);
5331174Svbart@nginx.com 
5341174Svbart@nginx.com     length = p - start;
5351174Svbart@nginx.com 
5361174Svbart@nginx.com     if (nxt_slow_path(length > NXT_CONF_MAX_TOKEN_LEN)) {
5371174Svbart@nginx.com         return NXT_ERROR;
5381174Svbart@nginx.com     }
5391174Svbart@nginx.com 
5401174Svbart@nginx.com     end = nxt_decode_uri(parse->buf, start, length);
5411174Svbart@nginx.com     if (nxt_slow_path(end == NULL)) {
5421174Svbart@nginx.com         return NXT_ERROR;
5431174Svbart@nginx.com     }
5441174Svbart@nginx.com 
5451174Svbart@nginx.com     token->length = end - parse->buf;
5461174Svbart@nginx.com     token->start = parse->buf;
5471174Svbart@nginx.com 
5481174Svbart@nginx.com     return NXT_OK;
549106Svbart@nginx.com }
550106Svbart@nginx.com 
551106Svbart@nginx.com 
552106Svbart@nginx.com nxt_conf_value_t *
nxt_conf_get_object_member(nxt_conf_value_t * value,nxt_str_t * name,uint32_t * index)553106Svbart@nginx.com nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name,
554106Svbart@nginx.com     uint32_t *index)
555106Svbart@nginx.com {
556106Svbart@nginx.com     nxt_str_t                 str;
557106Svbart@nginx.com     nxt_uint_t                n;
558106Svbart@nginx.com     nxt_conf_object_t         *object;
559106Svbart@nginx.com     nxt_conf_object_member_t  *member;
560106Svbart@nginx.com 
561116Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_OBJECT) {
562106Svbart@nginx.com         return NULL;
563106Svbart@nginx.com     }
564106Svbart@nginx.com 
565106Svbart@nginx.com     object = value->u.object;
566106Svbart@nginx.com 
567106Svbart@nginx.com     for (n = 0; n < object->count; n++) {
568106Svbart@nginx.com         member = &object->members[n];
569106Svbart@nginx.com 
570106Svbart@nginx.com         nxt_conf_get_string(&member->name, &str);
571106Svbart@nginx.com 
572106Svbart@nginx.com         if (nxt_strstr_eq(&str, name)) {
573106Svbart@nginx.com 
574106Svbart@nginx.com             if (index != NULL) {
575106Svbart@nginx.com                 *index = n;
576106Svbart@nginx.com             }
577106Svbart@nginx.com 
578106Svbart@nginx.com             return &member->value;
579106Svbart@nginx.com         }
580106Svbart@nginx.com     }
581106Svbart@nginx.com 
582106Svbart@nginx.com     return NULL;
583106Svbart@nginx.com }
584106Svbart@nginx.com 
585106Svbart@nginx.com 
586106Svbart@nginx.com nxt_int_t
nxt_conf_map_object(nxt_mp_t * mp,nxt_conf_value_t * value,nxt_conf_map_t * map,nxt_uint_t n,void * data)587213Svbart@nginx.com nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map,
588213Svbart@nginx.com     nxt_uint_t n, void *data)
589106Svbart@nginx.com {
5901439Svbart@nginx.com     double            num;
591213Svbart@nginx.com     nxt_str_t         str, *s;
592106Svbart@nginx.com     nxt_uint_t        i;
593106Svbart@nginx.com     nxt_conf_value_t  *v;
594106Svbart@nginx.com 
595106Svbart@nginx.com     union {
596111Sigor@sysoev.ru         uint8_t     ui8;
597111Sigor@sysoev.ru         int32_t     i32;
598111Sigor@sysoev.ru         int64_t     i64;
599839Svbart@nginx.com         int         i;
600111Sigor@sysoev.ru         ssize_t     size;
601111Sigor@sysoev.ru         off_t       off;
602111Sigor@sysoev.ru         nxt_msec_t  msec;
603111Sigor@sysoev.ru         double      dbl;
604111Sigor@sysoev.ru         nxt_str_t   str;
605213Svbart@nginx.com         char        *cstrz;
606111Sigor@sysoev.ru         void        *v;
607106Svbart@nginx.com     } *ptr;
608106Svbart@nginx.com 
609136Svbart@nginx.com     for (i = 0; i < n; i++) {
610106Svbart@nginx.com 
611106Svbart@nginx.com         v = nxt_conf_get_object_member(value, &map[i].name, NULL);
612106Svbart@nginx.com 
613116Svbart@nginx.com         if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
614106Svbart@nginx.com             continue;
615106Svbart@nginx.com         }
616106Svbart@nginx.com 
617106Svbart@nginx.com         ptr = nxt_pointer_to(data, map[i].offset);
618106Svbart@nginx.com 
619106Svbart@nginx.com         switch (map[i].type) {
620106Svbart@nginx.com 
621106Svbart@nginx.com         case NXT_CONF_MAP_INT8:
622106Svbart@nginx.com 
623136Svbart@nginx.com             if (v->type == NXT_CONF_VALUE_BOOLEAN) {
624136Svbart@nginx.com                 ptr->ui8 = v->u.boolean;
625106Svbart@nginx.com             }
626106Svbart@nginx.com 
627106Svbart@nginx.com             break;
628106Svbart@nginx.com 
629106Svbart@nginx.com         case NXT_CONF_MAP_INT32:
630106Svbart@nginx.com         case NXT_CONF_MAP_INT64:
631106Svbart@nginx.com         case NXT_CONF_MAP_INT:
632106Svbart@nginx.com         case NXT_CONF_MAP_SIZE:
633106Svbart@nginx.com         case NXT_CONF_MAP_OFF:
634111Sigor@sysoev.ru         case NXT_CONF_MAP_MSEC:
635106Svbart@nginx.com 
636116Svbart@nginx.com             if (v->type != NXT_CONF_VALUE_INTEGER) {
637136Svbart@nginx.com                 break;
638106Svbart@nginx.com             }
639106Svbart@nginx.com 
6401439Svbart@nginx.com             num = nxt_strtod(v->u.number, NULL);
6411439Svbart@nginx.com 
642106Svbart@nginx.com             switch (map[i].type) {
643106Svbart@nginx.com 
644106Svbart@nginx.com             case NXT_CONF_MAP_INT32:
6451439Svbart@nginx.com                 ptr->i32 = num;
646106Svbart@nginx.com                 break;
647106Svbart@nginx.com 
648106Svbart@nginx.com             case NXT_CONF_MAP_INT64:
6491439Svbart@nginx.com                 ptr->i64 = num;
650106Svbart@nginx.com                 break;
651106Svbart@nginx.com 
652106Svbart@nginx.com             case NXT_CONF_MAP_INT:
6531439Svbart@nginx.com                 ptr->i = num;
654106Svbart@nginx.com                 break;
655106Svbart@nginx.com 
656106Svbart@nginx.com             case NXT_CONF_MAP_SIZE:
6571439Svbart@nginx.com                 ptr->size = num;
658106Svbart@nginx.com                 break;
659106Svbart@nginx.com 
660106Svbart@nginx.com             case NXT_CONF_MAP_OFF:
6611439Svbart@nginx.com                 ptr->off = num;
662106Svbart@nginx.com                 break;
663106Svbart@nginx.com 
664111Sigor@sysoev.ru             case NXT_CONF_MAP_MSEC:
6651439Svbart@nginx.com                 ptr->msec = (nxt_msec_t) num * 1000;
666111Sigor@sysoev.ru                 break;
667111Sigor@sysoev.ru 
668106Svbart@nginx.com             default:
669106Svbart@nginx.com                 nxt_unreachable();
670106Svbart@nginx.com             }
671106Svbart@nginx.com 
672106Svbart@nginx.com             break;
673106Svbart@nginx.com 
674106Svbart@nginx.com         case NXT_CONF_MAP_DOUBLE:
675106Svbart@nginx.com 
676116Svbart@nginx.com             if (v->type == NXT_CONF_VALUE_NUMBER) {
6771439Svbart@nginx.com                 ptr->dbl = nxt_strtod(v->u.number, NULL);
678106Svbart@nginx.com             }
679106Svbart@nginx.com 
680106Svbart@nginx.com             break;
681106Svbart@nginx.com 
682106Svbart@nginx.com         case NXT_CONF_MAP_STR:
683213Svbart@nginx.com         case NXT_CONF_MAP_STR_COPY:
684213Svbart@nginx.com         case NXT_CONF_MAP_CSTRZ:
685213Svbart@nginx.com 
686213Svbart@nginx.com             if (v->type != NXT_CONF_VALUE_SHORT_STRING
687213Svbart@nginx.com                 && v->type != NXT_CONF_VALUE_STRING)
688106Svbart@nginx.com             {
689213Svbart@nginx.com                 break;
690213Svbart@nginx.com             }
691213Svbart@nginx.com 
692213Svbart@nginx.com             nxt_conf_get_string(v, &str);
693213Svbart@nginx.com 
694213Svbart@nginx.com             switch (map[i].type) {
695213Svbart@nginx.com 
696213Svbart@nginx.com             case NXT_CONF_MAP_STR:
697213Svbart@nginx.com                 ptr->str = str;
698213Svbart@nginx.com                 break;
699213Svbart@nginx.com 
700213Svbart@nginx.com             case NXT_CONF_MAP_STR_COPY:
701213Svbart@nginx.com 
702213Svbart@nginx.com                 s = nxt_str_dup(mp, &ptr->str, &str);
703213Svbart@nginx.com 
704213Svbart@nginx.com                 if (nxt_slow_path(s == NULL)) {
705213Svbart@nginx.com                     return NXT_ERROR;
706213Svbart@nginx.com                 }
707213Svbart@nginx.com 
708213Svbart@nginx.com                 break;
709213Svbart@nginx.com 
710213Svbart@nginx.com             case NXT_CONF_MAP_CSTRZ:
711213Svbart@nginx.com 
712213Svbart@nginx.com                 ptr->cstrz = nxt_str_cstrz(mp, &str);
713213Svbart@nginx.com 
714213Svbart@nginx.com                 if (nxt_slow_path(ptr->cstrz == NULL)) {
715213Svbart@nginx.com                     return NXT_ERROR;
716213Svbart@nginx.com                 }
717213Svbart@nginx.com 
718213Svbart@nginx.com                 break;
719213Svbart@nginx.com 
720213Svbart@nginx.com             default:
721213Svbart@nginx.com                 nxt_unreachable();
722106Svbart@nginx.com             }
723106Svbart@nginx.com 
724106Svbart@nginx.com             break;
725106Svbart@nginx.com 
726106Svbart@nginx.com         case NXT_CONF_MAP_PTR:
727106Svbart@nginx.com 
728106Svbart@nginx.com             ptr->v = v;
729106Svbart@nginx.com 
730106Svbart@nginx.com             break;
731106Svbart@nginx.com         }
732106Svbart@nginx.com     }
733106Svbart@nginx.com 
734106Svbart@nginx.com     return NXT_OK;
735106Svbart@nginx.com }
736106Svbart@nginx.com 
737106Svbart@nginx.com 
738106Svbart@nginx.com nxt_conf_value_t *
nxt_conf_next_object_member(nxt_conf_value_t * value,nxt_str_t * name,uint32_t * next)739106Svbart@nginx.com nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name,
740106Svbart@nginx.com     uint32_t *next)
741106Svbart@nginx.com {
742106Svbart@nginx.com     uint32_t                  n;
743106Svbart@nginx.com     nxt_conf_object_t         *object;
744106Svbart@nginx.com     nxt_conf_object_member_t  *member;
745106Svbart@nginx.com 
746116Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_OBJECT) {
747106Svbart@nginx.com         return NULL;
748106Svbart@nginx.com     }
749106Svbart@nginx.com 
750106Svbart@nginx.com     n = *next;
751106Svbart@nginx.com     object = value->u.object;
752106Svbart@nginx.com 
753106Svbart@nginx.com     if (n >= object->count) {
754106Svbart@nginx.com         return NULL;
755106Svbart@nginx.com     }
756106Svbart@nginx.com 
757106Svbart@nginx.com     member = &object->members[n];
758106Svbart@nginx.com     *next = n + 1;
759106Svbart@nginx.com 
760106Svbart@nginx.com     nxt_conf_get_string(&member->name, name);
761106Svbart@nginx.com 
762106Svbart@nginx.com     return &member->value;
763106Svbart@nginx.com }
764106Svbart@nginx.com 
765106Svbart@nginx.com 
766214Svbart@nginx.com nxt_conf_value_t *
nxt_conf_get_array_element(nxt_conf_value_t * value,uint32_t index)767214Svbart@nginx.com nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index)
768214Svbart@nginx.com {
769214Svbart@nginx.com     nxt_conf_array_t  *array;
770214Svbart@nginx.com 
771214Svbart@nginx.com     if (value->type != NXT_CONF_VALUE_ARRAY) {
772214Svbart@nginx.com         return NULL;
773214Svbart@nginx.com     }
774214Svbart@nginx.com 
775214Svbart@nginx.com     array = value->u.array;
776214Svbart@nginx.com 
777214Svbart@nginx.com     if (index >= array->count) {
778214Svbart@nginx.com         return NULL;
779214Svbart@nginx.com     }
780214Svbart@nginx.com 
781214Svbart@nginx.com     return &array->elements[index];
782214Svbart@nginx.com }
783214Svbart@nginx.com 
784214Svbart@nginx.com 
7852076Salx.manpages@gmail.com nxt_conf_value_t *
nxt_conf_get_array_element_or_itself(nxt_conf_value_t * value,uint32_t index)7862076Salx.manpages@gmail.com nxt_conf_get_array_element_or_itself(nxt_conf_value_t *value, uint32_t index)
7872076Salx.manpages@gmail.com {
7882076Salx.manpages@gmail.com     nxt_conf_array_t  *array;
7892076Salx.manpages@gmail.com 
7902076Salx.manpages@gmail.com     if (value->type != NXT_CONF_VALUE_ARRAY) {
7912076Salx.manpages@gmail.com         return (index == 0) ? value : NULL;
7922076Salx.manpages@gmail.com     }
7932076Salx.manpages@gmail.com 
7942076Salx.manpages@gmail.com     array = value->u.array;
7952076Salx.manpages@gmail.com 
7962076Salx.manpages@gmail.com     if (index >= array->count) {
7972076Salx.manpages@gmail.com         return NULL;
7982076Salx.manpages@gmail.com     }
7992076Salx.manpages@gmail.com 
8002076Salx.manpages@gmail.com     return &array->elements[index];
8012076Salx.manpages@gmail.com }
8022076Salx.manpages@gmail.com 
8032076Salx.manpages@gmail.com 
804962Sigor@sysoev.ru void
nxt_conf_array_qsort(nxt_conf_value_t * value,int (* compare)(const void *,const void *))805962Sigor@sysoev.ru nxt_conf_array_qsort(nxt_conf_value_t *value,
806962Sigor@sysoev.ru     int (*compare)(const void *, const void *))
807962Sigor@sysoev.ru {
808962Sigor@sysoev.ru     nxt_conf_array_t  *array;
809962Sigor@sysoev.ru 
810962Sigor@sysoev.ru     if (value->type != NXT_CONF_VALUE_ARRAY) {
811962Sigor@sysoev.ru         return;
812962Sigor@sysoev.ru     }
813962Sigor@sysoev.ru 
814962Sigor@sysoev.ru     array = value->u.array;
815962Sigor@sysoev.ru 
816962Sigor@sysoev.ru     nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare);
817962Sigor@sysoev.ru }
818962Sigor@sysoev.ru 
819962Sigor@sysoev.ru 
8201049Svbart@nginx.com nxt_conf_op_ret_t
nxt_conf_op_compile(nxt_mp_t * mp,nxt_conf_op_t ** ops,nxt_conf_value_t * root,nxt_str_t * path,nxt_conf_value_t * value,nxt_bool_t add)821106Svbart@nginx.com nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
8221049Svbart@nginx.com     nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add)
823106Svbart@nginx.com {
824106Svbart@nginx.com     nxt_str_t                 token;
8251174Svbart@nginx.com     nxt_int_t                 ret, index;
826106Svbart@nginx.com     nxt_conf_op_t             *op, **parent;
8271047Svbart@nginx.com     nxt_conf_value_t          *node;
828106Svbart@nginx.com     nxt_conf_path_parse_t     parse;
829106Svbart@nginx.com     nxt_conf_object_member_t  *member;
830106Svbart@nginx.com 
831106Svbart@nginx.com     parse.start = path->start;
832106Svbart@nginx.com     parse.end = path->start + path->length;
833106Svbart@nginx.com     parse.last = 0;
834106Svbart@nginx.com 
835106Svbart@nginx.com     parent = ops;
836106Svbart@nginx.com 
837106Svbart@nginx.com     for ( ;; ) {
838106Svbart@nginx.com         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
839106Svbart@nginx.com         if (nxt_slow_path(op == NULL)) {
8401049Svbart@nginx.com             return NXT_CONF_OP_ERROR;
841106Svbart@nginx.com         }
842106Svbart@nginx.com 
843106Svbart@nginx.com         *parent = op;
844106Svbart@nginx.com         parent = (nxt_conf_op_t **) &op->ctx;
845106Svbart@nginx.com 
8461174Svbart@nginx.com         ret = nxt_conf_path_next_token(&parse, &token);
8471174Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
8481174Svbart@nginx.com             return NXT_CONF_OP_ERROR;
8491174Svbart@nginx.com         }
850106Svbart@nginx.com 
8511048Svbart@nginx.com         switch (root->type) {
8521048Svbart@nginx.com 
8531048Svbart@nginx.com         case NXT_CONF_VALUE_OBJECT:
8541048Svbart@nginx.com             node = nxt_conf_get_object_member(root, &token, &op->index);
8551048Svbart@nginx.com             break;
8561048Svbart@nginx.com 
8571048Svbart@nginx.com         case NXT_CONF_VALUE_ARRAY:
8581048Svbart@nginx.com             index = nxt_int_parse(token.start, token.length);
8591048Svbart@nginx.com 
8601048Svbart@nginx.com             if (index < 0 || index > NXT_INT32_T_MAX) {
8611049Svbart@nginx.com                 return NXT_CONF_OP_NOT_FOUND;
8621048Svbart@nginx.com             }
8631048Svbart@nginx.com 
8641048Svbart@nginx.com             op->index = index;
8651048Svbart@nginx.com 
8661048Svbart@nginx.com             node = nxt_conf_get_array_element(root, index);
8671048Svbart@nginx.com             break;
8681048Svbart@nginx.com 
8691048Svbart@nginx.com         default:
8701048Svbart@nginx.com             node = NULL;
8711048Svbart@nginx.com         }
872106Svbart@nginx.com 
873106Svbart@nginx.com         if (parse.last) {
874106Svbart@nginx.com             break;
875106Svbart@nginx.com         }
876106Svbart@nginx.com 
8771047Svbart@nginx.com         if (node == NULL) {
8781049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
879106Svbart@nginx.com         }
880106Svbart@nginx.com 
881106Svbart@nginx.com         op->action = NXT_CONF_OP_PASS;
8821047Svbart@nginx.com         root = node;
883106Svbart@nginx.com     }
884106Svbart@nginx.com 
885106Svbart@nginx.com     if (value == NULL) {
886106Svbart@nginx.com 
8871047Svbart@nginx.com         if (node == NULL) {
8881049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
889106Svbart@nginx.com         }
890106Svbart@nginx.com 
891106Svbart@nginx.com         op->action = NXT_CONF_OP_DELETE;
892106Svbart@nginx.com 
8931049Svbart@nginx.com         return NXT_CONF_OP_OK;
8941049Svbart@nginx.com     }
8951049Svbart@nginx.com 
8961049Svbart@nginx.com     if (add) {
8971049Svbart@nginx.com         if (node == NULL) {
8981049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
8991049Svbart@nginx.com         }
9001049Svbart@nginx.com 
9011049Svbart@nginx.com         if (node->type != NXT_CONF_VALUE_ARRAY) {
9021049Svbart@nginx.com             return NXT_CONF_OP_NOT_ALLOWED;
9031049Svbart@nginx.com         }
9041049Svbart@nginx.com 
9051049Svbart@nginx.com         op->action = NXT_CONF_OP_PASS;
9061049Svbart@nginx.com 
9071049Svbart@nginx.com         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
9081049Svbart@nginx.com         if (nxt_slow_path(op == NULL)) {
9091049Svbart@nginx.com             return NXT_CONF_OP_ERROR;
9101049Svbart@nginx.com         }
9111049Svbart@nginx.com 
9121049Svbart@nginx.com         *parent = op;
9131049Svbart@nginx.com 
9141049Svbart@nginx.com         op->index = node->u.array->count;
9151049Svbart@nginx.com         op->action = NXT_CONF_OP_CREATE;
9161049Svbart@nginx.com         op->ctx = value;
9171049Svbart@nginx.com 
9181049Svbart@nginx.com         return NXT_CONF_OP_OK;
919106Svbart@nginx.com     }
920106Svbart@nginx.com 
9211048Svbart@nginx.com     if (node != NULL) {
9221048Svbart@nginx.com         op->action = NXT_CONF_OP_REPLACE;
9231048Svbart@nginx.com         op->ctx = value;
9241048Svbart@nginx.com 
9251049Svbart@nginx.com         return NXT_CONF_OP_OK;
9261048Svbart@nginx.com     }
9271048Svbart@nginx.com 
9281048Svbart@nginx.com     op->action = NXT_CONF_OP_CREATE;
9291048Svbart@nginx.com 
9301048Svbart@nginx.com     if (root->type == NXT_CONF_VALUE_ARRAY) {
9311048Svbart@nginx.com         if (op->index > root->u.array->count) {
9321049Svbart@nginx.com             return NXT_CONF_OP_NOT_FOUND;
9331048Svbart@nginx.com         }
9341048Svbart@nginx.com 
9351048Svbart@nginx.com         op->ctx = value;
9361048Svbart@nginx.com 
9371048Svbart@nginx.com     } else {
938106Svbart@nginx.com         member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t));
939106Svbart@nginx.com         if (nxt_slow_path(member == NULL)) {
9401049Svbart@nginx.com             return NXT_CONF_OP_ERROR;
941106Svbart@nginx.com         }
942106Svbart@nginx.com 
9431174Svbart@nginx.com         ret = nxt_conf_set_string_dup(&member->name, mp, &token);
9441174Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
9451174Svbart@nginx.com             return NXT_CONF_OP_ERROR;
9461174Svbart@nginx.com         }
947106Svbart@nginx.com 
948106Svbart@nginx.com         member->value = *value;
949106Svbart@nginx.com 
9501047Svbart@nginx.com         op->index = root->u.object->count;
951106Svbart@nginx.com         op->ctx = member;
952106Svbart@nginx.com     }
953106Svbart@nginx.com 
9541049Svbart@nginx.com     return NXT_CONF_OP_OK;
955106Svbart@nginx.com }
956106Svbart@nginx.com 
957106Svbart@nginx.com 
958106Svbart@nginx.com nxt_conf_value_t *
nxt_conf_clone(nxt_mp_t * mp,nxt_conf_op_t * op,nxt_conf_value_t * value)959106Svbart@nginx.com nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value)
960106Svbart@nginx.com {
961106Svbart@nginx.com     nxt_int_t         rc;
962106Svbart@nginx.com     nxt_conf_value_t  *copy;
963106Svbart@nginx.com 
964106Svbart@nginx.com     copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
965106Svbart@nginx.com     if (nxt_slow_path(copy == NULL)) {
966106Svbart@nginx.com         return NULL;
967106Svbart@nginx.com     }
968106Svbart@nginx.com 
969106Svbart@nginx.com     rc = nxt_conf_copy_value(mp, op, copy, value);
970106Svbart@nginx.com 
971106Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
972106Svbart@nginx.com         return NULL;
973106Svbart@nginx.com     }
974106Svbart@nginx.com 
975106Svbart@nginx.com     return copy;
976106Svbart@nginx.com }
977106Svbart@nginx.com 
978106Svbart@nginx.com 
979106Svbart@nginx.com static nxt_int_t
nxt_conf_copy_value(nxt_mp_t * mp,nxt_conf_op_t * op,nxt_conf_value_t * dst,nxt_conf_value_t * src)980106Svbart@nginx.com nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
981106Svbart@nginx.com     nxt_conf_value_t *src)
982106Svbart@nginx.com {
9831048Svbart@nginx.com     if (op != NULL
9841048Svbart@nginx.com         && src->type != NXT_CONF_VALUE_ARRAY
9851048Svbart@nginx.com         && src->type != NXT_CONF_VALUE_OBJECT)
9861048Svbart@nginx.com     {
987106Svbart@nginx.com         return NXT_ERROR;
988106Svbart@nginx.com     }
989106Svbart@nginx.com 
990106Svbart@nginx.com     switch (src->type) {
991106Svbart@nginx.com 
992116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
993106Svbart@nginx.com 
994172Svbart@nginx.com         dst->u.string.start = nxt_mp_nget(mp, src->u.string.length);
995172Svbart@nginx.com         if (nxt_slow_path(dst->u.string.start == NULL)) {
996106Svbart@nginx.com             return NXT_ERROR;
997106Svbart@nginx.com         }
998106Svbart@nginx.com 
999172Svbart@nginx.com         nxt_memcpy(dst->u.string.start, src->u.string.start,
1000172Svbart@nginx.com                    src->u.string.length);
1001172Svbart@nginx.com 
1002172Svbart@nginx.com         dst->u.string.length = src->u.string.length;
1003172Svbart@nginx.com 
1004106Svbart@nginx.com         break;
1005106Svbart@nginx.com 
1006116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
10071048Svbart@nginx.com         return nxt_conf_copy_array(mp, op, dst, src);
1008106Svbart@nginx.com 
1009116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
1010106Svbart@nginx.com         return nxt_conf_copy_object(mp, op, dst, src);
1011106Svbart@nginx.com 
1012106Svbart@nginx.com     default:
1013106Svbart@nginx.com         dst->u = src->u;
1014106Svbart@nginx.com     }
1015106Svbart@nginx.com 
10161048Svbart@nginx.com     dst->type = src->type;
10171048Svbart@nginx.com 
10181048Svbart@nginx.com     return NXT_OK;
10191048Svbart@nginx.com }
10201048Svbart@nginx.com 
10211048Svbart@nginx.com 
10221048Svbart@nginx.com static nxt_int_t
nxt_conf_copy_array(nxt_mp_t * mp,nxt_conf_op_t * op,nxt_conf_value_t * dst,nxt_conf_value_t * src)10231048Svbart@nginx.com nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
10241048Svbart@nginx.com     nxt_conf_value_t *src)
10251048Svbart@nginx.com {
10261048Svbart@nginx.com     size_t            size;
10271048Svbart@nginx.com     nxt_int_t         rc;
10281048Svbart@nginx.com     nxt_uint_t        s, d, count, index;
10291048Svbart@nginx.com     nxt_conf_op_t     *pass_op;
10301048Svbart@nginx.com     nxt_conf_value_t  *value;
10311048Svbart@nginx.com 
10321048Svbart@nginx.com     count = src->u.array->count;
10331048Svbart@nginx.com 
10341048Svbart@nginx.com     if (op != NULL) {
10351048Svbart@nginx.com         if (op->action == NXT_CONF_OP_CREATE) {
10361048Svbart@nginx.com             count++;
10371048Svbart@nginx.com 
10381048Svbart@nginx.com         } else if (op->action == NXT_CONF_OP_DELETE) {
10391048Svbart@nginx.com             count--;
10401048Svbart@nginx.com         }
10411048Svbart@nginx.com     }
10421048Svbart@nginx.com 
10431048Svbart@nginx.com     size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t);
10441048Svbart@nginx.com 
10451048Svbart@nginx.com     dst->u.array = nxt_mp_get(mp, size);
10461048Svbart@nginx.com     if (nxt_slow_path(dst->u.array == NULL)) {
10471048Svbart@nginx.com         return NXT_ERROR;
10481048Svbart@nginx.com     }
10491048Svbart@nginx.com 
10501048Svbart@nginx.com     dst->u.array->count = count;
10511048Svbart@nginx.com 
10521048Svbart@nginx.com     s = 0;
10531048Svbart@nginx.com     d = 0;
10541048Svbart@nginx.com 
10551048Svbart@nginx.com     pass_op = NULL;
10561048Svbart@nginx.com 
10571048Svbart@nginx.com     /*
10581048Svbart@nginx.com      * This initialization is needed only to
10591048Svbart@nginx.com      * suppress a warning on GCC 4.8 and older.
10601048Svbart@nginx.com      */
10611048Svbart@nginx.com     index = 0;
10621048Svbart@nginx.com 
10631048Svbart@nginx.com     do {
10641048Svbart@nginx.com         if (pass_op == NULL) {
10651048Svbart@nginx.com             index = (op == NULL) ? src->u.array->count : op->index;
10661048Svbart@nginx.com         }
10671048Svbart@nginx.com 
10681048Svbart@nginx.com         while (s != index) {
10691048Svbart@nginx.com             rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d],
10701048Svbart@nginx.com                                                   &src->u.array->elements[s]);
10711048Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
10721048Svbart@nginx.com                 return NXT_ERROR;
10731048Svbart@nginx.com             }
10741048Svbart@nginx.com 
10751048Svbart@nginx.com             s++;
10761048Svbart@nginx.com             d++;
10771048Svbart@nginx.com         }
10781048Svbart@nginx.com 
10791048Svbart@nginx.com         if (pass_op != NULL) {
10801048Svbart@nginx.com             pass_op = NULL;
10811048Svbart@nginx.com             continue;
10821048Svbart@nginx.com         }
10831048Svbart@nginx.com 
10841048Svbart@nginx.com         if (op != NULL) {
10851048Svbart@nginx.com             switch (op->action) {
10861048Svbart@nginx.com             case NXT_CONF_OP_PASS:
10871048Svbart@nginx.com                 pass_op = op->ctx;
10881048Svbart@nginx.com                 index++;
10891048Svbart@nginx.com                 break;
10901048Svbart@nginx.com 
10911048Svbart@nginx.com             case NXT_CONF_OP_CREATE:
10921048Svbart@nginx.com                 value = op->ctx;
10931048Svbart@nginx.com                 dst->u.array->elements[d] = *value;
10941048Svbart@nginx.com 
10951048Svbart@nginx.com                 d++;
10961048Svbart@nginx.com                 break;
10971048Svbart@nginx.com 
10981048Svbart@nginx.com             case NXT_CONF_OP_REPLACE:
10991048Svbart@nginx.com                 value = op->ctx;
11001048Svbart@nginx.com                 dst->u.array->elements[d] = *value;
11011048Svbart@nginx.com 
11021048Svbart@nginx.com                 s++;
11031048Svbart@nginx.com                 d++;
11041048Svbart@nginx.com                 break;
11051048Svbart@nginx.com 
11061048Svbart@nginx.com             case NXT_CONF_OP_DELETE:
11071048Svbart@nginx.com                 s++;
11081048Svbart@nginx.com                 break;
11091048Svbart@nginx.com             }
11101048Svbart@nginx.com 
11111048Svbart@nginx.com             op = NULL;
11121048Svbart@nginx.com         }
11131048Svbart@nginx.com 
11141048Svbart@nginx.com     } while (d != count);
11151048Svbart@nginx.com 
11161048Svbart@nginx.com     dst->type = src->type;
11171048Svbart@nginx.com 
1118106Svbart@nginx.com     return NXT_OK;
1119106Svbart@nginx.com }
1120106Svbart@nginx.com 
1121106Svbart@nginx.com 
1122106Svbart@nginx.com static nxt_int_t
nxt_conf_copy_object(nxt_mp_t * mp,nxt_conf_op_t * op,nxt_conf_value_t * dst,nxt_conf_value_t * src)1123106Svbart@nginx.com nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
1124106Svbart@nginx.com     nxt_conf_value_t *src)
1125106Svbart@nginx.com {
1126106Svbart@nginx.com     size_t                    size;
1127106Svbart@nginx.com     nxt_int_t                 rc;
1128106Svbart@nginx.com     nxt_uint_t                s, d, count, index;
1129106Svbart@nginx.com     nxt_conf_op_t             *pass_op;
1130106Svbart@nginx.com     nxt_conf_value_t          *value;
1131106Svbart@nginx.com     nxt_conf_object_member_t  *member;
1132106Svbart@nginx.com 
1133106Svbart@nginx.com     count = src->u.object->count;
1134106Svbart@nginx.com 
1135106Svbart@nginx.com     if (op != NULL) {
1136106Svbart@nginx.com         if (op->action == NXT_CONF_OP_CREATE) {
1137106Svbart@nginx.com             count++;
1138106Svbart@nginx.com 
1139106Svbart@nginx.com         } else if (op->action == NXT_CONF_OP_DELETE) {
1140106Svbart@nginx.com             count--;
1141106Svbart@nginx.com         }
1142106Svbart@nginx.com     }
1143106Svbart@nginx.com 
1144106Svbart@nginx.com     size = sizeof(nxt_conf_object_t)
1145106Svbart@nginx.com            + count * sizeof(nxt_conf_object_member_t);
1146106Svbart@nginx.com 
1147106Svbart@nginx.com     dst->u.object = nxt_mp_get(mp, size);
1148106Svbart@nginx.com     if (nxt_slow_path(dst->u.object == NULL)) {
1149106Svbart@nginx.com         return NXT_ERROR;
1150106Svbart@nginx.com     }
1151106Svbart@nginx.com 
1152106Svbart@nginx.com     dst->u.object->count = count;
1153106Svbart@nginx.com 
1154106Svbart@nginx.com     s = 0;
1155106Svbart@nginx.com     d = 0;
1156106Svbart@nginx.com 
1157106Svbart@nginx.com     pass_op = NULL;
1158106Svbart@nginx.com 
1159106Svbart@nginx.com     /*
1160106Svbart@nginx.com      * This initialization is needed only to
1161106Svbart@nginx.com      * suppress a warning on GCC 4.8 and older.
1162106Svbart@nginx.com      */
1163106Svbart@nginx.com     index = 0;
1164106Svbart@nginx.com 
1165106Svbart@nginx.com     do {
1166106Svbart@nginx.com         if (pass_op == NULL) {
11671047Svbart@nginx.com             index = (op == NULL) ? src->u.object->count : op->index;
1168106Svbart@nginx.com         }
1169106Svbart@nginx.com 
1170106Svbart@nginx.com         while (s != index) {
1171106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, NULL,
1172106Svbart@nginx.com                                      &dst->u.object->members[d].name,
1173106Svbart@nginx.com                                      &src->u.object->members[s].name);
1174106Svbart@nginx.com 
1175106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
1176106Svbart@nginx.com                 return NXT_ERROR;
1177106Svbart@nginx.com             }
1178106Svbart@nginx.com 
1179106Svbart@nginx.com             rc = nxt_conf_copy_value(mp, pass_op,
1180106Svbart@nginx.com                                      &dst->u.object->members[d].value,
1181106Svbart@nginx.com                                      &src->u.object->members[s].value);
1182106Svbart@nginx.com 
1183106Svbart@nginx.com             if (nxt_slow_path(rc != NXT_OK)) {
1184106Svbart@nginx.com                 return NXT_ERROR;
1185106Svbart@nginx.com             }
1186106Svbart@nginx.com 
1187106Svbart@nginx.com             s++;
1188106Svbart@nginx.com             d++;
1189106Svbart@nginx.com         }
1190106Svbart@nginx.com 
1191106Svbart@nginx.com         if (pass_op != NULL) {
1192106Svbart@nginx.com             pass_op = NULL;
1193106Svbart@nginx.com             continue;
1194106Svbart@nginx.com         }
1195106Svbart@nginx.com 
1196106Svbart@nginx.com         if (op != NULL) {
1197106Svbart@nginx.com             switch (op->action) {
1198106Svbart@nginx.com             case NXT_CONF_OP_PASS:
1199106Svbart@nginx.com                 pass_op = op->ctx;
1200106Svbart@nginx.com                 index++;
1201106Svbart@nginx.com                 break;
1202106Svbart@nginx.com 
1203106Svbart@nginx.com             case NXT_CONF_OP_CREATE:
1204106Svbart@nginx.com                 member = op->ctx;
1205106Svbart@nginx.com 
1206106Svbart@nginx.com                 rc = nxt_conf_copy_value(mp, NULL,
1207106Svbart@nginx.com                                          &dst->u.object->members[d].name,
1208106Svbart@nginx.com                                          &member->name);
1209106Svbart@nginx.com 
1210106Svbart@nginx.com                 if (nxt_slow_path(rc != NXT_OK)) {
1211106Svbart@nginx.com                     return NXT_ERROR;
1212106Svbart@nginx.com                 }
1213106Svbart@nginx.com 
1214106Svbart@nginx.com                 dst->u.object->members[d].value = member->value;
1215106Svbart@nginx.com 
1216106Svbart@nginx.com                 d++;
1217106Svbart@nginx.com                 break;
1218106Svbart@nginx.com 
1219106Svbart@nginx.com             case NXT_CONF_OP_REPLACE:
1220106Svbart@nginx.com                 rc = nxt_conf_copy_value(mp, NULL,
1221106Svbart@nginx.com                                          &dst->u.object->members[d].name,
1222106Svbart@nginx.com                                          &src->u.object->members[s].name);
1223106Svbart@nginx.com 
1224106Svbart@nginx.com                 if (nxt_slow_path(rc != NXT_OK)) {
1225106Svbart@nginx.com                     return NXT_ERROR;
1226106Svbart@nginx.com                 }
1227106Svbart@nginx.com 
1228106Svbart@nginx.com                 value = op->ctx;
1229106Svbart@nginx.com 
1230106Svbart@nginx.com                 dst->u.object->members[d].value = *value;
1231106Svbart@nginx.com 
1232106Svbart@nginx.com                 s++;
1233106Svbart@nginx.com                 d++;
1234106Svbart@nginx.com                 break;
1235106Svbart@nginx.com 
1236106Svbart@nginx.com             case NXT_CONF_OP_DELETE:
1237106Svbart@nginx.com                 s++;
1238106Svbart@nginx.com                 break;
1239106Svbart@nginx.com             }
1240106Svbart@nginx.com 
12411046Svbart@nginx.com             op = NULL;
1242106Svbart@nginx.com         }
1243106Svbart@nginx.com 
1244106Svbart@nginx.com     } while (d != count);
1245106Svbart@nginx.com 
1246106Svbart@nginx.com     dst->type = src->type;
1247106Svbart@nginx.com 
1248106Svbart@nginx.com     return NXT_OK;
1249106Svbart@nginx.com }
1250106Svbart@nginx.com 
1251106Svbart@nginx.com 
1252106Svbart@nginx.com nxt_conf_value_t *
nxt_conf_json_parse(nxt_mp_t * mp,u_char * start,u_char * end,nxt_conf_json_error_t * error)1253208Svbart@nginx.com nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
1254208Svbart@nginx.com     nxt_conf_json_error_t *error)
1255106Svbart@nginx.com {
1256106Svbart@nginx.com     u_char            *p;
1257106Svbart@nginx.com     nxt_conf_value_t  *value;
1258106Svbart@nginx.com 
1259106Svbart@nginx.com     value = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
1260106Svbart@nginx.com     if (nxt_slow_path(value == NULL)) {
1261106Svbart@nginx.com         return NULL;
1262106Svbart@nginx.com     }
1263106Svbart@nginx.com 
1264106Svbart@nginx.com     p = nxt_conf_json_skip_space(start, end);
1265106Svbart@nginx.com 
1266106Svbart@nginx.com     if (nxt_slow_path(p == end)) {
1267208Svbart@nginx.com 
1268208Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
1269311Snick@nginx.com             "An empty JSON payload isn't allowed.  It must be either a literal "
1270311Snick@nginx.com             "(null, true, or false), a number, a string (in double quotes "
1271311Snick@nginx.com             "\"\"), an array (with brackets []), or an object (with braces {})."
1272208Svbart@nginx.com         );
1273208Svbart@nginx.com 
1274106Svbart@nginx.com         return NULL;
1275106Svbart@nginx.com     }
1276106Svbart@nginx.com 
1277208Svbart@nginx.com     p = nxt_conf_json_parse_value(mp, value, p, end, error);
1278106Svbart@nginx.com 
1279106Svbart@nginx.com     if (nxt_slow_path(p == NULL)) {
1280106Svbart@nginx.com         return NULL;
1281106Svbart@nginx.com     }
1282106Svbart@nginx.com 
1283106Svbart@nginx.com     p = nxt_conf_json_skip_space(p, end);
1284106Svbart@nginx.com 
1285106Svbart@nginx.com     if (nxt_slow_path(p != end)) {
1286208Svbart@nginx.com 
1287208Svbart@nginx.com         nxt_conf_json_parse_error(error, p,
1288311Snick@nginx.com             "Unexpected character after the end of a valid JSON value."
1289208Svbart@nginx.com         );
1290208Svbart@nginx.com 
1291106Svbart@nginx.com         return NULL;
1292106Svbart@nginx.com     }
1293106Svbart@nginx.com 
1294106Svbart@nginx.com     return value;
1295106Svbart@nginx.com }
1296106Svbart@nginx.com 
1297106Svbart@nginx.com 
1298106Svbart@nginx.com static u_char *
nxt_conf_json_skip_space(u_char * start,const u_char * end)12992139Sandrew@digital-domain.net nxt_conf_json_skip_space(u_char *start, const u_char *end)
1300106Svbart@nginx.com {
13011363Svbart@nginx.com     u_char  *p, ch;
13021363Svbart@nginx.com 
13031363Svbart@nginx.com     enum {
13041363Svbart@nginx.com         sw_normal = 0,
13051363Svbart@nginx.com         sw_after_slash,
13061363Svbart@nginx.com         sw_single_comment,
13071363Svbart@nginx.com         sw_multi_comment,
13081363Svbart@nginx.com         sw_after_asterisk,
13091363Svbart@nginx.com     } state;
13101363Svbart@nginx.com 
13111363Svbart@nginx.com     state = sw_normal;
1312106Svbart@nginx.com 
1313106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
13141363Svbart@nginx.com         ch = *p;
13151363Svbart@nginx.com 
13161363Svbart@nginx.com         switch (state) {
13171363Svbart@nginx.com 
13181363Svbart@nginx.com         case sw_normal:
13191363Svbart@nginx.com             switch (ch) {
13201363Svbart@nginx.com             case ' ':
13211363Svbart@nginx.com             case '\t':
13221363Svbart@nginx.com             case '\n':
13231363Svbart@nginx.com             case '\r':
13241363Svbart@nginx.com                 continue;
13251363Svbart@nginx.com             case '/':
13261425Svbart@nginx.com                 start = p;
13271363Svbart@nginx.com                 state = sw_after_slash;
13281363Svbart@nginx.com                 continue;
13291363Svbart@nginx.com             }
13301363Svbart@nginx.com 
13311363Svbart@nginx.com             break;
13321363Svbart@nginx.com 
13331363Svbart@nginx.com         case sw_after_slash:
13341363Svbart@nginx.com             switch (ch) {
13351363Svbart@nginx.com             case '/':
13361363Svbart@nginx.com                 state = sw_single_comment;
13371363Svbart@nginx.com                 continue;
13381363Svbart@nginx.com             case '*':
13391363Svbart@nginx.com                 state = sw_multi_comment;
13401363Svbart@nginx.com                 continue;
13411363Svbart@nginx.com             }
13421363Svbart@nginx.com 
13431363Svbart@nginx.com             break;
13441363Svbart@nginx.com 
13451363Svbart@nginx.com         case sw_single_comment:
13461363Svbart@nginx.com             if (ch == '\n') {
13471363Svbart@nginx.com                 state = sw_normal;
13481363Svbart@nginx.com             }
13491363Svbart@nginx.com 
13501363Svbart@nginx.com             continue;
13511363Svbart@nginx.com 
13521363Svbart@nginx.com         case sw_multi_comment:
13531363Svbart@nginx.com             if (ch == '*') {
13541363Svbart@nginx.com                 state = sw_after_asterisk;
13551363Svbart@nginx.com             }
13561363Svbart@nginx.com 
13571363Svbart@nginx.com             continue;
13581363Svbart@nginx.com 
13591363Svbart@nginx.com         case sw_after_asterisk:
13601363Svbart@nginx.com             switch (ch) {
13611363Svbart@nginx.com             case '/':
13621363Svbart@nginx.com                 state = sw_normal;
13631363Svbart@nginx.com                 continue;
13641363Svbart@nginx.com             case '*':
13651363Svbart@nginx.com                 continue;
13661363Svbart@nginx.com             }
13671363Svbart@nginx.com 
13681363Svbart@nginx.com             state = sw_multi_comment;
1369106Svbart@nginx.com             continue;
1370106Svbart@nginx.com         }
1371106Svbart@nginx.com 
1372106Svbart@nginx.com         break;
1373106Svbart@nginx.com     }
1374106Svbart@nginx.com 
13751425Svbart@nginx.com     if (nxt_slow_path(state != sw_normal)) {
13761425Svbart@nginx.com         return start;
13771425Svbart@nginx.com     }
13781425Svbart@nginx.com 
1379106Svbart@nginx.com     return p;
1380106Svbart@nginx.com }
1381106Svbart@nginx.com 
1382106Svbart@nginx.com 
1383106Svbart@nginx.com static u_char *
nxt_conf_json_parse_value(nxt_mp_t * mp,nxt_conf_value_t * value,u_char * start,u_char * end,nxt_conf_json_error_t * error)1384106Svbart@nginx.com nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1385208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1386106Svbart@nginx.com {
1387208Svbart@nginx.com     u_char  ch, *p;
1388106Svbart@nginx.com 
1389106Svbart@nginx.com     ch = *start;
1390106Svbart@nginx.com 
1391106Svbart@nginx.com     switch (ch) {
1392106Svbart@nginx.com     case '{':
1393208Svbart@nginx.com         return nxt_conf_json_parse_object(mp, value, start, end, error);
1394106Svbart@nginx.com 
1395106Svbart@nginx.com     case '[':
1396208Svbart@nginx.com         return nxt_conf_json_parse_array(mp, value, start, end, error);
1397106Svbart@nginx.com 
1398106Svbart@nginx.com     case '"':
1399208Svbart@nginx.com         return nxt_conf_json_parse_string(mp, value, start, end, error);
1400106Svbart@nginx.com 
1401106Svbart@nginx.com     case 't':
1402106Svbart@nginx.com         if (nxt_fast_path(end - start >= 4
14032231Salx@nginx.com                           && memcmp(start, "true", 4) == 0))
1404106Svbart@nginx.com         {
1405106Svbart@nginx.com             value->u.boolean = 1;
1406116Svbart@nginx.com             value->type = NXT_CONF_VALUE_BOOLEAN;
1407106Svbart@nginx.com 
1408106Svbart@nginx.com             return start + 4;
1409106Svbart@nginx.com         }
1410106Svbart@nginx.com 
1411208Svbart@nginx.com         goto error;
1412106Svbart@nginx.com 
1413106Svbart@nginx.com     case 'f':
1414106Svbart@nginx.com         if (nxt_fast_path(end - start >= 5
14152231Salx@nginx.com                           && memcmp(start, "false", 5) == 0))
1416106Svbart@nginx.com         {
1417106Svbart@nginx.com             value->u.boolean = 0;
1418116Svbart@nginx.com             value->type = NXT_CONF_VALUE_BOOLEAN;
1419106Svbart@nginx.com 
1420106Svbart@nginx.com             return start + 5;
1421106Svbart@nginx.com         }
1422106Svbart@nginx.com 
1423208Svbart@nginx.com         goto error;
1424106Svbart@nginx.com 
1425106Svbart@nginx.com     case 'n':
1426106Svbart@nginx.com         if (nxt_fast_path(end - start >= 4
14272231Salx@nginx.com                           && memcmp(start, "null", 4) == 0))
1428106Svbart@nginx.com         {
1429116Svbart@nginx.com             value->type = NXT_CONF_VALUE_NULL;
1430106Svbart@nginx.com             return start + 4;
1431106Svbart@nginx.com         }
1432106Svbart@nginx.com 
1433208Svbart@nginx.com         goto error;
1434208Svbart@nginx.com 
1435208Svbart@nginx.com     case '-':
1436208Svbart@nginx.com         if (nxt_fast_path(end - start > 1)) {
1437208Svbart@nginx.com             ch = start[1];
1438208Svbart@nginx.com             break;
1439208Svbart@nginx.com         }
1440208Svbart@nginx.com 
1441208Svbart@nginx.com         goto error;
1442106Svbart@nginx.com     }
1443106Svbart@nginx.com 
1444208Svbart@nginx.com     if (nxt_fast_path((ch - '0') <= 9)) {
1445208Svbart@nginx.com         p = nxt_conf_json_parse_number(mp, value, start, end, error);
1446208Svbart@nginx.com 
1447383Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1448383Svbart@nginx.com             return NULL;
1449383Svbart@nginx.com         }
1450383Svbart@nginx.com 
1451208Svbart@nginx.com         if (p == end) {
1452208Svbart@nginx.com             return end;
1453208Svbart@nginx.com         }
1454208Svbart@nginx.com 
1455208Svbart@nginx.com         switch (*p) {
1456208Svbart@nginx.com         case ' ':
1457208Svbart@nginx.com         case '\t':
1458208Svbart@nginx.com         case '\r':
1459208Svbart@nginx.com         case '\n':
1460208Svbart@nginx.com         case ',':
1461208Svbart@nginx.com         case '}':
1462208Svbart@nginx.com         case ']':
1463208Svbart@nginx.com         case '{':
1464208Svbart@nginx.com         case '[':
1465208Svbart@nginx.com         case '"':
14661363Svbart@nginx.com         case '/':
1467208Svbart@nginx.com             return p;
1468208Svbart@nginx.com         }
1469106Svbart@nginx.com     }
1470106Svbart@nginx.com 
1471208Svbart@nginx.com error:
1472208Svbart@nginx.com 
1473208Svbart@nginx.com     nxt_conf_json_parse_error(error, start,
1474311Snick@nginx.com         "A valid JSON value is expected here.  It must be either a literal "
1475311Snick@nginx.com         "(null, true, or false), a number, a string (in double quotes \"\"), "
1476311Snick@nginx.com         "an array (with brackets []), or an object (with braces {})."
1477208Svbart@nginx.com     );
1478208Svbart@nginx.com 
1479106Svbart@nginx.com     return NULL;
1480106Svbart@nginx.com }
1481106Svbart@nginx.com 
1482106Svbart@nginx.com 
1483106Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_conf_object_hash_proto
1484106Svbart@nginx.com     nxt_aligned(64) =
1485106Svbart@nginx.com {
1486106Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
1487106Svbart@nginx.com     nxt_conf_object_hash_test,
1488106Svbart@nginx.com     nxt_conf_object_hash_alloc,
1489106Svbart@nginx.com     nxt_conf_object_hash_free,
1490106Svbart@nginx.com };
1491106Svbart@nginx.com 
1492106Svbart@nginx.com 
1493106Svbart@nginx.com static u_char *
nxt_conf_json_parse_object(nxt_mp_t * mp,nxt_conf_value_t * value,u_char * start,u_char * end,nxt_conf_json_error_t * error)1494106Svbart@nginx.com nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1495208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1496106Svbart@nginx.com {
1497208Svbart@nginx.com     u_char                    *p, *name;
1498106Svbart@nginx.com     nxt_mp_t                  *mp_temp;
1499106Svbart@nginx.com     nxt_int_t                 rc;
1500106Svbart@nginx.com     nxt_uint_t                count;
1501106Svbart@nginx.com     nxt_lvlhsh_t              hash;
1502106Svbart@nginx.com     nxt_lvlhsh_each_t         lhe;
1503106Svbart@nginx.com     nxt_conf_object_t         *object;
1504106Svbart@nginx.com     nxt_conf_object_member_t  *member, *element;
1505106Svbart@nginx.com 
1506106Svbart@nginx.com     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1507106Svbart@nginx.com     if (nxt_slow_path(mp_temp == NULL)) {
1508106Svbart@nginx.com         return NULL;
1509106Svbart@nginx.com     }
1510106Svbart@nginx.com 
1511106Svbart@nginx.com     nxt_lvlhsh_init(&hash);
1512106Svbart@nginx.com 
1513106Svbart@nginx.com     count = 0;
1514130Svbart@nginx.com     p = start;
1515130Svbart@nginx.com 
1516130Svbart@nginx.com     for ( ;; ) {
1517130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1518130Svbart@nginx.com 
1519130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1520208Svbart@nginx.com 
1521208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1522311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object without "
1523311Snick@nginx.com                 "a closing brace (})."
1524208Svbart@nginx.com             );
1525208Svbart@nginx.com 
1526130Svbart@nginx.com             goto error;
1527130Svbart@nginx.com         }
1528130Svbart@nginx.com 
1529130Svbart@nginx.com         if (*p != '"') {
1530130Svbart@nginx.com             if (nxt_fast_path(*p == '}')) {
1531106Svbart@nginx.com                 break;
1532106Svbart@nginx.com             }
1533106Svbart@nginx.com 
1534208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1535208Svbart@nginx.com                 "A double quote (\") is expected here.  There must be a valid "
1536208Svbart@nginx.com                 "JSON object member starts with a name, which is a string "
1537208Svbart@nginx.com                 "enclosed in double quotes."
1538208Svbart@nginx.com             );
1539208Svbart@nginx.com 
1540130Svbart@nginx.com             goto error;
1541130Svbart@nginx.com         }
1542130Svbart@nginx.com 
1543208Svbart@nginx.com         name = p;
1544208Svbart@nginx.com 
1545130Svbart@nginx.com         count++;
1546130Svbart@nginx.com 
1547130Svbart@nginx.com         member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
1548130Svbart@nginx.com         if (nxt_slow_path(member == NULL)) {
1549130Svbart@nginx.com             goto error;
1550130Svbart@nginx.com         }
1551130Svbart@nginx.com 
1552208Svbart@nginx.com         p = nxt_conf_json_parse_string(mp, &member->name, p, end, error);
1553130Svbart@nginx.com 
1554130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1555130Svbart@nginx.com             goto error;
1556130Svbart@nginx.com         }
1557130Svbart@nginx.com 
1558130Svbart@nginx.com         rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
1559130Svbart@nginx.com 
1560130Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1561208Svbart@nginx.com 
1562208Svbart@nginx.com             if (rc == NXT_DECLINED) {
1563208Svbart@nginx.com                 nxt_conf_json_parse_error(error, name,
1564208Svbart@nginx.com                     "Duplicate object member.  All JSON object members must "
1565208Svbart@nginx.com                     "have unique names."
1566208Svbart@nginx.com                 );
1567208Svbart@nginx.com             }
1568208Svbart@nginx.com 
1569130Svbart@nginx.com             goto error;
1570130Svbart@nginx.com         }
1571130Svbart@nginx.com 
1572130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1573130Svbart@nginx.com 
1574208Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1575208Svbart@nginx.com 
1576208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1577311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object member "
1578311Snick@nginx.com                 "without a value."
1579208Svbart@nginx.com             );
1580208Svbart@nginx.com 
1581208Svbart@nginx.com             goto error;
1582208Svbart@nginx.com         }
1583208Svbart@nginx.com 
1584208Svbart@nginx.com         if (nxt_slow_path(*p != ':')) {
1585208Svbart@nginx.com 
1586208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1587311Snick@nginx.com                 "A colon (:) is expected here.  There must be a colon after "
1588311Snick@nginx.com                 "a JSON member name."
1589208Svbart@nginx.com             );
1590208Svbart@nginx.com 
1591130Svbart@nginx.com             goto error;
1592130Svbart@nginx.com         }
1593130Svbart@nginx.com 
1594130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1595130Svbart@nginx.com 
1596130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1597208Svbart@nginx.com 
1598208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1599311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object member "
1600311Snick@nginx.com                 "without a value."
1601208Svbart@nginx.com             );
1602208Svbart@nginx.com 
1603130Svbart@nginx.com             goto error;
1604130Svbart@nginx.com         }
1605130Svbart@nginx.com 
1606208Svbart@nginx.com         p = nxt_conf_json_parse_value(mp, &member->value, p, end, error);
1607130Svbart@nginx.com 
1608130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1609130Svbart@nginx.com             goto error;
1610130Svbart@nginx.com         }
1611130Svbart@nginx.com 
1612130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1613130Svbart@nginx.com 
1614130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1615208Svbart@nginx.com 
1616208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1617311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an object without "
1618311Snick@nginx.com                 "a closing brace (})."
1619208Svbart@nginx.com             );
1620208Svbart@nginx.com 
1621130Svbart@nginx.com             goto error;
1622130Svbart@nginx.com         }
1623130Svbart@nginx.com 
1624130Svbart@nginx.com         if (*p != ',') {
1625130Svbart@nginx.com             if (nxt_fast_path(*p == '}')) {
1626130Svbart@nginx.com                 break;
1627106Svbart@nginx.com             }
1628106Svbart@nginx.com 
1629208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1630311Snick@nginx.com                 "Either a closing brace (}) or a comma (,) is expected here.  "
1631311Snick@nginx.com                 "Each JSON object must be enclosed in braces and its members "
1632311Snick@nginx.com                 "must be separated by commas."
1633208Svbart@nginx.com             );
1634208Svbart@nginx.com 
1635130Svbart@nginx.com             goto error;
1636106Svbart@nginx.com         }
1637106Svbart@nginx.com     }
1638106Svbart@nginx.com 
1639106Svbart@nginx.com     object = nxt_mp_get(mp, sizeof(nxt_conf_object_t)
1640106Svbart@nginx.com                             + count * sizeof(nxt_conf_object_member_t));
1641106Svbart@nginx.com     if (nxt_slow_path(object == NULL)) {
1642106Svbart@nginx.com         goto error;
1643106Svbart@nginx.com     }
1644106Svbart@nginx.com 
1645106Svbart@nginx.com     value->u.object = object;
1646116Svbart@nginx.com     value->type = NXT_CONF_VALUE_OBJECT;
1647106Svbart@nginx.com 
1648106Svbart@nginx.com     object->count = count;
1649106Svbart@nginx.com     member = object->members;
1650106Svbart@nginx.com 
1651598Sigor@sysoev.ru     nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto);
1652106Svbart@nginx.com 
1653106Svbart@nginx.com     for ( ;; ) {
1654106Svbart@nginx.com         element = nxt_lvlhsh_each(&hash, &lhe);
1655106Svbart@nginx.com 
1656106Svbart@nginx.com         if (element == NULL) {
1657106Svbart@nginx.com             break;
1658106Svbart@nginx.com         }
1659106Svbart@nginx.com 
1660106Svbart@nginx.com         *member++ = *element;
1661106Svbart@nginx.com     }
1662106Svbart@nginx.com 
1663106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1664106Svbart@nginx.com 
1665106Svbart@nginx.com     return p + 1;
1666106Svbart@nginx.com 
1667106Svbart@nginx.com error:
1668106Svbart@nginx.com 
1669106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1670106Svbart@nginx.com     return NULL;
1671106Svbart@nginx.com }
1672106Svbart@nginx.com 
1673106Svbart@nginx.com 
1674106Svbart@nginx.com static nxt_int_t
nxt_conf_object_hash_add(nxt_mp_t * mp,nxt_lvlhsh_t * lvlhsh,nxt_conf_object_member_t * member)1675106Svbart@nginx.com nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh,
1676106Svbart@nginx.com     nxt_conf_object_member_t *member)
1677106Svbart@nginx.com {
1678106Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1679106Svbart@nginx.com 
1680106Svbart@nginx.com     nxt_conf_get_string(&member->name, &lhq.key);
1681106Svbart@nginx.com 
1682106Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
1683106Svbart@nginx.com     lhq.replace = 0;
1684106Svbart@nginx.com     lhq.value = member;
1685106Svbart@nginx.com     lhq.proto = &nxt_conf_object_hash_proto;
1686106Svbart@nginx.com     lhq.pool = mp;
1687106Svbart@nginx.com 
1688106Svbart@nginx.com     return nxt_lvlhsh_insert(lvlhsh, &lhq);
1689106Svbart@nginx.com }
1690106Svbart@nginx.com 
1691106Svbart@nginx.com 
1692106Svbart@nginx.com static nxt_int_t
nxt_conf_object_hash_test(nxt_lvlhsh_query_t * lhq,void * data)1693106Svbart@nginx.com nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1694106Svbart@nginx.com {
1695106Svbart@nginx.com     nxt_str_t                 str;
1696106Svbart@nginx.com     nxt_conf_object_member_t  *member;
1697106Svbart@nginx.com 
1698106Svbart@nginx.com     member = data;
1699106Svbart@nginx.com 
1700106Svbart@nginx.com     nxt_conf_get_string(&member->name, &str);
1701106Svbart@nginx.com 
1702208Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED;
1703106Svbart@nginx.com }
1704106Svbart@nginx.com 
1705106Svbart@nginx.com 
1706106Svbart@nginx.com static void *
nxt_conf_object_hash_alloc(void * data,size_t size)1707106Svbart@nginx.com nxt_conf_object_hash_alloc(void *data, size_t size)
1708106Svbart@nginx.com {
1709106Svbart@nginx.com     return nxt_mp_align(data, size, size);
1710106Svbart@nginx.com }
1711106Svbart@nginx.com 
1712106Svbart@nginx.com 
1713106Svbart@nginx.com static void
nxt_conf_object_hash_free(void * data,void * p)1714106Svbart@nginx.com nxt_conf_object_hash_free(void *data, void *p)
1715106Svbart@nginx.com {
1716106Svbart@nginx.com     nxt_mp_free(data, p);
1717106Svbart@nginx.com }
1718106Svbart@nginx.com 
1719106Svbart@nginx.com 
1720106Svbart@nginx.com static u_char *
nxt_conf_json_parse_array(nxt_mp_t * mp,nxt_conf_value_t * value,u_char * start,u_char * end,nxt_conf_json_error_t * error)1721106Svbart@nginx.com nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1722208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1723106Svbart@nginx.com {
1724106Svbart@nginx.com     u_char            *p;
1725106Svbart@nginx.com     nxt_mp_t          *mp_temp;
1726106Svbart@nginx.com     nxt_uint_t        count;
1727106Svbart@nginx.com     nxt_list_t        *list;
1728106Svbart@nginx.com     nxt_conf_array_t  *array;
1729106Svbart@nginx.com     nxt_conf_value_t  *element;
1730106Svbart@nginx.com 
1731106Svbart@nginx.com     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1732106Svbart@nginx.com     if (nxt_slow_path(mp_temp == NULL)) {
1733106Svbart@nginx.com         return NULL;
1734106Svbart@nginx.com     }
1735106Svbart@nginx.com 
1736106Svbart@nginx.com     list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t));
1737106Svbart@nginx.com     if (nxt_slow_path(list == NULL)) {
1738106Svbart@nginx.com         goto error;
1739106Svbart@nginx.com     }
1740106Svbart@nginx.com 
1741106Svbart@nginx.com     count = 0;
1742130Svbart@nginx.com     p = start;
1743130Svbart@nginx.com 
1744130Svbart@nginx.com     for ( ;; ) {
1745130Svbart@nginx.com         p = nxt_conf_json_skip_space(p + 1, end);
1746130Svbart@nginx.com 
1747130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1748208Svbart@nginx.com 
1749208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1750311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an array without "
1751311Snick@nginx.com                 "a closing bracket (])."
1752208Svbart@nginx.com             );
1753208Svbart@nginx.com 
1754130Svbart@nginx.com             goto error;
1755130Svbart@nginx.com         }
1756130Svbart@nginx.com 
1757130Svbart@nginx.com         if (*p == ']') {
1758130Svbart@nginx.com             break;
1759130Svbart@nginx.com         }
1760130Svbart@nginx.com 
1761130Svbart@nginx.com         count++;
1762130Svbart@nginx.com 
1763130Svbart@nginx.com         element = nxt_list_add(list);
1764130Svbart@nginx.com         if (nxt_slow_path(element == NULL)) {
1765130Svbart@nginx.com             goto error;
1766130Svbart@nginx.com         }
1767130Svbart@nginx.com 
1768208Svbart@nginx.com         p = nxt_conf_json_parse_value(mp, element, p, end, error);
1769130Svbart@nginx.com 
1770130Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
1771130Svbart@nginx.com             goto error;
1772130Svbart@nginx.com         }
1773130Svbart@nginx.com 
1774130Svbart@nginx.com         p = nxt_conf_json_skip_space(p, end);
1775130Svbart@nginx.com 
1776130Svbart@nginx.com         if (nxt_slow_path(p == end)) {
1777208Svbart@nginx.com 
1778208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1779311Snick@nginx.com                 "Unexpected end of JSON payload.  There's an array without "
1780311Snick@nginx.com                 "a closing bracket (])."
1781208Svbart@nginx.com             );
1782208Svbart@nginx.com 
1783130Svbart@nginx.com             goto error;
1784130Svbart@nginx.com         }
1785130Svbart@nginx.com 
1786130Svbart@nginx.com         if (*p != ',') {
1787130Svbart@nginx.com             if (nxt_fast_path(*p == ']')) {
1788106Svbart@nginx.com                 break;
1789106Svbart@nginx.com             }
1790106Svbart@nginx.com 
1791208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1792311Snick@nginx.com                 "Either a closing bracket (]) or a comma (,) is expected "
1793311Snick@nginx.com                 "here.  Each array must be enclosed in brackets and its "
1794311Snick@nginx.com                 "members must be separated by commas."
1795208Svbart@nginx.com             );
1796208Svbart@nginx.com 
1797130Svbart@nginx.com             goto error;
1798106Svbart@nginx.com         }
1799106Svbart@nginx.com     }
1800106Svbart@nginx.com 
1801106Svbart@nginx.com     array = nxt_mp_get(mp, sizeof(nxt_conf_array_t)
1802106Svbart@nginx.com                            + count * sizeof(nxt_conf_value_t));
1803106Svbart@nginx.com     if (nxt_slow_path(array == NULL)) {
1804106Svbart@nginx.com         goto error;
1805106Svbart@nginx.com     }
1806106Svbart@nginx.com 
1807106Svbart@nginx.com     value->u.array = array;
1808116Svbart@nginx.com     value->type = NXT_CONF_VALUE_ARRAY;
1809106Svbart@nginx.com 
1810106Svbart@nginx.com     array->count = count;
1811106Svbart@nginx.com     element = array->elements;
1812106Svbart@nginx.com 
1813106Svbart@nginx.com     nxt_list_each(value, list) {
1814106Svbart@nginx.com         *element++ = *value;
1815106Svbart@nginx.com     } nxt_list_loop;
1816106Svbart@nginx.com 
1817106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1818106Svbart@nginx.com 
1819106Svbart@nginx.com     return p + 1;
1820106Svbart@nginx.com 
1821106Svbart@nginx.com error:
1822106Svbart@nginx.com 
1823106Svbart@nginx.com     nxt_mp_destroy(mp_temp);
1824106Svbart@nginx.com     return NULL;
1825106Svbart@nginx.com }
1826106Svbart@nginx.com 
1827106Svbart@nginx.com 
1828106Svbart@nginx.com static u_char *
nxt_conf_json_parse_string(nxt_mp_t * mp,nxt_conf_value_t * value,u_char * start,u_char * end,nxt_conf_json_error_t * error)1829106Svbart@nginx.com nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1830208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
1831106Svbart@nginx.com {
1832106Svbart@nginx.com     u_char      *p, ch, *last, *s;
1833106Svbart@nginx.com     size_t      size, surplus;
1834106Svbart@nginx.com     uint32_t    utf, utf_high;
1835106Svbart@nginx.com     nxt_uint_t  i;
1836106Svbart@nginx.com     enum {
1837106Svbart@nginx.com         sw_usual = 0,
1838106Svbart@nginx.com         sw_escape,
1839106Svbart@nginx.com         sw_encoded1,
1840106Svbart@nginx.com         sw_encoded2,
1841106Svbart@nginx.com         sw_encoded3,
1842106Svbart@nginx.com         sw_encoded4,
1843106Svbart@nginx.com     } state;
1844106Svbart@nginx.com 
1845106Svbart@nginx.com     start++;
1846106Svbart@nginx.com 
1847106Svbart@nginx.com     state = 0;
1848106Svbart@nginx.com     surplus = 0;
1849106Svbart@nginx.com 
1850106Svbart@nginx.com     for (p = start; nxt_fast_path(p != end); p++) {
1851106Svbart@nginx.com         ch = *p;
1852106Svbart@nginx.com 
1853106Svbart@nginx.com         switch (state) {
1854106Svbart@nginx.com 
1855106Svbart@nginx.com         case sw_usual:
1856106Svbart@nginx.com 
1857106Svbart@nginx.com             if (ch == '"') {
1858106Svbart@nginx.com                 break;
1859106Svbart@nginx.com             }
1860106Svbart@nginx.com 
1861106Svbart@nginx.com             if (ch == '\\') {
1862106Svbart@nginx.com                 state = sw_escape;
1863106Svbart@nginx.com                 continue;
1864106Svbart@nginx.com             }
1865106Svbart@nginx.com 
1866106Svbart@nginx.com             if (nxt_fast_path(ch >= ' ')) {
1867106Svbart@nginx.com                 continue;
1868106Svbart@nginx.com             }
1869106Svbart@nginx.com 
1870208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1871311Snick@nginx.com                 "Unexpected character.  All control characters in a JSON "
1872311Snick@nginx.com                 "string must be escaped."
1873208Svbart@nginx.com             );
1874208Svbart@nginx.com 
1875106Svbart@nginx.com             return NULL;
1876106Svbart@nginx.com 
1877106Svbart@nginx.com         case sw_escape:
1878106Svbart@nginx.com 
1879106Svbart@nginx.com             switch (ch) {
1880106Svbart@nginx.com             case '"':
1881106Svbart@nginx.com             case '\\':
1882106Svbart@nginx.com             case '/':
1883106Svbart@nginx.com             case 'n':
1884106Svbart@nginx.com             case 'r':
1885106Svbart@nginx.com             case 't':
1886106Svbart@nginx.com             case 'b':
1887106Svbart@nginx.com             case 'f':
1888106Svbart@nginx.com                 surplus++;
1889106Svbart@nginx.com                 state = sw_usual;
1890106Svbart@nginx.com                 continue;
1891106Svbart@nginx.com 
1892106Svbart@nginx.com             case 'u':
1893106Svbart@nginx.com                 /*
1894106Svbart@nginx.com                  * Basic unicode 6 bytes "\uXXXX" in JSON
1895106Svbart@nginx.com                  * and up to 3 bytes in UTF-8.
1896106Svbart@nginx.com                  *
1897106Svbart@nginx.com                  * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON
1898106Svbart@nginx.com                  * and 3 or 4 bytes in UTF-8.
1899106Svbart@nginx.com                  */
1900106Svbart@nginx.com                 surplus += 3;
1901106Svbart@nginx.com                 state = sw_encoded1;
1902106Svbart@nginx.com                 continue;
1903106Svbart@nginx.com             }
1904106Svbart@nginx.com 
1905208Svbart@nginx.com             nxt_conf_json_parse_error(error, p - 1,
1906311Snick@nginx.com                 "Unexpected backslash.  A literal backslash in a JSON string "
1907311Snick@nginx.com                 "must be escaped with a second backslash (\\\\)."
1908208Svbart@nginx.com             );
1909208Svbart@nginx.com 
1910106Svbart@nginx.com             return NULL;
1911106Svbart@nginx.com 
1912106Svbart@nginx.com         case sw_encoded1:
1913106Svbart@nginx.com         case sw_encoded2:
1914106Svbart@nginx.com         case sw_encoded3:
1915106Svbart@nginx.com         case sw_encoded4:
1916106Svbart@nginx.com 
1917106Svbart@nginx.com             if (nxt_fast_path((ch >= '0' && ch <= '9')
1918202Svbart@nginx.com                               || (ch >= 'A' && ch <= 'F')
1919202Svbart@nginx.com                               || (ch >= 'a' && ch <= 'f')))
1920106Svbart@nginx.com             {
1921106Svbart@nginx.com                 state = (state == sw_encoded4) ? sw_usual : state + 1;
1922106Svbart@nginx.com                 continue;
1923106Svbart@nginx.com             }
1924106Svbart@nginx.com 
1925208Svbart@nginx.com             nxt_conf_json_parse_error(error, p,
1926311Snick@nginx.com                 "Invalid escape sequence.  An escape sequence in a JSON "
1927311Snick@nginx.com                 "string must start with a backslash, followed by the lowercase "
1928311Snick@nginx.com                 "letter u, followed by four hexadecimal digits (\\uXXXX)."
1929208Svbart@nginx.com             );
1930208Svbart@nginx.com 
1931106Svbart@nginx.com             return NULL;
1932106Svbart@nginx.com         }
1933106Svbart@nginx.com 
1934106Svbart@nginx.com         break;
1935106Svbart@nginx.com     }
1936106Svbart@nginx.com 
1937106Svbart@nginx.com     if (nxt_slow_path(p == end)) {
1938208Svbart@nginx.com 
1939208Svbart@nginx.com         nxt_conf_json_parse_error(error, p,
1940311Snick@nginx.com             "Unexpected end of JSON payload.  There's a string without "
1941311Snick@nginx.com             "a final double quote (\")."
1942208Svbart@nginx.com         );
1943208Svbart@nginx.com 
1944106Svbart@nginx.com         return NULL;
1945106Svbart@nginx.com     }
1946106Svbart@nginx.com 
1947106Svbart@nginx.com     /* Points to the ending quote mark. */
1948106Svbart@nginx.com     last = p;
1949106Svbart@nginx.com 
1950106Svbart@nginx.com     size = last - start - surplus;
1951106Svbart@nginx.com 
1952106Svbart@nginx.com     if (size > NXT_CONF_MAX_SHORT_STRING) {
1953172Svbart@nginx.com 
1954172Svbart@nginx.com         if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
1955208Svbart@nginx.com 
1956208Svbart@nginx.com             nxt_conf_json_parse_error(error, start,
1957311Snick@nginx.com                 "The string is too long.  Such a long JSON string value "
1958311Snick@nginx.com                 "is not supported."
1959208Svbart@nginx.com             );
1960208Svbart@nginx.com 
1961106Svbart@nginx.com             return NULL;
1962106Svbart@nginx.com         }
1963106Svbart@nginx.com 
1964172Svbart@nginx.com         value->type = NXT_CONF_VALUE_STRING;
1965172Svbart@nginx.com 
1966172Svbart@nginx.com         value->u.string.start = nxt_mp_nget(mp, size);
1967172Svbart@nginx.com         if (nxt_slow_path(value->u.string.start == NULL)) {
1968172Svbart@nginx.com             return NULL;
1969172Svbart@nginx.com         }
1970172Svbart@nginx.com 
1971172Svbart@nginx.com         value->u.string.length = size;
1972172Svbart@nginx.com 
1973172Svbart@nginx.com         s = value->u.string.start;
1974106Svbart@nginx.com 
1975106Svbart@nginx.com     } else {
1976116Svbart@nginx.com         value->type = NXT_CONF_VALUE_SHORT_STRING;
1977173Svbart@nginx.com         value->u.str.length = size;
1978173Svbart@nginx.com 
1979173Svbart@nginx.com         s = value->u.str.start;
1980106Svbart@nginx.com     }
1981106Svbart@nginx.com 
1982106Svbart@nginx.com     if (surplus == 0) {
1983106Svbart@nginx.com         nxt_memcpy(s, start, size);
1984106Svbart@nginx.com         return last + 1;
1985106Svbart@nginx.com     }
1986106Svbart@nginx.com 
1987106Svbart@nginx.com     p = start;
1988106Svbart@nginx.com 
1989106Svbart@nginx.com     do {
1990106Svbart@nginx.com         ch = *p++;
1991106Svbart@nginx.com 
1992106Svbart@nginx.com         if (ch != '\\') {
1993106Svbart@nginx.com             *s++ = ch;
1994106Svbart@nginx.com             continue;
1995106Svbart@nginx.com         }
1996106Svbart@nginx.com 
1997106Svbart@nginx.com         ch = *p++;
1998106Svbart@nginx.com 
1999106Svbart@nginx.com         switch (ch) {
2000106Svbart@nginx.com         case '"':
2001106Svbart@nginx.com         case '\\':
2002106Svbart@nginx.com         case '/':
2003106Svbart@nginx.com             *s++ = ch;
2004106Svbart@nginx.com             continue;
2005106Svbart@nginx.com 
2006106Svbart@nginx.com         case 'n':
2007106Svbart@nginx.com             *s++ = '\n';
2008106Svbart@nginx.com             continue;
2009106Svbart@nginx.com 
2010106Svbart@nginx.com         case 'r':
2011106Svbart@nginx.com             *s++ = '\r';
2012106Svbart@nginx.com             continue;
2013106Svbart@nginx.com 
2014106Svbart@nginx.com         case 't':
2015106Svbart@nginx.com             *s++ = '\t';
2016106Svbart@nginx.com             continue;
2017106Svbart@nginx.com 
2018106Svbart@nginx.com         case 'b':
2019106Svbart@nginx.com             *s++ = '\b';
2020106Svbart@nginx.com             continue;
2021106Svbart@nginx.com 
2022106Svbart@nginx.com         case 'f':
2023106Svbart@nginx.com             *s++ = '\f';
2024106Svbart@nginx.com             continue;
2025106Svbart@nginx.com         }
2026106Svbart@nginx.com 
2027106Svbart@nginx.com         utf = 0;
2028106Svbart@nginx.com         utf_high = 0;
2029106Svbart@nginx.com 
2030106Svbart@nginx.com         for ( ;; ) {
2031106Svbart@nginx.com             for (i = 0; i < 4; i++) {
2032202Svbart@nginx.com                 utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A')
2033202Svbart@nginx.com                                                 : p[i] - '0');
2034106Svbart@nginx.com             }
2035106Svbart@nginx.com 
2036106Svbart@nginx.com             p += 4;
2037106Svbart@nginx.com 
2038207Svbart@nginx.com             if (utf_high != 0) {
2039611Svbart@nginx.com                 if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) {
2040208Svbart@nginx.com 
2041208Svbart@nginx.com                     nxt_conf_json_parse_error(error, p - 12,
2042311Snick@nginx.com                         "Invalid JSON encoding sequence.  This 12-byte "
2043311Snick@nginx.com                         "sequence composes an illegal UTF-16 surrogate pair."
2044208Svbart@nginx.com                     );
2045208Svbart@nginx.com 
2046207Svbart@nginx.com                     return NULL;
2047207Svbart@nginx.com                 }
2048207Svbart@nginx.com 
2049611Svbart@nginx.com                 utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000;
2050207Svbart@nginx.com 
2051106Svbart@nginx.com                 break;
2052106Svbart@nginx.com             }
2053106Svbart@nginx.com 
2054611Svbart@nginx.com             if (utf < 0xD800 || utf > 0xDFFF) {
2055106Svbart@nginx.com                 break;
2056106Svbart@nginx.com             }
2057106Svbart@nginx.com 
2058611Svbart@nginx.com             if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') {
2059208Svbart@nginx.com 
2060208Svbart@nginx.com                 nxt_conf_json_parse_error(error, p - 6,
2061311Snick@nginx.com                     "Invalid JSON encoding sequence.  This 6-byte sequence "
2062311Snick@nginx.com                     "does not represent a valid UTF character."
2063208Svbart@nginx.com                 );
2064208Svbart@nginx.com 
2065207Svbart@nginx.com                 return NULL;
2066207Svbart@nginx.com             }
2067207Svbart@nginx.com 
2068106Svbart@nginx.com             p += 2;
2069207Svbart@nginx.com 
2070207Svbart@nginx.com             utf_high = utf;
2071207Svbart@nginx.com             utf = 0;
2072106Svbart@nginx.com         }
2073106Svbart@nginx.com 
2074106Svbart@nginx.com         s = nxt_utf8_encode(s, utf);
2075106Svbart@nginx.com 
2076106Svbart@nginx.com     } while (p != last);
2077106Svbart@nginx.com 
2078106Svbart@nginx.com     if (size > NXT_CONF_MAX_SHORT_STRING) {
2079172Svbart@nginx.com         value->u.string.length = s - value->u.string.start;
2080106Svbart@nginx.com 
2081106Svbart@nginx.com     } else {
2082173Svbart@nginx.com         value->u.str.length = s - value->u.str.start;
2083106Svbart@nginx.com     }
2084106Svbart@nginx.com 
2085106Svbart@nginx.com     return last + 1;
2086106Svbart@nginx.com }
2087106Svbart@nginx.com 
2088106Svbart@nginx.com 
2089106Svbart@nginx.com static u_char *
nxt_conf_json_parse_number(nxt_mp_t * mp,nxt_conf_value_t * value,u_char * start,u_char * end,nxt_conf_json_error_t * error)2090106Svbart@nginx.com nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
2091208Svbart@nginx.com     u_char *end, nxt_conf_json_error_t *error)
2092106Svbart@nginx.com {
20931439Svbart@nginx.com     u_char  *p, *s, ch, c, *dot_pos;
20941439Svbart@nginx.com     size_t  size;
20951439Svbart@nginx.com     double  num;
20961439Svbart@nginx.com 
20971439Svbart@nginx.com     s = start;
20981439Svbart@nginx.com     ch = *s;
2099106Svbart@nginx.com 
2100106Svbart@nginx.com     if (ch == '-') {
21011439Svbart@nginx.com         s++;
2102106Svbart@nginx.com     }
2103106Svbart@nginx.com 
21041439Svbart@nginx.com     dot_pos = NULL;
21051439Svbart@nginx.com 
21061439Svbart@nginx.com     for (p = s; nxt_fast_path(p != end); p++) {
2107106Svbart@nginx.com         ch = *p;
2108106Svbart@nginx.com 
2109106Svbart@nginx.com         /* Values below '0' become >= 208. */
21101439Svbart@nginx.com         c = ch - '0';
21111439Svbart@nginx.com 
21121439Svbart@nginx.com         if (c > 9) {
21131439Svbart@nginx.com             if (ch == '.' && nxt_fast_path(dot_pos == NULL)) {
21141439Svbart@nginx.com                 dot_pos = p;
21151439Svbart@nginx.com                 continue;
21161439Svbart@nginx.com             }
21171439Svbart@nginx.com 
2118106Svbart@nginx.com             break;
2119106Svbart@nginx.com         }
21201439Svbart@nginx.com     }
21211439Svbart@nginx.com 
21221439Svbart@nginx.com     if (dot_pos != NULL) {
21231439Svbart@nginx.com         if (nxt_slow_path(p - dot_pos <= 1)) {
21241439Svbart@nginx.com             nxt_conf_json_parse_error(error, s,
21251439Svbart@nginx.com                 "The number is invalid.  A fraction part in JSON numbers "
21261439Svbart@nginx.com                 "must contain at least one digit."
2127208Svbart@nginx.com             );
2128208Svbart@nginx.com 
2129208Svbart@nginx.com             return NULL;
2130106Svbart@nginx.com         }
2131106Svbart@nginx.com 
21321439Svbart@nginx.com     } else {
21331439Svbart@nginx.com         dot_pos = p;
2134106Svbart@nginx.com     }
2135106Svbart@nginx.com 
21361439Svbart@nginx.com     if (nxt_slow_path(dot_pos - s > 1 && *start == '0')) {
21371439Svbart@nginx.com         nxt_conf_json_parse_error(error, s,
2138311Snick@nginx.com             "The number is invalid.  Leading zeros are not allowed in JSON "
2139311Snick@nginx.com             "numbers."
2140208Svbart@nginx.com         );
2141208Svbart@nginx.com 
2142106Svbart@nginx.com         return NULL;
2143106Svbart@nginx.com     }
2144106Svbart@nginx.com 
21451439Svbart@nginx.com     if (ch == 'e' || ch == 'E') {
21461439Svbart@nginx.com         p++;
21471439Svbart@nginx.com         s = p;
21481439Svbart@nginx.com 
21491439Svbart@nginx.com         if (nxt_fast_path(s != end)) {
21501439Svbart@nginx.com             ch = *s;
21511439Svbart@nginx.com 
21521439Svbart@nginx.com             if (ch == '-' || ch == '+') {
21531439Svbart@nginx.com                 s++;
21541439Svbart@nginx.com             }
21551439Svbart@nginx.com 
21561439Svbart@nginx.com             for (p = s; nxt_fast_path(p != end); p++) {
21571439Svbart@nginx.com                 ch = *p;
21581439Svbart@nginx.com 
21591439Svbart@nginx.com                 /* Values below '0' become >= 208. */
21601439Svbart@nginx.com                 c = ch - '0';
21611439Svbart@nginx.com 
21621439Svbart@nginx.com                 if (c > 9) {
21631439Svbart@nginx.com                     break;
21641439Svbart@nginx.com                 }
21651439Svbart@nginx.com             }
2166106Svbart@nginx.com         }
2167106Svbart@nginx.com 
21681439Svbart@nginx.com         if (nxt_slow_path(p == s)) {
21691439Svbart@nginx.com             nxt_conf_json_parse_error(error, start,
21701439Svbart@nginx.com                 "The number is invalid.  An exponent part in JSON numbers "
21711439Svbart@nginx.com                 "must contain at least one digit."
21721439Svbart@nginx.com             );
21731439Svbart@nginx.com 
2174106Svbart@nginx.com             return NULL;
2175106Svbart@nginx.com         }
2176106Svbart@nginx.com     }
2177106Svbart@nginx.com 
21781439Svbart@nginx.com     size = p - start;
21791439Svbart@nginx.com 
21801439Svbart@nginx.com     if (size > NXT_CONF_MAX_NUMBER_LEN) {
21811439Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
21821439Svbart@nginx.com             "The number is too long.  Such a long JSON number value "
21831439Svbart@nginx.com             "is not supported."
21841439Svbart@nginx.com         );
21851439Svbart@nginx.com 
2186106Svbart@nginx.com         return NULL;
2187106Svbart@nginx.com     }
2188106Svbart@nginx.com 
21891439Svbart@nginx.com     nxt_memcpy(value->u.number, start, size);
21901439Svbart@nginx.com     value->u.number[size] = '\0';
21911439Svbart@nginx.com 
21921439Svbart@nginx.com     nxt_errno = 0;
21931439Svbart@nginx.com     end = NULL;
21941439Svbart@nginx.com 
21951439Svbart@nginx.com     num = nxt_strtod(value->u.number, &end);
21961439Svbart@nginx.com 
21971442Svbart@nginx.com     if (nxt_slow_path(nxt_errno == NXT_ERANGE
21981442Svbart@nginx.com         || fabs(num) > (double) NXT_INT64_T_MAX))
21991442Svbart@nginx.com     {
22001439Svbart@nginx.com         nxt_conf_json_parse_error(error, start,
22011439Svbart@nginx.com             "The number is out of representable range.  Such JSON number "
22021439Svbart@nginx.com             "value is not supported."
22031439Svbart@nginx.com         );
22041439Svbart@nginx.com 
22051439Svbart@nginx.com         return NULL;
2206106Svbart@nginx.com     }
2207106Svbart@nginx.com 
22081439Svbart@nginx.com     if (nxt_slow_path(end == NULL || *end != '\0')) {
22091439Svbart@nginx.com         nxt_thread_log_alert("strtod(\"%s\", %s) failed %E", value->u.number,
22101439Svbart@nginx.com                              end == NULL ? (u_char *) "NULL" : end, nxt_errno);
22111439Svbart@nginx.com         return NULL;
2212106Svbart@nginx.com     }
22131439Svbart@nginx.com 
22141439Svbart@nginx.com     value->type = (num == trunc(num)) ? NXT_CONF_VALUE_INTEGER
22151439Svbart@nginx.com                                       : NXT_CONF_VALUE_NUMBER;
22161439Svbart@nginx.com 
22171439Svbart@nginx.com     return p;
2218106Svbart@nginx.com }
2219106Svbart@nginx.com 
2220106Svbart@nginx.com 
2221208Svbart@nginx.com static void
nxt_conf_json_parse_error(nxt_conf_json_error_t * error,u_char * pos,const char * detail)2222208Svbart@nginx.com nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
2223208Svbart@nginx.com     const char *detail)
2224208Svbart@nginx.com {
2225208Svbart@nginx.com     if (error == NULL) {
2226208Svbart@nginx.com         return;
2227208Svbart@nginx.com     }
2228208Svbart@nginx.com 
2229208Svbart@nginx.com     error->pos = pos;
2230208Svbart@nginx.com     error->detail = (u_char *) detail;
2231208Svbart@nginx.com }
2232208Svbart@nginx.com 
2233208Svbart@nginx.com 
2234106Svbart@nginx.com size_t
nxt_conf_json_length(nxt_conf_value_t * value,nxt_conf_json_pretty_t * pretty)2235106Svbart@nginx.com nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
2236106Svbart@nginx.com {
2237106Svbart@nginx.com     switch (value->type) {
2238106Svbart@nginx.com 
2239116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
2240703Svbart@nginx.com         return nxt_length("null");
2241106Svbart@nginx.com 
2242116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
2243703Svbart@nginx.com         return value->u.boolean ? nxt_length("true") : nxt_length("false");
2244106Svbart@nginx.com 
2245116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
2246116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
22471439Svbart@nginx.com         return nxt_strlen(value->u.number);
2248106Svbart@nginx.com 
2249116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
2250116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
2251106Svbart@nginx.com         return nxt_conf_json_string_length(value);
2252106Svbart@nginx.com 
2253116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
2254106Svbart@nginx.com         return nxt_conf_json_array_length(value, pretty);
2255106Svbart@nginx.com 
2256116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
2257106Svbart@nginx.com         return nxt_conf_json_object_length(value, pretty);
2258106Svbart@nginx.com     }
2259106Svbart@nginx.com 
2260106Svbart@nginx.com     nxt_unreachable();
2261106Svbart@nginx.com 
2262106Svbart@nginx.com     return 0;
2263106Svbart@nginx.com }
2264106Svbart@nginx.com 
2265106Svbart@nginx.com 
2266106Svbart@nginx.com u_char *
nxt_conf_json_print(u_char * p,nxt_conf_value_t * value,nxt_conf_json_pretty_t * pretty)2267106Svbart@nginx.com nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
2268106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2269106Svbart@nginx.com {
2270106Svbart@nginx.com     switch (value->type) {
2271106Svbart@nginx.com 
2272116Svbart@nginx.com     case NXT_CONF_VALUE_NULL:
2273106Svbart@nginx.com         return nxt_cpymem(p, "null", 4);
2274106Svbart@nginx.com 
2275116Svbart@nginx.com     case NXT_CONF_VALUE_BOOLEAN:
2276106Svbart@nginx.com         return value->u.boolean ? nxt_cpymem(p, "true", 4)
2277106Svbart@nginx.com                                 : nxt_cpymem(p, "false", 5);
2278106Svbart@nginx.com 
2279116Svbart@nginx.com     case NXT_CONF_VALUE_INTEGER:
2280116Svbart@nginx.com     case NXT_CONF_VALUE_NUMBER:
22811439Svbart@nginx.com         return nxt_cpystr(p, value->u.number);
2282106Svbart@nginx.com 
2283116Svbart@nginx.com     case NXT_CONF_VALUE_SHORT_STRING:
2284116Svbart@nginx.com     case NXT_CONF_VALUE_STRING:
2285106Svbart@nginx.com         return nxt_conf_json_print_string(p, value);
2286106Svbart@nginx.com 
2287116Svbart@nginx.com     case NXT_CONF_VALUE_ARRAY:
2288106Svbart@nginx.com         return nxt_conf_json_print_array(p, value, pretty);
2289106Svbart@nginx.com 
2290116Svbart@nginx.com     case NXT_CONF_VALUE_OBJECT:
2291106Svbart@nginx.com         return nxt_conf_json_print_object(p, value, pretty);
2292106Svbart@nginx.com     }
2293106Svbart@nginx.com 
2294106Svbart@nginx.com     nxt_unreachable();
2295106Svbart@nginx.com 
2296106Svbart@nginx.com     return p;
2297106Svbart@nginx.com }
2298106Svbart@nginx.com 
2299106Svbart@nginx.com 
2300106Svbart@nginx.com static size_t
nxt_conf_json_string_length(nxt_conf_value_t * value)2301106Svbart@nginx.com nxt_conf_json_string_length(nxt_conf_value_t *value)
2302106Svbart@nginx.com {
2303106Svbart@nginx.com     nxt_str_t  str;
2304106Svbart@nginx.com 
2305106Svbart@nginx.com     nxt_conf_get_string(value, &str);
2306106Svbart@nginx.com 
2307106Svbart@nginx.com     return 2 + nxt_conf_json_escape_length(str.start, str.length);
2308106Svbart@nginx.com }
2309106Svbart@nginx.com 
2310106Svbart@nginx.com 
2311106Svbart@nginx.com static u_char *
nxt_conf_json_print_string(u_char * p,nxt_conf_value_t * value)2312106Svbart@nginx.com nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value)
2313106Svbart@nginx.com {
2314106Svbart@nginx.com     nxt_str_t  str;
2315106Svbart@nginx.com 
2316106Svbart@nginx.com     nxt_conf_get_string(value, &str);
2317106Svbart@nginx.com 
2318106Svbart@nginx.com     *p++ = '"';
2319106Svbart@nginx.com 
2320106Svbart@nginx.com     p = nxt_conf_json_escape(p, str.start, str.length);
2321106Svbart@nginx.com 
2322106Svbart@nginx.com     *p++ = '"';
2323106Svbart@nginx.com 
2324106Svbart@nginx.com     return p;
2325106Svbart@nginx.com }
2326106Svbart@nginx.com 
2327106Svbart@nginx.com 
2328106Svbart@nginx.com static size_t
nxt_conf_json_array_length(nxt_conf_value_t * value,nxt_conf_json_pretty_t * pretty)2329106Svbart@nginx.com nxt_conf_json_array_length(nxt_conf_value_t *value,
2330106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2331106Svbart@nginx.com {
2332106Svbart@nginx.com     size_t            len;
2333106Svbart@nginx.com     nxt_uint_t        n;
2334106Svbart@nginx.com     nxt_conf_array_t  *array;
2335106Svbart@nginx.com 
2336106Svbart@nginx.com     array = value->u.array;
2337106Svbart@nginx.com 
2338106Svbart@nginx.com     /* [] */
2339106Svbart@nginx.com     len = 2;
2340106Svbart@nginx.com 
2341106Svbart@nginx.com     if (pretty != NULL) {
2342106Svbart@nginx.com         pretty->level++;
2343106Svbart@nginx.com     }
2344106Svbart@nginx.com 
2345106Svbart@nginx.com     value = array->elements;
2346106Svbart@nginx.com 
2347106Svbart@nginx.com     for (n = 0; n < array->count; n++) {
2348106Svbart@nginx.com         len += nxt_conf_json_length(&value[n], pretty);
2349106Svbart@nginx.com 
2350106Svbart@nginx.com         if (pretty != NULL) {
2351106Svbart@nginx.com             /* Indentation and new line. */
2352106Svbart@nginx.com             len += pretty->level + 2;
2353106Svbart@nginx.com         }
2354106Svbart@nginx.com     }
2355106Svbart@nginx.com 
2356106Svbart@nginx.com     if (pretty != NULL) {
2357106Svbart@nginx.com         pretty->level--;
2358106Svbart@nginx.com 
2359106Svbart@nginx.com         if (n != 0) {
2360106Svbart@nginx.com             /* Indentation and new line. */
2361106Svbart@nginx.com             len += pretty->level + 2;
2362106Svbart@nginx.com         }
2363106Svbart@nginx.com     }
2364106Svbart@nginx.com 
2365106Svbart@nginx.com     /* Reserve space for "n" commas. */
2366106Svbart@nginx.com     return len + n;
2367106Svbart@nginx.com }
2368106Svbart@nginx.com 
2369106Svbart@nginx.com 
2370106Svbart@nginx.com static u_char *
nxt_conf_json_print_array(u_char * p,nxt_conf_value_t * value,nxt_conf_json_pretty_t * pretty)2371106Svbart@nginx.com nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
2372106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2373106Svbart@nginx.com {
2374106Svbart@nginx.com     nxt_uint_t        n;
2375106Svbart@nginx.com     nxt_conf_array_t  *array;
2376106Svbart@nginx.com 
2377106Svbart@nginx.com     array = value->u.array;
2378106Svbart@nginx.com 
2379106Svbart@nginx.com     *p++ = '[';
2380106Svbart@nginx.com 
2381106Svbart@nginx.com     if (array->count != 0) {
2382106Svbart@nginx.com         value = array->elements;
2383106Svbart@nginx.com 
2384106Svbart@nginx.com         if (pretty != NULL) {
2385106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2386106Svbart@nginx.com 
2387106Svbart@nginx.com             pretty->level++;
2388106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2389106Svbart@nginx.com         }
2390106Svbart@nginx.com 
2391106Svbart@nginx.com         p = nxt_conf_json_print(p, &value[0], pretty);
2392106Svbart@nginx.com 
2393106Svbart@nginx.com         for (n = 1; n < array->count; n++) {
2394106Svbart@nginx.com             *p++ = ',';
2395106Svbart@nginx.com 
2396106Svbart@nginx.com             if (pretty != NULL) {
2397106Svbart@nginx.com                 p = nxt_conf_json_newline(p);
2398106Svbart@nginx.com                 p = nxt_conf_json_indentation(p, pretty->level);
2399106Svbart@nginx.com 
2400106Svbart@nginx.com                 pretty->more_space = 0;
2401106Svbart@nginx.com             }
2402106Svbart@nginx.com 
2403106Svbart@nginx.com             p = nxt_conf_json_print(p, &value[n], pretty);
2404106Svbart@nginx.com         }
2405106Svbart@nginx.com 
2406106Svbart@nginx.com         if (pretty != NULL) {
2407106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2408106Svbart@nginx.com 
2409106Svbart@nginx.com             pretty->level--;
2410106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2411106Svbart@nginx.com 
2412106Svbart@nginx.com             pretty->more_space = 1;
2413106Svbart@nginx.com         }
2414106Svbart@nginx.com     }
2415106Svbart@nginx.com 
2416106Svbart@nginx.com     *p++ = ']';
2417106Svbart@nginx.com 
2418106Svbart@nginx.com     return p;
2419106Svbart@nginx.com }
2420106Svbart@nginx.com 
2421106Svbart@nginx.com 
2422106Svbart@nginx.com static size_t
nxt_conf_json_object_length(nxt_conf_value_t * value,nxt_conf_json_pretty_t * pretty)2423106Svbart@nginx.com nxt_conf_json_object_length(nxt_conf_value_t *value,
2424106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2425106Svbart@nginx.com {
2426106Svbart@nginx.com     size_t                    len;
2427106Svbart@nginx.com     nxt_uint_t                n;
2428106Svbart@nginx.com     nxt_conf_object_t         *object;
2429106Svbart@nginx.com     nxt_conf_object_member_t  *member;
2430106Svbart@nginx.com 
2431106Svbart@nginx.com     object = value->u.object;
2432106Svbart@nginx.com 
2433106Svbart@nginx.com     /* {} */
2434106Svbart@nginx.com     len = 2;
2435106Svbart@nginx.com 
2436106Svbart@nginx.com     if (pretty != NULL) {
2437106Svbart@nginx.com         pretty->level++;
2438106Svbart@nginx.com     }
2439106Svbart@nginx.com 
2440106Svbart@nginx.com     member = object->members;
2441106Svbart@nginx.com 
2442106Svbart@nginx.com     for (n = 0; n < object->count; n++) {
2443106Svbart@nginx.com         len += nxt_conf_json_string_length(&member[n].name) + 1
2444106Svbart@nginx.com                + nxt_conf_json_length(&member[n].value, pretty) + 1;
2445106Svbart@nginx.com 
2446106Svbart@nginx.com         if (pretty != NULL) {
2447106Svbart@nginx.com             /*
2448106Svbart@nginx.com              * Indentation, space after ":", new line, and possible
2449106Svbart@nginx.com              * additional empty line between non-empty objects.
2450106Svbart@nginx.com              */
2451106Svbart@nginx.com             len += pretty->level + 1 + 2 + 2;
2452106Svbart@nginx.com         }
2453106Svbart@nginx.com     }
2454106Svbart@nginx.com 
2455106Svbart@nginx.com     if (pretty != NULL) {
2456106Svbart@nginx.com         pretty->level--;
2457106Svbart@nginx.com 
2458106Svbart@nginx.com         /* Indentation and new line. */
2459106Svbart@nginx.com         len += pretty->level + 2;
2460106Svbart@nginx.com     }
2461106Svbart@nginx.com 
2462106Svbart@nginx.com     return len;
2463106Svbart@nginx.com }
2464106Svbart@nginx.com 
2465106Svbart@nginx.com 
2466106Svbart@nginx.com static u_char *
nxt_conf_json_print_object(u_char * p,nxt_conf_value_t * value,nxt_conf_json_pretty_t * pretty)2467106Svbart@nginx.com nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
2468106Svbart@nginx.com     nxt_conf_json_pretty_t *pretty)
2469106Svbart@nginx.com {
2470106Svbart@nginx.com     nxt_uint_t                n;
2471106Svbart@nginx.com     nxt_conf_object_t         *object;
2472106Svbart@nginx.com     nxt_conf_object_member_t  *member;
2473106Svbart@nginx.com 
2474106Svbart@nginx.com     object = value->u.object;
2475106Svbart@nginx.com 
2476106Svbart@nginx.com     *p++ = '{';
2477106Svbart@nginx.com 
2478106Svbart@nginx.com     if (object->count != 0) {
2479106Svbart@nginx.com 
2480106Svbart@nginx.com         if (pretty != NULL) {
2481106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2482106Svbart@nginx.com             pretty->level++;
2483106Svbart@nginx.com         }
2484106Svbart@nginx.com 
2485106Svbart@nginx.com         member = object->members;
2486106Svbart@nginx.com 
2487106Svbart@nginx.com         n = 0;
2488106Svbart@nginx.com 
2489106Svbart@nginx.com         for ( ;; ) {
2490106Svbart@nginx.com             if (pretty != NULL) {
2491106Svbart@nginx.com                 p = nxt_conf_json_indentation(p, pretty->level);
2492106Svbart@nginx.com             }
2493106Svbart@nginx.com 
2494106Svbart@nginx.com             p = nxt_conf_json_print_string(p, &member[n].name);
2495106Svbart@nginx.com 
2496106Svbart@nginx.com             *p++ = ':';
2497106Svbart@nginx.com 
2498106Svbart@nginx.com             if (pretty != NULL) {
2499106Svbart@nginx.com                 *p++ = ' ';
2500106Svbart@nginx.com             }
2501106Svbart@nginx.com 
2502106Svbart@nginx.com             p = nxt_conf_json_print(p, &member[n].value, pretty);
2503106Svbart@nginx.com 
2504106Svbart@nginx.com             n++;
2505106Svbart@nginx.com 
2506106Svbart@nginx.com             if (n == object->count) {
2507106Svbart@nginx.com                 break;
2508106Svbart@nginx.com             }
2509106Svbart@nginx.com 
2510106Svbart@nginx.com             *p++ = ',';
2511106Svbart@nginx.com 
2512106Svbart@nginx.com             if (pretty != NULL) {
2513106Svbart@nginx.com                 p = nxt_conf_json_newline(p);
2514106Svbart@nginx.com 
2515106Svbart@nginx.com                 if (pretty->more_space) {
2516106Svbart@nginx.com                     pretty->more_space = 0;
2517106Svbart@nginx.com                     p = nxt_conf_json_newline(p);
2518106Svbart@nginx.com                 }
2519106Svbart@nginx.com             }
2520106Svbart@nginx.com         }
2521106Svbart@nginx.com 
2522106Svbart@nginx.com         if (pretty != NULL) {
2523106Svbart@nginx.com             p = nxt_conf_json_newline(p);
2524106Svbart@nginx.com 
2525106Svbart@nginx.com             pretty->level--;
2526106Svbart@nginx.com             p = nxt_conf_json_indentation(p, pretty->level);
2527106Svbart@nginx.com 
2528106Svbart@nginx.com             pretty->more_space = 1;
2529106Svbart@nginx.com         }
2530106Svbart@nginx.com     }
2531106Svbart@nginx.com 
2532106Svbart@nginx.com     *p++ = '}';
2533106Svbart@nginx.com 
2534106Svbart@nginx.com     return p;
2535106Svbart@nginx.com }
2536106Svbart@nginx.com 
2537106Svbart@nginx.com 
2538106Svbart@nginx.com static size_t
nxt_conf_json_escape_length(u_char * p,size_t size)2539106Svbart@nginx.com nxt_conf_json_escape_length(u_char *p, size_t size)
2540106Svbart@nginx.com {
2541106Svbart@nginx.com     u_char  ch;
2542106Svbart@nginx.com     size_t  len;
2543106Svbart@nginx.com 
2544106Svbart@nginx.com     len = size;
2545106Svbart@nginx.com 
2546106Svbart@nginx.com     while (size) {
2547106Svbart@nginx.com         ch = *p++;
2548106Svbart@nginx.com 
2549106Svbart@nginx.com         if (ch == '\\' || ch == '"') {
2550106Svbart@nginx.com             len++;
2551106Svbart@nginx.com 
2552611Svbart@nginx.com         } else if (ch <= 0x1F) {
2553106Svbart@nginx.com 
2554106Svbart@nginx.com             switch (ch) {
2555106Svbart@nginx.com             case '\n':
2556106Svbart@nginx.com             case '\r':
2557106Svbart@nginx.com             case '\t':
2558106Svbart@nginx.com             case '\b':
2559106Svbart@nginx.com             case '\f':
2560106Svbart@nginx.com                 len++;
2561106Svbart@nginx.com                 break;
2562106Svbart@nginx.com 
2563106Svbart@nginx.com             default:
2564106Svbart@nginx.com                 len += sizeof("\\u001F") - 2;
2565106Svbart@nginx.com             }
2566106Svbart@nginx.com         }
2567106Svbart@nginx.com 
2568106Svbart@nginx.com         size--;
2569106Svbart@nginx.com     }
2570106Svbart@nginx.com 
2571106Svbart@nginx.com     return len;
2572106Svbart@nginx.com }
2573106Svbart@nginx.com 
2574106Svbart@nginx.com 
2575106Svbart@nginx.com static u_char *
nxt_conf_json_escape(u_char * dst,u_char * src,size_t size)2576106Svbart@nginx.com nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
2577106Svbart@nginx.com {
2578106Svbart@nginx.com     u_char  ch;
2579106Svbart@nginx.com 
2580106Svbart@nginx.com     while (size) {
2581106Svbart@nginx.com         ch = *src++;
2582106Svbart@nginx.com 
2583611Svbart@nginx.com         if (ch > 0x1F) {
2584106Svbart@nginx.com 
2585106Svbart@nginx.com             if (ch == '\\' || ch == '"') {
2586106Svbart@nginx.com                 *dst++ = '\\';
2587106Svbart@nginx.com             }
2588106Svbart@nginx.com 
2589106Svbart@nginx.com             *dst++ = ch;
2590106Svbart@nginx.com 
2591106Svbart@nginx.com         } else {
2592106Svbart@nginx.com             *dst++ = '\\';
2593106Svbart@nginx.com 
2594106Svbart@nginx.com             switch (ch) {
2595106Svbart@nginx.com             case '\n':
2596106Svbart@nginx.com                 *dst++ = 'n';
2597106Svbart@nginx.com                 break;
2598106Svbart@nginx.com 
2599106Svbart@nginx.com             case '\r':
2600106Svbart@nginx.com                 *dst++ = 'r';
2601106Svbart@nginx.com                 break;
2602106Svbart@nginx.com 
2603106Svbart@nginx.com             case '\t':
2604106Svbart@nginx.com                 *dst++ = 't';
2605106Svbart@nginx.com                 break;
2606106Svbart@nginx.com 
2607106Svbart@nginx.com             case '\b':
2608106Svbart@nginx.com                 *dst++ = 'b';
2609106Svbart@nginx.com                 break;
2610106Svbart@nginx.com 
2611106Svbart@nginx.com             case '\f':
2612106Svbart@nginx.com                 *dst++ = 'f';
2613106Svbart@nginx.com                 break;
2614106Svbart@nginx.com 
2615106Svbart@nginx.com             default:
2616106Svbart@nginx.com                 *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
2617106Svbart@nginx.com                 *dst++ = '0' + (ch >> 4);
2618106Svbart@nginx.com 
2619611Svbart@nginx.com                 ch &= 0xF;
2620106Svbart@nginx.com 
2621106Svbart@nginx.com                 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
2622106Svbart@nginx.com             }
2623106Svbart@nginx.com         }
2624106Svbart@nginx.com 
2625106Svbart@nginx.com         size--;
2626106Svbart@nginx.com     }
2627106Svbart@nginx.com 
2628106Svbart@nginx.com     return dst;
2629106Svbart@nginx.com }
2630208Svbart@nginx.com 
2631208Svbart@nginx.com 
2632208Svbart@nginx.com void
nxt_conf_json_position(u_char * start,const u_char * pos,nxt_uint_t * line,nxt_uint_t * column)26332139Sandrew@digital-domain.net nxt_conf_json_position(u_char *start, const u_char *pos, nxt_uint_t *line,
2634208Svbart@nginx.com     nxt_uint_t *column)
2635208Svbart@nginx.com {
2636208Svbart@nginx.com     u_char      *p;
2637208Svbart@nginx.com     ssize_t     symbols;
2638208Svbart@nginx.com     nxt_uint_t  lines;
2639208Svbart@nginx.com 
2640208Svbart@nginx.com     lines = 1;
2641208Svbart@nginx.com 
2642208Svbart@nginx.com     for (p = start; p != pos; p++) {
2643208Svbart@nginx.com 
2644208Svbart@nginx.com         if (*p != '\n') {
2645208Svbart@nginx.com             continue;
2646208Svbart@nginx.com         }
2647208Svbart@nginx.com 
2648208Svbart@nginx.com         lines++;
2649208Svbart@nginx.com         start = p + 1;
2650208Svbart@nginx.com     }
2651208Svbart@nginx.com 
2652208Svbart@nginx.com     symbols = nxt_utf8_length(start, p - start);
2653208Svbart@nginx.com 
2654208Svbart@nginx.com     if (symbols != -1) {
2655208Svbart@nginx.com         *line = lines;
2656208Svbart@nginx.com         *column = 1 + symbols;
2657208Svbart@nginx.com     }
2658208Svbart@nginx.com }
2659