blob: 655ac3731382f17a5fa3678370fdb7c477fa513e [file] [log] [blame]
Michal Vasko1324b6c2018-09-07 11:16:23 +02001/**
2 * @file common.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief common internal definitions for libyang
5 *
6 * Copyright (c) 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejcib7db73a2018-10-24 14:18:40 +020014
15#include "common.h"
Michal Vasko1324b6c2018-09-07 11:16:23 +020016
Radek Krejci86d106e2018-10-18 09:53:19 +020017#include <assert.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020018#include <ctype.h>
Radek Krejci4546aa62019-07-15 16:53:32 +020019#include <errno.h>
20#include <stdarg.h>
21#include <stdlib.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020022#include <string.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020023#include <sys/mman.h>
24#include <sys/stat.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <unistd.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020026
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "extensions.h"
Michal Vasko841d1a92018-09-07 15:40:31 +020028#include "tree_schema.h"
Radek Krejcib4a4a272019-06-10 12:44:52 +020029#include "tree_schema_internal.h"
Michal Vasko1324b6c2018-09-07 11:16:23 +020030
Radek Krejcic59bc972018-09-17 16:13:06 +020031const char *const ly_stmt_list[] = {
32 [YANG_ACTION] = "action",
33 [YANG_ANYDATA] = "anydata",
34 [YANG_ANYXML] = "anyxml",
35 [YANG_ARGUMENT] = "argument",
36 [YANG_AUGMENT] = "augment",
37 [YANG_BASE] = "base",
38 [YANG_BELONGS_TO] = "belongs-to",
39 [YANG_BIT] = "bit",
40 [YANG_CASE] = "case",
41 [YANG_CHOICE] = "choice",
42 [YANG_CONFIG] = "config",
43 [YANG_CONTACT] = "contact",
44 [YANG_CONTAINER] = "container",
45 [YANG_CUSTOM] = "<extension-instance>",
46 [YANG_DEFAULT] = "default",
47 [YANG_DESCRIPTION] = "description",
48 [YANG_DEVIATE] = "deviate",
49 [YANG_DEVIATION] = "deviation",
50 [YANG_ENUM] = "enum",
51 [YANG_ERROR_APP_TAG] = "error-app-tag",
52 [YANG_ERROR_MESSAGE] = "error-message",
53 [YANG_EXTENSION] = "extension",
54 [YANG_FEATURE] = "feature",
55 [YANG_FRACTION_DIGITS] = "fraction-digits",
56 [YANG_GROUPING] = "grouping",
57 [YANG_IDENTITY] = "identitiy",
58 [YANG_IF_FEATURE] = "if-feature",
59 [YANG_IMPORT] = "import",
60 [YANG_INCLUDE] = "include",
61 [YANG_INPUT] = "input",
62 [YANG_KEY] = "key",
63 [YANG_LEAF] = "leaf",
64 [YANG_LEAF_LIST] = "leaf-list",
65 [YANG_LENGTH] = "length",
66 [YANG_LIST] = "list",
67 [YANG_MANDATORY] = "mandatory",
68 [YANG_MAX_ELEMENTS] = "max-elements",
69 [YANG_MIN_ELEMENTS] = "min-elements",
70 [YANG_MODIFIER] = "modifier",
71 [YANG_MODULE] = "module",
72 [YANG_MUST] = "must",
73 [YANG_NAMESPACE] = "namespace",
74 [YANG_NOTIFICATION] = "notification",
75 [YANG_ORDERED_BY] = "ordered-by",
76 [YANG_ORGANIZATION] = "organization",
77 [YANG_OUTPUT] = "output",
78 [YANG_PATH] = "path",
79 [YANG_PATTERN] = "pattern",
80 [YANG_POSITION] = "position",
81 [YANG_PREFIX] = "prefix",
82 [YANG_PRESENCE] = "presence",
83 [YANG_RANGE] = "range",
84 [YANG_REFERENCE] = "reference",
85 [YANG_REFINE] = "refine",
86 [YANG_REQUIRE_INSTANCE] = "require-instance",
87 [YANG_REVISION] = "revision",
88 [YANG_REVISION_DATE] = "revision-date",
89 [YANG_RPC] = "rpc",
90 [YANG_STATUS] = "status",
91 [YANG_SUBMODULE] = "submodule",
92 [YANG_TYPE] = "type",
93 [YANG_TYPEDEF] = "typedef",
94 [YANG_UNIQUE] = "unique",
95 [YANG_UNITS] = "units",
96 [YANG_USES] = "uses",
97 [YANG_VALUE] = "value",
98 [YANG_WHEN] = "when",
99 [YANG_YANG_VERSION] = "yang-version",
100 [YANG_YIN_ELEMENT] = "yin-element",
101 [YANG_SEMICOLON] = ";",
102 [YANG_LEFT_BRACE] = "{",
103 [YANG_RIGHT_BRACE] = "}",
David Sedlák21f87cd2019-07-03 16:53:23 +0200104 [YIN_TEXT] = "text",
105 [YIN_VALUE] = "value",
Radek Krejcic59bc972018-09-17 16:13:06 +0200106};
107
108const char *const lyext_substmt_list[] = {
109 [LYEXT_SUBSTMT_ARGUMENT] = "argument",
110 [LYEXT_SUBSTMT_BASE] = "base",
111 [LYEXT_SUBSTMT_BELONGSTO] = "belongs-to",
112 [LYEXT_SUBSTMT_CONTACT] = "contact",
113 [LYEXT_SUBSTMT_DEFAULT] = "default",
114 [LYEXT_SUBSTMT_DESCRIPTION] = "description",
115 [LYEXT_SUBSTMT_ERRTAG] = "error-app-tag",
116 [LYEXT_SUBSTMT_ERRMSG] = "error-message",
117 [LYEXT_SUBSTMT_KEY] = "key",
118 [LYEXT_SUBSTMT_NAMESPACE] = "namespace",
119 [LYEXT_SUBSTMT_ORGANIZATION] = "organization",
120 [LYEXT_SUBSTMT_PATH] = "path",
121 [LYEXT_SUBSTMT_PREFIX] = "prefix",
122 [LYEXT_SUBSTMT_PRESENCE] = "presence",
123 [LYEXT_SUBSTMT_REFERENCE] = "reference",
124 [LYEXT_SUBSTMT_REVISIONDATE] = "revision-date",
125 [LYEXT_SUBSTMT_UNITS] = "units",
126 [LYEXT_SUBSTMT_VALUE] = "value",
127 [LYEXT_SUBSTMT_VERSION] = "yang-version",
128 [LYEXT_SUBSTMT_MODIFIER] = "modifier",
129 [LYEXT_SUBSTMT_REQINSTANCE] = "require-instance",
130 [LYEXT_SUBSTMT_YINELEM] = "yin-element",
131 [LYEXT_SUBSTMT_CONFIG] = "config",
132 [LYEXT_SUBSTMT_MANDATORY] = "mandatory",
133 [LYEXT_SUBSTMT_ORDEREDBY] = "ordered-by",
134 [LYEXT_SUBSTMT_STATUS] = "status",
135 [LYEXT_SUBSTMT_FRACDIGITS] = "fraction-digits",
136 [LYEXT_SUBSTMT_MAX] = "max-elements",
137 [LYEXT_SUBSTMT_MIN] = "min-elements",
138 [LYEXT_SUBSTMT_POSITION] = "position",
139 [LYEXT_SUBSTMT_UNIQUE] = "unique",
140 [LYEXT_SUBSTMT_IFFEATURE] = "if-feature",
141};
142
143const char *const ly_devmod_list[] = {
144 [LYS_DEV_NOT_SUPPORTED] = "not-supported",
145 [LYS_DEV_ADD] = "add",
146 [LYS_DEV_DELETE] = "delete",
147 [LYS_DEV_REPLACE] = "replace",
148};
149
Michal Vasko1324b6c2018-09-07 11:16:23 +0200150void *
151ly_realloc(void *ptr, size_t size)
152{
153 void *new_mem;
154
155 new_mem = realloc(ptr, size);
156 if (!new_mem) {
157 free(ptr);
158 }
159
160 return new_mem;
161}
Michal Vasko841d1a92018-09-07 15:40:31 +0200162
Radek Krejcib416be62018-10-01 14:51:45 +0200163LY_ERR
164ly_getutf8(const char **input, unsigned int *utf8_char, size_t *bytes_read)
165{
166 unsigned int c, len;
167 int aux;
168 int i;
169
Radek Krejcicc6a45c2019-05-13 10:16:14 +0200170 if (bytes_read) {
171 (*bytes_read) = 0;
172 }
173
Radek Krejcib416be62018-10-01 14:51:45 +0200174 c = (*input)[0];
175 LY_CHECK_RET(!c, LY_EINVAL);
176
177 if (!(c & 0x80)) {
178 /* one byte character */
179 len = 1;
180
181 if (c < 0x20 && c != 0x9 && c != 0xa && c != 0xd) {
182 return LY_EINVAL;
183 }
184 } else if ((c & 0xe0) == 0xc0) {
185 /* two bytes character */
186 len = 2;
187
188 aux = (*input)[1];
189 if ((aux & 0xc0) != 0x80) {
190 return LY_EINVAL;
191 }
192 c = ((c & 0x1f) << 6) | (aux & 0x3f);
193
194 if (c < 0x80) {
195 return LY_EINVAL;
196 }
197 } else if ((c & 0xf0) == 0xe0) {
198 /* three bytes character */
199 len = 3;
200
201 c &= 0x0f;
202 for (i = 1; i <= 2; i++) {
203 aux = (*input)[i];
204 if ((aux & 0xc0) != 0x80) {
205 return LY_EINVAL;
206 }
207
208 c = (c << 6) | (aux & 0x3f);
209 }
210
211 if (c < 0x800 || (c > 0xd7ff && c < 0xe000) || c > 0xfffd) {
212 return LY_EINVAL;
213 }
214 } else if ((c & 0xf8) == 0xf0) {
215 /* four bytes character */
216 len = 4;
217
218 c &= 0x07;
219 for (i = 1; i <= 3; i++) {
220 aux = (*input)[i];
221 if ((aux & 0xc0) != 0x80) {
222 return LY_EINVAL;
223 }
224
225 c = (c << 6) | (aux & 0x3f);
226 }
227
228 if (c < 0x1000 || c > 0x10ffff) {
229 return LY_EINVAL;
230 }
231 } else {
232 return LY_EINVAL;
233 }
234
235 (*utf8_char) = c;
236 (*input) += len;
237 if (bytes_read) {
238 (*bytes_read) = len;
239 }
240 return LY_SUCCESS;
241}
242
Radek Krejcid972c252018-09-25 13:23:39 +0200243size_t
244LY_VCODE_INSTREXP_len(const char *str)
245{
246 size_t len = 0;
247 if (!str) {
248 return len;
249 } else if (!str[0]) {
250 return 1;
251 }
252 for (len = 1; len < LY_VCODE_INSTREXP_MAXLEN && str[len]; ++len);
253 return len;
254}
255
Radek Krejcif345c012018-09-19 11:12:59 +0200256LY_ERR
Radek Krejci86d106e2018-10-18 09:53:19 +0200257ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
Michal Vasko841d1a92018-09-07 15:40:31 +0200258{
Radek Krejci86d106e2018-10-18 09:53:19 +0200259 struct stat sb;
260 long pagesize;
261 size_t m;
Michal Vasko841d1a92018-09-07 15:40:31 +0200262
Radek Krejci86d106e2018-10-18 09:53:19 +0200263 assert(length);
264 assert(addr);
265 assert(fd >= 0);
Michal Vasko841d1a92018-09-07 15:40:31 +0200266
Radek Krejci86d106e2018-10-18 09:53:19 +0200267 if (fstat(fd, &sb) == -1) {
268 LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
269 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200270 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200271 if (!S_ISREG(sb.st_mode)) {
272 LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
273 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200274 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200275 if (!sb.st_size) {
276 *addr = NULL;
277 return LY_SUCCESS;
278 }
279 pagesize = sysconf(_SC_PAGESIZE);
280
281 m = sb.st_size % pagesize;
282 if (m && pagesize - m >= 1) {
283 /* there will be enough space (at least 1 byte) after the file content mapping to provide zeroed NULL-termination byte */
284 *length = sb.st_size + 1;
285 *addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE, fd, 0);
286 } else {
287 /* there will not be enough bytes after the file content mapping for the additional bytes and some of them
288 * would overflow into another page that would not be zerroed and any access into it would generate SIGBUS.
289 * Therefore we have to do the following hack with double mapping. First, the required number of bytes
290 * (including the additinal bytes) is required as anonymous and thus they will be really provided (actually more
291 * because of using whole pages) and also initialized by zeros. Then, the file is mapped to the same address
292 * where the anonymous mapping starts. */
293 *length = sb.st_size + pagesize;
294 *addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
295 *addr = mmap(*addr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
296 }
297 if (*addr == MAP_FAILED) {
298 LOGERR(ctx, LY_ESYS, "mmap() failed (%s).", strerror(errno));
299 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200300 }
301
Radek Krejcif345c012018-09-19 11:12:59 +0200302 return LY_SUCCESS;
Radek Krejci86d106e2018-10-18 09:53:19 +0200303}
Michal Vasko841d1a92018-09-07 15:40:31 +0200304
Radek Krejci86d106e2018-10-18 09:53:19 +0200305LY_ERR
306ly_munmap(void *addr, size_t length)
307{
308 if (munmap(addr, length)) {
309 return LY_ESYS;
310 }
311 return LY_SUCCESS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200312}
Radek Krejci4f28eda2018-11-12 11:46:16 +0100313
314LY_ERR
Radek Krejci4546aa62019-07-15 16:53:32 +0200315ly_strcat(char **dest, const char *format, ...)
316{
317 va_list fp;
318 char *addition = NULL;
319 size_t len;
320
321 va_start(fp, format);
322 len = vasprintf(&addition, format, fp);
323 len += (*dest ? strlen(*dest) : 0) + 1;
324
325 if (*dest) {
326 *dest = ly_realloc(*dest, len);
327 if (!*dest) {
328 return LY_EMEM;
329 }
330 *dest = strcat(*dest, addition);
331 free(addition);
332 } else {
333 *dest = addition;
334 }
335
336 va_end(fp);
337 return LY_SUCCESS;
338}
339
340LY_ERR
Radek Krejci249973a2019-06-10 10:50:54 +0200341ly_parse_int(const char *val_str, size_t val_len, int64_t min, int64_t max, int base, int64_t *ret)
Radek Krejci4f28eda2018-11-12 11:46:16 +0100342{
343 char *strptr;
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200344 int64_t i;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100345
Radek Krejci249973a2019-06-10 10:50:54 +0200346 LY_CHECK_ARG_RET(NULL, val_str, val_str[0], val_len, LY_EINVAL);
Radek Krejci4f28eda2018-11-12 11:46:16 +0100347
348 /* convert to 64-bit integer, all the redundant characters are handled */
349 errno = 0;
350 strptr = NULL;
351
352 /* parse the value */
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200353 i = strtoll(val_str, &strptr, base);
Radek Krejci249973a2019-06-10 10:50:54 +0200354 if (errno || strptr == val_str) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100355 return LY_EVALID;
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200356 } else if ((i < min) || (i > max)) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100357 return LY_EDENIED;
358 } else if (strptr && *strptr) {
359 while (isspace(*strptr)) {
360 ++strptr;
361 }
Radek Krejci249973a2019-06-10 10:50:54 +0200362 if (*strptr && strptr < val_str + val_len) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100363 return LY_EVALID;
364 }
365 }
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200366
367 *ret = i;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100368 return LY_SUCCESS;
369}
370
371LY_ERR
Radek Krejci249973a2019-06-10 10:50:54 +0200372ly_parse_uint(const char *val_str, size_t val_len, uint64_t max, int base, uint64_t *ret)
Radek Krejci4f28eda2018-11-12 11:46:16 +0100373{
374 char *strptr;
375 uint64_t u;
376
377 LY_CHECK_ARG_RET(NULL, val_str, val_str[0], LY_EINVAL);
378
379 errno = 0;
380 strptr = NULL;
381 u = strtoull(val_str, &strptr, base);
Radek Krejci249973a2019-06-10 10:50:54 +0200382 if (errno || strptr == val_str) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100383 return LY_EVALID;
384 } else if ((u > max) || (u && val_str[0] == '-')) {
385 return LY_EDENIED;
386 } else if (strptr && *strptr) {
387 while (isspace(*strptr)) {
388 ++strptr;
389 }
Radek Krejci249973a2019-06-10 10:50:54 +0200390 if (*strptr && strptr < val_str + val_len) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100391 return LY_EVALID;
392 }
393 }
394
395 *ret = u;
396 return LY_SUCCESS;
397}
Radek Krejcib4a4a272019-06-10 12:44:52 +0200398
399/**
400 * @brief Parse an identifier.
401 *
402 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
403 * identifier = (ALPHA / "_")
404 * *(ALPHA / DIGIT / "_" / "-" / ".")
405 *
406 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
407 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
408 */
409static LY_ERR
410lys_parse_id(const char **id)
411{
412 assert(id && *id);
413
414 if (!is_yangidentstartchar(**id)) {
415 return LY_EINVAL;
416 }
417 ++(*id);
418
419 while (is_yangidentchar(**id)) {
420 ++(*id);
421 }
422 return LY_SUCCESS;
423}
424
425LY_ERR
426ly_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
427{
428 assert(id && *id);
429 assert(prefix && prefix_len);
430 assert(name && name_len);
431
432 *prefix = *id;
433 *prefix_len = 0;
434 *name = NULL;
435 *name_len = 0;
436
437 LY_CHECK_RET(lys_parse_id(id));
438 if (**id == ':') {
439 /* there is prefix */
440 *prefix_len = *id - *prefix;
441 ++(*id);
442 *name = *id;
443
444 LY_CHECK_RET(lys_parse_id(id));
445 *name_len = *id - *name;
446 } else {
447 /* there is no prefix, so what we have as prefix now is actually the name */
448 *name = *prefix;
449 *name_len = *id - *name;
450 *prefix = NULL;
451 }
452
453 return LY_SUCCESS;
454}
455
456LY_ERR
Radek Krejci084289f2019-07-09 17:35:30 +0200457ly_parse_instance_predicate(const char **pred, size_t limit, LYD_FORMAT format,
458 const char **prefix, size_t *prefix_len, const char **id, size_t *id_len, const char **value, size_t *value_len,
459 const char **errmsg)
Radek Krejcib4a4a272019-06-10 12:44:52 +0200460{
461 LY_ERR ret = LY_EVALID;
462 const char *in = *pred;
463 size_t offset = 1;
464 int expr = 0;
465 char quot;
466
467 assert(in[0] == '\[');
468
469 *prefix = *id = *value = NULL;
470 *prefix_len = *id_len = *value_len = 0;
471
472 /* leading *WSP */
473 for (; isspace(in[offset]); offset++);
474
475 if (isdigit(in[offset])) {
476 /* pos: "[" *WSP positive-integer-value *WSP "]" */
477 if (in[offset] == '0') {
478 /* zero */
479 *errmsg = "The position predicate cannot be zero.";
480 goto error;
481 }
482
483 /* positive-integer-value */
Radek Krejci10bfdf82019-06-10 14:08:13 +0200484 *value = &in[offset++];
Radek Krejcib4a4a272019-06-10 12:44:52 +0200485 for (; isdigit(in[offset]); offset++);
Radek Krejci10bfdf82019-06-10 14:08:13 +0200486 *value_len = &in[offset] - *value;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200487
488 } else if (in[offset] == '.') {
489 /* leaf-list-predicate: "[" *WSP "." *WSP "=" *WSP quoted-string *WSP "]" */
490 *id = &in[offset];
491 *id_len = 1;
492 offset++;
493 expr = 1;
Radek Krejci10bfdf82019-06-10 14:08:13 +0200494 } else if (in[offset] == '-') {
495 /* typically negative value */
496 *errmsg = "Invalid instance predicate format (negative position or invalid node-identifier).";
497 goto error;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200498 } else {
499 /* key-predicate: "[" *WSP node-identifier *WSP "=" *WSP quoted-string *WSP "]" */
500 in = &in[offset];
501 if (ly_parse_nodeid(&in, prefix, prefix_len, id, id_len)) {
502 *errmsg = "Invalid node-identifier.";
503 goto error;
504 }
Radek Krejci084289f2019-07-09 17:35:30 +0200505 if (format == LYD_XML && !(*prefix)) {
506 /* all node names MUST be qualified with explicit namespace prefix */
507 *errmsg = "Missing prefix of a node name.";
508 goto error;
509 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200510 offset = in - *pred;
511 in = *pred;
Radek Krejci10bfdf82019-06-10 14:08:13 +0200512 expr = 2;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200513 }
514
515 if (expr) {
516 /* *WSP "=" *WSP quoted-string *WSP "]" */
517 for (; isspace(in[offset]); offset++);
518
519 if (in[offset] != '=') {
Radek Krejci10bfdf82019-06-10 14:08:13 +0200520 if (expr == 1) {
521 *errmsg = "Unexpected character instead of \'=\' in leaf-list-predicate.";
522 } else { /* 2 */
523 *errmsg = "Unexpected character instead of \'=\' in key-predicate.";
524 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200525 goto error;
526 }
527 offset++;
528 for (; isspace(in[offset]); offset++);
529
530 /* quoted-string */
531 quot = in[offset++];
532 if (quot != '\'' && quot != '\"') {
533 *errmsg = "String value is not quoted.";
534 goto error;
535 }
536 *value = &in[offset];
Radek Krejci084289f2019-07-09 17:35:30 +0200537 for (;offset < limit && (in[offset] != quot || (offset && in[offset - 1] == '\\')); offset++);
Radek Krejci10bfdf82019-06-10 14:08:13 +0200538 if (in[offset] == quot) {
539 *value_len = &in[offset] - *value;
540 offset++;
541 } else {
542 *errmsg = "Value is not terminated quoted-string.";
543 goto error;
544 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200545 }
546
547 /* *WSP "]" */
548 for(; isspace(in[offset]); offset++);
549 if (in[offset] != ']') {
Radek Krejci10bfdf82019-06-10 14:08:13 +0200550 if (expr == 0) {
551 *errmsg = "Predicate (pos) is not terminated by \']\' character.";
552 } else if (expr == 1) {
553 *errmsg = "Predicate (leaf-list-predicate) is not terminated by \']\' character.";
554 } else { /* 2 */
555 *errmsg = "Predicate (key-predicate) is not terminated by \']\' character.";
556 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200557 goto error;
558 }
Radek Krejci10bfdf82019-06-10 14:08:13 +0200559 offset++;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200560
Radek Krejci10bfdf82019-06-10 14:08:13 +0200561 if (offset <= limit) {
562 *pred = &in[offset];
Radek Krejcib4a4a272019-06-10 12:44:52 +0200563 return LY_SUCCESS;
564 }
565
566 /* we read after the limit */
567 *errmsg = "Predicate is incomplete.";
568 *prefix = *id = *value = NULL;
569 *prefix_len = *id_len = *value_len = 0;
570 offset = limit;
571 ret = LY_EINVAL;
572
573error:
574 *pred = &in[offset];
575 return ret;
576}