xref: /unit/src/nxt_conf.c (revision 1236:46331b9ef11a)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Valentin V. Bartenev
5  * Copyright (C) NGINX, Inc.
6  */
7 
8 #include <nxt_main.h>
9 #include <nxt_conf.h>
10 #if 0
11 #include <math.h>
12 #include <float.h>
13 #endif
14 
15 
16 #define NXT_CONF_MAX_SHORT_STRING  14
17 #define NXT_CONF_MAX_STRING        NXT_INT32_T_MAX
18 
19 #define NXT_CONF_MAX_TOKEN_LEN     256
20 
21 
22 typedef enum {
23     NXT_CONF_VALUE_NULL = 0,
24     NXT_CONF_VALUE_BOOLEAN,
25     NXT_CONF_VALUE_INTEGER,
26     NXT_CONF_VALUE_NUMBER,
27     NXT_CONF_VALUE_SHORT_STRING,
28     NXT_CONF_VALUE_STRING,
29     NXT_CONF_VALUE_ARRAY,
30     NXT_CONF_VALUE_OBJECT,
31 } nxt_conf_value_type_t;
32 
33 
34 typedef enum {
35     NXT_CONF_OP_PASS = 0,
36     NXT_CONF_OP_CREATE,
37     NXT_CONF_OP_REPLACE,
38     NXT_CONF_OP_DELETE,
39 } nxt_conf_op_action_t;
40 
41 
42 typedef struct nxt_conf_array_s   nxt_conf_array_t;
43 typedef struct nxt_conf_object_s  nxt_conf_object_t;
44 
45 
46 struct nxt_conf_value_s {
47     union {
48         uint8_t               boolean;  /* 1 bit. */
49         int64_t               integer;
50         double                number;
51 
52         struct {
53             u_char            start[NXT_CONF_MAX_SHORT_STRING];
54             uint8_t           length;
55         } str;
56 
57         struct {
58             u_char            *start;
59             uint32_t          length;
60         } nxt_packed string;
61 
62         nxt_conf_array_t      *array;
63         nxt_conf_object_t     *object;
64     } nxt_packed u;
65 
66     uint8_t                   type;  /* 3 bits. */
67 } nxt_aligned(8);
68 
69 
70 struct nxt_conf_array_s {
71     nxt_uint_t                count;
72     nxt_conf_value_t          elements[];
73 };
74 
75 
76 typedef struct {
77     nxt_conf_value_t          name;
78     nxt_conf_value_t          value;
79 } nxt_conf_object_member_t;
80 
81 
82 struct nxt_conf_object_s {
83     nxt_uint_t                count;
84     nxt_conf_object_member_t  members[];
85 };
86 
87 
88 struct nxt_conf_op_s {
89     uint32_t                  index;
90     uint32_t                  action;  /* nxt_conf_op_action_t */
91     void                      *ctx;
92 };
93 
94 
95 typedef struct {
96     u_char                    *start;
97     u_char                    *end;
98     nxt_bool_t                last;
99     u_char                    buf[NXT_CONF_MAX_TOKEN_LEN];
100 } nxt_conf_path_parse_t;
101 
102 
103 static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse,
104     nxt_str_t *token);
105 
106 static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end);
107 static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
108     u_char *start, u_char *end, nxt_conf_json_error_t *error);
109 static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
110     u_char *start, u_char *end, nxt_conf_json_error_t *error);
111 static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
112     nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
113 static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
114     void *data);
115 static void *nxt_conf_object_hash_alloc(void *data, size_t size);
116 static void nxt_conf_object_hash_free(void *data, void *p);
117 static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
118     u_char *start, u_char *end, nxt_conf_json_error_t *error);
119 static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value,
120     u_char *start, u_char *end, nxt_conf_json_error_t *error);
121 static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value,
122     u_char *start, u_char *end, nxt_conf_json_error_t *error);
123 static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
124     const char *detail);
125 
126 static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
127     nxt_conf_value_t *dst, nxt_conf_value_t *src);
128 static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op,
129     nxt_conf_value_t *dst, nxt_conf_value_t *src);
130 static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op,
131     nxt_conf_value_t *dst, nxt_conf_value_t *src);
132 
133 static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value);
134 static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value);
135 static size_t nxt_conf_json_string_length(nxt_conf_value_t *value);
136 static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value);
137 static size_t nxt_conf_json_array_length(nxt_conf_value_t *value,
138     nxt_conf_json_pretty_t *pretty);
139 static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
140     nxt_conf_json_pretty_t *pretty);
141 static size_t nxt_conf_json_object_length(nxt_conf_value_t *value,
142     nxt_conf_json_pretty_t *pretty);
143 static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
144     nxt_conf_json_pretty_t *pretty);
145 
146 static size_t nxt_conf_json_escape_length(u_char *p, size_t size);
147 static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
148 
149 
150 #define nxt_conf_json_newline(p)                                              \
151     ((p)[0] = '\r', (p)[1] = '\n', (p) + 2)
152 
153 
154 nxt_inline u_char *
155 nxt_conf_json_indentation(u_char *p, uint32_t level)
156 {
157     while (level) {
158         *p++ = '\t';
159         level--;
160     }
161 
162     return p;
163 }
164 
165 
166 void
167 nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
168 {
169     if (value->type == NXT_CONF_VALUE_SHORT_STRING) {
170         str->length = value->u.str.length;
171         str->start = value->u.str.start;
172 
173     } else {
174         str->length = value->u.string.length;
175         str->start = value->u.string.start;
176     }
177 }
178 
179 
180 void
181 nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str)
182 {
183     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
184         value->type = NXT_CONF_VALUE_STRING;
185         value->u.string.length = str->length;
186         value->u.string.start = str->start;
187 
188     } else {
189         value->type = NXT_CONF_VALUE_SHORT_STRING;
190         value->u.str.length = str->length;
191 
192         nxt_memcpy(value->u.str.start, str->start, str->length);
193     }
194 }
195 
196 
197 nxt_int_t
198 nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str)
199 {
200     nxt_str_t  tmp, *ptr;
201 
202     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
203         value->type = NXT_CONF_VALUE_STRING;
204 
205         ptr = nxt_str_dup(mp, &tmp, str);
206         if (nxt_slow_path(ptr == NULL)) {
207             return NXT_ERROR;
208         }
209 
210         value->u.string.length = tmp.length;
211         value->u.string.start = tmp.start;
212 
213     } else {
214         value->type = NXT_CONF_VALUE_SHORT_STRING;
215         value->u.str.length = str->length;
216 
217         nxt_memcpy(value->u.str.start, str->start, str->length);
218     }
219 
220     return NXT_OK;
221 }
222 
223 
224 int64_t
225 nxt_conf_get_integer(nxt_conf_value_t *value)
226 {
227     return value->u.integer;
228 }
229 
230 
231 uint8_t
232 nxt_conf_get_boolean(nxt_conf_value_t *value)
233 {
234     return value->u.boolean;
235 }
236 
237 
238 nxt_uint_t
239 nxt_conf_object_members_count(nxt_conf_value_t *value)
240 {
241     return value->u.object->count;
242 }
243 
244 
245 nxt_conf_value_t *
246 nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count)
247 {
248     size_t            size;
249     nxt_conf_value_t  *value;
250 
251     size = sizeof(nxt_conf_value_t)
252            + sizeof(nxt_conf_object_t)
253            + count * sizeof(nxt_conf_object_member_t);
254 
255     value = nxt_mp_get(mp, size);
256     if (nxt_slow_path(value == NULL)) {
257         return NULL;
258     }
259 
260     value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
261     value->u.object->count = count;
262 
263     value->type = NXT_CONF_VALUE_OBJECT;
264 
265     return value;
266 }
267 
268 
269 void
270 nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
271     nxt_conf_value_t *value, uint32_t index)
272 {
273     nxt_conf_object_member_t  *member;
274 
275     member = &object->u.object->members[index];
276 
277     nxt_conf_set_string(&member->name, name);
278 
279     member->value = *value;
280 }
281 
282 
283 void
284 nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
285     nxt_str_t *value, uint32_t index)
286 {
287     nxt_conf_object_member_t  *member;
288 
289     member = &object->u.object->members[index];
290 
291     nxt_conf_set_string(&member->name, name);
292 
293     nxt_conf_set_string(&member->value, value);
294 }
295 
296 
297 nxt_int_t
298 nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp,
299     nxt_str_t *name, nxt_str_t *value, uint32_t index)
300 {
301     nxt_conf_object_member_t  *member;
302 
303     member = &object->u.object->members[index];
304 
305     nxt_conf_set_string(&member->name, name);
306 
307     return nxt_conf_set_string_dup(&member->value, mp, value);
308 }
309 
310 
311 void
312 nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
313     int64_t value, uint32_t index)
314 {
315     nxt_conf_object_member_t  *member;
316 
317     member = &object->u.object->members[index];
318 
319     nxt_conf_set_string(&member->name, name);
320 
321     member->value.u.integer = value;
322     member->value.type = NXT_CONF_VALUE_INTEGER;
323 }
324 
325 
326 void
327 nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name,
328     uint32_t index)
329 {
330     nxt_conf_object_member_t  *member;
331 
332     member = &object->u.object->members[index];
333 
334     nxt_conf_set_string(&member->name, name);
335 
336     member->value.type = NXT_CONF_VALUE_NULL;
337 }
338 
339 
340 nxt_conf_value_t *
341 nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count)
342 {
343     size_t            size;
344     nxt_conf_value_t  *value;
345 
346     size = sizeof(nxt_conf_value_t)
347            + sizeof(nxt_conf_array_t)
348            + count * sizeof(nxt_conf_value_t);
349 
350     value = nxt_mp_get(mp, size);
351     if (nxt_slow_path(value == NULL)) {
352         return NULL;
353     }
354 
355     value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
356     value->u.array->count = count;
357 
358     value->type = NXT_CONF_VALUE_ARRAY;
359 
360     return value;
361 }
362 
363 
364 void
365 nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
366     nxt_conf_value_t *value)
367 {
368     array->u.array->elements[index] = *value;
369 }
370 
371 
372 nxt_int_t
373 nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
374     nxt_uint_t index, nxt_str_t *value)
375 {
376     nxt_conf_value_t  *element;
377 
378     element = &array->u.array->elements[index];
379 
380     return nxt_conf_set_string_dup(element, mp, value);
381 }
382 
383 
384 nxt_uint_t
385 nxt_conf_array_elements_count(nxt_conf_value_t *value)
386 {
387     return value->u.array->count;
388 }
389 
390 
391 nxt_uint_t
392 nxt_conf_type(nxt_conf_value_t *value)
393 {
394     switch (value->type) {
395 
396     case NXT_CONF_VALUE_NULL:
397         return NXT_CONF_NULL;
398 
399     case NXT_CONF_VALUE_BOOLEAN:
400         return NXT_CONF_BOOLEAN;
401 
402     case NXT_CONF_VALUE_INTEGER:
403         return NXT_CONF_INTEGER;
404 
405     case NXT_CONF_VALUE_NUMBER:
406         return NXT_CONF_NUMBER;
407 
408     case NXT_CONF_VALUE_SHORT_STRING:
409     case NXT_CONF_VALUE_STRING:
410         return NXT_CONF_STRING;
411 
412     case NXT_CONF_VALUE_ARRAY:
413         return NXT_CONF_ARRAY;
414 
415     case NXT_CONF_VALUE_OBJECT:
416         return NXT_CONF_OBJECT;
417     }
418 
419     nxt_unreachable();
420 
421     return 0;
422 }
423 
424 
425 nxt_conf_value_t *
426 nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path)
427 {
428     nxt_str_t              token;
429     nxt_int_t              ret, index;
430     nxt_conf_path_parse_t  parse;
431 
432     parse.start = path->start;
433     parse.end = path->start + path->length;
434     parse.last = 0;
435 
436     do {
437         ret = nxt_conf_path_next_token(&parse, &token);
438         if (nxt_slow_path(ret != NXT_OK)) {
439             return NULL;
440         }
441 
442         if (token.length == 0) {
443 
444             if (parse.last) {
445                 break;
446             }
447 
448             return NULL;
449         }
450 
451         switch (value->type) {
452 
453         case NXT_CONF_VALUE_OBJECT:
454             value = nxt_conf_get_object_member(value, &token, NULL);
455             break;
456 
457         case NXT_CONF_VALUE_ARRAY:
458             index = nxt_int_parse(token.start, token.length);
459 
460             if (index < 0 || index > NXT_INT32_T_MAX) {
461                 return NULL;
462             }
463 
464             value = nxt_conf_get_array_element(value, index);
465             break;
466 
467         default:
468             return NULL;
469         }
470 
471         if (value == NULL) {
472             return NULL;
473         }
474 
475     } while (parse.last == 0);
476 
477     return value;
478 }
479 
480 
481 static nxt_int_t
482 nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token)
483 {
484     u_char  *p, *start, *end;
485     size_t  length;
486 
487     start = parse->start + 1;
488 
489     p = start;
490 
491     while (p < parse->end && *p != '/') {
492         p++;
493     }
494 
495     parse->start = p;
496     parse->last = (p >= parse->end);
497 
498     length = p - start;
499 
500     if (nxt_slow_path(length > NXT_CONF_MAX_TOKEN_LEN)) {
501         return NXT_ERROR;
502     }
503 
504     end = nxt_decode_uri(parse->buf, start, length);
505     if (nxt_slow_path(end == NULL)) {
506         return NXT_ERROR;
507     }
508 
509     token->length = end - parse->buf;
510     token->start = parse->buf;
511 
512     return NXT_OK;
513 }
514 
515 
516 nxt_conf_value_t *
517 nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name,
518     uint32_t *index)
519 {
520     nxt_str_t                 str;
521     nxt_uint_t                n;
522     nxt_conf_object_t         *object;
523     nxt_conf_object_member_t  *member;
524 
525     if (value->type != NXT_CONF_VALUE_OBJECT) {
526         return NULL;
527     }
528 
529     object = value->u.object;
530 
531     for (n = 0; n < object->count; n++) {
532         member = &object->members[n];
533 
534         nxt_conf_get_string(&member->name, &str);
535 
536         if (nxt_strstr_eq(&str, name)) {
537 
538             if (index != NULL) {
539                 *index = n;
540             }
541 
542             return &member->value;
543         }
544     }
545 
546     return NULL;
547 }
548 
549 
550 nxt_int_t
551 nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map,
552     nxt_uint_t n, void *data)
553 {
554     nxt_str_t         str, *s;
555     nxt_uint_t        i;
556     nxt_conf_value_t  *v;
557 
558     union {
559         uint8_t     ui8;
560         int32_t     i32;
561         int64_t     i64;
562         int         i;
563         ssize_t     size;
564         off_t       off;
565         nxt_msec_t  msec;
566         double      dbl;
567         nxt_str_t   str;
568         char        *cstrz;
569         void        *v;
570     } *ptr;
571 
572     for (i = 0; i < n; i++) {
573 
574         v = nxt_conf_get_object_member(value, &map[i].name, NULL);
575 
576         if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
577             continue;
578         }
579 
580         ptr = nxt_pointer_to(data, map[i].offset);
581 
582         switch (map[i].type) {
583 
584         case NXT_CONF_MAP_INT8:
585 
586             if (v->type == NXT_CONF_VALUE_BOOLEAN) {
587                 ptr->ui8 = v->u.boolean;
588             }
589 
590             break;
591 
592         case NXT_CONF_MAP_INT32:
593         case NXT_CONF_MAP_INT64:
594         case NXT_CONF_MAP_INT:
595         case NXT_CONF_MAP_SIZE:
596         case NXT_CONF_MAP_OFF:
597         case NXT_CONF_MAP_MSEC:
598 
599             if (v->type != NXT_CONF_VALUE_INTEGER) {
600                 break;
601             }
602 
603             switch (map[i].type) {
604 
605             case NXT_CONF_MAP_INT32:
606                 ptr->i32 = v->u.integer;
607                 break;
608 
609             case NXT_CONF_MAP_INT64:
610                 ptr->i64 = v->u.integer;
611                 break;
612 
613             case NXT_CONF_MAP_INT:
614                 ptr->i = v->u.integer;
615                 break;
616 
617             case NXT_CONF_MAP_SIZE:
618                 ptr->size = v->u.integer;
619                 break;
620 
621             case NXT_CONF_MAP_OFF:
622                 ptr->off = v->u.integer;
623                 break;
624 
625             case NXT_CONF_MAP_MSEC:
626                 ptr->msec = v->u.integer * 1000;
627                 break;
628 
629             default:
630                 nxt_unreachable();
631             }
632 
633             break;
634 
635         case NXT_CONF_MAP_DOUBLE:
636 
637             if (v->type == NXT_CONF_VALUE_NUMBER) {
638                 ptr->dbl = v->u.number;
639 
640             } else if (v->type == NXT_CONF_VALUE_INTEGER) {
641                 ptr->dbl = v->u.integer;
642 
643             }
644 
645             break;
646 
647         case NXT_CONF_MAP_STR:
648         case NXT_CONF_MAP_STR_COPY:
649         case NXT_CONF_MAP_CSTRZ:
650 
651             if (v->type != NXT_CONF_VALUE_SHORT_STRING
652                 && v->type != NXT_CONF_VALUE_STRING)
653             {
654                 break;
655             }
656 
657             nxt_conf_get_string(v, &str);
658 
659             switch (map[i].type) {
660 
661             case NXT_CONF_MAP_STR:
662                 ptr->str = str;
663                 break;
664 
665             case NXT_CONF_MAP_STR_COPY:
666 
667                 s = nxt_str_dup(mp, &ptr->str, &str);
668 
669                 if (nxt_slow_path(s == NULL)) {
670                     return NXT_ERROR;
671                 }
672 
673                 break;
674 
675             case NXT_CONF_MAP_CSTRZ:
676 
677                 ptr->cstrz = nxt_str_cstrz(mp, &str);
678 
679                 if (nxt_slow_path(ptr->cstrz == NULL)) {
680                     return NXT_ERROR;
681                 }
682 
683                 break;
684 
685             default:
686                 nxt_unreachable();
687             }
688 
689             break;
690 
691         case NXT_CONF_MAP_PTR:
692 
693             ptr->v = v;
694 
695             break;
696         }
697     }
698 
699     return NXT_OK;
700 }
701 
702 
703 nxt_conf_value_t *
704 nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name,
705     uint32_t *next)
706 {
707     uint32_t                  n;
708     nxt_conf_object_t         *object;
709     nxt_conf_object_member_t  *member;
710 
711     if (value->type != NXT_CONF_VALUE_OBJECT) {
712         return NULL;
713     }
714 
715     n = *next;
716     object = value->u.object;
717 
718     if (n >= object->count) {
719         return NULL;
720     }
721 
722     member = &object->members[n];
723     *next = n + 1;
724 
725     nxt_conf_get_string(&member->name, name);
726 
727     return &member->value;
728 }
729 
730 
731 nxt_conf_value_t *
732 nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index)
733 {
734     nxt_conf_array_t  *array;
735 
736     if (value->type != NXT_CONF_VALUE_ARRAY) {
737         return NULL;
738     }
739 
740     array = value->u.array;
741 
742     if (index >= array->count) {
743         return NULL;
744     }
745 
746     return &array->elements[index];
747 }
748 
749 
750 void
751 nxt_conf_array_qsort(nxt_conf_value_t *value,
752     int (*compare)(const void *, const void *))
753 {
754     nxt_conf_array_t  *array;
755 
756     if (value->type != NXT_CONF_VALUE_ARRAY) {
757         return;
758     }
759 
760     array = value->u.array;
761 
762     nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare);
763 }
764 
765 
766 nxt_conf_op_ret_t
767 nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
768     nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add)
769 {
770     nxt_str_t                 token;
771     nxt_int_t                 ret, index;
772     nxt_conf_op_t             *op, **parent;
773     nxt_conf_value_t          *node;
774     nxt_conf_path_parse_t     parse;
775     nxt_conf_object_member_t  *member;
776 
777     parse.start = path->start;
778     parse.end = path->start + path->length;
779     parse.last = 0;
780 
781     parent = ops;
782 
783     for ( ;; ) {
784         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
785         if (nxt_slow_path(op == NULL)) {
786             return NXT_CONF_OP_ERROR;
787         }
788 
789         *parent = op;
790         parent = (nxt_conf_op_t **) &op->ctx;
791 
792         ret = nxt_conf_path_next_token(&parse, &token);
793         if (nxt_slow_path(ret != NXT_OK)) {
794             return NXT_CONF_OP_ERROR;
795         }
796 
797         switch (root->type) {
798 
799         case NXT_CONF_VALUE_OBJECT:
800             node = nxt_conf_get_object_member(root, &token, &op->index);
801             break;
802 
803         case NXT_CONF_VALUE_ARRAY:
804             index = nxt_int_parse(token.start, token.length);
805 
806             if (index < 0 || index > NXT_INT32_T_MAX) {
807                 return NXT_CONF_OP_NOT_FOUND;
808             }
809 
810             op->index = index;
811 
812             node = nxt_conf_get_array_element(root, index);
813             break;
814 
815         default:
816             node = NULL;
817         }
818 
819         if (parse.last) {
820             break;
821         }
822 
823         if (node == NULL) {
824             return NXT_CONF_OP_NOT_FOUND;
825         }
826 
827         op->action = NXT_CONF_OP_PASS;
828         root = node;
829     }
830 
831     if (value == NULL) {
832 
833         if (node == NULL) {
834             return NXT_CONF_OP_NOT_FOUND;
835         }
836 
837         op->action = NXT_CONF_OP_DELETE;
838 
839         return NXT_CONF_OP_OK;
840     }
841 
842     if (add) {
843         if (node == NULL) {
844             return NXT_CONF_OP_NOT_FOUND;
845         }
846 
847         if (node->type != NXT_CONF_VALUE_ARRAY) {
848             return NXT_CONF_OP_NOT_ALLOWED;
849         }
850 
851         op->action = NXT_CONF_OP_PASS;
852 
853         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
854         if (nxt_slow_path(op == NULL)) {
855             return NXT_CONF_OP_ERROR;
856         }
857 
858         *parent = op;
859 
860         op->index = node->u.array->count;
861         op->action = NXT_CONF_OP_CREATE;
862         op->ctx = value;
863 
864         return NXT_CONF_OP_OK;
865     }
866 
867     if (node != NULL) {
868         op->action = NXT_CONF_OP_REPLACE;
869         op->ctx = value;
870 
871         return NXT_CONF_OP_OK;
872     }
873 
874     op->action = NXT_CONF_OP_CREATE;
875 
876     if (root->type == NXT_CONF_VALUE_ARRAY) {
877         if (op->index > root->u.array->count) {
878             return NXT_CONF_OP_NOT_FOUND;
879         }
880 
881         op->ctx = value;
882 
883     } else {
884         member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t));
885         if (nxt_slow_path(member == NULL)) {
886             return NXT_CONF_OP_ERROR;
887         }
888 
889         ret = nxt_conf_set_string_dup(&member->name, mp, &token);
890         if (nxt_slow_path(ret != NXT_OK)) {
891             return NXT_CONF_OP_ERROR;
892         }
893 
894         member->value = *value;
895 
896         op->index = root->u.object->count;
897         op->ctx = member;
898     }
899 
900     return NXT_CONF_OP_OK;
901 }
902 
903 
904 nxt_conf_value_t *
905 nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value)
906 {
907     nxt_int_t         rc;
908     nxt_conf_value_t  *copy;
909 
910     copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
911     if (nxt_slow_path(copy == NULL)) {
912         return NULL;
913     }
914 
915     rc = nxt_conf_copy_value(mp, op, copy, value);
916 
917     if (nxt_slow_path(rc != NXT_OK)) {
918         return NULL;
919     }
920 
921     return copy;
922 }
923 
924 
925 static nxt_int_t
926 nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
927     nxt_conf_value_t *src)
928 {
929     if (op != NULL
930         && src->type != NXT_CONF_VALUE_ARRAY
931         && src->type != NXT_CONF_VALUE_OBJECT)
932     {
933         return NXT_ERROR;
934     }
935 
936     switch (src->type) {
937 
938     case NXT_CONF_VALUE_STRING:
939 
940         dst->u.string.start = nxt_mp_nget(mp, src->u.string.length);
941         if (nxt_slow_path(dst->u.string.start == NULL)) {
942             return NXT_ERROR;
943         }
944 
945         nxt_memcpy(dst->u.string.start, src->u.string.start,
946                    src->u.string.length);
947 
948         dst->u.string.length = src->u.string.length;
949 
950         break;
951 
952     case NXT_CONF_VALUE_ARRAY:
953         return nxt_conf_copy_array(mp, op, dst, src);
954 
955     case NXT_CONF_VALUE_OBJECT:
956         return nxt_conf_copy_object(mp, op, dst, src);
957 
958     default:
959         dst->u = src->u;
960     }
961 
962     dst->type = src->type;
963 
964     return NXT_OK;
965 }
966 
967 
968 static nxt_int_t
969 nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
970     nxt_conf_value_t *src)
971 {
972     size_t            size;
973     nxt_int_t         rc;
974     nxt_uint_t        s, d, count, index;
975     nxt_conf_op_t     *pass_op;
976     nxt_conf_value_t  *value;
977 
978     count = src->u.array->count;
979 
980     if (op != NULL) {
981         if (op->action == NXT_CONF_OP_CREATE) {
982             count++;
983 
984         } else if (op->action == NXT_CONF_OP_DELETE) {
985             count--;
986         }
987     }
988 
989     size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t);
990 
991     dst->u.array = nxt_mp_get(mp, size);
992     if (nxt_slow_path(dst->u.array == NULL)) {
993         return NXT_ERROR;
994     }
995 
996     dst->u.array->count = count;
997 
998     s = 0;
999     d = 0;
1000 
1001     pass_op = NULL;
1002 
1003     /*
1004      * This initialization is needed only to
1005      * suppress a warning on GCC 4.8 and older.
1006      */
1007     index = 0;
1008 
1009     do {
1010         if (pass_op == NULL) {
1011             index = (op == NULL) ? src->u.array->count : op->index;
1012         }
1013 
1014         while (s != index) {
1015             rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d],
1016                                                   &src->u.array->elements[s]);
1017             if (nxt_slow_path(rc != NXT_OK)) {
1018                 return NXT_ERROR;
1019             }
1020 
1021             s++;
1022             d++;
1023         }
1024 
1025         if (pass_op != NULL) {
1026             pass_op = NULL;
1027             continue;
1028         }
1029 
1030         if (op != NULL) {
1031             switch (op->action) {
1032             case NXT_CONF_OP_PASS:
1033                 pass_op = op->ctx;
1034                 index++;
1035                 break;
1036 
1037             case NXT_CONF_OP_CREATE:
1038                 value = op->ctx;
1039                 dst->u.array->elements[d] = *value;
1040 
1041                 d++;
1042                 break;
1043 
1044             case NXT_CONF_OP_REPLACE:
1045                 value = op->ctx;
1046                 dst->u.array->elements[d] = *value;
1047 
1048                 s++;
1049                 d++;
1050                 break;
1051 
1052             case NXT_CONF_OP_DELETE:
1053                 s++;
1054                 break;
1055             }
1056 
1057             op = NULL;
1058         }
1059 
1060     } while (d != count);
1061 
1062     dst->type = src->type;
1063 
1064     return NXT_OK;
1065 }
1066 
1067 
1068 static nxt_int_t
1069 nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
1070     nxt_conf_value_t *src)
1071 {
1072     size_t                    size;
1073     nxt_int_t                 rc;
1074     nxt_uint_t                s, d, count, index;
1075     nxt_conf_op_t             *pass_op;
1076     nxt_conf_value_t          *value;
1077     nxt_conf_object_member_t  *member;
1078 
1079     count = src->u.object->count;
1080 
1081     if (op != NULL) {
1082         if (op->action == NXT_CONF_OP_CREATE) {
1083             count++;
1084 
1085         } else if (op->action == NXT_CONF_OP_DELETE) {
1086             count--;
1087         }
1088     }
1089 
1090     size = sizeof(nxt_conf_object_t)
1091            + count * sizeof(nxt_conf_object_member_t);
1092 
1093     dst->u.object = nxt_mp_get(mp, size);
1094     if (nxt_slow_path(dst->u.object == NULL)) {
1095         return NXT_ERROR;
1096     }
1097 
1098     dst->u.object->count = count;
1099 
1100     s = 0;
1101     d = 0;
1102 
1103     pass_op = NULL;
1104 
1105     /*
1106      * This initialization is needed only to
1107      * suppress a warning on GCC 4.8 and older.
1108      */
1109     index = 0;
1110 
1111     do {
1112         if (pass_op == NULL) {
1113             index = (op == NULL) ? src->u.object->count : op->index;
1114         }
1115 
1116         while (s != index) {
1117             rc = nxt_conf_copy_value(mp, NULL,
1118                                      &dst->u.object->members[d].name,
1119                                      &src->u.object->members[s].name);
1120 
1121             if (nxt_slow_path(rc != NXT_OK)) {
1122                 return NXT_ERROR;
1123             }
1124 
1125             rc = nxt_conf_copy_value(mp, pass_op,
1126                                      &dst->u.object->members[d].value,
1127                                      &src->u.object->members[s].value);
1128 
1129             if (nxt_slow_path(rc != NXT_OK)) {
1130                 return NXT_ERROR;
1131             }
1132 
1133             s++;
1134             d++;
1135         }
1136 
1137         if (pass_op != NULL) {
1138             pass_op = NULL;
1139             continue;
1140         }
1141 
1142         if (op != NULL) {
1143             switch (op->action) {
1144             case NXT_CONF_OP_PASS:
1145                 pass_op = op->ctx;
1146                 index++;
1147                 break;
1148 
1149             case NXT_CONF_OP_CREATE:
1150                 member = op->ctx;
1151 
1152                 rc = nxt_conf_copy_value(mp, NULL,
1153                                          &dst->u.object->members[d].name,
1154                                          &member->name);
1155 
1156                 if (nxt_slow_path(rc != NXT_OK)) {
1157                     return NXT_ERROR;
1158                 }
1159 
1160                 dst->u.object->members[d].value = member->value;
1161 
1162                 d++;
1163                 break;
1164 
1165             case NXT_CONF_OP_REPLACE:
1166                 rc = nxt_conf_copy_value(mp, NULL,
1167                                          &dst->u.object->members[d].name,
1168                                          &src->u.object->members[s].name);
1169 
1170                 if (nxt_slow_path(rc != NXT_OK)) {
1171                     return NXT_ERROR;
1172                 }
1173 
1174                 value = op->ctx;
1175 
1176                 dst->u.object->members[d].value = *value;
1177 
1178                 s++;
1179                 d++;
1180                 break;
1181 
1182             case NXT_CONF_OP_DELETE:
1183                 s++;
1184                 break;
1185             }
1186 
1187             op = NULL;
1188         }
1189 
1190     } while (d != count);
1191 
1192     dst->type = src->type;
1193 
1194     return NXT_OK;
1195 }
1196 
1197 
1198 nxt_conf_value_t *
1199 nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
1200     nxt_conf_json_error_t *error)
1201 {
1202     u_char            *p;
1203     nxt_conf_value_t  *value;
1204 
1205     value = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
1206     if (nxt_slow_path(value == NULL)) {
1207         return NULL;
1208     }
1209 
1210     p = nxt_conf_json_skip_space(start, end);
1211 
1212     if (nxt_slow_path(p == end)) {
1213 
1214         nxt_conf_json_parse_error(error, start,
1215             "An empty JSON payload isn't allowed.  It must be either a literal "
1216             "(null, true, or false), a number, a string (in double quotes "
1217             "\"\"), an array (with brackets []), or an object (with braces {})."
1218         );
1219 
1220         return NULL;
1221     }
1222 
1223     p = nxt_conf_json_parse_value(mp, value, p, end, error);
1224 
1225     if (nxt_slow_path(p == NULL)) {
1226         return NULL;
1227     }
1228 
1229     p = nxt_conf_json_skip_space(p, end);
1230 
1231     if (nxt_slow_path(p != end)) {
1232 
1233         nxt_conf_json_parse_error(error, p,
1234             "Unexpected character after the end of a valid JSON value."
1235         );
1236 
1237         return NULL;
1238     }
1239 
1240     return value;
1241 }
1242 
1243 
1244 static u_char *
1245 nxt_conf_json_skip_space(u_char *start, u_char *end)
1246 {
1247     u_char  *p;
1248 
1249     for (p = start; nxt_fast_path(p != end); p++) {
1250 
1251         switch (*p) {
1252         case ' ':
1253         case '\t':
1254         case '\r':
1255         case '\n':
1256             continue;
1257         }
1258 
1259         break;
1260     }
1261 
1262     return p;
1263 }
1264 
1265 
1266 static u_char *
1267 nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1268     u_char *end, nxt_conf_json_error_t *error)
1269 {
1270     u_char  ch, *p;
1271 
1272     ch = *start;
1273 
1274     switch (ch) {
1275     case '{':
1276         return nxt_conf_json_parse_object(mp, value, start, end, error);
1277 
1278     case '[':
1279         return nxt_conf_json_parse_array(mp, value, start, end, error);
1280 
1281     case '"':
1282         return nxt_conf_json_parse_string(mp, value, start, end, error);
1283 
1284     case 't':
1285         if (nxt_fast_path(end - start >= 4
1286                           && nxt_memcmp(start, "true", 4) == 0))
1287         {
1288             value->u.boolean = 1;
1289             value->type = NXT_CONF_VALUE_BOOLEAN;
1290 
1291             return start + 4;
1292         }
1293 
1294         goto error;
1295 
1296     case 'f':
1297         if (nxt_fast_path(end - start >= 5
1298                           && nxt_memcmp(start, "false", 5) == 0))
1299         {
1300             value->u.boolean = 0;
1301             value->type = NXT_CONF_VALUE_BOOLEAN;
1302 
1303             return start + 5;
1304         }
1305 
1306         goto error;
1307 
1308     case 'n':
1309         if (nxt_fast_path(end - start >= 4
1310                           && nxt_memcmp(start, "null", 4) == 0))
1311         {
1312             value->type = NXT_CONF_VALUE_NULL;
1313             return start + 4;
1314         }
1315 
1316         goto error;
1317 
1318     case '-':
1319         if (nxt_fast_path(end - start > 1)) {
1320             ch = start[1];
1321             break;
1322         }
1323 
1324         goto error;
1325     }
1326 
1327     if (nxt_fast_path((ch - '0') <= 9)) {
1328         p = nxt_conf_json_parse_number(mp, value, start, end, error);
1329 
1330         if (nxt_slow_path(p == NULL)) {
1331             return NULL;
1332         }
1333 
1334         if (p == end) {
1335             return end;
1336         }
1337 
1338         switch (*p) {
1339         case ' ':
1340         case '\t':
1341         case '\r':
1342         case '\n':
1343         case ',':
1344         case '}':
1345         case ']':
1346         case '{':
1347         case '[':
1348         case '"':
1349             return p;
1350         }
1351     }
1352 
1353 error:
1354 
1355     nxt_conf_json_parse_error(error, start,
1356         "A valid JSON value is expected here.  It must be either a literal "
1357         "(null, true, or false), a number, a string (in double quotes \"\"), "
1358         "an array (with brackets []), or an object (with braces {})."
1359     );
1360 
1361     return NULL;
1362 }
1363 
1364 
1365 static const nxt_lvlhsh_proto_t  nxt_conf_object_hash_proto
1366     nxt_aligned(64) =
1367 {
1368     NXT_LVLHSH_DEFAULT,
1369     nxt_conf_object_hash_test,
1370     nxt_conf_object_hash_alloc,
1371     nxt_conf_object_hash_free,
1372 };
1373 
1374 
1375 static u_char *
1376 nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1377     u_char *end, nxt_conf_json_error_t *error)
1378 {
1379     u_char                    *p, *name;
1380     nxt_mp_t                  *mp_temp;
1381     nxt_int_t                 rc;
1382     nxt_uint_t                count;
1383     nxt_lvlhsh_t              hash;
1384     nxt_lvlhsh_each_t         lhe;
1385     nxt_conf_object_t         *object;
1386     nxt_conf_object_member_t  *member, *element;
1387 
1388     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1389     if (nxt_slow_path(mp_temp == NULL)) {
1390         return NULL;
1391     }
1392 
1393     nxt_lvlhsh_init(&hash);
1394 
1395     count = 0;
1396     p = start;
1397 
1398     for ( ;; ) {
1399         p = nxt_conf_json_skip_space(p + 1, end);
1400 
1401         if (nxt_slow_path(p == end)) {
1402 
1403             nxt_conf_json_parse_error(error, p,
1404                 "Unexpected end of JSON payload.  There's an object without "
1405                 "a closing brace (})."
1406             );
1407 
1408             goto error;
1409         }
1410 
1411         if (*p != '"') {
1412             if (nxt_fast_path(*p == '}')) {
1413                 break;
1414             }
1415 
1416             nxt_conf_json_parse_error(error, p,
1417                 "A double quote (\") is expected here.  There must be a valid "
1418                 "JSON object member starts with a name, which is a string "
1419                 "enclosed in double quotes."
1420             );
1421 
1422             goto error;
1423         }
1424 
1425         name = p;
1426 
1427         count++;
1428 
1429         member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
1430         if (nxt_slow_path(member == NULL)) {
1431             goto error;
1432         }
1433 
1434         p = nxt_conf_json_parse_string(mp, &member->name, p, end, error);
1435 
1436         if (nxt_slow_path(p == NULL)) {
1437             goto error;
1438         }
1439 
1440         rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
1441 
1442         if (nxt_slow_path(rc != NXT_OK)) {
1443 
1444             if (rc == NXT_DECLINED) {
1445                 nxt_conf_json_parse_error(error, name,
1446                     "Duplicate object member.  All JSON object members must "
1447                     "have unique names."
1448                 );
1449             }
1450 
1451             goto error;
1452         }
1453 
1454         p = nxt_conf_json_skip_space(p, end);
1455 
1456         if (nxt_slow_path(p == end)) {
1457 
1458             nxt_conf_json_parse_error(error, p,
1459                 "Unexpected end of JSON payload.  There's an object member "
1460                 "without a value."
1461             );
1462 
1463             goto error;
1464         }
1465 
1466         if (nxt_slow_path(*p != ':')) {
1467 
1468             nxt_conf_json_parse_error(error, p,
1469                 "A colon (:) is expected here.  There must be a colon after "
1470                 "a JSON member name."
1471             );
1472 
1473             goto error;
1474         }
1475 
1476         p = nxt_conf_json_skip_space(p + 1, end);
1477 
1478         if (nxt_slow_path(p == end)) {
1479 
1480             nxt_conf_json_parse_error(error, p,
1481                 "Unexpected end of JSON payload.  There's an object member "
1482                 "without a value."
1483             );
1484 
1485             goto error;
1486         }
1487 
1488         p = nxt_conf_json_parse_value(mp, &member->value, p, end, error);
1489 
1490         if (nxt_slow_path(p == NULL)) {
1491             goto error;
1492         }
1493 
1494         p = nxt_conf_json_skip_space(p, end);
1495 
1496         if (nxt_slow_path(p == end)) {
1497 
1498             nxt_conf_json_parse_error(error, p,
1499                 "Unexpected end of JSON payload.  There's an object without "
1500                 "a closing brace (})."
1501             );
1502 
1503             goto error;
1504         }
1505 
1506         if (*p != ',') {
1507             if (nxt_fast_path(*p == '}')) {
1508                 break;
1509             }
1510 
1511             nxt_conf_json_parse_error(error, p,
1512                 "Either a closing brace (}) or a comma (,) is expected here.  "
1513                 "Each JSON object must be enclosed in braces and its members "
1514                 "must be separated by commas."
1515             );
1516 
1517             goto error;
1518         }
1519     }
1520 
1521     object = nxt_mp_get(mp, sizeof(nxt_conf_object_t)
1522                             + count * sizeof(nxt_conf_object_member_t));
1523     if (nxt_slow_path(object == NULL)) {
1524         goto error;
1525     }
1526 
1527     value->u.object = object;
1528     value->type = NXT_CONF_VALUE_OBJECT;
1529 
1530     object->count = count;
1531     member = object->members;
1532 
1533     nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto);
1534 
1535     for ( ;; ) {
1536         element = nxt_lvlhsh_each(&hash, &lhe);
1537 
1538         if (element == NULL) {
1539             break;
1540         }
1541 
1542         *member++ = *element;
1543     }
1544 
1545     nxt_mp_destroy(mp_temp);
1546 
1547     return p + 1;
1548 
1549 error:
1550 
1551     nxt_mp_destroy(mp_temp);
1552     return NULL;
1553 }
1554 
1555 
1556 static nxt_int_t
1557 nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh,
1558     nxt_conf_object_member_t *member)
1559 {
1560     nxt_lvlhsh_query_t  lhq;
1561 
1562     nxt_conf_get_string(&member->name, &lhq.key);
1563 
1564     lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
1565     lhq.replace = 0;
1566     lhq.value = member;
1567     lhq.proto = &nxt_conf_object_hash_proto;
1568     lhq.pool = mp;
1569 
1570     return nxt_lvlhsh_insert(lvlhsh, &lhq);
1571 }
1572 
1573 
1574 static nxt_int_t
1575 nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1576 {
1577     nxt_str_t                 str;
1578     nxt_conf_object_member_t  *member;
1579 
1580     member = data;
1581 
1582     nxt_conf_get_string(&member->name, &str);
1583 
1584     return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED;
1585 }
1586 
1587 
1588 static void *
1589 nxt_conf_object_hash_alloc(void *data, size_t size)
1590 {
1591     return nxt_mp_align(data, size, size);
1592 }
1593 
1594 
1595 static void
1596 nxt_conf_object_hash_free(void *data, void *p)
1597 {
1598     nxt_mp_free(data, p);
1599 }
1600 
1601 
1602 static u_char *
1603 nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1604     u_char *end, nxt_conf_json_error_t *error)
1605 {
1606     u_char            *p;
1607     nxt_mp_t          *mp_temp;
1608     nxt_uint_t        count;
1609     nxt_list_t        *list;
1610     nxt_conf_array_t  *array;
1611     nxt_conf_value_t  *element;
1612 
1613     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1614     if (nxt_slow_path(mp_temp == NULL)) {
1615         return NULL;
1616     }
1617 
1618     list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t));
1619     if (nxt_slow_path(list == NULL)) {
1620         goto error;
1621     }
1622 
1623     count = 0;
1624     p = start;
1625 
1626     for ( ;; ) {
1627         p = nxt_conf_json_skip_space(p + 1, end);
1628 
1629         if (nxt_slow_path(p == end)) {
1630 
1631             nxt_conf_json_parse_error(error, p,
1632                 "Unexpected end of JSON payload.  There's an array without "
1633                 "a closing bracket (])."
1634             );
1635 
1636             goto error;
1637         }
1638 
1639         if (*p == ']') {
1640             break;
1641         }
1642 
1643         count++;
1644 
1645         element = nxt_list_add(list);
1646         if (nxt_slow_path(element == NULL)) {
1647             goto error;
1648         }
1649 
1650         p = nxt_conf_json_parse_value(mp, element, p, end, error);
1651 
1652         if (nxt_slow_path(p == NULL)) {
1653             goto error;
1654         }
1655 
1656         p = nxt_conf_json_skip_space(p, end);
1657 
1658         if (nxt_slow_path(p == end)) {
1659 
1660             nxt_conf_json_parse_error(error, p,
1661                 "Unexpected end of JSON payload.  There's an array without "
1662                 "a closing bracket (])."
1663             );
1664 
1665             goto error;
1666         }
1667 
1668         if (*p != ',') {
1669             if (nxt_fast_path(*p == ']')) {
1670                 break;
1671             }
1672 
1673             nxt_conf_json_parse_error(error, p,
1674                 "Either a closing bracket (]) or a comma (,) is expected "
1675                 "here.  Each array must be enclosed in brackets and its "
1676                 "members must be separated by commas."
1677             );
1678 
1679             goto error;
1680         }
1681     }
1682 
1683     array = nxt_mp_get(mp, sizeof(nxt_conf_array_t)
1684                            + count * sizeof(nxt_conf_value_t));
1685     if (nxt_slow_path(array == NULL)) {
1686         goto error;
1687     }
1688 
1689     value->u.array = array;
1690     value->type = NXT_CONF_VALUE_ARRAY;
1691 
1692     array->count = count;
1693     element = array->elements;
1694 
1695     nxt_list_each(value, list) {
1696         *element++ = *value;
1697     } nxt_list_loop;
1698 
1699     nxt_mp_destroy(mp_temp);
1700 
1701     return p + 1;
1702 
1703 error:
1704 
1705     nxt_mp_destroy(mp_temp);
1706     return NULL;
1707 }
1708 
1709 
1710 static u_char *
1711 nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1712     u_char *end, nxt_conf_json_error_t *error)
1713 {
1714     u_char      *p, ch, *last, *s;
1715     size_t      size, surplus;
1716     uint32_t    utf, utf_high;
1717     nxt_uint_t  i;
1718     enum {
1719         sw_usual = 0,
1720         sw_escape,
1721         sw_encoded1,
1722         sw_encoded2,
1723         sw_encoded3,
1724         sw_encoded4,
1725     } state;
1726 
1727     start++;
1728 
1729     state = 0;
1730     surplus = 0;
1731 
1732     for (p = start; nxt_fast_path(p != end); p++) {
1733         ch = *p;
1734 
1735         switch (state) {
1736 
1737         case sw_usual:
1738 
1739             if (ch == '"') {
1740                 break;
1741             }
1742 
1743             if (ch == '\\') {
1744                 state = sw_escape;
1745                 continue;
1746             }
1747 
1748             if (nxt_fast_path(ch >= ' ')) {
1749                 continue;
1750             }
1751 
1752             nxt_conf_json_parse_error(error, p,
1753                 "Unexpected character.  All control characters in a JSON "
1754                 "string must be escaped."
1755             );
1756 
1757             return NULL;
1758 
1759         case sw_escape:
1760 
1761             switch (ch) {
1762             case '"':
1763             case '\\':
1764             case '/':
1765             case 'n':
1766             case 'r':
1767             case 't':
1768             case 'b':
1769             case 'f':
1770                 surplus++;
1771                 state = sw_usual;
1772                 continue;
1773 
1774             case 'u':
1775                 /*
1776                  * Basic unicode 6 bytes "\uXXXX" in JSON
1777                  * and up to 3 bytes in UTF-8.
1778                  *
1779                  * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON
1780                  * and 3 or 4 bytes in UTF-8.
1781                  */
1782                 surplus += 3;
1783                 state = sw_encoded1;
1784                 continue;
1785             }
1786 
1787             nxt_conf_json_parse_error(error, p - 1,
1788                 "Unexpected backslash.  A literal backslash in a JSON string "
1789                 "must be escaped with a second backslash (\\\\)."
1790             );
1791 
1792             return NULL;
1793 
1794         case sw_encoded1:
1795         case sw_encoded2:
1796         case sw_encoded3:
1797         case sw_encoded4:
1798 
1799             if (nxt_fast_path((ch >= '0' && ch <= '9')
1800                               || (ch >= 'A' && ch <= 'F')
1801                               || (ch >= 'a' && ch <= 'f')))
1802             {
1803                 state = (state == sw_encoded4) ? sw_usual : state + 1;
1804                 continue;
1805             }
1806 
1807             nxt_conf_json_parse_error(error, p,
1808                 "Invalid escape sequence.  An escape sequence in a JSON "
1809                 "string must start with a backslash, followed by the lowercase "
1810                 "letter u, followed by four hexadecimal digits (\\uXXXX)."
1811             );
1812 
1813             return NULL;
1814         }
1815 
1816         break;
1817     }
1818 
1819     if (nxt_slow_path(p == end)) {
1820 
1821         nxt_conf_json_parse_error(error, p,
1822             "Unexpected end of JSON payload.  There's a string without "
1823             "a final double quote (\")."
1824         );
1825 
1826         return NULL;
1827     }
1828 
1829     /* Points to the ending quote mark. */
1830     last = p;
1831 
1832     size = last - start - surplus;
1833 
1834     if (size > NXT_CONF_MAX_SHORT_STRING) {
1835 
1836         if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
1837 
1838             nxt_conf_json_parse_error(error, start,
1839                 "The string is too long.  Such a long JSON string value "
1840                 "is not supported."
1841             );
1842 
1843             return NULL;
1844         }
1845 
1846         value->type = NXT_CONF_VALUE_STRING;
1847 
1848         value->u.string.start = nxt_mp_nget(mp, size);
1849         if (nxt_slow_path(value->u.string.start == NULL)) {
1850             return NULL;
1851         }
1852 
1853         value->u.string.length = size;
1854 
1855         s = value->u.string.start;
1856 
1857     } else {
1858         value->type = NXT_CONF_VALUE_SHORT_STRING;
1859         value->u.str.length = size;
1860 
1861         s = value->u.str.start;
1862     }
1863 
1864     if (surplus == 0) {
1865         nxt_memcpy(s, start, size);
1866         return last + 1;
1867     }
1868 
1869     p = start;
1870 
1871     do {
1872         ch = *p++;
1873 
1874         if (ch != '\\') {
1875             *s++ = ch;
1876             continue;
1877         }
1878 
1879         ch = *p++;
1880 
1881         switch (ch) {
1882         case '"':
1883         case '\\':
1884         case '/':
1885             *s++ = ch;
1886             continue;
1887 
1888         case 'n':
1889             *s++ = '\n';
1890             continue;
1891 
1892         case 'r':
1893             *s++ = '\r';
1894             continue;
1895 
1896         case 't':
1897             *s++ = '\t';
1898             continue;
1899 
1900         case 'b':
1901             *s++ = '\b';
1902             continue;
1903 
1904         case 'f':
1905             *s++ = '\f';
1906             continue;
1907         }
1908 
1909         utf = 0;
1910         utf_high = 0;
1911 
1912         for ( ;; ) {
1913             for (i = 0; i < 4; i++) {
1914                 utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A')
1915                                                 : p[i] - '0');
1916             }
1917 
1918             p += 4;
1919 
1920             if (utf_high != 0) {
1921                 if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) {
1922 
1923                     nxt_conf_json_parse_error(error, p - 12,
1924                         "Invalid JSON encoding sequence.  This 12-byte "
1925                         "sequence composes an illegal UTF-16 surrogate pair."
1926                     );
1927 
1928                     return NULL;
1929                 }
1930 
1931                 utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000;
1932 
1933                 break;
1934             }
1935 
1936             if (utf < 0xD800 || utf > 0xDFFF) {
1937                 break;
1938             }
1939 
1940             if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') {
1941 
1942                 nxt_conf_json_parse_error(error, p - 6,
1943                     "Invalid JSON encoding sequence.  This 6-byte sequence "
1944                     "does not represent a valid UTF character."
1945                 );
1946 
1947                 return NULL;
1948             }
1949 
1950             p += 2;
1951 
1952             utf_high = utf;
1953             utf = 0;
1954         }
1955 
1956         s = nxt_utf8_encode(s, utf);
1957 
1958     } while (p != last);
1959 
1960     if (size > NXT_CONF_MAX_SHORT_STRING) {
1961         value->u.string.length = s - value->u.string.start;
1962 
1963     } else {
1964         value->u.str.length = s - value->u.str.start;
1965     }
1966 
1967     return last + 1;
1968 }
1969 
1970 
1971 static u_char *
1972 nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1973     u_char *end, nxt_conf_json_error_t *error)
1974 {
1975     u_char     *p, ch;
1976     uint64_t   integer;
1977     nxt_int_t  sign;
1978 #if 0
1979     uint64_t   frac, power
1980     nxt_int_t  e, negative;
1981 #endif
1982 
1983     static const uint64_t cutoff = NXT_INT64_T_MAX / 10;
1984     static const uint64_t cutlim = NXT_INT64_T_MAX % 10;
1985 
1986     ch = *start;
1987 
1988     if (ch == '-') {
1989         sign = -1;
1990         start++;
1991 
1992     } else {
1993         sign = 1;
1994     }
1995 
1996     integer = 0;
1997 
1998     for (p = start; nxt_fast_path(p != end); p++) {
1999         ch = *p;
2000 
2001         /* Values below '0' become >= 208. */
2002         ch = ch - '0';
2003 
2004         if (ch > 9) {
2005             break;
2006         }
2007 
2008         if (nxt_slow_path(integer >= cutoff
2009                           && (integer > cutoff || ch > cutlim)))
2010         {
2011             nxt_conf_json_parse_error(error, start,
2012                 "The integer is too large.  Such a large JSON integer value "
2013                 "is not supported."
2014             );
2015 
2016             return NULL;
2017         }
2018 
2019         integer = integer * 10 + ch;
2020     }
2021 
2022     if (nxt_slow_path(p - start > 1 && *start == '0')) {
2023 
2024         nxt_conf_json_parse_error(error, start,
2025             "The number is invalid.  Leading zeros are not allowed in JSON "
2026             "numbers."
2027         );
2028 
2029         return NULL;
2030     }
2031 
2032     if (ch != '.') {
2033         value->type = NXT_CONF_VALUE_INTEGER;
2034         value->u.integer = sign * integer;
2035         return p;
2036     }
2037 
2038 #if 0
2039     start = p + 1;
2040 
2041     frac = 0;
2042     power = 1;
2043 
2044     for (p = start; nxt_fast_path(p != end); p++) {
2045         ch = *p;
2046 
2047         /* Values below '0' become >= 208. */
2048         ch = ch - '0';
2049 
2050         if (ch > 9) {
2051             break;
2052         }
2053 
2054         if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim))
2055                           || power > cutoff))
2056         {
2057             return NULL;
2058         }
2059 
2060         frac = frac * 10 + ch;
2061         power *= 10;
2062     }
2063 
2064     if (nxt_slow_path(p == start)) {
2065         return NULL;
2066     }
2067 
2068     value->type = NXT_CONF_VALUE_NUMBER;
2069     value->u.number = integer + (double) frac / power;
2070 
2071     value->u.number = copysign(value->u.number, sign);
2072 
2073     if (ch == 'e' || ch == 'E') {
2074         start = p + 1;
2075 
2076         ch = *start;
2077 
2078         if (ch == '-' || ch == '+') {
2079             start++;
2080         }
2081 
2082         negative = (ch == '-') ? 1 : 0;
2083         e = 0;
2084 
2085         for (p = start; nxt_fast_path(p != end); p++) {
2086             ch = *p;
2087 
2088             /* Values below '0' become >= 208. */
2089             ch = ch - '0';
2090 
2091             if (ch > 9) {
2092                 break;
2093             }
2094 
2095             e = e * 10 + ch;
2096 
2097             if (nxt_slow_path(e > DBL_MAX_10_EXP)) {
2098                 return NULL;
2099             }
2100         }
2101 
2102         if (nxt_slow_path(p == start)) {
2103             return NULL;
2104         }
2105 
2106         if (negative) {
2107             value->u.number /= exp10(e);
2108 
2109         } else {
2110             value->u.number *= exp10(e);
2111         }
2112     }
2113 
2114     if (nxt_fast_path(isfinite(value->u.number))) {
2115         return p;
2116     }
2117 #else
2118 
2119     nxt_conf_json_parse_error(error, start,
2120         "The number is not an integer.  JSON numbers with decimals and "
2121         "exponents are not supported."
2122     );
2123 
2124 #endif
2125 
2126     return NULL;
2127 }
2128 
2129 
2130 static void
2131 nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
2132     const char *detail)
2133 {
2134     if (error == NULL) {
2135         return;
2136     }
2137 
2138     error->pos = pos;
2139     error->detail = (u_char *) detail;
2140 }
2141 
2142 
2143 size_t
2144 nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
2145 {
2146     switch (value->type) {
2147 
2148     case NXT_CONF_VALUE_NULL:
2149         return nxt_length("null");
2150 
2151     case NXT_CONF_VALUE_BOOLEAN:
2152         return value->u.boolean ? nxt_length("true") : nxt_length("false");
2153 
2154     case NXT_CONF_VALUE_INTEGER:
2155         return nxt_conf_json_integer_length(value);
2156 
2157     case NXT_CONF_VALUE_NUMBER:
2158         /* TODO */
2159         return 0;
2160 
2161     case NXT_CONF_VALUE_SHORT_STRING:
2162     case NXT_CONF_VALUE_STRING:
2163         return nxt_conf_json_string_length(value);
2164 
2165     case NXT_CONF_VALUE_ARRAY:
2166         return nxt_conf_json_array_length(value, pretty);
2167 
2168     case NXT_CONF_VALUE_OBJECT:
2169         return nxt_conf_json_object_length(value, pretty);
2170     }
2171 
2172     nxt_unreachable();
2173 
2174     return 0;
2175 }
2176 
2177 
2178 u_char *
2179 nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
2180     nxt_conf_json_pretty_t *pretty)
2181 {
2182     switch (value->type) {
2183 
2184     case NXT_CONF_VALUE_NULL:
2185         return nxt_cpymem(p, "null", 4);
2186 
2187     case NXT_CONF_VALUE_BOOLEAN:
2188         return value->u.boolean ? nxt_cpymem(p, "true", 4)
2189                                 : nxt_cpymem(p, "false", 5);
2190 
2191     case NXT_CONF_VALUE_INTEGER:
2192         return nxt_conf_json_print_integer(p, value);
2193 
2194     case NXT_CONF_VALUE_NUMBER:
2195         /* TODO */
2196         return p;
2197 
2198     case NXT_CONF_VALUE_SHORT_STRING:
2199     case NXT_CONF_VALUE_STRING:
2200         return nxt_conf_json_print_string(p, value);
2201 
2202     case NXT_CONF_VALUE_ARRAY:
2203         return nxt_conf_json_print_array(p, value, pretty);
2204 
2205     case NXT_CONF_VALUE_OBJECT:
2206         return nxt_conf_json_print_object(p, value, pretty);
2207     }
2208 
2209     nxt_unreachable();
2210 
2211     return p;
2212 }
2213 
2214 
2215 static size_t
2216 nxt_conf_json_integer_length(nxt_conf_value_t *value)
2217 {
2218     int64_t  num;
2219 
2220     num = llabs(value->u.integer);
2221 
2222     if (num <= 9999) {
2223         return nxt_length("-9999");
2224     }
2225 
2226     if (num <= 99999999999LL) {
2227         return nxt_length("-99999999999");
2228     }
2229 
2230     return NXT_INT64_T_LEN;
2231 }
2232 
2233 
2234 static u_char *
2235 nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value)
2236 {
2237     return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer);
2238 }
2239 
2240 
2241 static size_t
2242 nxt_conf_json_string_length(nxt_conf_value_t *value)
2243 {
2244     nxt_str_t  str;
2245 
2246     nxt_conf_get_string(value, &str);
2247 
2248     return 2 + nxt_conf_json_escape_length(str.start, str.length);
2249 }
2250 
2251 
2252 static u_char *
2253 nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value)
2254 {
2255     nxt_str_t  str;
2256 
2257     nxt_conf_get_string(value, &str);
2258 
2259     *p++ = '"';
2260 
2261     p = nxt_conf_json_escape(p, str.start, str.length);
2262 
2263     *p++ = '"';
2264 
2265     return p;
2266 }
2267 
2268 
2269 static size_t
2270 nxt_conf_json_array_length(nxt_conf_value_t *value,
2271     nxt_conf_json_pretty_t *pretty)
2272 {
2273     size_t            len;
2274     nxt_uint_t        n;
2275     nxt_conf_array_t  *array;
2276 
2277     array = value->u.array;
2278 
2279     /* [] */
2280     len = 2;
2281 
2282     if (pretty != NULL) {
2283         pretty->level++;
2284     }
2285 
2286     value = array->elements;
2287 
2288     for (n = 0; n < array->count; n++) {
2289         len += nxt_conf_json_length(&value[n], pretty);
2290 
2291         if (pretty != NULL) {
2292             /* Indentation and new line. */
2293             len += pretty->level + 2;
2294         }
2295     }
2296 
2297     if (pretty != NULL) {
2298         pretty->level--;
2299 
2300         if (n != 0) {
2301             /* Indentation and new line. */
2302             len += pretty->level + 2;
2303         }
2304     }
2305 
2306     /* Reserve space for "n" commas. */
2307     return len + n;
2308 }
2309 
2310 
2311 static u_char *
2312 nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
2313     nxt_conf_json_pretty_t *pretty)
2314 {
2315     nxt_uint_t        n;
2316     nxt_conf_array_t  *array;
2317 
2318     array = value->u.array;
2319 
2320     *p++ = '[';
2321 
2322     if (array->count != 0) {
2323         value = array->elements;
2324 
2325         if (pretty != NULL) {
2326             p = nxt_conf_json_newline(p);
2327 
2328             pretty->level++;
2329             p = nxt_conf_json_indentation(p, pretty->level);
2330         }
2331 
2332         p = nxt_conf_json_print(p, &value[0], pretty);
2333 
2334         for (n = 1; n < array->count; n++) {
2335             *p++ = ',';
2336 
2337             if (pretty != NULL) {
2338                 p = nxt_conf_json_newline(p);
2339                 p = nxt_conf_json_indentation(p, pretty->level);
2340 
2341                 pretty->more_space = 0;
2342             }
2343 
2344             p = nxt_conf_json_print(p, &value[n], pretty);
2345         }
2346 
2347         if (pretty != NULL) {
2348             p = nxt_conf_json_newline(p);
2349 
2350             pretty->level--;
2351             p = nxt_conf_json_indentation(p, pretty->level);
2352 
2353             pretty->more_space = 1;
2354         }
2355     }
2356 
2357     *p++ = ']';
2358 
2359     return p;
2360 }
2361 
2362 
2363 static size_t
2364 nxt_conf_json_object_length(nxt_conf_value_t *value,
2365     nxt_conf_json_pretty_t *pretty)
2366 {
2367     size_t                    len;
2368     nxt_uint_t                n;
2369     nxt_conf_object_t         *object;
2370     nxt_conf_object_member_t  *member;
2371 
2372     object = value->u.object;
2373 
2374     /* {} */
2375     len = 2;
2376 
2377     if (pretty != NULL) {
2378         pretty->level++;
2379     }
2380 
2381     member = object->members;
2382 
2383     for (n = 0; n < object->count; n++) {
2384         len += nxt_conf_json_string_length(&member[n].name) + 1
2385                + nxt_conf_json_length(&member[n].value, pretty) + 1;
2386 
2387         if (pretty != NULL) {
2388             /*
2389              * Indentation, space after ":", new line, and possible
2390              * additional empty line between non-empty objects.
2391              */
2392             len += pretty->level + 1 + 2 + 2;
2393         }
2394     }
2395 
2396     if (pretty != NULL) {
2397         pretty->level--;
2398 
2399         /* Indentation and new line. */
2400         len += pretty->level + 2;
2401     }
2402 
2403     return len;
2404 }
2405 
2406 
2407 static u_char *
2408 nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
2409     nxt_conf_json_pretty_t *pretty)
2410 {
2411     nxt_uint_t                n;
2412     nxt_conf_object_t         *object;
2413     nxt_conf_object_member_t  *member;
2414 
2415     object = value->u.object;
2416 
2417     *p++ = '{';
2418 
2419     if (object->count != 0) {
2420 
2421         if (pretty != NULL) {
2422             p = nxt_conf_json_newline(p);
2423             pretty->level++;
2424         }
2425 
2426         member = object->members;
2427 
2428         n = 0;
2429 
2430         for ( ;; ) {
2431             if (pretty != NULL) {
2432                 p = nxt_conf_json_indentation(p, pretty->level);
2433             }
2434 
2435             p = nxt_conf_json_print_string(p, &member[n].name);
2436 
2437             *p++ = ':';
2438 
2439             if (pretty != NULL) {
2440                 *p++ = ' ';
2441             }
2442 
2443             p = nxt_conf_json_print(p, &member[n].value, pretty);
2444 
2445             n++;
2446 
2447             if (n == object->count) {
2448                 break;
2449             }
2450 
2451             *p++ = ',';
2452 
2453             if (pretty != NULL) {
2454                 p = nxt_conf_json_newline(p);
2455 
2456                 if (pretty->more_space) {
2457                     pretty->more_space = 0;
2458                     p = nxt_conf_json_newline(p);
2459                 }
2460             }
2461         }
2462 
2463         if (pretty != NULL) {
2464             p = nxt_conf_json_newline(p);
2465 
2466             pretty->level--;
2467             p = nxt_conf_json_indentation(p, pretty->level);
2468 
2469             pretty->more_space = 1;
2470         }
2471     }
2472 
2473     *p++ = '}';
2474 
2475     return p;
2476 }
2477 
2478 
2479 static size_t
2480 nxt_conf_json_escape_length(u_char *p, size_t size)
2481 {
2482     u_char  ch;
2483     size_t  len;
2484 
2485     len = size;
2486 
2487     while (size) {
2488         ch = *p++;
2489 
2490         if (ch == '\\' || ch == '"') {
2491             len++;
2492 
2493         } else if (ch <= 0x1F) {
2494 
2495             switch (ch) {
2496             case '\n':
2497             case '\r':
2498             case '\t':
2499             case '\b':
2500             case '\f':
2501                 len++;
2502                 break;
2503 
2504             default:
2505                 len += sizeof("\\u001F") - 2;
2506             }
2507         }
2508 
2509         size--;
2510     }
2511 
2512     return len;
2513 }
2514 
2515 
2516 static u_char *
2517 nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
2518 {
2519     u_char  ch;
2520 
2521     while (size) {
2522         ch = *src++;
2523 
2524         if (ch > 0x1F) {
2525 
2526             if (ch == '\\' || ch == '"') {
2527                 *dst++ = '\\';
2528             }
2529 
2530             *dst++ = ch;
2531 
2532         } else {
2533             *dst++ = '\\';
2534 
2535             switch (ch) {
2536             case '\n':
2537                 *dst++ = 'n';
2538                 break;
2539 
2540             case '\r':
2541                 *dst++ = 'r';
2542                 break;
2543 
2544             case '\t':
2545                 *dst++ = 't';
2546                 break;
2547 
2548             case '\b':
2549                 *dst++ = 'b';
2550                 break;
2551 
2552             case '\f':
2553                 *dst++ = 'f';
2554                 break;
2555 
2556             default:
2557                 *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
2558                 *dst++ = '0' + (ch >> 4);
2559 
2560                 ch &= 0xF;
2561 
2562                 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
2563             }
2564         }
2565 
2566         size--;
2567     }
2568 
2569     return dst;
2570 }
2571 
2572 
2573 void
2574 nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line,
2575     nxt_uint_t *column)
2576 {
2577     u_char      *p;
2578     ssize_t     symbols;
2579     nxt_uint_t  lines;
2580 
2581     lines = 1;
2582 
2583     for (p = start; p != pos; p++) {
2584 
2585         if (*p != '\n') {
2586             continue;
2587         }
2588 
2589         lines++;
2590         start = p + 1;
2591     }
2592 
2593     symbols = nxt_utf8_length(start, p - start);
2594 
2595     if (symbols != -1) {
2596         *line = lines;
2597         *column = 1 + symbols;
2598     }
2599 }
2600