printer YANG FEATURE initial implementation of YANG printer
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 88da234..21d9aec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -180,6 +180,8 @@
src/tree_schema_compile.c
src/tree_schema_helpers.c
src/parser_yang.c
+ src/printer.c
+ src/printer_yang.c
src/xml.c
src/xpath.c)
@@ -201,6 +203,7 @@
src/libyang.h
src/context.h
src/tree_schema.h
+ src/printer_schema.h
src/extensions.h
src/dict.h
src/log.h
diff --git a/src/libyang.h b/src/libyang.h
index 3c001fc..7b89268 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -26,6 +26,7 @@
#include "dict.h"
#include "context.h"
#include "tree_schema.h"
+#include "printer_schema.h"
/**
* @mainpage About
diff --git a/src/log.h b/src/log.h
index d8b0a04..0074d83 100644
--- a/src/log.h
+++ b/src/log.h
@@ -150,7 +150,8 @@
LY_EINT, /**< Internal error */
LY_EVALID, /**< Validation failure */
LY_EPLUGIN, /**< Error reported by a plugin */
- LY_EDENIED /**< Operation is not allowed */
+ LY_EDENIED, /**< Operation is not allowed */
+ LY_EOTHER /**< Unknown error */
} LY_ERR;
/**
diff --git a/src/parser_yang.c b/src/parser_yang.c
index a45a979..83ad888 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -571,6 +571,7 @@
* @param[in] ctx yang parser context for logging.
* @param[in,out] data Data to read from, always moved to currently handled character.
* @param[in] arg Type of YANG keyword argument expected.
+ * @param[out] flags optional output argument to get flag of the argument's quoting (LYS_*QOUTED - see [schema node flags](@ref snodeflags))
* @param[out] word_p Pointer to the read string. Can return NULL if \p arg is #Y_MAYBE_STR_ARG.
* @param[out] word_b Pointer to a dynamically-allocated buffer holding the read string. If not needed,
* set to NULL. Otherwise equal to \p word_p.
@@ -579,7 +580,8 @@
* @return LY_ERR values.
*/
static LY_ERR
-get_argument(struct ly_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len)
+get_argument(struct ly_parser_ctx *ctx, const char **data, enum yang_arg arg,
+ uint16_t *flags, char **word_p, char **word_b, size_t *word_len)
{
size_t buf_len = 0;
@@ -600,6 +602,9 @@
"unquoted string character, optsep, semicolon or opening brace");
return LY_EVALID;
}
+ if (flags) {
+ (*flags) |= (**data) == '\'' ? LYS_SINGLEQUOTED : LYS_DOUBLEQUOTED;
+ }
LY_CHECK_RET(read_qstring(ctx, data, arg, word_p, word_b, word_len, &buf_len));
goto str_end;
case '/':
@@ -1028,7 +1033,7 @@
stmt->stmt = lydict_insert(ctx->ctx, word, word_len);
/* get optional argument */
- LY_CHECK_RET(get_argument(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_MAYBE_STR_ARG, &stmt->flags, &word, &buf, &word_len));
if (word) {
if (buf) {
@@ -1075,7 +1080,7 @@
e->insubstmt_index = insubstmt_index;
/* get optional argument */
- LY_CHECK_RET(get_argument(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_MAYBE_STR_ARG, NULL, &word, &buf, &word_len));
if (word) {
INSERT_WORD(ctx, buf, e->argument, word, word_len);
@@ -1116,7 +1121,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, arg, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, arg, NULL, &word, &buf, &word_len));
/* store value and spend buf if allocated */
INSERT_WORD(ctx, buf, *value, word, word_len);
@@ -1158,7 +1163,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 3) && !strncmp(word, "1.0", word_len)) {
*version = LYS_VERSION_1_0;
@@ -1209,7 +1214,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, *belongsto, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -1259,7 +1264,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
/* check value */
if (lysp_check_date(ctx, word, word_len, "revision-date")) {
@@ -1306,7 +1311,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *includes, inc, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, inc->name, word, word_len);
@@ -1363,7 +1368,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *imports, imp, LY_EVALID);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, imp->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -1420,7 +1425,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *revs, rev, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
/* check value */
if (lysp_check_date(ctx, word, word_len, "revision")) {
@@ -1475,7 +1480,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *texts, item, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, arg, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, arg, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, *item, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -1515,7 +1520,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 4) && !strncmp(word, "true", word_len)) {
*flags |= LYS_CONFIG_W;
@@ -1565,7 +1570,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 4) && !strncmp(word, "true", word_len)) {
*flags |= LYS_MAND_TRUE;
@@ -1610,7 +1615,7 @@
enum yang_keyword kw;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, restr->arg, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -1681,7 +1686,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 7) && !strncmp(word, "current", word_len)) {
*flags |= LYS_STATUS_CURR;
@@ -1737,7 +1742,7 @@
*when_p = when;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, when->cond, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -1793,7 +1798,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, any->name, word, word_len);
/* parse substatements */
@@ -1865,7 +1870,7 @@
*flags |= LYS_SET_VALUE;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_VALUE) && !strncmp(word, "-0", 2))) {
LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
@@ -1941,7 +1946,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *enums, enm, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, enum_kw == YANG_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, enum_kw == YANG_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
if (enum_kw == YANG_ENUM) {
if (!word_len) {
LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
@@ -2022,7 +2027,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
@@ -2086,7 +2091,7 @@
*flags |= LYS_SET_REQINST;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 4) && !strncmp(word, "true", word_len)) {
*reqinst = 1;
@@ -2134,7 +2139,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len != 12) || strncmp(word, "invert-match", word_len)) {
LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
@@ -2187,7 +2192,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *patterns, restr, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
/* add special meaning first byte */
if (buf) {
@@ -2255,7 +2260,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, type->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -2360,7 +2365,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, leaf->name, word, word_len);
/* parse substatements */
@@ -2449,7 +2454,7 @@
*flags |= LYS_SET_MAX;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
@@ -2516,7 +2521,7 @@
*flags |= LYS_SET_MIN;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
@@ -2577,7 +2582,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 6) && !strncmp(word, "system", word_len)) {
*flags |= LYS_ORDBY_SYSTEM;
@@ -2637,7 +2642,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, llist->name, word, word_len);
/* parse substatements */
@@ -2733,7 +2738,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *refines, rf, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, rf->nodeid, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -2801,7 +2806,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *typedefs, tpdf, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, tpdf->name, word, word_len);
/* parse substatements */
@@ -2875,7 +2880,7 @@
}
/* initiate structure */
- inout_p->nodetype = LYS_INOUT;
+ inout_p->nodetype = &((struct lysp_action*)parent)->input == inout_p ? LYS_INPUT : LYS_OUTPUT;
inout_p->parent = parent;
/* parse substatements */
@@ -2955,7 +2960,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *actions, act, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, act->name, word, word_len);
act->nodetype = LYS_ACTION;
act->parent = parent;
@@ -3028,7 +3033,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *notifs, notif, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, notif->name, word, word_len);
notif->nodetype = LYS_NOTIF;
notif->parent = parent;
@@ -3123,7 +3128,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *groupings, grp, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, grp->name, word, word_len);
grp->nodetype = LYS_GROUPING;
grp->parent = parent;
@@ -3217,7 +3222,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *augments, aug, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, aug->nodeid, word, word_len);
aug->nodetype = LYS_AUGMENT;
aug->parent = parent;
@@ -3321,7 +3326,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, uses->name, word, word_len);
/* parse substatements */
@@ -3394,7 +3399,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, cas->name, word, word_len);
/* parse substatements */
@@ -3485,7 +3490,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, choice->name, word, word_len);
/* parse substatements */
@@ -3593,7 +3598,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, cont->name, word, word_len);
/* parse substatements */
@@ -3715,7 +3720,7 @@
}
/* get name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, list->name, word, word_len);
/* parse substatements */
@@ -3847,7 +3852,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 4) && !strncmp(word, "true", word_len)) {
*flags |= LYS_YINELEM_TRUE;
@@ -3898,7 +3903,7 @@
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, *argument, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -3938,7 +3943,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *extensions, ex, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, ex->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -3992,7 +3997,7 @@
uint32_t *d_min, *d_max;
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len == 13) && !strncmp(word, "not-supported", word_len)) {
dev_mod = LYS_DEV_NOT_SUPPORTED;
@@ -4201,7 +4206,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *deviations, dev, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, dev->nodeid, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -4255,7 +4260,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *features, feat, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, feat->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -4304,7 +4309,7 @@
LY_ARRAY_NEW_RET(ctx->ctx, *identities, ident, LY_EMEM);
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, ident->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -4386,7 +4391,7 @@
struct lysp_submodule *dup;
/* (sub)module name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, mod->mod->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -4596,7 +4601,7 @@
struct lysp_submodule *dup;
/* submodule name */
- LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, submod->name, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -4812,7 +4817,7 @@
LY_CHECK_GOTO(ret, cleanup);
/* read some trailing spaces or new lines */
- ret = get_argument(context, &data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
+ ret = get_argument(context, &data, Y_MAYBE_STR_ARG, NULL, &word, &buf, &word_len);
LY_CHECK_GOTO(ret, cleanup);
if (word) {
@@ -4869,7 +4874,7 @@
LY_CHECK_GOTO(ret, cleanup);
/* read some trailing spaces or new lines */
- ret = get_argument(context, &data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
+ ret = get_argument(context, &data, Y_MAYBE_STR_ARG, NULL, &word, &buf, &word_len);
LY_CHECK_GOTO(ret, cleanup);
if (word) {
diff --git a/src/printer.c b/src/printer.c
new file mode 100644
index 0000000..653dca8
--- /dev/null
+++ b/src/printer.c
@@ -0,0 +1,395 @@
+/**
+ * @file printer.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Wrapper for all libyang printers.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "printer_internal.h"
+
+/**
+ * @brief informational structure shared by printers
+ */
+struct ext_substmt_info_s ext_substmt_info[] = {
+ {NULL, NULL, 0}, /**< LYEXT_SUBSTMT_SELF */
+ {"argument", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ARGUMENT */
+ {"base", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BASE */
+ {"belongs-to", "module", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BELONGSTO */
+ {"contact", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_CONTACT */
+ {"default", "value", 0}, /**< LYEXT_SUBSTMT_DEFAULT */
+ {"description", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_DESCRIPTION */
+ {"error-app-tag", "value", 0}, /**< LYEXT_SUBSTMT_ERRTAG */
+ {"error-message", "value", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ERRMSG */
+ {"key", "value", 0}, /**< LYEXT_SUBSTMT_KEY */
+ {"namespace", "uri", 0}, /**< LYEXT_SUBSTMT_NAMESPACE */
+ {"organization", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ORGANIZATION */
+ {"path", "value", 0}, /**< LYEXT_SUBSTMT_PATH */
+ {"prefix", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_PREFIX */
+ {"presence", "value", 0}, /**< LYEXT_SUBSTMT_PRESENCE */
+ {"reference", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_REFERENCE */
+ {"revision-date", "date", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REVISIONDATE */
+ {"units", "name", 0}, /**< LYEXT_SUBSTMT_UNITS */
+ {"value", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VALUE */
+ {"yang-version", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VERSION */
+ {"modifier", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MODIFIER */
+ {"require-instance", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REQINST */
+ {"yin-element", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_YINELEM */
+ {"config", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_CONFIG */
+ {"mandatory", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MANDATORY */
+ {"ordered-by", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ORDEREDBY */
+ {"status", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_STATUS */
+ {"fraction-digits", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_DIGITS */
+ {"max-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MAX */
+ {"min-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MIN */
+ {"position", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_POSITION */
+ {"unique", "tag", 0}, /**< LYEXT_SUBSTMT_UNIQUE */
+};
+
+LY_ERR
+ly_print(struct lyout *out, const char *format, ...)
+{
+ int count = 0;
+ char *msg = NULL, *aux;
+ va_list ap;
+#ifndef HAVE_VDPRINTF
+ FILE *stream;
+#endif
+
+ va_start(ap, format);
+
+ switch (out->type) {
+ case LYOUT_FD:
+#ifdef HAVE_VDPRINTF
+ count = vdprintf(out->method.fd, format, ap);
+#else
+ stream = fdopen(dup(out->method.fd), "a+");
+ if (stream) {
+ count = vfprintf(stream, format, ap);
+ fclose(stream);
+ }
+#endif
+ break;
+ case LYOUT_STREAM:
+ count = vfprintf(out->method.f, format, ap);
+ break;
+ case LYOUT_MEMORY:
+ count = vasprintf(&msg, format, ap);
+ if (out->method.mem.len + count + 1 > out->method.mem.size) {
+ aux = ly_realloc(out->method.mem.buf, out->method.mem.len + count + 1);
+ if (!aux) {
+ out->method.mem.buf = NULL;
+ out->method.mem.len = 0;
+ out->method.mem.size = 0;
+ LOGMEM(NULL);
+ va_end(ap);
+ return -1;
+ }
+ out->method.mem.buf = aux;
+ out->method.mem.size = out->method.mem.len + count + 1;
+ }
+ memcpy(&out->method.mem.buf[out->method.mem.len], msg, count);
+ out->method.mem.len += count;
+ out->method.mem.buf[out->method.mem.len] = '\0';
+ free(msg);
+ break;
+ case LYOUT_CALLBACK:
+ count = vasprintf(&msg, format, ap);
+ count = out->method.clb.f(out->method.clb.arg, msg, count);
+ free(msg);
+ break;
+ }
+
+ va_end(ap);
+
+ if (count < 0) {
+ return LY_EOTHER;
+ } else {
+ return LY_SUCCESS;
+ }
+}
+
+void
+ly_print_flush(struct lyout *out)
+{
+ switch (out->type) {
+ case LYOUT_STREAM:
+ fflush(out->method.f);
+ break;
+ case LYOUT_FD:
+ case LYOUT_MEMORY:
+ case LYOUT_CALLBACK:
+ /* nothing to do */
+ break;
+ }
+}
+
+LY_ERR
+ly_write(struct lyout *out, const char *buf, size_t count)
+{
+ int written = 0;
+
+ if (out->hole_count) {
+ /* we are buffering data after a hole */
+ if (out->buf_len + count > out->buf_size) {
+ out->buffered = ly_realloc(out->buffered, out->buf_len + count);
+ if (!out->buffered) {
+ out->buf_len = 0;
+ out->buf_size = 0;
+ LOGMEM_RET(NULL);
+ }
+ out->buf_size = out->buf_len + count;
+ }
+
+ memcpy(&out->buffered[out->buf_len], buf, count);
+ out->buf_len += count;
+ return LY_SUCCESS;
+ }
+
+ switch (out->type) {
+ case LYOUT_MEMORY:
+ if (out->method.mem.len + count + 1 > out->method.mem.size) {
+ out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + count + 1);
+ if (!out->method.mem.buf) {
+ out->method.mem.len = 0;
+ out->method.mem.size = 0;
+ LOGMEM_RET(NULL);
+ }
+ out->method.mem.size = out->method.mem.len + count + 1;
+ }
+ memcpy(&out->method.mem.buf[out->method.mem.len], buf, count);
+ out->method.mem.len += count;
+ out->method.mem.buf[out->method.mem.len] = '\0';
+ return LY_SUCCESS;
+ case LYOUT_FD:
+ written = write(out->method.fd, buf, count);
+ break;
+ case LYOUT_STREAM:
+ written = fwrite(buf, sizeof *buf, count, out->method.f);
+ break;
+ case LYOUT_CALLBACK:
+ written = out->method.clb.f(out->method.clb.arg, buf, count);
+ break;
+ }
+
+ if (written < 0) {
+ return LY_EOTHER;
+ } else {
+ return LY_SUCCESS;
+ }
+}
+
+LY_ERR
+ly_write_skip(struct lyout *out, size_t count, size_t *position)
+{
+ switch (out->type) {
+ case LYOUT_MEMORY:
+ if (out->method.mem.len + count > out->method.mem.size) {
+ out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + count);
+ if (!out->method.mem.buf) {
+ out->method.mem.len = 0;
+ out->method.mem.size = 0;
+ LOGMEM_RET(NULL);
+ }
+ out->method.mem.size = out->method.mem.len + count;
+ }
+
+ /* save the current position */
+ *position = out->method.mem.len;
+
+ /* skip the memory */
+ out->method.mem.len += count;
+ break;
+ case LYOUT_FD:
+ case LYOUT_STREAM:
+ case LYOUT_CALLBACK:
+ /* buffer the hole */
+ if (out->buf_len + count > out->buf_size) {
+ out->buffered = ly_realloc(out->buffered, out->buf_len + count);
+ if (!out->buffered) {
+ out->buf_len = 0;
+ out->buf_size = 0;
+ LOGMEM_RET(NULL);
+ }
+ out->buf_size = out->buf_len + count;
+ }
+
+ /* save the current position */
+ *position = out->buf_len;
+
+ /* skip the memory */
+ out->buf_len += count;
+
+ /* increase hole counter */
+ ++out->hole_count;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+ly_write_skipped(struct lyout *out, size_t position, const char *buf, size_t count)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+ switch (out->type) {
+ case LYOUT_MEMORY:
+ /* write */
+ memcpy(&out->method.mem.buf[position], buf, count);
+ break;
+ case LYOUT_FD:
+ case LYOUT_STREAM:
+ case LYOUT_CALLBACK:
+ if (out->buf_len < position + count) {
+ LOGMEM_RET(NULL);
+ }
+
+ /* write into the hole */
+ memcpy(&out->buffered[position], buf, count);
+
+ /* decrease hole counter */
+ --out->hole_count;
+
+ if (!out->hole_count) {
+ /* all holes filled, we can write the buffer */
+ ret = ly_write(out, out->buffered, out->buf_len);
+ out->buf_len = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static LY_ERR
+lys_print_(struct lyout *out, const struct lys_module *module, LYS_OUTFORMAT format, int UNUSED(line_length), int UNUSED(options))
+{
+ LY_ERR ret;
+
+ switch (format) {
+ case LYS_OUT_YANG:
+ ret = yang_print_parsed(out, module);
+ break;
+ case LYS_OUT_YANG_COMPILED:
+ ret = yang_print_compiled(out, module);
+ break;
+ /* TODO not yet implemented
+ case LYS_OUT_YIN:
+ lys_disable_deviations((struct lys_module *)module);
+ ret = yin_print_model(out, module);
+ lys_enable_deviations((struct lys_module *)module);
+ break;
+ case LYS_OUT_TREE:
+ ret = tree_print_model(out, module, target_node, line_length, options);
+ break;
+ case LYS_OUT_INFO:
+ ret = info_print_model(out, module, target_node);
+ break;
+ case LYS_OUT_JSON:
+ ret = jsons_print_model(out, module, target_node);
+ break;
+ */
+ default:
+ LOGERR(module->ctx, LY_EINVAL, "Unknown output format.");
+ ret = LY_EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+API LY_ERR
+lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, f, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+
+ out.type = LYOUT_STREAM;
+ out.method.f = f;
+
+ return lys_print_(&out, module, format, line_length, options);
+}
+
+API LY_ERR
+lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ FILE *f;
+ LY_ERR ret;
+
+ LY_CHECK_ARG_RET(NULL, path, module, LY_EINVAL);
+
+ f = fopen(path, "w");
+ if (!f) {
+ LOGERR(module->ctx, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
+ return LY_ESYS;
+ }
+
+ ret = lys_print_file(f, module, format, line_length, options);
+ fclose(f);
+ return ret;
+}
+
+API LY_ERR
+lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, fd >= 0, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+
+ out.type = LYOUT_FD;
+ out.method.fd = fd;
+
+ return lys_print_(&out, module, format, line_length, options);
+}
+
+API LY_ERR
+lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ struct lyout out;
+ LY_ERR r;
+
+ LY_CHECK_ARG_RET(NULL, strp, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+
+ out.type = LYOUT_MEMORY;
+
+ r = lys_print_(&out, module, format, line_length, options);
+
+ *strp = out.method.mem.buf;
+ return r;
+}
+
+API LY_ERR
+lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lys_module *module,
+ LYS_OUTFORMAT format, int line_length, int options)
+{
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, writeclb, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+
+ out.type = LYOUT_CALLBACK;
+ out.method.clb.f = writeclb;
+ out.method.clb.arg = arg;
+
+ return lys_print_(&out, module, format, line_length, options);
+}
diff --git a/src/printer_internal.h b/src/printer_internal.h
new file mode 100644
index 0000000..4d61285
--- /dev/null
+++ b/src/printer_internal.h
@@ -0,0 +1,80 @@
+/**
+ * @file printer_internal.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Internal structures and functions for libyang
+ *
+ * Copyright (c) 2015-2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PRINTER_INTERNAL_H_
+#define LY_PRINTER_INTERNAL_H_
+
+#include "printer_schema.h"
+
+typedef enum LYOUT_TYPE {
+ LYOUT_FD, /**< file descriptor */
+ LYOUT_STREAM, /**< FILE stream */
+ LYOUT_MEMORY, /**< memory */
+ LYOUT_CALLBACK /**< print via provided callback */
+} LYOUT_TYPE;
+
+struct lyout {
+ LYOUT_TYPE type;
+ union {
+ int fd;
+ FILE *f;
+ struct {
+ char *buf;
+ size_t len;
+ size_t size;
+ } mem;
+ struct {
+ ssize_t (*f)(void *arg, const void *buf, size_t count);
+ void *arg;
+ } clb;
+ } method;
+
+ /* buffer for holes */
+ char *buffered;
+ size_t buf_len;
+ size_t buf_size;
+
+ /* hole counter */
+ size_t hole_count;
+};
+
+struct ext_substmt_info_s {
+ const char *name;
+ const char *arg;
+ int flags;
+#define SUBST_FLAG_YIN 0x1 /**< has YIN element */
+#define SUBST_FLAG_ID 0x2 /**< the value is identifier -> no quotes */
+};
+
+/* filled in printer.c */
+extern struct ext_substmt_info_s ext_substmt_info[];
+
+
+/**
+ * @brief
+ */
+LY_ERR yang_print_parsed(struct lyout *out, const struct lys_module *module);
+
+/**
+ * @brief
+ */
+LY_ERR yang_print_compiled(struct lyout *out, const struct lys_module *module);
+
+LY_ERR ly_print(struct lyout *out, const char *format, ...);
+
+void ly_print_flush(struct lyout *out);
+
+LY_ERR ly_write(struct lyout *out, const char *buf, size_t count);
+
+#endif /* LY_PRINTER_INTERNAL_H_ */
diff --git a/src/printer_schema.h b/src/printer_schema.h
new file mode 100644
index 0000000..48d71b0
--- /dev/null
+++ b/src/printer_schema.h
@@ -0,0 +1,83 @@
+/**
+ * @file printer_schema.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Schema printers for libyang
+ *
+ * Copyright (c) 2015-2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PRINTER_SCHEMA_H_
+#define LY_PRINTER_SCHEMA_H_
+
+#include <unistd.h>
+
+/**
+ * @brief Print schema tree in the specified format into a memory block.
+ * It is up to caller to free the returned string by free().
+ *
+ * @param[out] strp Pointer to store the resulting dump.
+ * @param[in] module Schema tree to print.
+ * @param[in] format Schema output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE printer.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return 0 on success, 1 on failure (#ly_errno is set).
+ */
+LY_ERR lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options);
+
+/**
+ * @brief Print schema tree in the specified format into a file descriptor.
+ *
+ * @param[in] module Schema tree to print.
+ * @param[in] fd File descriptor where to print the data.
+ * @param[in] format Schema output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE format.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return 0 on success, 1 on failure (#ly_errno is set).
+ */
+LY_ERR lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options);
+
+/**
+ * @brief Print schema tree in the specified format into a file stream.
+ *
+ * @param[in] module Schema tree to print.
+ * @param[in] f File stream where to print the schema.
+ * @param[in] format Schema output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE printer.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return 0 on success, 1 on failure (#ly_errno is set).
+ */
+LY_ERR lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options);
+
+/**
+ * @brief Print schema tree in the specified format into a file.
+ *
+ * @param[in] path File where to print the schema.
+ * @param[in] module Schema tree to print.
+ * @param[in] format Schema output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE printer.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return 0 on success, 1 on failure (#ly_errno is set).
+ */
+LY_ERR lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options);
+
+/**
+ * @brief Print schema tree in the specified format using a provided callback.
+ *
+ * @param[in] module Schema tree to print.
+ * @param[in] writeclb Callback function to write the data (see write(1)).
+ * @param[in] arg Optional caller-specific argument to be passed to the \p writeclb callback.
+ * @param[in] format Schema output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE printer.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return LY_ERR value.
+ */
+LY_ERR lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg,
+ const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options);
+
+#endif /* LY_PRINTER_SCHEMA_H_ */
diff --git a/src/printer_yang.c b/src/printer_yang.c
new file mode 100755
index 0000000..51d0960
--- /dev/null
+++ b/src/printer_yang.c
@@ -0,0 +1,1401 @@
+/**
+ * @file printer_yang.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief YANG printer
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "common.h"
+
+#include "printer_internal.h"
+#include "tree_schema.h"
+#include "tree_schema_internal.h"
+
+#define LEVEL ctx->level
+#define INDENT (LEVEL)*2,""
+
+struct ypr_ctx {
+ struct lyout *out;
+ unsigned int level;
+ const struct lys_module *module;
+};
+
+static void
+ypr_encode(struct lyout *out, const char *text, int len)
+{
+ int i, start_len;
+ const char *start;
+ char special = 0;
+
+ if (!len) {
+ return;
+ }
+
+ if (len < 0) {
+ len = strlen(text);
+ }
+
+ start = text;
+ start_len = 0;
+ for (i = 0; i < len; ++i) {
+ switch (text[i]) {
+ case '\n':
+ case '\t':
+ case '\"':
+ case '\\':
+ special = text[i];
+ break;
+ default:
+ ++start_len;
+ break;
+ }
+
+ if (special) {
+ ly_write(out, start, start_len);
+ switch (special) {
+ case '\n':
+ ly_write(out, "\\n", 2);
+ break;
+ case '\t':
+ ly_write(out, "\\t", 2);
+ break;
+ case '\"':
+ ly_write(out, "\\\"", 2);
+ break;
+ case '\\':
+ ly_write(out, "\\\\", 2);
+ break;
+ }
+
+ start += start_len + 1;
+ start_len = 0;
+
+ special = 0;
+ }
+ }
+
+ ly_write(out, start, start_len);
+}
+
+static void
+ypr_open(struct lyout *out, int *flag)
+{
+ if (flag && !*flag) {
+ *flag = 1;
+ ly_print(out, " {\n");
+ }
+}
+
+static void
+ypr_close(struct ypr_ctx *ctx, int flag)
+{
+ if (flag) {
+ ly_print(ctx->out, "%*s}\n", INDENT);
+ } else {
+ ly_print(ctx->out, ";\n");
+ }
+}
+
+static void
+ypr_text(struct ypr_ctx *ctx, const char *name, const char *text, int singleline, int closed)
+{
+ const char *s, *t;
+
+ if (singleline) {
+ ly_print(ctx->out, "%*s%s \"", INDENT, name);
+ } else {
+ ly_print(ctx->out, "%*s%s\n", INDENT, name);
+ LEVEL++;
+
+ ly_print(ctx->out, "%*s\"", INDENT);
+ }
+ t = text;
+ while ((s = strchr(t, '\n'))) {
+ ypr_encode(ctx->out, t, s - t);
+ ly_print(ctx->out, "\n");
+ t = s + 1;
+ if (*t != '\n') {
+ ly_print(ctx->out, "%*s ", INDENT);
+ }
+ }
+
+ ypr_encode(ctx->out, t, strlen(t));
+ if (closed) {
+ ly_print(ctx->out, "\";\n");
+ } else {
+ ly_print(ctx->out, "\"");
+ }
+ if (!singleline) {
+ LEVEL--;
+ }
+}
+
+static void
+ypr_parsed_stmt(struct ypr_ctx *ctx, struct lysp_stmt *stmt)
+{
+ struct lysp_stmt *childstmt;
+ const char *s, *t;
+
+ if (stmt->arg) {
+ if (stmt->flags) {
+ ly_print(ctx->out, "%*s%s\n", INDENT, stmt->stmt);
+ LEVEL++;
+ ly_print(ctx->out, "%*s%c", INDENT, (stmt->flags & LYS_DOUBLEQUOTED) ? '\"' : '\'');
+ t = stmt->arg;
+ while ((s = strchr(t, '\n'))) {
+ ypr_encode(ctx->out, t, s - t);
+ ly_print(ctx->out, "\n");
+ t = s + 1;
+ if (*t != '\n') {
+ ly_print(ctx->out, "%*s ", INDENT);
+ }
+ }
+ LEVEL--;
+ ypr_encode(ctx->out, t, strlen(t));
+ ly_print(ctx->out, "%c%s", (stmt->flags & LYS_DOUBLEQUOTED) ? '\"' : '\'', stmt->child ? " {\n" : ";\n");
+ } else {
+ ly_print(ctx->out, "%*s%s %s%s", INDENT, stmt->stmt, stmt->arg, stmt->child ? " {\n" : ";\n");
+ }
+ } else {
+ ly_print(ctx->out, "%*s%s%s", INDENT, stmt->stmt, stmt->child ? " {\n" : ";\n");
+ }
+
+ if (stmt->child) {
+ LEVEL++;
+ LY_LIST_FOR(stmt->child, childstmt) {
+ ypr_parsed_stmt(ctx, childstmt);
+ }
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+ }
+}
+
+/**
+ * @param[in] count Number of extensions to print, 0 to print them all.
+ */
+static void
+ypr_parsed_extension_instances(struct ypr_ctx *ctx, LYEXT_SUBSTMT substmt, uint8_t substmt_index,
+ struct lysp_ext_instance *ext, int *flag, unsigned int count)
+{
+ unsigned int u;
+ struct lysp_stmt *stmt;
+
+ if (!count && ext) {
+ count = LY_ARRAY_SIZE(ext);
+ }
+ LY_ARRAY_FOR(ext, u) {
+ if (!count) {
+ break;
+ }
+ if (ext->insubstmt == substmt && ext->insubstmt_index == substmt_index) {
+ ypr_open(ctx->out, flag);
+ if (ext[u].argument) {
+ ly_print(ctx->out, "%*s%s %s%s", INDENT, ext[u].name, ext[u].argument, ext[u].child ? " {\n" : ";\n");
+ } else {
+ ly_print(ctx->out, "%*s%s%s", INDENT, ext[u].name, ext[u].child ? " {\n" : ";\n");
+ }
+
+ if (ext[u].child) {
+ LEVEL++;
+ LY_LIST_FOR(ext[u].child, stmt) {
+ ypr_parsed_stmt(ctx, stmt);
+ }
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+ }
+ }
+ count--;
+ }
+}
+
+static void
+ypr_parsed_substmt(struct ypr_ctx *ctx, LYEXT_SUBSTMT substmt, uint8_t substmt_index, const char *text, struct lysp_ext_instance *ext)
+{
+ unsigned int u;
+ int extflag = 0;
+
+ if (!text) {
+ /* nothing to print */
+ return;
+ }
+
+ if (ext_substmt_info[substmt].flags & SUBST_FLAG_ID) {
+ ly_print(ctx->out, "%*s%s %s", INDENT, ext_substmt_info[substmt].name, text);
+ } else {
+ ypr_text(ctx, ext_substmt_info[substmt].name, text,
+ (ext_substmt_info[substmt].flags & SUBST_FLAG_YIN) ? 0 : 1, 0);
+ }
+
+ LEVEL++;
+ LY_ARRAY_FOR(ext, u) {
+ if (ext[u].insubstmt != substmt || ext[u].insubstmt_index != substmt_index) {
+ continue;
+ }
+ ypr_parsed_extension_instances(ctx, substmt, substmt_index, &ext[u], &extflag, 1);
+ }
+ LEVEL--;
+ ypr_close(ctx, extflag);
+}
+
+static void
+ypr_parsed_unsigned(struct ypr_ctx *ctx, LYEXT_SUBSTMT substmt, uint8_t substmt_index, struct lysp_ext_instance *exts,
+ unsigned int attr_value, int *flag)
+{
+ char *str;
+
+ if (asprintf(&str, "%u", attr_value) == -1) {
+ LOGMEM(ctx->module->ctx);
+ return;
+ }
+ ypr_open(ctx->out, flag);
+ ypr_parsed_substmt(ctx, substmt, substmt_index, str, exts);
+ free(str);
+}
+
+static void
+ypr_parsed_signed(struct ypr_ctx *ctx, LYEXT_SUBSTMT substmt, uint8_t substmt_index, struct lysp_ext_instance *exts,
+ signed int attr_value, int *flag)
+{
+ char *str;
+
+ if (asprintf(&str, "%d", attr_value) == -1) {
+ LOGMEM(ctx->module->ctx);
+ return;
+ }
+ ypr_open(ctx->out, flag);
+ ypr_parsed_substmt(ctx, substmt, substmt_index, str, exts);
+ free(str);
+}
+
+static void
+ypr_parsed_revision(struct ypr_ctx *ctx, const struct lysp_revision *rev)
+{
+ if (rev->dsc || rev->ref || rev->exts) {
+ ly_print(ctx->out, "%*srevision %s {\n", INDENT, rev->date);
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, rev->exts, NULL, 0);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DESCRIPTION, 0, rev->dsc, rev->exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REFERENCE, 0, rev->ref, rev->exts);
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+ } else {
+ ly_print(ctx->out, "%*srevision %s;\n", INDENT, rev->date);
+ }
+}
+
+static void
+ypr_parsed_mandatory(struct ypr_ctx *ctx, uint16_t flags, struct lysp_ext_instance *exts, int *flag)
+{
+ if (flags & LYS_MAND_MASK) {
+ ypr_open(ctx->out, flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MANDATORY, 0, (flags & LYS_MAND_TRUE) ? "true" : "false", exts);
+ }
+}
+
+static void
+ypr_parsed_config(struct ypr_ctx *ctx, uint16_t flags, struct lysp_ext_instance *exts, int *flag)
+{
+ if (flags & LYS_CONFIG_MASK) {
+ ypr_open(ctx->out, flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_CONFIG, 0, (flags & LYS_CONFIG_W) ? "true" : "false", exts);
+ }
+}
+
+static void
+ypr_parsed_status(struct ypr_ctx *ctx, uint16_t flags, struct lysp_ext_instance *exts, int *flag)
+{
+ const char *status = NULL;
+
+ if (flags & LYS_STATUS_CURR) {
+ ypr_open(ctx->out, flag);
+ status = "current";
+ } else if (flags & LYS_STATUS_DEPRC) {
+ ypr_open(ctx->out, flag);
+ status = "deprecated";
+ } else if (flags & LYS_STATUS_OBSLT) {
+ ypr_open(ctx->out, flag);
+ status = "obsolete";
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_STATUS, 0, status, exts);
+}
+
+static void
+ypr_description(struct ypr_ctx *ctx, const char *dsc, struct lysp_ext_instance *exts, int *flag)
+{
+ if (dsc) {
+ ypr_open(ctx->out, flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DESCRIPTION, 0, dsc, exts);
+ }
+}
+
+static void
+ypr_reference(struct ypr_ctx *ctx, const char *ref, struct lysp_ext_instance *exts, int *flag)
+{
+ if (ref) {
+ ypr_open(ctx->out, flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REFERENCE, 0, ref, exts);
+ }
+}
+
+static void
+ypr_parsed_iffeatures(struct ypr_ctx *ctx, const char **iff, struct lysp_ext_instance *exts, int *flag)
+{
+ unsigned int u;
+ int extflag;
+
+ LY_ARRAY_FOR(iff, u) {
+ ypr_open(ctx->out, flag);
+ extflag = 0;
+
+ ly_print(ctx->out, "%*sif-feature \"%s\"", INDENT, iff[u]);
+
+ /* extensions */
+ LEVEL++;
+ LY_ARRAY_FOR(exts, u) {
+ if (exts[u].insubstmt != LYEXT_SUBSTMT_IFFEATURE || exts[u].insubstmt_index != u) {
+ continue;
+ }
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_IFFEATURE, u, &exts[u], &extflag, 1);
+ }
+ LEVEL--;
+ ypr_close(ctx, extflag);
+ }
+}
+
+static void
+ypr_parsed_extension(struct ypr_ctx *ctx, const struct lysp_ext *ext)
+{
+ int flag = 0, flag2 = 0;
+ unsigned int i;
+
+ ly_print(ctx->out, "%*sextension %s", INDENT, ext->name);
+ LEVEL++;
+
+ if (ext->exts) {
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, ext->exts, &flag, 0);
+ }
+
+ if (ext->argument) {
+ ypr_open(ctx->out, &flag);
+ ly_print(ctx->out, "%*sargument %s", INDENT, ext->argument);
+ if (ext->exts) {
+ LEVEL++;
+ i = -1;
+ while ((i = lysp_ext_instance_iter(ext->exts, i + 1, LYEXT_SUBSTMT_ARGUMENT)) != LY_ARRAY_SIZE(ext->exts)) {
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_ARGUMENT, 0, &ext->exts[i], &flag2, 1);
+ }
+ LEVEL--;
+ }
+ if ((ext->flags & LYS_YINELEM_MASK) ||
+ (ext->exts && lysp_ext_instance_iter(ext->exts, 0, LYEXT_SUBSTMT_YINELEM) != LY_ARRAY_SIZE(ext->exts))) {
+ ypr_open(ctx->out, &flag2);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_YINELEM, 0, (ext->flags & LYS_YINELEM_TRUE) ? "true" : "false", ext->exts);
+ }
+ ypr_close(ctx, flag2);
+ }
+
+ ypr_parsed_status(ctx, ext->flags, ext->exts, &flag);
+ ypr_description(ctx, ext->dsc, ext->exts, &flag);
+ ypr_reference(ctx, ext->ref, ext->exts, &flag);
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_feature(struct ypr_ctx *ctx, const struct lysp_feature *feat)
+{
+ int flag = 0;
+
+ ly_print(ctx->out, "\n%*sfeature %s", INDENT, feat->name);
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, feat->exts, &flag, 0);
+ ypr_parsed_iffeatures(ctx, feat->iffeatures, feat->exts, &flag);
+ ypr_parsed_status(ctx, feat->flags, feat->exts, &flag);
+ ypr_description(ctx, feat->dsc, feat->exts, &flag);
+ ypr_reference(ctx, feat->ref, feat->exts, &flag);
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_identity(struct ypr_ctx *ctx, const struct lysp_ident *ident)
+{
+ int flag = 0;
+ unsigned int u;
+
+ ly_print(ctx->out, "\n%*sidentity %s", INDENT, ident->name);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, ident->exts, &flag, 0);
+ ypr_parsed_iffeatures(ctx, ident->iffeatures, ident->exts, &flag);
+
+ LY_ARRAY_FOR(ident->bases, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_BASE, u, ident->bases[u], ident->exts);
+ }
+
+ ypr_parsed_status(ctx, ident->flags, ident->exts, &flag);
+ ypr_description(ctx, ident->dsc, ident->exts, &flag);
+ ypr_reference(ctx, ident->ref, ident->exts, &flag);
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_restr(struct ypr_ctx *ctx, const struct lysp_restr *restr, const char *name, int *flag)
+{
+ int inner_flag = 0;
+
+ if (!restr) {
+ return;
+ }
+
+ ypr_open(ctx->out, flag);
+ ly_print(ctx->out, "%*s%s \"", INDENT, name);
+ ypr_encode(ctx->out, (restr->arg[0] != 0x15 && restr->arg[0] != 0x06) ? restr->arg : &restr->arg[1], -1);
+ ly_print(ctx->out, "\"");
+
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, restr->exts, &inner_flag, 0);
+ if (restr->arg[0] == 0x15) {
+ /* special byte value in pattern's expression: 0x15 - invert-match, 0x06 - match */
+ ypr_open(ctx->out, &inner_flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MODIFIER, 0, "invert-match", restr->exts);
+ }
+ if (restr->emsg) {
+ ypr_open(ctx->out, &inner_flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_ERRMSG, 0, restr->emsg, restr->exts);
+ }
+ if (restr->eapptag) {
+ ypr_open(ctx->out, &inner_flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_ERRTAG, 0, restr->eapptag, restr->exts);
+ }
+ if (restr->dsc != NULL) {
+ ypr_open(ctx->out, &inner_flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DESCRIPTION, 0, restr->dsc,restr->exts);
+ }
+ if (restr->ref != NULL) {
+ ypr_open(ctx->out, &inner_flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REFERENCE, 0, restr->ref, restr->exts);
+ }
+ LEVEL--;
+ ypr_close(ctx, inner_flag);
+}
+
+static void
+ypr_parsed_when(struct ypr_ctx *ctx, struct lysp_when *when, int *flag)
+{
+ int inner_flag = 0;
+
+ if (!when) {
+ return;
+ }
+ ypr_open(ctx->out, flag);
+
+ ly_print(ctx->out, "%*swhen \"", INDENT);
+ ypr_encode(ctx->out, when->cond, -1);
+ ly_print(ctx->out, "\"");
+
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, when->exts, &inner_flag, 0);
+ ypr_description(ctx, when->dsc, when->exts, &inner_flag);
+ ypr_reference(ctx, when->ref, when->exts, &inner_flag);
+ LEVEL--;
+ ypr_close(ctx, inner_flag);
+}
+
+static void
+ypr_parsed_enum(struct ypr_ctx *ctx, const struct lysp_type_enum *items, LY_DATA_TYPE type, int *flag)
+{
+ unsigned int u;
+ int inner_flag;
+
+ LY_ARRAY_FOR(items, u) {
+ ypr_open(ctx->out, flag);
+ ly_print(ctx->out, "%*s%s \"", INDENT, type == LY_TYPE_BITS ? "bit" : "enum");
+ ypr_encode(ctx->out, items[u].name, -1);
+ ly_print(ctx->out, "\"");
+ inner_flag = 0;
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, items[u].exts, &inner_flag, 0);
+ ypr_parsed_iffeatures(ctx, items[u].iffeatures, items[u].exts, &inner_flag);
+ if (items[u].flags & LYS_SET_VALUE) {
+ if (type == LY_TYPE_BITS) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_POSITION, 0, items[u].exts, items[u].value, &inner_flag);
+ } else { /* LY_TYPE_ENUM */
+ ypr_parsed_signed(ctx, LYEXT_SUBSTMT_VALUE, 0, items[u].exts, items[u].value, &inner_flag);
+ }
+ }
+ ypr_parsed_status(ctx, items[u].flags, items[u].exts, &inner_flag);
+ ypr_description(ctx, items[u].dsc, items[u].exts, &inner_flag);
+ ypr_reference(ctx, items[u].ref, items[u].exts, &inner_flag);
+ LEVEL--;
+ ypr_close(ctx, inner_flag);
+ }
+}
+
+static void
+ypr_parsed_type(struct ypr_ctx *ctx, const struct lysp_type *type)
+{
+ unsigned int u;
+ int flag = 0;
+
+ ly_print(ctx->out, "%*stype %s", INDENT, type->name);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, type->exts, &flag, 0);
+
+ ypr_parsed_restr(ctx, type->range, "range", &flag);
+ ypr_parsed_restr(ctx, type->length, "length", &flag);
+ LY_ARRAY_FOR(type->patterns, u) {
+ ypr_parsed_restr(ctx, &type->patterns[u], "pattern", &flag);
+ }
+ ypr_parsed_enum(ctx, type->bits, LY_TYPE_BITS, &flag);
+ ypr_parsed_enum(ctx, type->enums, LY_TYPE_ENUM, &flag);
+
+ if (type->path) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_PATH, 0, type->path, type->exts);
+ }
+ if (type->flags & LYS_SET_REQINST) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REQINSTANCE, 0, type->require_instance ? "true" : "false", type->exts);
+ }
+ if (type->flags & LYS_SET_FRDIGITS) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_FRACDIGITS, 0, type->exts, type->fraction_digits, &flag);
+ }
+ LY_ARRAY_FOR(type->bases, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_BASE, u, type->bases[u], type->exts);
+ }
+ LY_ARRAY_FOR(type->types, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_type(ctx, &type->types[u]);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_typedef(struct ypr_ctx *ctx, const struct lysp_tpdf *tpdf)
+{
+ ly_print(ctx->out, "\n%*stypedef %s {\n", INDENT, tpdf->name);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, tpdf->exts, NULL, 0);
+
+ ypr_parsed_type(ctx, &tpdf->type);
+
+ if (tpdf->units) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNITS, 0, tpdf->units, tpdf->exts);
+ }
+ if (tpdf->dflt) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, 0, tpdf->dflt, tpdf->exts);
+ }
+
+ ypr_parsed_status(ctx, tpdf->flags, tpdf->exts, NULL);
+ ypr_description(ctx, tpdf->dsc, tpdf->exts, NULL);
+ ypr_reference(ctx, tpdf->ref, tpdf->exts, NULL);
+
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+}
+
+static void ypr_parsed_node(struct ypr_ctx *ctx, const struct lysp_node *node);
+static void ypr_parsed_action(struct ypr_ctx *ctx, const struct lysp_action *action);
+
+static void
+ypr_parsed_grouping(struct ypr_ctx *ctx, const struct lysp_grp *grp)
+{
+ unsigned int u;
+ int flag = 0;
+ struct lysp_node *data;
+
+ ly_print(ctx->out, "\n%*sgrouping %s", INDENT, grp->name);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, grp->exts, &flag, 0);
+ ypr_parsed_status(ctx, grp->flags, grp->exts, NULL);
+ ypr_description(ctx, grp->dsc, grp->exts, NULL);
+ ypr_reference(ctx, grp->ref, grp->exts, NULL);
+
+ LY_ARRAY_FOR(grp->typedefs, u) {
+ ypr_parsed_typedef(ctx, &grp->typedefs[u]);
+ }
+
+ LY_ARRAY_FOR(grp->groupings, u) {
+ ypr_parsed_grouping(ctx, &grp->groupings[u]);
+ }
+
+ LY_LIST_FOR(grp->data, data) {
+ ypr_parsed_node(ctx, data);
+ }
+
+ LY_ARRAY_FOR(grp->actions, u) {
+ ypr_parsed_action(ctx, &grp->actions[u]);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_inout(struct ypr_ctx *ctx, const struct lysp_action_inout *inout, int *flag)
+{
+ unsigned int u;
+ struct lysp_node *data;
+
+ if (!inout->nodetype) {
+ /* nodetype not set -> input/output is empty */
+ return;
+ }
+ ypr_open(ctx->out, flag);
+
+ ly_print(ctx->out, "\n%*s%s {\n", INDENT, (inout->nodetype == LYS_INPUT ? "input" : "output"));
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, inout->exts, NULL, 0);
+ LY_ARRAY_FOR(inout->musts, u) {
+ ypr_parsed_restr(ctx, &inout->musts[u], "must", NULL);
+ }
+ LY_ARRAY_FOR(inout->typedefs, u) {
+ ypr_parsed_typedef(ctx, &inout->typedefs[u]);
+ }
+ LY_ARRAY_FOR(inout->groupings, u) {
+ ypr_parsed_grouping(ctx, &inout->groupings[u]);
+ }
+
+ LY_LIST_FOR(inout->data, data) {
+ ypr_parsed_node(ctx, data);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, 1);
+}
+
+static void
+ypr_parsed_notification(struct ypr_ctx *ctx, const struct lysp_notif *notif)
+{
+ unsigned int u;
+ int flag = 0;
+ struct lysp_node *data;
+
+ ly_print(ctx->out, "%*snotification %s", INDENT, notif->name);
+
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, notif->exts, &flag, 0);
+ ypr_parsed_iffeatures(ctx, notif->iffeatures, notif->exts, &flag);
+
+ LY_ARRAY_FOR(notif->musts, u) {
+ ypr_parsed_restr(ctx, ¬if->musts[u], "must", &flag);
+ }
+ ypr_parsed_status(ctx, notif->flags, notif->exts, &flag);
+ ypr_description(ctx, notif->dsc, notif->exts, &flag);
+ ypr_reference(ctx, notif->ref, notif->exts, &flag);
+
+ LY_ARRAY_FOR(notif->typedefs, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_typedef(ctx, ¬if->typedefs[u]);
+ }
+
+ LY_ARRAY_FOR(notif->groupings, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_grouping(ctx, ¬if->groupings[u]);
+ }
+
+ LY_LIST_FOR(notif->data, data) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_node(ctx, data);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_action(struct ypr_ctx *ctx, const struct lysp_action *action)
+{
+ unsigned int u;
+ int flag = 0;
+
+ ly_print(ctx->out, "%*s%s %s", INDENT, action->parent ? "action" : "rpc", action->name);
+
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, action->exts, &flag, 0);
+ ypr_parsed_iffeatures(ctx, action->iffeatures, action->exts, &flag);
+ ypr_parsed_status(ctx, action->flags, action->exts, &flag);
+ ypr_description(ctx, action->dsc, action->exts, &flag);
+ ypr_reference(ctx, action->ref, action->exts, &flag);
+
+ LY_ARRAY_FOR(action->typedefs, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_typedef(ctx, &action->typedefs[u]);
+ }
+
+ LY_ARRAY_FOR(action->groupings, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_grouping(ctx, &action->groupings[u]);
+ }
+
+ ypr_parsed_inout(ctx, &action->input, &flag);
+ ypr_parsed_inout(ctx, &action->output, &flag);
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_node_common1(struct ypr_ctx *ctx, const struct lysp_node *node, int *flag)
+{
+ ly_print(ctx->out, "\n%*s%s %s%s", INDENT, lys_nodetype2str(node->nodetype), node->name, flag ? "" : " {\n");
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, node->exts, flag, 0);
+ ypr_parsed_when(ctx, node->when, flag);
+ ypr_parsed_iffeatures(ctx, node->iffeatures, node->exts, flag);
+}
+
+static void
+ypr_parsed_node_common2(struct ypr_ctx *ctx, const struct lysp_node *node, int *flag)
+{
+ ypr_parsed_config(ctx, node->flags, node->exts, flag);
+ if (node->nodetype & (LYS_CHOICE | LYS_LEAF | LYS_ANYDATA)) {
+ ypr_parsed_mandatory(ctx, node->flags, node->exts, flag);
+ }
+ ypr_parsed_status(ctx, node->flags, node->exts, flag);
+ ypr_description(ctx, node->dsc, node->exts, flag);
+ ypr_reference(ctx, node->ref, node->exts, flag);
+
+}
+
+static void
+ypr_parsed_container(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ unsigned int u;
+ int flag = 0;
+ struct lysp_node *child;
+ struct lysp_node_container *cont = (struct lysp_node_container *)node;
+
+ ypr_parsed_node_common1(ctx, node, &flag);
+
+ LY_ARRAY_FOR(cont->musts, u) {
+ ypr_parsed_restr(ctx, &cont->musts[u], "must", &flag);
+ }
+ if (cont->presence) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_PRESENCE, 0, cont->presence, cont->exts);
+ }
+
+ ypr_parsed_node_common2(ctx, node, &flag);
+
+ LY_ARRAY_FOR(cont->typedefs, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_typedef(ctx, &cont->typedefs[u]);
+ }
+
+ LY_ARRAY_FOR(cont->groupings, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_grouping(ctx, &cont->groupings[u]);
+ }
+
+ LY_LIST_FOR(cont->child, child) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_node(ctx, child);
+ }
+
+ LY_ARRAY_FOR(cont->actions, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_action(ctx, &cont->actions[u]);
+ }
+
+ LY_ARRAY_FOR(cont->notifs, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_notification(ctx, &cont->notifs[u]);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_choice(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ int flag = 0;
+ struct lysp_node *child;
+ struct lysp_node_choice *choice = (struct lysp_node_choice *)node;
+
+ ypr_parsed_node_common1(ctx, node, &flag);
+
+ if (choice->dflt) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, 0, choice->dflt, choice->exts);
+ }
+
+ ypr_parsed_node_common2(ctx, node, &flag);
+
+ LY_LIST_FOR(choice->child, child) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_node(ctx, child);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_leaf(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ unsigned int u;
+ struct lysp_node_leaf *leaf = (struct lysp_node_leaf *)node;
+
+ ypr_parsed_node_common1(ctx, node, NULL);
+
+ ypr_parsed_type(ctx, &leaf->type);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNITS, 0, leaf->units, leaf->exts);
+ LY_ARRAY_FOR(leaf->musts, u) {
+ ypr_parsed_restr(ctx, &leaf->musts[u], "must", NULL);
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, 0, leaf->dflt, leaf->exts);
+
+ ypr_parsed_node_common2(ctx, node, NULL);
+
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+}
+
+static void
+ypr_parsed_leaflist(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ unsigned int u;
+ struct lysp_node_leaflist *llist = (struct lysp_node_leaflist *)node;
+
+ ypr_parsed_node_common1(ctx, node, NULL);
+
+ ypr_parsed_type(ctx, &llist->type);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNITS, 0, llist->units, llist->exts);
+ LY_ARRAY_FOR(llist->musts, u) {
+ ypr_parsed_restr(ctx, &llist->musts[u], "must", NULL);
+ }
+ LY_ARRAY_FOR(llist->dflts, u) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, u, llist->dflts[u], llist->exts);
+ }
+
+ ypr_parsed_config(ctx, node->flags, node->exts, NULL);
+
+ if (llist->flags & LYS_SET_MIN) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MIN, 0, llist->exts, llist->min, NULL);
+ }
+ if (llist->flags & LYS_SET_MAX) {
+ if (llist->max) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MAX, 0, llist->exts, llist->max, NULL);
+ } else {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MAX, 0, "unbounded", llist->exts);
+ }
+ }
+
+ if (llist->flags & LYS_ORDBY_MASK) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_ORDEREDBY, 0, (llist->flags & LYS_ORDBY_USER) ? "user" : "system", llist->exts);
+ }
+
+ ypr_parsed_status(ctx, node->flags, node->exts, NULL);
+ ypr_description(ctx, node->dsc, node->exts, NULL);
+ ypr_reference(ctx, node->ref, node->exts, NULL);
+
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+}
+
+static void
+ypr_parsed_list(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ unsigned int u;
+ int flag = 0;
+ struct lysp_node *child;
+ struct lysp_node_list *list = (struct lysp_node_list *)node;
+
+ ypr_parsed_node_common1(ctx, node, &flag);
+
+ LY_ARRAY_FOR(list->musts, u) {
+ ypr_parsed_restr(ctx, &list->musts[u], "must", NULL);
+ }
+ if (list->key) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_KEY, 0, list->key, list->exts);
+ }
+ LY_ARRAY_FOR(list->uniques, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNIQUE, u, list->uniques[u], list->exts);
+ }
+
+ ypr_parsed_config(ctx, node->flags, node->exts, NULL);
+
+ if (list->flags & LYS_SET_MIN) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MIN, 0, list->exts, list->min, NULL);
+ }
+ if (list->flags & LYS_SET_MAX) {
+ if (list->max) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MAX, 0, list->exts, list->max, NULL);
+ } else {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MAX, 0, "unbounded", list->exts);
+ }
+ }
+
+ if (list->flags & LYS_ORDBY_MASK) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_ORDEREDBY, 0, (list->flags & LYS_ORDBY_USER) ? "user" : "system", list->exts);
+ }
+
+ ypr_parsed_status(ctx, node->flags, node->exts, NULL);
+ ypr_description(ctx, node->dsc, node->exts, NULL);
+ ypr_reference(ctx, node->ref, node->exts, NULL);
+
+ LY_ARRAY_FOR(list->typedefs, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_typedef(ctx, &list->typedefs[u]);
+ }
+
+ LY_ARRAY_FOR(list->groupings, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_grouping(ctx, &list->groupings[u]);
+ }
+
+ LY_LIST_FOR(list->child, child) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_node(ctx, child);
+ }
+
+ LY_ARRAY_FOR(list->actions, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_action(ctx, &list->actions[u]);
+ }
+
+ LY_ARRAY_FOR(list->notifs, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_notification(ctx, &list->notifs[u]);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_refine(struct ypr_ctx *ctx, struct lysp_refine *refine)
+{
+ unsigned int u;
+ int flag = 0;
+
+ ly_print(ctx->out, "%*srefine \"%s\"", INDENT, refine->nodeid);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, refine->exts, &flag, 0);
+ ypr_parsed_iffeatures(ctx, refine->iffeatures, refine->exts, &flag);
+
+ LY_ARRAY_FOR(refine->musts, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_restr(ctx, &refine->musts[u], "must", NULL);
+ }
+
+ if (refine->presence) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_PRESENCE, 0, refine->presence, refine->exts);
+ }
+
+ LY_ARRAY_FOR(refine->dflts, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, u, refine->dflts[u], refine->exts);
+ }
+
+ ypr_parsed_config(ctx, refine->flags, refine->exts, &flag);
+ ypr_parsed_mandatory(ctx, refine->flags, refine->exts, &flag);
+
+ if (refine->flags & LYS_SET_MIN) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MIN, 0, refine->exts, refine->min, NULL);
+ }
+ if (refine->flags & LYS_SET_MAX) {
+ ypr_open(ctx->out, &flag);
+ if (refine->max) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MAX, 0, refine->exts, refine->max, NULL);
+ } else {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MAX, 0, "unbounded", refine->exts);
+ }
+ }
+
+ ypr_description(ctx, refine->dsc, refine->exts, &flag);
+ ypr_reference(ctx, refine->ref, refine->exts, &flag);
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_augment(struct ypr_ctx *ctx, const struct lysp_augment *aug)
+{
+ unsigned int u;
+ struct lysp_node *child;
+
+ ly_print(ctx->out, "%*saugment \"%s\" {\n", INDENT, aug->nodeid);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, aug->exts, NULL, 0);
+ ypr_parsed_when(ctx, aug->when, NULL);
+ ypr_parsed_iffeatures(ctx, aug->iffeatures, aug->exts, NULL);
+ ypr_parsed_status(ctx, aug->flags, aug->exts, NULL);
+ ypr_description(ctx, aug->dsc, aug->exts, NULL);
+ ypr_reference(ctx, aug->ref, aug->exts, NULL);
+
+ LY_LIST_FOR(aug->child, child) {
+ ypr_parsed_node(ctx, child);
+ }
+
+ LY_ARRAY_FOR(aug->actions, u) {
+ ypr_parsed_action(ctx, &aug->actions[u]);
+ }
+
+ LY_ARRAY_FOR(aug->notifs, u) {
+ ypr_parsed_notification(ctx, &aug->notifs[u]);
+ }
+
+ LEVEL--;
+ ly_print(ctx->out, "%*s}\n", INDENT);
+}
+
+
+static void
+ypr_parsed_uses(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ unsigned int u;
+ int flag = 0;
+ struct lysp_node_uses *uses = (struct lysp_node_uses *)node;
+
+ ypr_parsed_node_common1(ctx, node, &flag);
+ ypr_parsed_node_common2(ctx, node, &flag);
+
+ LY_ARRAY_FOR(uses->refines, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_refine(ctx, &uses->refines[u]);
+ }
+
+ LY_ARRAY_FOR(uses->augments, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_augment(ctx, &uses->augments[u]);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_anydata(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ unsigned int u;
+ int flag = 0;
+ struct lysp_node_anydata *any = (struct lysp_node_anydata *)node;
+
+ ypr_parsed_node_common1(ctx, node, &flag);
+
+ LY_ARRAY_FOR(any->musts, u) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_restr(ctx, &any->musts[u], "must", NULL);
+ }
+
+ ypr_parsed_node_common2(ctx, node, &flag);
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_case(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ int flag = 0;
+ struct lysp_node *child;
+ struct lysp_node_case *cas = (struct lysp_node_case *)node;
+
+ ypr_parsed_node_common1(ctx, node, &flag);
+ ypr_parsed_node_common2(ctx, node, &flag);
+
+ LY_LIST_FOR(cas->child, child) {
+ ypr_open(ctx->out, &flag);
+ ypr_parsed_node(ctx, child);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, flag);
+}
+
+static void
+ypr_parsed_node(struct ypr_ctx *ctx, const struct lysp_node *node)
+{
+ switch (node->nodetype) {
+ case LYS_CONTAINER:
+ ypr_parsed_container(ctx, node);
+ break;
+ case LYS_CHOICE:
+ ypr_parsed_choice(ctx, node);
+ break;
+ case LYS_LEAF:
+ ypr_parsed_leaf(ctx, node);
+ break;
+ case LYS_LEAFLIST:
+ ypr_parsed_leaflist(ctx, node);
+ break;
+ case LYS_LIST:
+ ypr_parsed_list(ctx, node);
+ break;
+ case LYS_USES:
+ ypr_parsed_uses(ctx, node);
+ break;
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ ypr_parsed_anydata(ctx, node);
+ break;
+ case LYS_CASE:
+ ypr_parsed_case(ctx, node);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+ypr_parsed_deviation(struct ypr_ctx *ctx, const struct lysp_deviation *deviation)
+{
+ unsigned int u, v;
+ struct lysp_deviate_add *add;
+ struct lysp_deviate_rpl *rpl;
+ struct lysp_deviate_del *del;
+
+ ly_print(ctx->out, "%*sdeviation \"%s\" {\n", INDENT, deviation->nodeid);
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, deviation->exts, NULL, 0);
+ ypr_description(ctx, deviation->dsc, deviation->exts, NULL);
+ ypr_reference(ctx, deviation->ref, deviation->exts, NULL);
+
+ LY_ARRAY_FOR(deviation->deviates, u) {
+ ly_print(ctx->out, "%*sdeviate ", INDENT);
+ if (deviation->deviates[u].mod == LYS_DEV_NOT_SUPPORTED) {
+ if (deviation->deviates[u].exts) {
+ ly_print(ctx->out, "not-supported {\n");
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, deviation->deviates[u].exts, NULL, 0);
+ } else {
+ ly_print(ctx->out, "not-supported;\n");
+ continue;
+ }
+ } else if (deviation->deviates[u].mod == LYS_DEV_ADD) {
+ add = (struct lysp_deviate_add*)&deviation->deviates[u];
+ ly_print(ctx->out, "add {\n");
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, add->exts, NULL, 0);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNITS, 0, add->units, add->exts);
+ LY_ARRAY_FOR(add->musts, v) {
+ ypr_parsed_restr(ctx, &add->musts[v], "must", NULL);
+ }
+ LY_ARRAY_FOR(add->uniques, v) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNIQUE, v, add->uniques[v], add->exts);
+ }
+ LY_ARRAY_FOR(add->dflts, v) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, v, add->dflts[v], add->exts);
+ }
+ ypr_parsed_config(ctx, add->flags, add->exts, NULL);
+ ypr_parsed_mandatory(ctx, add->flags, add->exts, NULL);
+ if (add->flags & LYS_SET_MIN) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MIN, 0, add->exts, add->min, NULL);
+ }
+ if (add->flags & LYS_SET_MAX) {
+ if (add->max) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MAX, 0, add->exts, add->max, NULL);
+ } else {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MAX, 0, "unbounded", add->exts);
+ }
+ }
+ } else if (deviation->deviates[u].mod == LYS_DEV_REPLACE) {
+ rpl = (struct lysp_deviate_rpl*)&deviation->deviates[u];
+ ly_print(ctx->out, "replace {\n");
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, rpl->exts, NULL, 0);
+ if (rpl->type) {
+ ypr_parsed_type(ctx, rpl->type);
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNITS, 0, rpl->units, rpl->exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, v, rpl->dflt, rpl->exts);
+ ypr_parsed_config(ctx, rpl->flags, rpl->exts, NULL);
+ ypr_parsed_mandatory(ctx, rpl->flags, rpl->exts, NULL);
+ if (rpl->flags & LYS_SET_MIN) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MIN, 0, rpl->exts, rpl->min, NULL);
+ }
+ if (rpl->flags & LYS_SET_MAX) {
+ if (rpl->max) {
+ ypr_parsed_unsigned(ctx, LYEXT_SUBSTMT_MAX, 0, rpl->exts, rpl->max, NULL);
+ } else {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_MAX, 0, "unbounded", rpl->exts);
+ }
+ }
+ } else if (deviation->deviates[u].mod == LYS_DEV_DELETE) {
+ del = (struct lysp_deviate_del*)&deviation->deviates[u];
+ ly_print(ctx->out, "delete {\n");
+ LEVEL++;
+
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, del->exts, NULL, 0);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNITS, 0, del->units, del->exts);
+ LY_ARRAY_FOR(del->musts, v) {
+ ypr_parsed_restr(ctx, &del->musts[v], "must", NULL);
+ }
+ LY_ARRAY_FOR(del->uniques, v) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_UNIQUE, v, del->uniques[v], del->exts);
+ }
+ LY_ARRAY_FOR(del->dflts, v) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DEFAULT, v, del->dflts[v], del->exts);
+ }
+ }
+
+ LEVEL--;
+ ypr_close(ctx, 1);
+ }
+
+ LEVEL--;
+ ypr_close(ctx, 1);
+}
+
+LY_ERR
+yang_print_parsed(struct lyout *out, const struct lys_module *module)
+{
+ unsigned int u;
+ struct lysp_node *data;
+ struct lysp_module *modp = module->parsed;
+ struct ypr_ctx ctx_ = {.out = out, .level = 0, .module = module}, *ctx = &ctx_;
+
+ ly_print(ctx->out, "%*smodule %s {\n", INDENT, module->name);
+ LEVEL++;
+
+ /* module-header-stmts */
+ if (module->version) {
+ if (module->version) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_VERSION, 0, module->version == LYS_VERSION_1_1 ? "1.1" : "1", modp->exts);
+ }
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_NAMESPACE, 0, module->ns, modp->exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_PREFIX, 0, module->prefix, modp->exts);
+
+ /* linkage-stmts */
+ LY_ARRAY_FOR(modp->imports, u) {
+ ly_print(out, "\n%*simport %s {\n", INDENT, modp->imports[u].module->name);
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, modp->imports[u].exts, NULL, 0);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_PREFIX, 0, modp->imports[u].prefix, modp->imports[u].exts);
+ if (modp->imports[u].rev[0]) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REVISIONDATE, 0, modp->imports[u].rev, modp->imports[u].exts);
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DESCRIPTION, 0, modp->imports[u].dsc, modp->imports[u].exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REFERENCE, 0, modp->imports[u].ref, modp->imports[u].exts);
+ LEVEL--;
+ ly_print(out, "%*s}\n", INDENT);
+ }
+ LY_ARRAY_FOR(modp->includes, u) {
+ if (modp->includes[u].rev[0] || modp->includes[u].dsc || modp->includes[u].ref || modp->includes[u].exts) {
+ ly_print(out, "\n%*sinclude %s {\n", INDENT, modp->includes[u].submodule->name);
+ LEVEL++;
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, modp->includes[u].exts, NULL, 0);
+ if (modp->includes[u].rev[0]) {
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REVISIONDATE, 0, modp->includes[u].rev, modp->includes[u].exts);
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DESCRIPTION, 0, modp->includes[u].dsc, modp->includes[u].exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REFERENCE, 0, modp->includes[u].ref, modp->includes[u].exts);
+ LEVEL--;
+ ly_print(out, "%*s}\n", INDENT);
+ } else {
+ ly_print(out, "\n%*sinclude \"%s\";\n", INDENT, modp->includes[u].submodule->name);
+ }
+ }
+
+ /* meta-stmts */
+ if (module->org || module->contact || module->dsc || module->ref) {
+ ly_print(out, "\n");
+ }
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_ORGANIZATION, 0, module->org, modp->exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_CONTACT, 0, module->contact, modp->exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_DESCRIPTION, 0, module->dsc, modp->exts);
+ ypr_parsed_substmt(ctx, LYEXT_SUBSTMT_REFERENCE, 0, module->ref, modp->exts);
+
+ /* revision-stmts */
+ if (modp->revs) {
+ ly_print(out, "\n");
+ }
+ LY_ARRAY_FOR(modp->revs, u) {
+ ypr_parsed_revision(ctx, &modp->revs[u]);
+ }
+ /* body-stmts */
+ LY_ARRAY_FOR(modp->extensions, u) {
+ ly_print(out, "\n");
+ ypr_parsed_extension(ctx, &modp->extensions[u]);
+ }
+ if (modp->exts) {
+ ly_print(out, "\n");
+ ypr_parsed_extension_instances(ctx, LYEXT_SUBSTMT_SELF, 0, module->parsed->exts, NULL, 0);
+ }
+
+ LY_ARRAY_FOR(modp->features, u) {
+ ypr_parsed_feature(ctx, &modp->features[u]);
+ }
+
+ LY_ARRAY_FOR(modp->identities, u) {
+ ypr_parsed_identity(ctx, &modp->identities[u]);
+ }
+
+ LY_ARRAY_FOR(modp->typedefs, u) {
+ ypr_parsed_typedef(ctx, &modp->typedefs[u]);
+ }
+
+ LY_ARRAY_FOR(modp->groupings, u) {
+ ypr_parsed_grouping(ctx, &modp->groupings[u]);
+ }
+
+ LY_LIST_FOR(modp->data, data) {
+ ypr_parsed_node(ctx, data);
+ }
+
+ LY_ARRAY_FOR(modp->augments, u) {
+ ypr_parsed_augment(ctx, &modp->augments[u]);
+ }
+
+ LY_ARRAY_FOR(modp->rpcs, u) {
+ ypr_parsed_action(ctx, &modp->rpcs[u]);
+ }
+
+ LY_ARRAY_FOR(modp->notifs, u) {
+ ypr_parsed_notification(ctx, &modp->notifs[u]);
+ }
+
+ LY_ARRAY_FOR(modp->deviations, u) {
+ ypr_parsed_deviation(ctx, &modp->deviations[u]);
+ }
+
+ LEVEL--;
+ ly_print(out, "%*s}\n", INDENT);
+ ly_print_flush(out);
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+yang_print_compiled(struct lyout *out, const struct lys_module *module)
+{
+ (void) out;
+ (void) module;
+
+ return LY_SUCCESS;
+}
diff --git a/src/tree_schema.h b/src/tree_schema.h
index f53499b..5952a0d 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -17,6 +17,7 @@
#include <pcre.h>
#include <stdint.h>
+#include <stdio.h>
#include "extensions.h"
@@ -142,6 +143,8 @@
LYS_OUT_UNKNOWN = 0, /**< unknown format, used as return value in case of error */
LYS_OUT_YANG = 1, /**< YANG schema output format */
LYS_OUT_YIN = 2, /**< YIN schema output format */
+ LYS_OUT_YANG_COMPILED, /**< YANG schema output format of the compiled schema tree */
+
LYS_OUT_TREE, /**< Tree schema output format, for more information see the [printers](@ref howtoschemasprinters) page */
LYS_OUT_INFO, /**< Info schema output format, for more information see the [printers](@ref howtoschemasprinters) page */
LYS_OUT_JSON, /**< JSON schema output format, reflecting YIN format with conversion of attributes to object's members */
@@ -160,7 +163,9 @@
#define LYS_CASE 0x0040 /**< case statement node */
#define LYS_USES 0x0080 /**< uses statement node */
-#define LYS_INOUT 0x200
+#define LYS_INPUT 0x100
+#define LYS_OUTPUT 0x200
+#define LYS_INOUT 0x300
#define LYS_ACTION 0x400 /**< RPC or action */
#define LYS_NOTIF 0x800
#define LYS_GROUPING 0x1000
@@ -245,6 +250,7 @@
const char *arg; /**< statement's argument */
struct lysp_stmt *next; /**< link to the next statement */
struct lysp_stmt *child; /**< list of the statement's substatements (linked list) */
+ uint16_t flags;
};
/**
@@ -494,48 +500,50 @@
*
* 1 - container 6 - anydata/anyxml 11 - output 16 - grouping 21 - enum
* 2 - choice 7 - case 12 - feature 17 - uses 22 - type
- * 3 - leaf 8 - notification 13 - identity 18 - refine
+ * 3 - leaf 8 - notification 13 - identity 18 - refine 23 - stmt
* 4 - leaflist 9 - rpc 14 - extension 19 - augment
* 5 - list 10 - input 15 - typedef 20 - deviate
*
- * 1 1 1 1 1 1 1 1 1 1 2 2 2
- * bit name 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
- * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 1 LYS_CONFIG_W |x|x|x|x|x|x|x| | | | | | | | | | |x| |x| | |
- * LYS_SET_BASE | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | | | | | | | | |x| |x| | |
- * LYS_SET_BIT | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x| | |x|x|x|x|x|x| |x|x|x| |
- * LYS_SET_ENUM | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x| | |x|x|x|x|x|x| |x|x|x| |
- * LYS_SET_FRDIGITS | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x| | |x|x|x|x|x|x| |x|x|x| |
- * LYS_SET_LENGTH | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 6 LYS_MAND_TRUE | |x|x| | |x| | | | | | | | | | | |x| |x| | |
- * LYS_SET_PATH | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 7 LYS_MAND_FALSE | |x|x| | |x| | | | | | | | | | | |x| |x| | |
- * LYS_ORDBY_USER | | | |x|x| | | | | | | | | | | | | | | | | |
- * LYS_SET_PATTERN | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | | | | | | | | | |
- * LYS_YINELEM_TRUE | | | | | | | | | | | | | |x| | | | | | | | |
- * LYS_SET_RANGE | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 9 LYS_YINELEM_FALSE| | | | | | | | | | | | | |x| | | | | | | | |
- * LYS_SET_TYPE | | | | | | | | | | | | | | | | | | | | | |x|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 10 LYS_SET_VALUE | | | | | | | | | | | | | | | | | | | | |x| |
- * LYS_SET_REQINST | | | | | | | | | | | | | | | | | | | | | |x|
- * LYS_SET_MIN | | | |x|x| | | | | | | | | | | | |x| |x| | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 11 LYS_SET_MAX | | | |x|x| | | | | | | | | | | | |x| |x| | |
- * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2
+ * bit name 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 LYS_CONFIG_W |x|x|x|x|x|x|x| | | | | | | | | | |x| |x| | | |
+ * LYS_SET_BASE | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | | | | | | | | |x| |x| | | |
+ * LYS_SET_BIT | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x| | |x|x|x|x|x|x| |x|x|x| | |
+ * LYS_SET_ENUM | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x| | |x|x|x|x|x|x| |x|x|x| | |
+ * LYS_SET_FRDIGITS | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x| | |x|x|x|x|x|x| |x|x|x| | |
+ * LYS_SET_LENGTH | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 6 LYS_MAND_TRUE | |x|x| | |x| | | | | | | | | | | |x| |x| | | |
+ * LYS_SET_PATH | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 7 LYS_MAND_FALSE | |x|x| | |x| | | | | | | | | | | |x| |x| | | |
+ * LYS_ORDBY_USER | | | |x|x| | | | | | | | | | | | | | | | | | |
+ * LYS_SET_PATTERN | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | | | | | | | | | | |
+ * LYS_YINELEM_TRUE | | | | | | | | | | | | | |x| | | | | | | | | |
+ * LYS_SET_RANGE | | | | | | | | | | | | | | | | | | | | | |x| |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 9 LYS_YINELEM_FALSE| | | | | | | | | | | | | |x| | | | | | | | | |
+ * LYS_SET_TYPE | | | | | | | | | | | | | | | | | | | | | |x| |
+ * LYS_SINGLEQUOTED | | | | | | | | | | | | | | | | | | | | | | |x|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 10 LYS_SET_VALUE | | | | | | | | | | | | | | | | | | | | |x| | |
+ * LYS_SET_REQINST | | | | | | | | | | | | | | | | | | | | | |x| |
+ * LYS_SET_MIN | | | |x|x| | | | | | | | | | | | |x| |x| | | |
+ * LYS_DOUBLEQUOTED | | | | | | | | | | | | | | | | | | | | | | |x|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 11 LYS_SET_MAX | | | |x|x| | | | | | | | | | | | |x| |x| | | |
+ * ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
@@ -640,6 +648,9 @@
#define LYS_SET_UNITS 0x0400 /**< flag to know if the leaf's/leaflist's units are their own (flag set) or it is taken from the type. */
#define LYS_SET_CONFIG 0x0800 /**< flag to know if the config property was set explicitly (flag set) or it is inherited. */
+#define LYS_SINGLEQUOTED 0x100 /**< flag for single-quoted argument of an extension instance's substatement */
+#define LYS_DOUBLEQUOTED 0x200 /**< flag for double-quoted argument of an extension instance's substatement */
+
#define LYS_FLAGS_COMPILED_MASK 0xff /**< mask for flags that maps to the compiled structures */
/** @} */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index f86d249..60162bb 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -638,8 +638,8 @@
COMPILE_CHECK_UNIQUENESS(ctx, idents, name, ident, "identity", ident_p->name);
DUP_STRING(ctx->ctx, ident_p->name, ident->name);
- DUP_STRING(ctx->ctx, ident_p->ref, ident->dsc);
- DUP_STRING(ctx->ctx, ident_p->ref, ident->dsc);
+ DUP_STRING(ctx->ctx, ident_p->dsc, ident->dsc);
+ DUP_STRING(ctx->ctx, ident_p->ref, ident->ref);
COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
/* backlings (derived) can be added no sooner than when all the identities in the current module are present */
COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index ef83436..6fda323 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1215,3 +1215,18 @@
return NULL;
}
+unsigned int
+lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt)
+{
+ LY_CHECK_ARG_RET(NULL, ext, LY_EINVAL);
+
+ for (; index < LY_ARRAY_SIZE(ext); index++) {
+ if (ext[index].insubstmt == substmt) {
+ return index;
+ }
+ }
+
+ return LY_ARRAY_SIZE(ext);
+}
+
+
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 0db6a1f..8b7d66b 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -228,6 +228,18 @@
struct lysc_action **lysc_node_actions_p(struct lysc_node *node);
/**
+ * @brief Iterate over the specified type of the extension instances
+ *
+ * @param[in] ext ([Sized array](@ref sizedarrays)) of extensions to explore
+ * @param[in] index Index in the \p ext array where to start searching (first call with 0, the consequent calls with
+ * the returned index increased by 1 (until the iteration is not terminated by returning LY_ARRAY_SIZE(ext).
+ * @param[in] substmt Type of the extension (its belongins to the specific substatement) to iterate, use
+ * #LYEXT_SUBSTMT_ALL to go through all the extensions in the array
+ * @result index in the ext array, LY_ARRAY_SIZE(ext) value if not present.
+ */
+unsigned int lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt);
+
+/**
* @brief Get the covering schema module structure for the given parsed module structure.
* @param[in] ctx libyang context to search.
* @param[in] mod Parsed schema structure.
diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt
index 9657398..f3dc31f 100644
--- a/tests/src/CMakeLists.txt
+++ b/tests/src/CMakeLists.txt
@@ -7,7 +7,8 @@
src_parser_yang
src_tree_schema
src_tree_schema_compile
- src_tree_schema_helpers)
+ src_tree_schema_helpers
+ src_printer_yang)
set(local_tests_wraps
" "
"-Wl,--wrap=realloc"
@@ -17,6 +18,7 @@
" "
" "
" "
+ " "
" ")
set(tests ${tests} ${local_tests} PARENT_SCOPE)
set(tests_wraps ${tests_wraps} ${local_tests_wraps} PARENT_SCOPE)
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 2c68caf..8dca6c5 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -186,13 +186,13 @@
ctx.line = 1;
str = " // this is a text of / one * line */ comment\nargument";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_string_equal("argument", word);
assert_null(buf);
assert_int_equal(8, len);
str = "/* this is a \n * text // of / block * comment */\"arg\" + \"ume\" \n + \n \"nt\"";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_string_equal("argument", word);
assert_ptr_equal(buf, word);
assert_int_equal(8, len);
@@ -223,33 +223,33 @@
/* missing argument */
str = ";";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_MAYBE_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_MAYBE_STR_ARG, NULL, &word, &buf, &len));
assert_null(word);
str = "{";
- assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Invalid character sequence \"{\", expected an argument. Line number 1.");
/* invalid escape sequence */
str = "\"\\s\"";
- assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Double-quoted string unknown special character \'\\s\'. Line number 1.");
str = "\'\\s\'"; /* valid, since it is not an escape sequence in single quoted string */
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_int_equal(2, len);
assert_string_equal("\\s\'", word);
assert_int_equal('\0', str[0]); /* input has been eaten */
/* invalid character after the argument */
str = "hello\"";
- assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Invalid character sequence \"\"\", expected unquoted string character, optsep, semicolon or opening brace. Line number 1.");
str = "hello}";
- assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Invalid character sequence \"}\", expected unquoted string character, optsep, semicolon or opening brace. Line number 1.");
str = "hello/x\t"; /* slash is not an invalid character */
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_int_equal(7, len);
assert_string_equal("hello/x\t", word);
@@ -257,20 +257,20 @@
/* different quoting */
str = "hello ";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_null(buf);
assert_int_equal(5, len);
assert_string_equal("hello ", word);
str = "hello/*comment*/\n";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_null(buf);
assert_int_equal(5, len);
assert_false(strncmp("hello", word, len));
str = "\"hello\\n\\t\\\"\\\\\";";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_null(buf);
assert_int_equal(9, len);
assert_string_equal("hello\\n\\t\\\"\\\\\";", word);
@@ -280,7 +280,7 @@
/* - space and tabs before newline are stripped out
* - space and tabs after newline (indentation) are stripped out
*/
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_non_null(buf);
assert_ptr_equal(word, buf);
assert_int_equal(14, len);
@@ -289,7 +289,7 @@
ctx.indent = 14;
str = "\"hello\n \tworld!\"";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_non_null(buf);
assert_ptr_equal(word, buf);
assert_int_equal(12, len);
@@ -297,30 +297,30 @@
free(buf);
str = "\'hello\'";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_null(buf);
assert_int_equal(5, len);
assert_false(strncmp("hello", word, 5));
str = "\"hel\" +\t\n\"lo\"";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_ptr_equal(word, buf);
assert_int_equal(5, len);
assert_string_equal("hello", word);
free(buf);
str = "\"hel\" +\t\nlo"; /* unquoted the second part */
- assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Both string parts divided by '+' must be quoted. Line number 5.");
str = "\'he\'\t\n+ \"llo\"";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_ptr_equal(word, buf);
assert_int_equal(5, len);
assert_string_equal("hello", word);
free(buf);
str = " \t\n\"he\"+\'llo\'";
- assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_SUCCESS, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
assert_ptr_equal(word, buf);
assert_int_equal(5, len);
assert_string_equal("hello", word);
@@ -328,7 +328,7 @@
/* missing argument */
str = ";";
- assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, &word, &buf, &len));
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Invalid character sequence \";\", expected an argument. Line number 7.");
}
@@ -1914,14 +1914,14 @@
assert_non_null(rpcs->typedefs);
assert_int_equal(LYS_STATUS_CURR, rpcs->flags);
/* input */
- assert_int_equal(rpcs->input.nodetype, LYS_INOUT);
+ assert_int_equal(rpcs->input.nodetype, LYS_INPUT);
assert_non_null(rpcs->input.groupings);
assert_non_null(rpcs->input.exts);
assert_non_null(rpcs->input.musts);
assert_non_null(rpcs->input.typedefs);
assert_non_null(rpcs->input.data);
/* output */
- assert_int_equal(rpcs->output.nodetype, LYS_INOUT);
+ assert_int_equal(rpcs->output.nodetype, LYS_OUTPUT);
assert_non_null(rpcs->output.groupings);
assert_non_null(rpcs->output.exts);
assert_non_null(rpcs->output.musts);
diff --git a/tests/src/test_printer_yang.c b/tests/src/test_printer_yang.c
new file mode 100644
index 0000000..922b170
--- /dev/null
+++ b/tests/src/test_printer_yang.c
@@ -0,0 +1,202 @@
+/*
+ * @file test_printer_yang.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from printer_yang.c
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "../../src/common.c"
+#include "../../src/set.c"
+#include "../../src/log.c"
+#include "../../src/hash_table.c"
+#include "../../src/xpath.c"
+#include "../../src/parser_yang.c"
+#include "../../src/context.c"
+#include "../../src/tree_schema_helpers.c"
+#include "../../src/tree_schema_free.c"
+#include "../../src/tree_schema_compile.c"
+#include "../../src/tree_schema.c"
+#include "../../src/printer_yang.c"
+#include "../../src/printer.c"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libyang.h"
+
+#define BUFSIZE 1024
+char logbuf[BUFSIZE] = {0};
+int store = -1; /* negative for infinite logging, positive for limited logging */
+
+/* set to 0 to printing error messages to stderr instead of checking them in code */
+#define ENABLE_LOGGER_CHECKING 1
+
+#if ENABLE_LOGGER_CHECKING
+static void
+logger(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+ (void) level; /* unused */
+ if (store) {
+ if (path && path[0]) {
+ snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
+ } else {
+ strncpy(logbuf, msg, BUFSIZE - 1);
+ }
+ if (store > 0) {
+ --store;
+ }
+ }
+}
+#endif
+
+static int
+logger_setup(void **state)
+{
+ (void) state; /* unused */
+#if ENABLE_LOGGER_CHECKING
+ ly_set_log_clb(logger, 1);
+#endif
+ return 0;
+}
+
+static int
+logger_teardown(void **state)
+{
+ (void) state; /* unused */
+#if ENABLE_LOGGER_CHECKING
+ if (*state) {
+ fprintf(stderr, "%s\n", logbuf);
+ }
+#endif
+ return 0;
+}
+
+void
+logbuf_clean(void)
+{
+ logbuf[0] = '\0';
+}
+
+#if ENABLE_LOGGER_CHECKING
+# define logbuf_assert(str) assert_string_equal(logbuf, str)
+#else
+# define logbuf_assert(str)
+#endif
+
+
+static void
+test_module(void **state)
+{
+ *state = test_module;
+
+ struct ly_ctx *ctx = {0};
+ const struct lys_module *mod;
+ const char *orig = "module a {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:test:a\";\n"
+ " prefix a;\n\n"
+ " import ietf-yang-types {\n"
+ " prefix yt;\n"
+ " revision-date 2013-07-15;\n"
+ " description\n"
+ " \"YANG types\";\n"
+ " reference\n"
+ " \"RFC reference\";\n"
+ " }\n\n"
+ " organization\n"
+ " \"ORG\";\n"
+ " contact\n"
+ " \"Radek Krejci.\";\n"
+ " description\n"
+ " \"Long multiline\n"
+ " description.\";\n"
+ " reference\n"
+ " \"some reference\";\n"
+ "}\n";
+ char *printed;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx));
+
+ assert_non_null(mod = lys_parse_mem(ctx, orig, LYS_IN_YANG));
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0, 0));
+ assert_string_equal(printed, orig);
+ free(printed);
+
+ orig = "module b {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:test:b\";\n"
+ " prefix b;\n\n"
+ " revision 2019-04-16 {\n"
+ " description\n"
+ " \"text\";\n"
+ " reference\n"
+ " \"text\";\n"
+ " }\n"
+ " revision 2019-04-15 {\n"
+ " description\n"
+ " \"initial revision\";\n"
+ " }\n\n"
+ " feature f1 {\n"
+ " status current;\n"
+ " description\n"
+ " \"text\";\n"
+ " reference\n"
+ " \"text\";\n"
+ " }\n\n"
+ " feature f2 {\n"
+ " if-feature \"not f1\";\n"
+ " }\n"
+ "}\n";
+ assert_non_null(mod = lys_parse_mem(ctx, orig, LYS_IN_YANG));
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0, 0));
+ assert_string_equal(printed, orig);
+ free(printed);
+
+ orig = "module c {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:test:c\";\n"
+ " prefix c;\n\n"
+ " feature f1;\n\n"
+ " identity i1 {\n"
+ " if-feature \"f1\";\n"
+ " description\n"
+ " \"text\";\n"
+ " reference\n"
+ " \"text32\";\n"
+ " }\n\n"
+ " identity i2 {\n"
+ " base i1;\n"
+ " status obsolete;\n"
+ " }\n"
+ "}\n";
+ assert_non_null(mod = lys_parse_mem(ctx, orig, LYS_IN_YANG));
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0, 0));
+ assert_string_equal(printed, orig);
+ free(printed);
+
+ *state = NULL;
+ ly_ctx_destroy(ctx, NULL);
+}
+
+/* TODO: include */
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_module, logger_setup, logger_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}