#include <assert.h>
#include <string.h>
#include "compat.h"
#include "ly_common.h"
#include "out_internal.h"
#include "plugins_exts.h"
#include "plugins_types.h"
#include "printer_internal.h"
#include "printer_schema.h"
#include "tree_schema_internal.h"
#include "xpath.h"
typedef enum {
PT_PRINT = 0,
PT_CHAR_COUNT
} pt_ly_out_clb_arg_flag;
struct ly_out_clb_arg {
pt_ly_out_clb_arg_flag mode;
struct ly_out *out;
size_t counter;
LY_ERR last_error;
};
#define PT_INIT_LY_OUT_CLB_ARG(MODE, OUT, COUNTER, LAST_ERROR) \
(struct ly_out_clb_arg) { \
.mode = MODE, .out = OUT, \
.counter = COUNTER, .last_error = LAST_ERROR \
}
#define PT_LINEBREAK -1
typedef enum {
PT_INDENT_EMPTY = 0,
PT_INDENT_LONG_LINE_BREAK = 2,
PT_INDENT_LINE_BEGIN = 2,
PT_INDENT_BTW_SIBLINGS = 2,
PT_INDENT_BEFORE_KEYS = 1,
PT_INDENT_BEFORE_TYPE = 4,
PT_INDENT_BEFORE_IFFEATURES = 1
} pt_cnf_indent;
typedef enum {
PT_INDENT_IN_NODE_NORMAL = 0,
PT_INDENT_IN_NODE_DIVIDED,
PT_INDENT_IN_NODE_FAILED
} pt_indent_in_node_type;
struct pt_indent_in_node {
pt_indent_in_node_type type;
int16_t btw_name_opts;
int16_t btw_opts_type;
int16_t btw_type_iffeatures;
};
typedef enum {
PT_WRAPPER_TOP = 0,
PT_WRAPPER_BODY
} pt_wrapper_type;
struct pt_wrapper {
pt_wrapper_type type;
uint64_t bit_marks1;
uint32_t actual_pos;
};
#define PT_INIT_WRAPPER_TOP \
(struct pt_wrapper) { \
.type = PT_WRAPPER_TOP, .actual_pos = 0, .bit_marks1 = 0 \
}
#define PT_INIT_WRAPPER_BODY \
(struct pt_wrapper) { \
.type = PT_WRAPPER_BODY, .actual_pos = 0, .bit_marks1 = 0 \
}
struct pt_indent {
struct pt_wrapper wrapper;
struct pt_indent_in_node in_node;
};
#define PT_INIT_INDENT(WRAPPER, INDENT_IN_NODE) \
(struct pt_indent){ \
.wrapper = WRAPPER, .in_node = INDENT_IN_NODE \
}
#define PT_FLAGS_TYPE_EMPTY "--"
#define PT_FLAGS_TYPE_RW "rw"
#define PT_FLAGS_TYPE_RO "ro"
#define PT_FLAGS_TYPE_RPC_INPUT_PARAMS "-w"
#define PT_FLAGS_TYPE_USES_OF_GROUPING "-u"
#define PT_FLAGS_TYPE_RPC "-x"
#define PT_FLAGS_TYPE_NOTIF "-n"
#define PT_FLAGS_TYPE_EXT ""
#define PT_FLAGS_TYPE_MOUNT_POINT "mp"
#define PT_NODE_NAME_PREFIX_CHOICE "("
#define PT_NODE_NAME_PREFIX_CASE ":("
#define PT_NODE_NAME_TRIPLE_DOT "..."
#define PT_STATUS_CURRENT "+"
#define PT_STATUS_DEPRECATED "x"
#define PT_STATUS_OBSOLETE "o"
typedef enum {
PT_NODE_ELSE = 0,
PT_NODE_CASE,
PT_NODE_CHOICE,
PT_NODE_TRIPLE_DOT
} pt_node_type;
#define PT_NODE_OPTIONAL "?"
#define PT_NODE_CONTAINER "!"
#define PT_NODE_LISTLEAFLIST "*"
#define PT_NODE_MOUNTED "/"
#define PT_NODE_MOUNTED_PARENT_REF "@"
struct pt_node_name {
pt_node_type type;
ly_bool keys;
const char *module_prefix;
const char *str;
const char *opts;
};
#define PT_EMPTY_NODE_NAME \
(struct pt_node_name) { \
.type = PT_NODE_ELSE, .keys = 0, .module_prefix = NULL, .str = NULL, .opts = NULL \
}
#define PT_NODE_NAME_IS_EMPTY(NODE_NAME) \
!NODE_NAME.str
typedef enum {
PT_TYPE_NAME = 0,
PT_TYPE_TARGET,
PT_TYPE_LEAFREF,
PT_TYPE_EMPTY
} pt_lf_type_id;
struct pt_lf_type {
pt_lf_type_id type;
const char *str;
};
#define PT_EMPTY_LF_TYPE \
(struct pt_lf_type) {.type = PT_TYPE_EMPTY, .str = NULL}
#define PT_LF_TYPE_IS_EMPTY(LF_TYPE) \
LF_TYPE.type == PT_TYPE_EMPTY
#define PT_INIT_LF_TYPE(LF_TYPE, STRING) \
(struct pt_lf_type) {.type = LF_TYPE, .str = STRING}
typedef enum {
PT_IFF_NON_PRESENT = 0,
PT_IFF_PRESENT
} pt_iffeatures_type;
struct pt_iffeatures {
pt_iffeatures_type type;
};
#define PT_EMPTY_IFFEATURES \
(struct pt_iffeatures) {.type = PT_IFF_NON_PRESENT}
#define PT_EMPTY_IFFEATURES_IS_EMPTY(IFF_TYPE) \
(IFF_TYPE == PT_IFF_NON_PRESENT)
struct pt_node {
const char *status;
const char *flags;
struct pt_node_name name;
struct pt_lf_type type;
struct pt_iffeatures iffeatures;
ly_bool last_one;
};
#define PT_EMPTY_NODE \
(struct pt_node) { \
.status = NULL, \
.flags = NULL, \
.name = PT_EMPTY_NODE_NAME, \
.type = PT_EMPTY_LF_TYPE, \
.iffeatures = PT_EMPTY_IFFEATURES, \
.last_one = 1 \
}
typedef enum {
PT_ANCESTOR_ELSE = 0,
PT_ANCESTOR_RPC_INPUT,
PT_ANCESTOR_RPC_OUTPUT,
PT_ANCESTOR_NOTIF
} pt_parent_type;
struct pt_parent_cache {
pt_parent_type ancestor;
uint16_t lys_status;
uint16_t lys_config;
const struct lysp_node_list *last_list;
};
#define PT_EMPTY_PARENT_CACHE \
(struct pt_parent_cache) { \
.ancestor = PT_ANCESTOR_ELSE, .lys_status = LYS_STATUS_CURR, \
.lys_config = LYS_CONFIG_W, .last_list = NULL \
}
#define PT_KEYWORD_MODULE "module"
#define PT_KEYWORD_SUBMODULE "submodule"
#define PT_KEYWORD_AUGMENT "augment"
#define PT_KEYWORD_RPC "rpcs"
#define PT_KEYWORD_NOTIF "notifications"
#define PT_KEYWORD_GROUPING "grouping"
struct pt_keyword_stmt {
const char *section_name;
const char *argument;
ly_bool has_node;
};
#define PT_EMPTY_KEYWORD_STMT \
(struct pt_keyword_stmt) {.section_name = NULL, .argument = NULL, .has_node = 0}
typedef enum {
PT_SECT_MODULE = 0,
PT_SECT_AUGMENT,
PT_SECT_RPCS,
PT_SECT_NOTIF,
PT_SECT_GROUPING,
PT_SECT_PLUG_DATA
} pt_current_section;
typedef enum {
PT_EXT_GENERIC,
PT_EXT_SCHEMA_MOUNT,
PT_EXT_SCHEMA_MOUNT_REF
} pt_extension_type;
struct pt_ext_tree_schema {
pt_extension_type ext;
ly_bool compiled;
union {
const struct lysc_node *ctree;
const struct lysp_node *ptree;
};
};
struct pt_ext_schema_mount {
const struct lysc_node *mount_point;
struct pt_ext_tree_schema *schemas;
struct ly_set *parent_refs;
ly_bool mp_has_normal_node;
};
struct pt_extension {
struct pt_ext_tree_schema *schema;
struct pt_ext_schema_mount *schema_mount;
};
struct pt_tree_ctx {
ly_bool lysc_tree;
pt_current_section section;
const struct lysp_module *pmod;
const struct lysc_module *cmod;
const struct lysp_node *pn;
const struct lysc_node *cn;
LY_ERR last_error;
struct pt_extension plugin_ctx;
struct ly_out *out;
size_t max_line_length;
};
#define PT_TREE_CTX_LYSP_NODE_PRESENT(CN) \
(CN->priv)
#define PT_TREE_CTX_GET_LYSP_NODE(CN) \
((const struct lysp_node *)CN->priv)
#define PT_LAST_ARRAY_ITEM(ARR, ITEM) \
(&ARR[LY_ARRAY_COUNT(ARR) - 1] == ITEM)
#define PT_LAST_SCHEMA_MOUNT(PT_EXTENSION) \
(PT_EXTENSION.schema ? \
PT_LAST_ARRAY_ITEM(PT_EXTENSION.schema_mount->schemas, PT_EXTENSION.schema): \
1)
#define PT_LAST_SCHEMA(PT_EXTENSION) \
(PT_EXTENSION.schema_mount ? PT_LAST_SCHEMA_MOUNT(PT_EXTENSION) : 1)
static ly_bool
pt_charptr_has_data(const char *str)
{
return (str) && (str[0] != '\0');
}
static ly_bool
pt_word_is_present(const char *src, const char *word, char delim)
{
const char *hit;
if ((!src) || (src[0] == '\0') || (!word)) {
return 0;
}
hit = strstr(src, word);
if (hit) {
if ((hit == src) || (hit[-1] == delim)) {
char delim_or_end = (hit + strlen(word))[0];
if ((delim_or_end == '\0') || (delim_or_end == delim)) {
return 1;
}
}
for ( ; (src[0] != '\0') && (src[0] != delim); src++) {}
src = src[0] == '\0' ? src : src + 1;
return pt_word_is_present(src, word, delim);
} else {
return 0;
}
}
static struct pt_wrapper
pt_wrapper_set_shift(struct pt_wrapper wr)
{
assert(wr.actual_pos < 64);
wr.actual_pos++;
return wr;
}
static struct pt_wrapper
pt_wrapper_set_mark(struct pt_wrapper wr)
{
assert(wr.actual_pos < 64);
wr.bit_marks1 |= 1U << wr.actual_pos;
return pt_wrapper_set_shift(wr);
}
static struct pt_wrapper
pt_wrapper_if_last_sibling(struct pt_wrapper wr, ly_bool last_one)
{
return last_one ? pt_wrapper_set_shift(wr) : pt_wrapper_set_mark(wr);
}
static ly_bool
pt_wrapper_eq(struct pt_wrapper first, struct pt_wrapper second)
{
const ly_bool a = first.type == second.type;
const ly_bool b = first.bit_marks1 == second.bit_marks1;
const ly_bool c = first.actual_pos == second.actual_pos;
return a && b && c;
}
static void
pt_print_wrapper(struct pt_wrapper wr, struct ly_out *out)
{
uint32_t lb;
switch (wr.type) {
case PT_WRAPPER_TOP:
lb = PT_INDENT_LINE_BEGIN;
break;
case PT_WRAPPER_BODY:
lb = PT_INDENT_LINE_BEGIN * 2;
break;
default:
assert(0);
}
ly_print_(out, "%*c", lb, ' ');
if (pt_wrapper_eq(wr, PT_INIT_WRAPPER_TOP)) {
return;
}
for (uint32_t i = 0; i < wr.actual_pos; i++) {
if ((wr.bit_marks1 >> i) & 1U) {
ly_print_(out, "|");
} else {
ly_print_(out, " ");
}
if (i != wr.actual_pos) {
ly_print_(out, "%*c", PT_INDENT_BTW_SIBLINGS, ' ');
}
}
}
static uint32_t
pt_gap_to_opts(const struct pt_node *node)
{
uint32_t len = 0;
if (node->name.keys) {
return 0;
}
assert(node->flags);
len += strlen(node->flags);
len += 1;
switch (node->name.type) {
case PT_NODE_CASE:
len += 2;
break;
case PT_NODE_CHOICE:
len += 2;
break;
default:
break;
}
if (node->name.module_prefix) {
len += strlen(node->name.module_prefix) + 1;
}
if (node->name.str) {
len += strlen(node->name.str);
}
if (node->name.opts) {
len += strlen(node->name.opts);
}
return len;
}
static uint32_t
pt_gap_to_type(const struct pt_node *node)
{
uint32_t len, opts_len;
if (node->name.keys) {
return 0;
}
len = pt_gap_to_opts(node);
opts_len = 0;
opts_len += node->name.opts ? strlen(node->name.opts) : 0;
if (opts_len >= PT_INDENT_BEFORE_TYPE) {
len += 1;
} else if (node->name.opts) {
len += PT_INDENT_BEFORE_TYPE - opts_len;
} else {
len += PT_INDENT_BEFORE_TYPE;
}
return len;
}
static int16_t
pt_calc_btw_opts_type(const struct pt_node *node, int16_t max_gap_before_type)
{
uint32_t to_opts_len;
to_opts_len = pt_gap_to_opts(node);
if (to_opts_len == 0) {
return 1;
} else {
return max_gap_before_type - to_opts_len;
}
}
static struct pt_wrapper
pt_count_depth(const struct pt_wrapper *wr_in, const struct lysc_node *node)
{
struct pt_wrapper wr = wr_in ? *wr_in : PT_INIT_WRAPPER_TOP;
const struct lysc_node *parent;
if (!node) {
return wr;
}
for (parent = node->parent; parent; parent = parent->parent) {
wr = pt_wrapper_set_shift(wr);
}
return wr;
}
static struct pt_node pt_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc);
static ly_bool pt_node_is_empty(const struct pt_node *node);
static struct pt_node pt_modi_next_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc);
static uint32_t
pt_max_gap_to_type(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
struct pt_node node;
int32_t maxlen, len;
maxlen = 0;
for (node = pt_modi_first_sibling(ca, tc);
!pt_node_is_empty(&node);
node = pt_modi_next_sibling(ca, tc)) {
len = pt_gap_to_type(&node);
maxlen = maxlen < len ? len : maxlen;
}
pt_modi_first_sibling(ca, tc);
return maxlen;
}
static uint32_t
pt_try_unified_indent(struct pt_parent_cache ca, struct pt_tree_ctx tc)
{
return pt_max_gap_to_type(ca, &tc);
}
static ly_bool
pt_mark_is_used(struct pt_node_name node_name)
{
if (PT_NODE_NAME_IS_EMPTY(node_name)) {
return 0;
} else if (node_name.keys) {
return 0;
}
switch (node_name.type) {
case PT_NODE_ELSE:
case PT_NODE_CASE:
return 0;
default:
return node_name.opts ? 1 : 0;
}
}
static struct pt_indent_in_node
pt_default_indent_in_node(const struct pt_node *node)
{
struct pt_indent_in_node ret;
uint32_t opts_len = 0;
ret.type = PT_INDENT_IN_NODE_NORMAL;
ret.btw_name_opts = node->name.keys ? PT_INDENT_BEFORE_KEYS : 0;
if (!(PT_LF_TYPE_IS_EMPTY(node->type))) {
if (pt_mark_is_used(node->name)) {
opts_len += node->name.opts ? strlen(node->name.opts) : 0;
ret.btw_opts_type = PT_INDENT_BEFORE_TYPE > opts_len ? 1 : PT_INDENT_BEFORE_TYPE - opts_len;
} else {
ret.btw_opts_type = PT_INDENT_BEFORE_TYPE;
}
} else {
ret.btw_opts_type = 0;
}
ret.btw_type_iffeatures = node->iffeatures.type == PT_IFF_PRESENT ? PT_INDENT_BEFORE_IFFEATURES : 0;
return ret;
}
static struct pt_indent_in_node
pt_indent_in_node_place_break(struct pt_indent_in_node indent)
{
struct pt_indent_in_node ret = indent;
if ((indent.btw_type_iffeatures != PT_LINEBREAK) && (indent.btw_type_iffeatures != 0)) {
ret.btw_type_iffeatures = PT_LINEBREAK;
} else if ((indent.btw_opts_type != PT_LINEBREAK) && (indent.btw_opts_type != 0)) {
ret.btw_opts_type = PT_LINEBREAK;
} else if ((indent.btw_name_opts != PT_LINEBREAK) && (indent.btw_name_opts != 0)) {
ret.btw_name_opts = PT_LINEBREAK;
} else {
ret.type = PT_INDENT_IN_NODE_FAILED;
}
return ret;
}
static void
pt_first_half_node(const struct pt_indent_in_node *indent, struct pt_node *node)
{
if (indent->btw_name_opts == PT_LINEBREAK) {
node->type = PT_EMPTY_LF_TYPE;
node->iffeatures = PT_EMPTY_IFFEATURES;
} else if (indent->btw_opts_type == PT_LINEBREAK) {
node->type = PT_EMPTY_LF_TYPE;
node->iffeatures = PT_EMPTY_IFFEATURES;
} else if (indent->btw_type_iffeatures == PT_LINEBREAK) {
node->iffeatures = PT_EMPTY_IFFEATURES;
}
}
static void
pt_second_half_node(struct pt_indent_in_node *indent, struct pt_node *node)
{
if (indent->btw_name_opts < 0) {
indent->btw_name_opts = 0;
indent->btw_opts_type = PT_LF_TYPE_IS_EMPTY(node->type) ? 0 : PT_INDENT_BEFORE_TYPE;
indent->btw_type_iffeatures = node->iffeatures.type == PT_IFF_NON_PRESENT ? 0 : PT_INDENT_BEFORE_IFFEATURES;
} else if (indent->btw_opts_type == PT_LINEBREAK) {
indent->btw_name_opts = 0;
indent->btw_opts_type = 0;
indent->btw_type_iffeatures = node->iffeatures.type == PT_IFF_NON_PRESENT ? 0 : PT_INDENT_BEFORE_IFFEATURES;
} else if (indent->btw_type_iffeatures == PT_LINEBREAK) {
node->type = PT_EMPTY_LF_TYPE;
indent->btw_name_opts = 0;
indent->btw_opts_type = 0;
indent->btw_type_iffeatures = 0;
}
}
static void pt_print_line(const struct pt_node *node, struct pt_tree_ctx *tc,
struct pt_indent indent);
static void
pt_try_normal_indent_in_node_(struct pt_tree_ctx *tc, struct pt_node *node,
struct pt_indent *indent, size_t *cnt)
{
pt_print_line(node, tc, PT_INIT_INDENT(indent->wrapper, indent->in_node));
if (*cnt <= tc->max_line_length) {
return;
} else {
indent->in_node = pt_indent_in_node_place_break(indent->in_node);
if (indent->in_node.type != PT_INDENT_IN_NODE_FAILED) {
pt_first_half_node(&indent->in_node, node);
*cnt = 0;
pt_try_normal_indent_in_node_(tc, node, indent, cnt);
indent->in_node.type = indent->in_node.type == PT_INDENT_IN_NODE_FAILED ?
PT_INDENT_IN_NODE_FAILED : PT_INDENT_IN_NODE_DIVIDED;
}
return;
}
}
static void
pt_try_normal_indent_in_node(struct pt_node *node, struct pt_tree_ctx *tc,
struct pt_indent *indent)
{
struct ly_out_clb_arg *data;
data = tc->out->method.clb.arg;
data->counter = 0;
data->mode = PT_CHAR_COUNT;
pt_try_normal_indent_in_node_(tc, node, indent, &data->counter);
data->mode = PT_PRINT;
}
static void
pt_print_keyword_stmt_begin(const struct pt_keyword_stmt *ks, struct ly_out *out)
{
if (!strcmp(ks->section_name, PT_KEYWORD_MODULE) ||
!strcmp(ks->section_name, PT_KEYWORD_SUBMODULE)) {
ly_print_(out, "%s: ", ks->section_name);
return;
}
ly_print_(out, "%*c", PT_INDENT_LINE_BEGIN, ' ');
if (ks->argument) {
ly_print_(out, "%s ", ks->section_name);
} else {
ly_print_(out, "%s", ks->section_name);
}
}
static void
pt_print_keyword_stmt_str(const struct pt_keyword_stmt *ks, struct ly_out *out)
{
if ((!ks->argument) || (ks->argument[0] == '\0')) {
return;
}
ly_print_(out, "%s", ks->argument);
}
static void
pt_print_keyword_stmt_end(const struct pt_keyword_stmt *ks, struct ly_out *out)
{
if (!strcmp(ks->section_name, PT_KEYWORD_MODULE) || !strcmp(ks->section_name, PT_KEYWORD_SUBMODULE)) {
return;
} else if (ks->has_node) {
ly_print_(out, ":");
}
}
static void
pt_print_keyword_stmt(const struct pt_keyword_stmt *ks,
ly_bool *once, struct ly_out *out)
{
if (once && *once) {
ly_print_(out, "\n");
ly_print_(out, "\n");
*once = 0;
} else if (once) {
ly_print_(out, "\n");
}
assert(ks->section_name);
pt_print_keyword_stmt_begin(ks, out);
pt_print_keyword_stmt_str(ks, out);
pt_print_keyword_stmt_end(ks, out);
}
static ssize_t
pt_ly_out_clb_func(void *user_data, const void *buf, size_t count)
{
LY_ERR erc = LY_SUCCESS;
struct ly_out_clb_arg *data = (struct ly_out_clb_arg *)user_data;
switch (data->mode) {
case PT_PRINT:
erc = ly_write_(data->out, buf, count);
break;
case PT_CHAR_COUNT:
data->counter = data->counter + count;
break;
default:
break;
}
if (erc != LY_SUCCESS) {
data->last_error = erc;
return -1;
} else {
return count;
}
}
static ly_bool
pt_node_is_empty(const struct pt_node *node)
{
const ly_bool a = PT_EMPTY_IFFEATURES_IS_EMPTY(node->iffeatures.type);
const ly_bool b = PT_LF_TYPE_IS_EMPTY(node->type);
const ly_bool c = PT_NODE_NAME_IS_EMPTY(node->name);
const ly_bool d = node->flags == NULL;
const ly_bool e = node->status == NULL;
return a && b && c && d && e;
}
static ly_bool
pt_node_body_is_empty(const struct pt_node *node)
{
const ly_bool a = PT_EMPTY_IFFEATURES_IS_EMPTY(node->iffeatures.type);
const ly_bool b = PT_LF_TYPE_IS_EMPTY(node->type);
const ly_bool c = !node->name.keys;
return a && b && c;
}
static void
pt_print_node_name(struct pt_node_name node_name, struct ly_out *out)
{
const char *mod_prefix;
const char *colon;
const char pt_node_name_suffix_choice[] = ")";
const char pt_node_name_suffix_case[] = ")";
assert(!PT_NODE_NAME_IS_EMPTY(node_name));
if (node_name.module_prefix) {
mod_prefix = node_name.module_prefix;
colon = ":";
} else {
mod_prefix = "";
colon = "";
}
switch (node_name.type) {
case PT_NODE_ELSE:
ly_print_(out, "%s%s%s", mod_prefix, colon, node_name.str);
break;
case PT_NODE_CASE:
ly_print_(out, "%s%s%s%s%s", PT_NODE_NAME_PREFIX_CASE, mod_prefix, colon, node_name.str, pt_node_name_suffix_case);
break;
case PT_NODE_CHOICE:
ly_print_(out, "%s%s%s%s%s", PT_NODE_NAME_PREFIX_CHOICE, mod_prefix, colon, node_name.str, pt_node_name_suffix_choice);
break;
case PT_NODE_TRIPLE_DOT:
ly_print_(out, "%s", PT_NODE_NAME_TRIPLE_DOT);
break;
default:
break;
}
if (node_name.opts) {
ly_print_(out, "%s", node_name.opts);
}
}
static char *
pt_flags2status(uint16_t flags)
{
return flags & LYS_STATUS_OBSLT ? PT_STATUS_OBSOLETE :
flags & LYS_STATUS_DEPRC ? PT_STATUS_DEPRECATED :
PT_STATUS_CURRENT;
}
static char *
pt_flags2config(uint16_t flags)
{
return flags & LYS_CONFIG_R ? PT_FLAGS_TYPE_RO :
flags & LYS_CONFIG_W ? PT_FLAGS_TYPE_RW :
PT_FLAGS_TYPE_EMPTY;
}
static void
pt_print_keys(const struct pt_tree_ctx *tc)
{
const struct lysp_node_list *list;
if (tc->lysc_tree) {
assert(PT_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
list = (const struct lysp_node_list *)PT_TREE_CTX_GET_LYSP_NODE(tc->cn);
} else {
list = (const struct lysp_node_list *)tc->pn;
}
assert(list->nodetype & LYS_LIST);
if (pt_charptr_has_data(list->key)) {
ly_print_(tc->out, "%s", list->key);
}
}
static void
pt_print_opts_keys(struct pt_node_name node_name, int16_t btw_name_opts,
struct pt_tree_ctx *tc)
{
if (!node_name.keys) {
return;
}
if (btw_name_opts > 0) {
ly_print_(tc->out, "%*c", btw_name_opts, ' ');
}
ly_print_(tc->out, "[");
pt_print_keys(tc);
ly_print_(tc->out, "]");
}
static void
pt_print_type(struct pt_lf_type type, struct ly_out *out)
{
if (PT_LF_TYPE_IS_EMPTY(type)) {
return;
}
switch (type.type) {
case PT_TYPE_NAME:
ly_print_(out, "%s", type.str);
break;
case PT_TYPE_TARGET:
ly_print_(out, "-> %s", type.str);
break;
case PT_TYPE_LEAFREF:
ly_print_(out, "leafref");
default:
break;
}
}
static void
pt_print_features_names(const struct pt_tree_ctx *tc)
{
const struct lysp_qname *iffs;
if (tc->lysc_tree) {
assert(PT_TREE_CTX_LYSP_NODE_PRESENT(tc->cn));
iffs = PT_TREE_CTX_GET_LYSP_NODE(tc->cn)->iffeatures;
} else {
iffs = tc->pn->iffeatures;
}
LY_ARRAY_COUNT_TYPE i;
LY_ARRAY_FOR(iffs, i) {
if (i == 0) {
ly_print_(tc->out, "%s", iffs[i].str);
} else {
ly_print_(tc->out, ",%s", iffs[i].str);
}
}
}
static void
pt_print_iffeatures(struct pt_iffeatures iff, struct pt_tree_ctx *tc)
{
if (iff.type == PT_IFF_PRESENT) {
ly_print_(tc->out, "{");
pt_print_features_names(tc);
ly_print_(tc->out, "}?");
}
}
static void
pt_print_node_up_to_name(const struct pt_node *node, struct ly_out *out)
{
if (node->name.type == PT_NODE_TRIPLE_DOT) {
pt_print_node_name(node->name, out);
return;
}
ly_print_(out, "%s", node->status);
ly_print_(out, "--");
if (node->flags && (node->name.type != PT_NODE_CASE)) {
ly_print_(out, "%s", node->flags);
ly_print_(out, " ");
}
pt_print_node_name(node->name, out);
}
static void
pt_print_divided_node_up_to_name(const struct pt_node *node, struct ly_out *out)
{
uint32_t space = strlen(node->flags);
if (node->name.type == PT_NODE_CASE) {
space += strlen(PT_NODE_NAME_PREFIX_CASE);
} else if (node->name.type == PT_NODE_CHOICE) {
space += strlen(PT_NODE_NAME_PREFIX_CHOICE);
} else {
space += strlen(" ");
}
space += PT_INDENT_LONG_LINE_BREAK;
ly_print_(out, "%*c", space, ' ');
}
static void
pt_print_node(const struct pt_node *node, struct pt_tree_ctx *tc,
struct pt_indent_in_node indent)
{
ly_bool triple_dot;
ly_bool divided;
assert(!pt_node_is_empty(node));
triple_dot = node->name.type == PT_NODE_TRIPLE_DOT;
divided = indent.type == PT_INDENT_IN_NODE_DIVIDED;
if (triple_dot) {
pt_print_node_name(node->name, tc->out);
return;
} else if (!divided) {
pt_print_node_up_to_name(node, tc->out);
} else {
pt_print_divided_node_up_to_name(node, tc->out);
}
pt_print_opts_keys(node->name, indent.btw_name_opts, tc);
if (indent.btw_opts_type > 0) {
ly_print_(tc->out, "%*c", indent.btw_opts_type, ' ');
}
pt_print_type(node->type, tc->out);
if (indent.btw_type_iffeatures > 0) {
ly_print_(tc->out, "%*c", indent.btw_type_iffeatures, ' ');
}
pt_print_iffeatures(node->iffeatures, tc);
}
static void
pt_print_line(const struct pt_node *node, struct pt_tree_ctx *tc,
struct pt_indent indent)
{
pt_print_wrapper(indent.wrapper, tc->out);
pt_print_node(node, tc, indent.in_node);
}
static void
pt_print_line_up_to_node_name(const struct pt_node *node, struct pt_wrapper wr, struct ly_out *out)
{
pt_print_wrapper(wr, out);
pt_print_node_up_to_name(node, out);
}
static ly_bool
pt_indent_in_node_are_eq(struct pt_indent_in_node first, struct pt_indent_in_node second)
{
const ly_bool a = first.type == second.type;
const ly_bool b = first.btw_name_opts == second.btw_name_opts;
const ly_bool c = first.btw_opts_type == second.btw_opts_type;
const ly_bool d = first.btw_type_iffeatures == second.btw_type_iffeatures;
return a && b && c && d;
}
static void
pt_print_divided_node(const struct pt_node *node_p, struct pt_tree_ctx *tc,
struct pt_indent indent_p)
{
struct pt_node node;
struct pt_indent indent;
ly_bool entire_node_was_printed;
indent = indent_p;
node = *node_p;
pt_try_normal_indent_in_node(&node, tc, &indent);
if (indent.in_node.type == PT_INDENT_IN_NODE_FAILED) {
indent.in_node.type = PT_INDENT_IN_NODE_DIVIDED;
}
pt_print_line(&node, tc, PT_INIT_INDENT(indent_p.wrapper, indent.in_node));
entire_node_was_printed = pt_indent_in_node_are_eq(indent_p.in_node, indent.in_node);
if (!entire_node_was_printed) {
ly_print_(tc->out, "\n");
node = *node_p;
pt_second_half_node(&indent.in_node, &node);
pt_print_divided_node(&node, tc, PT_INIT_INDENT(indent.wrapper, indent.in_node));
} else {
return;
}
}
static void
pt_print_entire_node_(const struct pt_node *node_p, struct pt_tree_ctx *tc,
struct pt_indent indent_p)
{
struct pt_wrapper wr;
struct pt_node node_try;
struct pt_indent indent_try;
struct pt_indent indent_merge;
indent_try = indent_p;
node_try = *node_p;
pt_try_normal_indent_in_node(&node_try, tc, &indent_try);
if (indent_try.in_node.type == PT_INDENT_IN_NODE_NORMAL) {
pt_print_line(node_p, tc, indent_p);
} else if (indent_try.in_node.type == PT_INDENT_IN_NODE_DIVIDED) {
indent_merge = PT_INIT_INDENT(indent_p.wrapper, indent_try.in_node);
indent_merge.in_node.type = PT_INDENT_IN_NODE_NORMAL;
pt_print_line(&node_try, tc, indent_merge);
ly_print_(tc->out, "\n");
node_try = *node_p;
pt_second_half_node(&indent_try.in_node, &node_try);
wr = pt_wrapper_if_last_sibling(indent_p.wrapper, node_try.last_one);
indent_merge = PT_INIT_INDENT(wr, indent_try.in_node);
pt_print_divided_node(&node_try, tc, indent_merge);
} else if (indent_try.in_node.type == PT_INDENT_IN_NODE_FAILED) {
pt_print_line_up_to_node_name(node_p, indent_p.wrapper, tc->out);
if (pt_node_body_is_empty(node_p)) {
return;
}
ly_print_(tc->out, "\n");
node_try = *node_p;
pt_second_half_node(&indent_try.in_node, &node_try);
indent_try.in_node.type = PT_INDENT_IN_NODE_DIVIDED;
wr = pt_wrapper_if_last_sibling(indent_p.wrapper, node_try.last_one);
indent_merge = PT_INIT_INDENT(wr, indent_try.in_node);
pt_print_divided_node(&node_try, tc, indent_merge);
}
}
static ly_bool
pt_leafref_target_is_too_long(const struct pt_node *node, struct pt_wrapper wr,
size_t mll, struct ly_out *out)
{
size_t type_len;
struct ly_out_clb_arg *data;
if (node->type.type != PT_TYPE_TARGET) {
return 0;
}
data = out->method.clb.arg;
data->counter = 0;
data->mode = PT_CHAR_COUNT;
pt_print_wrapper(wr, out);
ly_print_(out, "%*c", PT_INDENT_BTW_SIBLINGS, ' ');
pt_print_divided_node_up_to_name(node, out);
data->mode = PT_PRINT;
type_len = strlen(node->type.str);
return data->counter + type_len > mll;
}
static void
pt_print_entire_node(struct pt_node node, uint32_t max_gap_before_type, struct pt_wrapper wr,
struct pt_tree_ctx *tc)
{
struct pt_indent_in_node indent = pt_default_indent_in_node(&node);
if ((max_gap_before_type > 0) && (node.type.type != PT_TYPE_EMPTY)) {
indent.btw_opts_type = pt_calc_btw_opts_type(&node, max_gap_before_type);
}
if (pt_leafref_target_is_too_long(&node, wr, tc->max_line_length, tc->out)) {
node.type.type = PT_TYPE_LEAFREF;
}
pt_print_entire_node_(&node, tc, PT_INIT_INDENT(wr, indent));
}
static void
pt_create_implicit_case_node(const struct pt_node *node, struct pt_node *case_node)
{
case_node->status = node->status;
case_node->flags = PT_FLAGS_TYPE_EMPTY;
case_node->name.type = PT_NODE_CASE;
case_node->name.keys = node->name.keys;
case_node->name.module_prefix = node->name.module_prefix;
case_node->name.str = node->name.str;
case_node->name.opts = node->name.opts;
case_node->type = PT_EMPTY_LF_TYPE;
case_node->iffeatures = PT_EMPTY_IFFEATURES;
case_node->last_one = node->last_one;
}
static const void *pt_next_sibling(const void *node, struct pt_tree_ctx *tc, ly_bool update);
static struct pt_wrapper
pt_print_implicit_node(const struct pt_node *node, struct pt_wrapper wr,
struct pt_tree_ctx *tc)
{
const void *sibl;
struct pt_node case_node;
struct pt_wrapper wr_case_child;
pt_create_implicit_case_node(node, &case_node);
ly_print_(tc->out, "\n");
pt_print_entire_node(case_node, 0, wr, tc);
ly_print_(tc->out, "\n");
sibl = tc->lysc_tree ? pt_next_sibling(tc->cn, tc, 0) : pt_next_sibling(tc->pn, tc, 0);
wr_case_child = sibl ?
pt_wrapper_set_mark(wr) : pt_wrapper_set_shift(wr);
return wr_case_child;
}
static ly_bool
pt_need_implicit_node_case(struct pt_tree_ctx *tc)
{
return !tc->lysc_tree && tc->pn->parent &&
(tc->pn->parent->nodetype & LYS_CHOICE) &&
(tc->pn->nodetype & (LYS_ANYDATA | LYS_CHOICE | LYS_CONTAINER |
LYS_LEAF | LYS_LEAFLIST));
}
static const void *
pt_get_node(const struct pt_tree_ctx *tc)
{
return tc->lysc_tree ?
(const void *)tc->cn :
(const void *)tc->pn;
}
static const void *
pt_get_child(const struct pt_tree_ctx *tc)
{
if (!pt_get_node(tc)) {
return NULL;
}
if (tc->lysc_tree) {
return lysc_node_child(tc->cn);
} else {
return lysp_node_child(tc->pn);
}
}
static uint16_t
pt_nodetype(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
((const struct lysc_node *)node)->nodetype :
((const struct lysp_node *)node)->nodetype;
}
static uint16_t
pt_lysp_flags(const struct pt_tree_ctx *tc, const void *node)
{
const struct lysc_node *cn;
if (!tc->lysc_tree) {
return ((const struct lysp_node *)node)->flags;
}
cn = (const struct lysc_node *)node;
if (PT_TREE_CTX_LYSP_NODE_PRESENT(cn)) {
return PT_TREE_CTX_GET_LYSP_NODE(cn)->flags;
} else {
return 0;
}
}
static const void *
pt_next(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)((const struct lysc_node *)node)->next :
(const void *)((const struct lysp_node *)node)->next;
}
static const void *
pt_parent(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)((const struct lysc_node *)node)->parent :
(const void *)((const struct lysp_node *)node)->parent;
}
static const void *
pt_child(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)lysc_node_child(node) :
(const void *)lysp_node_child(node);
}
static const void *
pt_actions(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)lysc_node_actions(node) :
(const void *)lysp_node_actions(node);
}
static const void *
pt_action_input(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)&((const struct lysc_node_action *)node)->input :
(const void *)&((const struct lysp_node_action *)node)->input;
}
static const void *
pt_action_output(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)&((const struct lysc_node_action *)node)->output :
(const void *)&((const struct lysp_node_action *)node)->output;
}
static const void *
pt_notifs(const struct pt_tree_ctx *tc, const void *node)
{
return tc->lysc_tree ?
(const void *)lysc_node_notifs(node) :
(const void *)lysp_node_notifs(node);
}
static ly_bool pt_schema_mount_skip(const struct lysc_node *node, const struct ly_set *refs);
static ly_bool
pt_ignore_node(const void *node, const struct pt_tree_ctx *tc)
{
struct pt_extension plugin_ctx;
plugin_ctx = tc->plugin_ctx;
if (node && plugin_ctx.schema_mount && (plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF) &&
pt_schema_mount_skip(node, plugin_ctx.schema_mount->parent_refs)) {
return 1;
} else if (node && (pt_lysp_flags(tc, node) & LYS_INTERNAL)) {
return 1;
} else {
return 0;
}
}
static void pt_ext_set_next_schema_mount(struct pt_tree_ctx *tc);
static const void *
pt_next_sibling(const void *node, struct pt_tree_ctx *tc, ly_bool update)
{
const void *tmp, *parent, *sibl;
struct pt_tree_ctx tc_copy;
assert(node);
if (pt_nodetype(tc, node) & (LYS_RPC | LYS_ACTION)) {
if ((tmp = pt_next(tc, node))) {
sibl = tmp;
} else if ((parent = pt_parent(tc, node))) {
sibl = pt_notifs(tc, parent);
} else {
sibl = NULL;
}
} else if (pt_nodetype(tc, node) & LYS_INPUT) {
if ((parent = pt_parent(tc, node))) {
if (pt_child(tc, pt_action_output(tc, parent))) {
sibl = pt_action_output(tc, parent);
} else {
sibl = NULL;
}
} else {
sibl = NULL;
}
} else if (pt_nodetype(tc, node) & LYS_OUTPUT) {
sibl = NULL;
} else if (pt_nodetype(tc, node) & LYS_NOTIF) {
sibl = pt_next(tc, node);
} else {
if ((tmp = pt_next(tc, node))) {
sibl = tmp;
} else if ((parent = pt_parent(tc, node))) {
if ((tmp = pt_actions(tc, parent))) {
sibl = tmp;
} else if ((tmp = pt_notifs(tc, parent))) {
sibl = tmp;
} else {
sibl = NULL;
}
} else {
sibl = NULL;
}
}
if (pt_ignore_node(sibl, tc)) {
return pt_next_sibling(sibl, tc, update);
}
if (!sibl && !pt_parent(tc, node) && tc->plugin_ctx.schema_mount &&
!PT_LAST_SCHEMA_MOUNT(tc->plugin_ctx)) {
tc_copy = *tc;
pt_ext_set_next_schema_mount(tc);
if (tc->lysc_tree) {
sibl = (const void *)tc->plugin_ctx.schema->ctree;
} else {
sibl = (const void *)tc->plugin_ctx.schema->ptree;
}
if (pt_ignore_node(sibl, tc)) {
sibl = pt_next_sibling(sibl, tc, update);
}
if (!update) {
*tc = tc_copy;
}
}
return sibl;
}
static const void *
pt_next_child(const void *node, struct pt_tree_ctx *tc, ly_bool update)
{
const void *tmp, *child;
assert(node);
if (tc->plugin_ctx.schema_mount && (tc->plugin_ctx.schema_mount->mount_point == node)) {
child = tc->plugin_ctx.schema_mount->schemas->ctree;
if (update) {
tc->plugin_ctx.schema = tc->plugin_ctx.schema_mount->schemas;
}
} else if (pt_nodetype(tc, node) & (LYS_ACTION | LYS_RPC)) {
if (pt_child(tc, pt_action_input(tc, node))) {
child = pt_action_input(tc, node);
} else if (pt_child(tc, pt_action_output(tc, node))) {
child = pt_action_output(tc, node);
} else {
child = NULL;
}
} else {
if ((tmp = pt_child(tc, node))) {
child = tmp;
} else {
if ((tmp = pt_actions(tc, node))) {
child = tmp;
} else if ((tmp = pt_notifs(tc, node))) {
child = tmp;
} else {
child = NULL;
}
}
}
if (pt_ignore_node(child, tc)) {
return pt_next_sibling(child, tc, update);
}
return child;
}
static ly_bool
pt_node_is_last_sibling(struct pt_tree_ctx *tc)
{
const void *sibl;
const void *parent;
sibl = tc->lysc_tree ? pt_next_sibling(tc->cn, tc, 0) : pt_next_sibling(tc->pn, tc, 0);
parent = tc->lysc_tree ? pt_parent(tc, tc->cn) : pt_parent(tc, tc->pn);
if (parent) {
return !sibl;
} else if (tc->plugin_ctx.schema_mount) {
return !sibl && !tc->plugin_ctx.schema_mount->mp_has_normal_node;
} else {
return !sibl && PT_LAST_SCHEMA(tc->plugin_ctx);
}
}
static struct pt_parent_cache
pt_parent_cache_for_child(struct pt_parent_cache ca, const struct pt_tree_ctx *tc)
{
struct pt_parent_cache ret = PT_EMPTY_PARENT_CACHE;
if (!tc->lysc_tree) {
const struct lysp_node *pn = tc->pn;
ret.ancestor =
pn->nodetype & (LYS_INPUT) ? PT_ANCESTOR_RPC_INPUT :
pn->nodetype & (LYS_OUTPUT) ? PT_ANCESTOR_RPC_OUTPUT :
pn->nodetype & (LYS_NOTIF) ? PT_ANCESTOR_NOTIF :
ca.ancestor;
ret.lys_status =
pn->flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT) ? pn->flags :
ca.lys_status;
ret.lys_config =
ca.ancestor == PT_ANCESTOR_RPC_INPUT ? 0 :
ca.ancestor == PT_ANCESTOR_RPC_OUTPUT ? LYS_CONFIG_R :
pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W) ? pn->flags :
ca.lys_config;
ret.last_list =
pn->nodetype & (LYS_LIST) ? (struct lysp_node_list *)pn :
ca.last_list;
}
return ret;
}
static struct pt_keyword_stmt
pt_read_module_name(const struct pt_tree_ctx *tc)
{
assert(tc);
struct pt_keyword_stmt module = PT_EMPTY_KEYWORD_STMT;
module.section_name = !tc->lysc_tree && tc->pmod->is_submod ?
PT_KEYWORD_SUBMODULE :
PT_KEYWORD_MODULE;
module.argument = !tc->lysc_tree ?
LYSP_MODULE_NAME(tc->pmod) :
tc->cmod->mod->name;
module.has_node = pt_get_node(tc) ? 1 : 0;
return module;
}
static struct pt_node pt_pnode_read(struct pt_parent_cache ca, struct pt_tree_ctx *tc);
static struct pt_node pt_cnode_read(struct pt_tree_ctx *tc);
static struct pt_node
pt_read_node(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
if (tc->lysc_tree) {
return pt_cnode_read(tc);
} else {
return pt_pnode_read(ca, tc);
}
}
static ly_bool
pt_pnode_list_has_keys(const struct lysp_node *pn)
{
return pt_charptr_has_data(((const struct lysp_node_list *)pn)->key);
}
static ly_bool
pt_pnode_has_iffeature(const struct lysp_node *pn)
{
LY_ARRAY_COUNT_TYPE u;
const struct lysp_qname *iffs;
ly_bool ret = 0;
iffs = pn->iffeatures;
LY_ARRAY_FOR(iffs, u) {
ret = 1;
break;
}
return ret;
}
static ly_bool
pt_pnode_leaf_is_key(const struct lysp_node *pn, const struct lysp_node_list *ca_last_list)
{
const struct lysp_node_leaf *leaf = (const struct lysp_node_leaf *)pn;
const struct lysp_node_list *list = ca_last_list;
if (!list) {
return 0;
}
return pt_charptr_has_data(list->key) ?
pt_word_is_present(list->key, leaf->name, ' ') : 0;
}
static ly_bool
pt_pnode_container_has_presence(const struct lysp_node *pn)
{
return pt_charptr_has_data(((struct lysp_node_container *)pn)->presence);
}
static char *
pt_pnode_resolve_status(uint16_t nodetype, uint16_t flags, uint16_t ca_lys_status)
{
if (nodetype & (LYS_INPUT | LYS_OUTPUT)) {
return pt_flags2status(ca_lys_status);
} else if ((ca_lys_status & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) && !(flags & (LYS_STATUS_CURR | LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
return pt_flags2status(ca_lys_status);
} else {
return pt_flags2status(flags);
}
}
static ly_bool pt_ext_is_present(struct pt_tree_ctx *tc, const char *ext_name);
static const char *
pt_pnode_resolve_flags(struct pt_tree_ctx *tc, pt_parent_type ca_ancestor,
uint16_t ca_lys_config)
{
const struct lysp_node *pn;
pn = tc->pn;
if (pt_ext_is_present(tc, "mount-point")) {
return PT_FLAGS_TYPE_MOUNT_POINT;
} else if (pn->nodetype & LYS_USES) {
return PT_FLAGS_TYPE_USES_OF_GROUPING;
} else if (tc->plugin_ctx.schema && (tc->plugin_ctx.schema->ext == PT_EXT_GENERIC)) {
return PT_FLAGS_TYPE_EXT;
} else if ((pn->nodetype & LYS_INPUT) || (ca_ancestor == PT_ANCESTOR_RPC_INPUT)) {
return PT_FLAGS_TYPE_RPC_INPUT_PARAMS;
} else if ((pn->nodetype & LYS_OUTPUT) || (ca_ancestor == PT_ANCESTOR_RPC_OUTPUT)) {
return PT_FLAGS_TYPE_RO;
} else if (ca_ancestor == PT_ANCESTOR_NOTIF) {
return PT_FLAGS_TYPE_RO;
} else if (pn->nodetype & LYS_NOTIF) {
return PT_FLAGS_TYPE_NOTIF;
} else if (pn->nodetype & (LYS_RPC | LYS_ACTION)) {
return PT_FLAGS_TYPE_RPC;
} else if (!(pn->flags & (LYS_CONFIG_R | LYS_CONFIG_W))) {
return pt_flags2config(ca_lys_config);
} else {
return pt_flags2config(pn->flags);
}
}
static void
pt_pnode_resolve_opts(struct pt_tree_ctx *tc, const struct lysp_node_list *ca_last_list,
pt_node_type *type, const char **opts)
{
if (tc->plugin_ctx.schema && !tc->pn->parent &&
(tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT)) {
*opts = PT_NODE_MOUNTED;
} else if (tc->plugin_ctx.schema && !tc->pn->parent &&
(tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) {
*opts = PT_NODE_MOUNTED_PARENT_REF;
} else if (tc->pn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
*type = PT_NODE_ELSE;
} else if (tc->pn->nodetype & LYS_CASE) {
*type = PT_NODE_CASE;
} else if ((tc->pn->nodetype & LYS_CHOICE) && !(tc->pn->flags & LYS_MAND_TRUE)) {
*type = PT_NODE_CHOICE;
*opts = PT_NODE_OPTIONAL;
} else if (tc->pn->nodetype & LYS_CHOICE) {
*type = PT_NODE_CHOICE;
} else if ((tc->pn->nodetype & LYS_CONTAINER) && (pt_pnode_container_has_presence(tc->pn))) {
*opts = PT_NODE_CONTAINER;
} else if (tc->pn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
*opts = PT_NODE_LISTLEAFLIST;
} else if ((tc->pn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(tc->pn->flags & LYS_MAND_TRUE)) {
*opts = PT_NODE_OPTIONAL;
} else if ((tc->pn->nodetype & LYS_LEAF) && !(tc->pn->flags & LYS_MAND_TRUE) && (!pt_pnode_leaf_is_key(tc->pn, ca_last_list))) {
*opts = PT_NODE_OPTIONAL;
} else {
*type = PT_NODE_ELSE;
}
}
static struct pt_lf_type
pt_pnode_resolve_type(const struct lysp_node *pn)
{
const char *str = NULL;
const struct lysp_node_leaf *leaf;
const struct lysp_node_leaflist *list;
if (!pn) {
return PT_EMPTY_LF_TYPE;
} else if (pn->nodetype & LYS_LEAFLIST) {
list = (const struct lysp_node_leaflist *)pn;
str = list->type.path ? list->type.path->expr : NULL;
if (pt_charptr_has_data(str)) {
return PT_INIT_LF_TYPE(PT_TYPE_TARGET, str);
}
str = list->type.name;
if (pt_charptr_has_data(str)) {
return PT_INIT_LF_TYPE(PT_TYPE_NAME, str);
} else {
return PT_EMPTY_LF_TYPE;
}
} else if (pn->nodetype & LYS_LEAF) {
leaf = (const struct lysp_node_leaf *)pn;
str = leaf->type.path ? leaf->type.path->expr : NULL;
if (pt_charptr_has_data(str)) {
return PT_INIT_LF_TYPE(PT_TYPE_TARGET, str);
}
str = leaf->type.name;
if (pt_charptr_has_data(str)) {
return PT_INIT_LF_TYPE(PT_TYPE_NAME, str);
} else {
return PT_EMPTY_LF_TYPE;
}
} else if (pn->nodetype == LYS_ANYDATA) {
return PT_INIT_LF_TYPE(PT_TYPE_NAME, "anydata");
} else if (pn->nodetype & LYS_ANYXML) {
return PT_INIT_LF_TYPE(PT_TYPE_NAME, "anyxml");
} else {
return PT_EMPTY_LF_TYPE;
}
}
static struct pt_iffeatures
pt_pnode_resolve_iffeatures(const struct lysp_node *pn)
{
struct pt_iffeatures iff;
if (pn && pt_pnode_has_iffeature(pn)) {
iff.type = PT_IFF_PRESENT;
} else {
iff.type = PT_IFF_NON_PRESENT;
}
return iff;
}
static struct pt_node
pt_pnode_read(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
const struct lysp_node *pn;
struct pt_node ret;
assert(tc && tc->pn && tc->pn->nodetype != LYS_UNKNOWN);
pn = tc->pn;
ret = PT_EMPTY_NODE;
ret.status = pt_pnode_resolve_status(pn->nodetype, pn->flags, ca.lys_status);
ret.flags = pt_pnode_resolve_flags(tc, ca.ancestor, ca.lys_config);
pt_pnode_resolve_opts(tc, ca.last_list, &ret.name.type, &ret.name.opts);
ret.name.keys = (tc->pn->nodetype & LYS_LIST) && pt_pnode_list_has_keys(tc->pn);
ret.name.module_prefix = NULL;
ret.name.str = pn->name;
ret.type = pt_pnode_resolve_type(pn);
ret.iffeatures = pt_pnode_resolve_iffeatures(pn);
ret.last_one = !pt_next_sibling(pn, tc, 0);
return ret;
}
static const char *
pt_cnode_resolve_flags(struct pt_tree_ctx *tc)
{
const struct lysc_node *cn;
cn = tc->cn;
if (pt_ext_is_present(tc, "mount-point")) {
return PT_FLAGS_TYPE_MOUNT_POINT;
} else if (tc->plugin_ctx.schema && (tc->plugin_ctx.schema->ext == PT_EXT_GENERIC)) {
return PT_FLAGS_TYPE_EXT;
} else if ((cn->nodetype & LYS_INPUT) || (cn->flags & LYS_IS_INPUT)) {
return PT_FLAGS_TYPE_RPC_INPUT_PARAMS;
} else if ((cn->nodetype & LYS_OUTPUT) || (cn->flags & LYS_IS_OUTPUT)) {
return PT_FLAGS_TYPE_RO;
} else if (cn->nodetype & LYS_NOTIF) {
return PT_FLAGS_TYPE_NOTIF;
} else if (cn->nodetype & (LYS_RPC | LYS_ACTION)) {
return PT_FLAGS_TYPE_RPC;
} else {
return pt_flags2config(cn->flags);
}
}
static void
pt_cnode_resolve_opts(struct pt_tree_ctx *tc, pt_node_type *type, const char **opts)
{
if (tc->plugin_ctx.schema && !tc->cn->parent &&
(tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT)) {
*opts = PT_NODE_MOUNTED;
} else if (tc->plugin_ctx.schema && !tc->cn->parent &&
(tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) {
*opts = PT_NODE_MOUNTED_PARENT_REF;
} else if (tc->cn->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
*type = PT_NODE_ELSE;
} else if (tc->cn->nodetype & LYS_CASE) {
*type = PT_NODE_CASE;
} else if ((tc->cn->nodetype & LYS_CHOICE) && !(tc->cn->flags & LYS_MAND_TRUE)) {
*type = PT_NODE_CHOICE;
*opts = PT_NODE_OPTIONAL;
} else if (tc->cn->nodetype & LYS_CHOICE) {
*type = PT_NODE_CHOICE;
} else if ((tc->cn->nodetype & LYS_CONTAINER) && (tc->cn->flags & LYS_PRESENCE)) {
*opts = PT_NODE_CONTAINER;
} else if (tc->cn->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
*opts = PT_NODE_LISTLEAFLIST;
} else if ((tc->cn->nodetype & (LYS_ANYDATA | LYS_ANYXML)) && !(tc->cn->flags & LYS_MAND_TRUE)) {
*opts = PT_NODE_OPTIONAL;
} else if ((tc->cn->nodetype & LYS_LEAF) && !(tc->cn->flags & (LYS_MAND_TRUE | LYS_KEY))) {
*opts = PT_NODE_OPTIONAL;
} else {
*type = PT_NODE_ELSE;
}
}
static const char *
pt_cnode_resolve_prefix(const struct lysc_node *cn, const struct lysc_module *current_compiled_module)
{
const struct lys_module *node_module;
const char *ret = NULL;
node_module = cn->module;
if (!node_module || !current_compiled_module) {
return NULL;
} else if (node_module->compiled != current_compiled_module) {
ret = node_module->prefix;
}
return ret;
}
static struct pt_node
pt_cnode_read(struct pt_tree_ctx *tc)
{
const struct lysc_node *cn;
struct pt_node ret;
assert(tc && tc->cn);
cn = tc->cn;
ret = PT_EMPTY_NODE;
ret.status = pt_flags2status(cn->flags);
ret.flags = pt_cnode_resolve_flags(tc);
pt_cnode_resolve_opts(tc, &ret.name.type, &ret.name.opts);
ret.name.keys = (cn->nodetype & LYS_LIST) && !(cn->flags & LYS_KEYLESS);
ret.name.module_prefix = pt_cnode_resolve_prefix(cn, tc->cmod);
ret.name.str = cn->name;
ret.type = pt_pnode_resolve_type(PT_TREE_CTX_GET_LYSP_NODE(cn));
ret.iffeatures = pt_pnode_resolve_iffeatures(PT_TREE_CTX_GET_LYSP_NODE(cn));
ret.last_one = !pt_next_sibling(cn, tc, 0);
return ret;
}
static struct pt_node
pt_modi_next_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
const void *node, *sibl;
node = pt_get_node(tc);
sibl = pt_next_sibling(node, tc, 1);
if (!sibl) {
return PT_EMPTY_NODE;
}
if (tc->plugin_ctx.schema) {
tc->lysc_tree = tc->plugin_ctx.schema->compiled;
}
if (tc->lysc_tree) {
tc->cn = sibl;
return pt_cnode_read(tc);
} else {
tc->pn = sibl;
return pt_pnode_read(ca, tc);
}
}
static struct pt_node
pt_modi_next_child(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
const void *node, *child;
node = pt_get_node(tc);
child = pt_next_child(node, tc, 1);
if (!child) {
return PT_EMPTY_NODE;
}
if (tc->plugin_ctx.schema) {
tc->lysc_tree = tc->plugin_ctx.schema->compiled;
}
if (tc->lysc_tree) {
tc->cn = child;
return pt_cnode_read(tc);
} else {
tc->pn = child;
return pt_pnode_read(ca, tc);
}
}
static void
pt_modi_next_child2(struct pt_tree_ctx *tc)
{
const void *node = pt_get_child(tc);
if (tc->lysc_tree) {
tc->cn = node;
} else {
tc->pn = node;
}
}
static ly_bool
pt_modi_parent(struct pt_tree_ctx *tc)
{
if (tc->lysc_tree) {
assert(tc && tc->cn);
if (tc->cn->parent) {
tc->cn = tc->cn->parent;
return 1;
} else {
return 0;
}
} else {
assert(tc && tc->pn);
if (!tc->pn->parent) {
return 0;
}
if (((tc->section == PT_SECT_AUGMENT) || (tc->section == PT_SECT_GROUPING)) &&
!tc->pn->parent->parent) {
return 0;
}
tc->pn = tc->pn->parent;
return 1;
}
}
static struct pt_node
pt_cnode_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
struct pt_node node;
assert(tc && tc->cn);
if (pt_modi_parent(tc)) {
node = pt_modi_next_child(ca, tc);
} else {
switch (tc->section) {
case PT_SECT_MODULE:
tc->cn = tc->cn->module->compiled->data;
break;
case PT_SECT_RPCS:
tc->cn = (const struct lysc_node *)tc->cmod->rpcs;
break;
case PT_SECT_NOTIF:
tc->cn = (const struct lysc_node *)tc->cmod->notifs;
break;
case PT_SECT_PLUG_DATA:
if ((tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT) ||
(tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) {
tc->cn = tc->plugin_ctx.schema_mount->schemas->ctree;
tc->plugin_ctx.schema = tc->plugin_ctx.schema_mount->schemas;
} else {
tc->cn = tc->plugin_ctx.schema->ctree;
}
break;
default:
assert(0);
}
if (pt_ignore_node(tc->cn, tc)) {
node = pt_modi_next_sibling(ca, tc);
} else {
node = pt_cnode_read(tc);
}
}
return node;
}
static struct pt_node
pt_pnode_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
struct pt_node node;
assert(tc && tc->pn);
if (pt_modi_parent(tc)) {
node = pt_modi_next_child(ca, tc);
} else {
switch (tc->section) {
case PT_SECT_MODULE:
tc->pn = tc->pmod->data;
break;
case PT_SECT_AUGMENT:
tc->pn = lysp_node_child(tc->pn->parent);
break;
case PT_SECT_RPCS:
tc->pn = (const struct lysp_node *)tc->pmod->rpcs;
break;
case PT_SECT_NOTIF:
tc->pn = (const struct lysp_node *)tc->pmod->notifs;
break;
case PT_SECT_GROUPING:
tc->pn = lysp_node_child(tc->pn->parent);
break;
case PT_SECT_PLUG_DATA:
if ((tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT) ||
(tc->plugin_ctx.schema->ext == PT_EXT_SCHEMA_MOUNT_REF)) {
tc->pn = tc->plugin_ctx.schema_mount->schemas->ptree;
tc->plugin_ctx.schema = tc->plugin_ctx.schema_mount->schemas;
} else {
tc->pn = tc->plugin_ctx.schema->ptree;
}
break;
default:
assert(0);
}
if (pt_ignore_node(tc->pn, tc)) {
node = pt_modi_next_sibling(ca, tc);
} else {
node = pt_pnode_read(ca, tc);
}
}
return node;
}
static struct pt_node
pt_modi_first_sibling(struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
return tc->lysc_tree ? pt_cnode_modi_first_sibling(ca, tc) : pt_pnode_modi_first_sibling(ca, tc);
}
static struct pt_keyword_stmt
pt_modi_get_rpcs(struct pt_tree_ctx *tc)
{
assert(tc);
const void *actions;
struct pt_keyword_stmt rpc = PT_EMPTY_KEYWORD_STMT;
if (tc->lysc_tree) {
actions = tc->cmod->rpcs;
if (actions) {
tc->cn = actions;
}
} else {
actions = tc->pmod->rpcs;
if (actions) {
tc->pn = actions;
}
}
if (actions) {
tc->section = PT_SECT_RPCS;
rpc.section_name = PT_KEYWORD_RPC;
rpc.has_node = pt_get_node(tc) ? 1 : 0;
}
return rpc;
}
static struct pt_keyword_stmt
pt_modi_get_notifications(struct pt_tree_ctx *tc)
{
assert(tc);
const void *notifs;
struct pt_keyword_stmt notif = PT_EMPTY_KEYWORD_STMT;
if (tc->lysc_tree) {
notifs = tc->cmod->notifs;
if (notifs) {
tc->cn = notifs;
}
} else {
notifs = tc->pmod->notifs;
if (notifs) {
tc->pn = notifs;
}
}
if (notifs) {
tc->section = PT_SECT_NOTIF;
notif.section_name = PT_KEYWORD_NOTIF;
notif.has_node = pt_get_node(tc) ? 1 : 0;
}
return notif;
}
static struct pt_keyword_stmt
pt_modi_get_augment(struct pt_tree_ctx *tc, uint32_t index)
{
assert(tc);
const struct lysp_node_augment *augs, *elem;
struct pt_keyword_stmt aug = PT_EMPTY_KEYWORD_STMT;
uint32_t i;
i = 0;
augs = tc->pmod->augments;
LY_LIST_FOR(augs, elem) {
if (i == index) {
tc->pn = &elem->node;
aug.section_name = PT_KEYWORD_AUGMENT;
aug.argument = elem->nodeid;
aug.has_node = pt_get_child(tc) ? 1 : 0;
return aug;
}
i++;
}
return PT_EMPTY_KEYWORD_STMT;
}
static struct pt_keyword_stmt
pt_modi_get_grouping(struct pt_tree_ctx *tc, uint32_t index)
{
assert(tc);
const struct lysp_node_grp *grps, *elem;
struct pt_keyword_stmt group = PT_EMPTY_KEYWORD_STMT;
uint32_t i;
i = 0;
grps = tc->pmod->groupings;
LY_LIST_FOR(grps, elem) {
if (i == index) {
tc->pn = &elem->node;
group.section_name = PT_KEYWORD_GROUPING;
group.argument = elem->name;
group.has_node = pt_get_child(tc) ? 1 : 0;
return group;
}
i++;
}
return PT_EMPTY_KEYWORD_STMT;
}
static void
pt_ext_set_next_schema_mount(struct pt_tree_ctx *tc)
{
LY_ARRAY_COUNT_TYPE i;
struct pt_ext_tree_schema *schemas;
ly_bool set_next = 0;
assert(!PT_LAST_SCHEMA_MOUNT(tc->plugin_ctx));
schemas = tc->plugin_ctx.schema_mount->schemas;
LY_ARRAY_FOR(schemas, i) {
if (set_next) {
tc->plugin_ctx.schema = &schemas[i];
tc->lysc_tree = tc->plugin_ctx.schema->compiled;
break;
} else if (&schemas[i] == tc->plugin_ctx.schema) {
set_next = 1;
}
}
assert(set_next);
}
static ly_bool
pt_ext_parent_is_valid(ly_bool lysc_tree, void *ext)
{
enum ly_stmt parent_stmt;
if (lysc_tree) {
parent_stmt = ((struct lysc_ext_instance *)ext)->parent_stmt;
} else {
parent_stmt = ((struct lysp_ext_instance *)ext)->parent_stmt;
}
if ((parent_stmt & LY_STMT_OP_MASK) || (parent_stmt & LY_STMT_DATA_NODE_MASK) ||
(parent_stmt & LY_STMT_SUBMODULE) || parent_stmt & LY_STMT_MODULE) {
return 1;
} else {
return 0;
}
}
static void *
pt_ext_iter_next(ly_bool lysc_tree, void *exts, LY_ARRAY_COUNT_TYPE *i)
{
void *ext = NULL;
struct lysc_ext_instance *ce;
struct lysp_ext_instance *pe;
if (!exts) {
return NULL;
}
if (lysc_tree) {
ce = exts;
while (*i < LY_ARRAY_COUNT(ce)) {
if (ce->def->plugin_ref && pt_ext_parent_is_valid(1, &ce[*i])) {
ext = &ce[*i];
break;
}
++(*i);
}
} else {
pe = exts;
while (*i < LY_ARRAY_COUNT(pe)) {
if (pt_ext_parent_is_valid(0, &pe[*i])) {
ext = &pe[*i];
break;
}
++(*i);
}
}
++(*i);
return ext;
}
static void *
pt_ext_iter(const struct pt_tree_ctx *tc, const char *ext_name,
ly_bool from_module, LY_ARRAY_COUNT_TYPE *i)
{
struct lysp_ext_instance *ext_pars;
struct lysc_ext_instance *ext_comp;
void *ext = NULL;
const char *name = "";
do {
if (tc->lysc_tree) {
ext_comp = from_module ? tc->cmod->exts : tc->cn->exts;
ext_comp = ext = pt_ext_iter_next(1, ext_comp, i);
if (ext_comp) {
name = ext_comp->def->name;
assert(name);
}
} else {
ext_pars = from_module ? tc->pmod->exts : tc->pn->exts;
ext_pars = ext = pt_ext_iter_next(0, ext_pars, i);
if (ext_pars) {
name = strchr(ext_pars->name, ':') + 1;
assert(name);
}
}
} while (ext && ext_name && strcmp(name, ext_name));
return ext;
}
static ly_bool
pt_ext_is_present(struct pt_tree_ctx *tc, const char *ext_name)
{
uint64_t i = 0;
if (pt_ext_iter(tc, ext_name, 0, &i)) {
return 1;
} else {
return 0;
}
}
static ly_bool
pt_schema_mount_skip(const struct lysc_node *node, const struct ly_set *refs)
{
uint32_t i;
const struct lysc_module *mod;
struct lysc_node *ref, *iter;
ly_bool skip;
mod = node->module->compiled;
skip = 1;
for (i = 0; (i < refs->count) && skip; i++) {
ref = refs->snodes[i];
if (ref->module->compiled != mod) {
continue;
}
for (iter = ref; iter; iter = iter->parent) {
if (iter == node) {
skip = 0;
break;
}
}
}
return skip;
}
static LY_ERR
pt_ext_sprinter_ctree_add_nodes(const struct pt_ext_schema_mount *ctx, struct lysc_node *nodes, ly_bool parent_ref)
{
struct pt_ext_tree_schema *new;
LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL);
if (!nodes) {
return LY_SUCCESS;
}
LY_ARRAY_NEW_RET(NULL, ((struct pt_ext_schema_mount *)ctx)->schemas, new, LY_EMEM);
new->compiled = 1;
new->ctree = nodes;
new->ext = parent_ref ? PT_EXT_SCHEMA_MOUNT_REF : PT_EXT_SCHEMA_MOUNT;
return LY_SUCCESS;
}
static LY_ERR
pt_ext_sprinter_ptree_add_nodes(const struct pt_ext_schema_mount *ctx, struct lysp_node *nodes, ly_bool parent_ref)
{
struct pt_ext_tree_schema *new;
LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL);
if (!nodes) {
return LY_SUCCESS;
}
LY_ARRAY_NEW_RET(NULL, ((struct pt_ext_schema_mount *)ctx)->schemas, new, LY_EMEM);
new->compiled = 0;
new->ptree = nodes;
new->ext = parent_ref ? PT_EXT_SCHEMA_MOUNT_REF : PT_EXT_SCHEMA_MOUNT;
return LY_SUCCESS;
}
static LY_ERR
pt_create_mount_point(ly_bool compiled, void *ext, struct pt_ext_schema_mount *schema_mount)
{
LY_ERR rc = LY_SUCCESS;
const struct ly_ctx *ext_ctx = NULL;
const struct lys_module *mod;
struct ly_set *refs = NULL;
struct lysc_node *tree1, *tree2;
uint32_t i, j;
ly_bool from_parent_ref, is_first;
if (!compiled) {
return LY_SUCCESS;
}
if (lyplg_ext_schema_mount_get_ctx(ext, NULL, &ext_ctx)) {
return LY_SUCCESS;
}
rc = lyplg_ext_schema_mount_get_parent_ref(ext, NULL, &refs);
LY_CHECK_GOTO(rc, cleanup);
i = ly_ctx_internal_modules_count(ext_ctx);
while ((mod = ly_ctx_get_module_iter(ext_ctx, &i))) {
from_parent_ref = 0;
for (j = 0; refs && j < refs->count; j++) {
if (!strcmp(mod->ns, refs->snodes[j]->module->ns)) {
from_parent_ref = 1;
break;
}
}
if (from_parent_ref) {
continue;
}
if ((ext_ctx->opts & LY_CTX_SET_PRIV_PARSED) && mod->compiled) {
rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, mod->compiled->data, 0);
LY_CHECK_GOTO(rc, cleanup);
if (mod->compiled->rpcs) {
rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, &mod->compiled->rpcs->node, 0);
}
LY_CHECK_GOTO(rc, cleanup);
if (mod->compiled->notifs) {
rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, &mod->compiled->notifs->node, 0);
}
LY_CHECK_GOTO(rc, cleanup);
} else {
rc = pt_ext_sprinter_ptree_add_nodes(schema_mount, mod->parsed->data, 0);
LY_CHECK_GOTO(rc, cleanup);
if (mod->parsed->rpcs) {
rc = pt_ext_sprinter_ptree_add_nodes(schema_mount, &mod->parsed->rpcs->node, 0);
}
LY_CHECK_GOTO(rc, cleanup);
if (mod->parsed->notifs) {
rc = pt_ext_sprinter_ptree_add_nodes(schema_mount, &mod->parsed->notifs->node, 0);
}
LY_CHECK_GOTO(rc, cleanup);
}
}
for (i = 0; refs && (i < refs->count); i++) {
tree1 = refs->snodes[i]->module->compiled->data;
is_first = 1;
for (j = 0; j < i; j++) {
tree2 = refs->snodes[j]->module->compiled->data;
if (tree1 == tree2) {
is_first = 0;
break;
}
}
if (is_first) {
rc = pt_ext_sprinter_ctree_add_nodes(schema_mount, tree1, 1);
LY_CHECK_GOTO(rc, cleanup);
}
}
schema_mount->parent_refs = refs;
cleanup:
if (rc) {
ly_set_free(refs, NULL);
}
return rc;
}
static void pt_print_subtree(struct pt_node *node, uint32_t max_gap_before_type, struct pt_wrapper wr,
struct pt_parent_cache ca, ly_bool print_root, struct pt_tree_ctx *tc);
static void
pt_print_schema_mount(struct pt_wrapper wr, struct pt_parent_cache ca,
struct pt_tree_ctx tc)
{
LY_ERR rc;
LY_ARRAY_COUNT_TYPE i;
void *ext;
struct pt_ext_schema_mount schema_mount = {0};
struct pt_node node;
if (!tc.lysc_tree) {
return;
}
if (pt_next_child(pt_get_node(&tc), &tc, 0)) {
schema_mount.mp_has_normal_node = 1;
}
tc.section = PT_SECT_PLUG_DATA;
tc.pmod = NULL;
tc.cmod = NULL;
i = 0;
while ((ext = pt_ext_iter(&tc, "mount-point", 0, &i))) {
rc = pt_create_mount_point(tc.lysc_tree, ext, &schema_mount);
LY_CHECK_ERR_GOTO(rc, tc.last_error = rc, end);
if (!schema_mount.schemas) {
goto end;
}
schema_mount.mount_point = tc.cn;
tc.plugin_ctx.schema_mount = &schema_mount;
tc.plugin_ctx.schema = schema_mount.schemas;
tc.lysc_tree = tc.plugin_ctx.schema->compiled;
node = PT_EMPTY_NODE;
pt_print_subtree(&node, 0, wr, ca, 0, &tc);
break;
}
end:
LY_ARRAY_FREE(schema_mount.schemas);
if (schema_mount.parent_refs) {
ly_set_free(schema_mount.parent_refs, NULL);
}
return;
}
static void
pt_print_parents(const struct lysc_node *node, struct pt_wrapper *wr_in, struct pt_tree_ctx *tc)
{
uint32_t max_gap_before_type;
struct pt_wrapper wr;
struct pt_node print_node;
assert(tc && tc->section == PT_SECT_MODULE);
if (!node) {
return;
}
pt_print_parents(node->parent, wr_in, tc);
tc->cn = node;
wr = pt_count_depth(wr_in, node);
ly_print_(tc->out, "\n");
print_node = pt_read_node(PT_EMPTY_PARENT_CACHE, tc);
print_node.last_one = 1;
max_gap_before_type = pt_max_gap_to_type(PT_EMPTY_PARENT_CACHE, tc);
tc->cn = node;
pt_print_entire_node(print_node, max_gap_before_type, wr, tc);
}
static void pt_print_subtree(struct pt_node *node, uint32_t max_gap_before_type, struct pt_wrapper wr,
struct pt_parent_cache ca, ly_bool print_root, struct pt_tree_ctx *tc);
static void
pt_print_siblings(struct pt_node *node, struct pt_wrapper wr,
struct pt_parent_cache ca, struct pt_tree_ctx *tc)
{
uint32_t max_gap_before_type;
max_gap_before_type = pt_try_unified_indent(ca, *tc);
do {
if (pt_need_implicit_node_case(tc)) {
struct pt_wrapper wr_case_child;
wr_case_child = pt_print_implicit_node(node, wr, tc);
pt_print_subtree(node, max_gap_before_type, wr_case_child, ca, 1, tc);
} else {
ly_print_(tc->out, "\n");
pt_print_subtree(node, max_gap_before_type, wr, ca, 1, tc);
}
*node = pt_modi_next_sibling(ca, tc);
} while (!pt_node_is_empty(node));
}
static void
pt_print_subtree(struct pt_node *node, uint32_t max_gap_before_type, struct pt_wrapper wr,
struct pt_parent_cache ca, ly_bool print_root, struct pt_tree_ctx *tc)
{
if (print_root && !pt_node_is_empty(node)) {
pt_print_entire_node(*node, max_gap_before_type, wr, tc);
if (pt_ext_is_present(tc, "mount-point")) {
pt_print_schema_mount(wr, ca, *tc);
}
}
wr = pt_node_is_last_sibling(tc) ?
pt_wrapper_set_shift(wr) : pt_wrapper_set_mark(wr);
ca = pt_parent_cache_for_child(ca, tc);
*node = pt_modi_next_child(ca, tc);
if (pt_node_is_empty(node)) {
return;
}
pt_print_siblings(node, wr, ca, tc);
pt_modi_parent(tc);
}
static void
pt_print_trees(struct pt_wrapper wr, struct pt_tree_ctx *tc)
{
struct pt_parent_cache ca;
struct pt_node node;
uint32_t max_gap_before_type;
if (!pt_get_node(tc)) {
return;
}
ca = PT_EMPTY_PARENT_CACHE;
max_gap_before_type = pt_try_unified_indent(ca, *tc);
if (!tc->lysc_tree) {
if ((tc->section == PT_SECT_GROUPING) && !tc->pn->parent->parent) {
ca.lys_config = 0x0;
}
}
for (node = pt_modi_first_sibling(ca, tc);
!pt_node_is_empty(&node);
node = pt_modi_next_sibling(ca, tc)) {
ly_print_(tc->out, "\n");
pt_print_subtree(&node, max_gap_before_type, wr, ca, 1, tc);
}
}
static void
pt_lysp_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length,
struct pt_tree_ctx *tc)
{
*tc = (struct pt_tree_ctx) {
.lysc_tree = 0,
.section = PT_SECT_MODULE,
.pmod = module->parsed,
.cmod = NULL,
.pn = module->parsed ? module->parsed->data : NULL,
.cn = NULL,
.last_error = 0,
.plugin_ctx = {
.schema_mount = NULL,
.schema = NULL,
},
.out = out,
.max_line_length = max_line_length
};
}
static void
pt_lysc_tree_ctx(const struct lys_module *module, struct ly_out *out, size_t max_line_length,
struct pt_tree_ctx *tc)
{
*tc = (struct pt_tree_ctx) {
.lysc_tree = 1,
.section = PT_SECT_MODULE,
.pmod = module->parsed,
.cmod = module->compiled,
.pn = NULL,
.cn = module->compiled->data,
.last_error = 0,
.plugin_ctx = {
.schema_mount = NULL,
.schema = NULL,
},
.out = out,
.max_line_length = max_line_length
};
}
static void
pt_reset_to_lysp_tree_ctx(struct pt_tree_ctx *tc)
{
LY_ERR erc;
erc = tc->last_error;
pt_lysp_tree_ctx(tc->pmod->mod, tc->out, tc->max_line_length, tc);
tc->last_error = erc;
}
static ly_bool
pt_nodeid_target_is_local(const struct lysp_node_augment *pn, const struct lysp_module *pmod)
{
const char *id, *prefix, *name;
uint32_t prefix_len, name_len;
const struct lys_module *mod;
ly_bool ret = 0;
if (pn == NULL) {
return ret;
}
id = pn->nodeid;
if (!id) {
return ret;
}
assert(id[0] == '/');
++id;
ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len);
if (prefix) {
mod = ly_resolve_prefix(pmod->mod->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, pmod);
ret = mod ? (mod->parsed == pmod) : 0;
} else {
ret = 1;
}
return ret;
}
static void
pt_print_module_section(struct pt_tree_ctx *tc)
{
struct pt_keyword_stmt module = PT_EMPTY_KEYWORD_STMT;
module = pt_read_module_name(tc);
pt_print_keyword_stmt(&module, NULL, tc->out);
pt_print_trees(PT_INIT_WRAPPER_TOP, tc);
}
static void
pt_print_augmentations(struct pt_tree_ctx tc)
{
uint32_t i;
ly_bool once = 1;
ly_bool origin_was_lysc_tree = 0;
struct pt_keyword_stmt aug = PT_EMPTY_KEYWORD_STMT;
if (tc.lysc_tree) {
origin_was_lysc_tree = 1;
pt_reset_to_lysp_tree_ctx(&tc);
}
for (i = 0; ((aug = pt_modi_get_augment(&tc, i))).section_name; i++) {
tc.section = PT_SECT_AUGMENT;
if (origin_was_lysc_tree) {
if (pt_nodeid_target_is_local((const struct lysp_node_augment *)tc.pn, tc.pmod)) {
continue;
}
}
pt_print_keyword_stmt(&aug, &once, tc.out);
pt_modi_next_child2(&tc);
pt_print_trees(PT_INIT_WRAPPER_BODY, &tc);
}
}
static void
pt_print_rpcs(struct pt_tree_ctx *tc)
{
ly_bool once = 1;
struct pt_keyword_stmt rpc = PT_EMPTY_KEYWORD_STMT;
rpc = pt_modi_get_rpcs(tc);
if (rpc.section_name) {
pt_print_keyword_stmt(&rpc, &once, tc->out);
pt_print_trees(PT_INIT_WRAPPER_BODY, tc);
}
}
static void
pt_print_notifications(struct pt_tree_ctx *tc)
{
ly_bool once = 1;
struct pt_keyword_stmt notifs = PT_EMPTY_KEYWORD_STMT;
notifs = pt_modi_get_notifications(tc);
if (notifs.section_name) {
pt_print_keyword_stmt(¬ifs, &once, tc->out);
pt_print_trees(PT_INIT_WRAPPER_BODY, tc);
}
}
static void
pt_print_groupings(struct pt_tree_ctx *tc)
{
uint32_t i;
ly_bool once = 1;
struct pt_keyword_stmt group = PT_EMPTY_KEYWORD_STMT;
if (tc->lysc_tree) {
return;
}
for (i = 0; ((group = pt_modi_get_grouping(tc, i))).section_name; i++) {
tc->section = PT_SECT_GROUPING;
pt_print_keyword_stmt(&group, &once, tc->out);
pt_modi_next_child2(tc);
pt_print_trees(PT_INIT_WRAPPER_BODY, tc);
}
}
static void *
pt_ext_parsed_read_storage(struct lysp_ext_instance *ext, int stmt_mask)
{
LY_ARRAY_COUNT_TYPE i;
enum ly_stmt stmt;
void *substmts, **storage_p, *node = NULL;
substmts = (void *)((struct lysp_ext_instance *)ext)->substmts;
LY_ARRAY_FOR(substmts, i) {
stmt = ((struct lysp_ext_instance *)ext)->substmts[i].stmt;
storage_p = ((struct lysp_ext_instance *)ext)->substmts[i].storage_p;
if (storage_p && (stmt & stmt_mask)) {
return *storage_p;
}
}
return node;
}
static void *
pt_ext_read(void *ext, ly_bool *compiled, struct pt_keyword_stmt *ks)
{
struct lysc_ext_instance *ext_comp;
struct lysp_ext_instance *ext_pars;
const char *name;
void *schema;
if (!*compiled) {
ext_pars = ext;
ks->argument = ext_pars->argument;
name = strchr(ext_pars->name, ':') + 1;
ks->section_name = name;
if (!strcmp(ks->section_name, "augment-structure")) {
schema = pt_ext_parsed_read_storage(ext_pars, LY_STMT_AUGMENT);
schema = ((struct lysp_node_augment *)schema)->child;
} else {
schema = pt_ext_parsed_read_storage(ext_pars, LY_STMT_DATA_NODE_MASK);
}
*compiled = 0;
return schema;
}
ext_comp = ext;
ks->argument = ext_comp->argument;
ks->section_name = ext_comp->def->name;
lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, sizeof schema, (const void **)&schema);
*compiled = 1;
if (schema) {
return schema;
}
*compiled = 0;
if (!strcmp(ks->section_name, "augment-structure")) {
lyplg_ext_parsed_get_storage(ext_comp, LY_STMT_AUGMENT, sizeof schema, (const void **)&schema);
schema = ((struct lysp_node_augment *)schema)->child;
} else {
lyplg_ext_parsed_get_storage(ext_comp, LY_STMT_DATA_NODE_MASK, sizeof schema, (const void **)&schema);
}
return schema;
}
static void
pt_print_extensions(struct pt_tree_ctx tc)
{
ly_bool once = 1;
LY_ARRAY_COUNT_TYPE i = 0;
struct pt_keyword_stmt ks = PT_EMPTY_KEYWORD_STMT;
struct pt_node node;
void *schema;
void *ext;
struct pt_ext_tree_schema ext_schema;
ly_bool origin_lysc_tree = tc.lysc_tree;
tc.section = PT_SECT_PLUG_DATA;
tc.plugin_ctx.schema = &ext_schema;
tc.plugin_ctx.schema->ext = PT_EXT_GENERIC;
while ((ext = pt_ext_iter(&tc, NULL, 1, &i))) {
tc.lysc_tree = origin_lysc_tree;
schema = pt_ext_read(ext, &tc.lysc_tree, &ks);
if (!strcmp(ks.section_name, "mount-point") ||
!strcmp(ks.section_name, "annotation")) {
continue;
}
if (tc.lysc_tree) {
tc.cn = schema;
tc.plugin_ctx.schema->ctree = tc.cn;
tc.plugin_ctx.schema->compiled = 1;
ks.has_node = tc.cn ? 1 : 0;
} else {
tc.pn = schema;
tc.plugin_ctx.schema->ptree = tc.pn;
tc.plugin_ctx.schema->compiled = 0;
ks.has_node = tc.pn ? 1 : 0;
}
pt_print_keyword_stmt(&ks, &once, tc.out);
if (!ks.has_node) {
continue;
}
node = pt_modi_first_sibling(PT_EMPTY_PARENT_CACHE, &tc);
pt_print_siblings(&node, PT_INIT_WRAPPER_BODY, PT_EMPTY_PARENT_CACHE, &tc);
tc.lysc_tree = origin_lysc_tree;
}
}
static void
pt_print_sections(struct pt_tree_ctx *tc)
{
pt_print_module_section(tc);
pt_print_augmentations(*tc);
pt_print_rpcs(tc);
pt_print_notifications(tc);
pt_print_groupings(tc);
pt_print_extensions(*tc);
ly_print_(tc->out, "\n");
}
static LY_ERR
pt_print_check_error(struct ly_out_clb_arg *out, struct pt_tree_ctx *tc)
{
if (out->last_error) {
return out->last_error;
} else if (tc->last_error) {
return tc->last_error;
} else {
return LY_SUCCESS;
}
}
LY_ERR
tree_print_module(struct ly_out *out, const struct lys_module *module, uint32_t UNUSED(options), size_t line_length)
{
struct pt_tree_ctx tc;
struct ly_out *new_out;
LY_ERR erc;
struct ly_out_clb_arg clb_arg = PT_INIT_LY_OUT_CLB_ARG(PT_PRINT, out, 0, LY_SUCCESS);
LY_CHECK_ARG_RET3(module->ctx, out, module, module->parsed, LY_EINVAL);
if ((erc = ly_out_new_clb(&pt_ly_out_clb_func, &clb_arg, &new_out))) {
return erc;
}
line_length = line_length == 0 ? SIZE_MAX : line_length;
if ((module->ctx->opts & LY_CTX_SET_PRIV_PARSED) && module->compiled) {
pt_lysc_tree_ctx(module, new_out, line_length, &tc);
} else {
pt_lysp_tree_ctx(module, new_out, line_length, &tc);
}
pt_print_sections(&tc);
erc = pt_print_check_error(&clb_arg, &tc);
ly_out_free(new_out, NULL, 1);
return erc;
}
LY_ERR
tree_print_compiled_node(struct ly_out *out, const struct lysc_node *node, uint32_t options, size_t line_length)
{
struct pt_tree_ctx tc;
struct ly_out *new_out;
struct pt_wrapper wr;
LY_ERR erc;
struct ly_out_clb_arg clb_arg = PT_INIT_LY_OUT_CLB_ARG(PT_PRINT, out, 0, LY_SUCCESS);
struct pt_keyword_stmt module = PT_EMPTY_KEYWORD_STMT;
assert(out && node);
if (!(node->module->ctx->opts & LY_CTX_SET_PRIV_PARSED)) {
return LY_EINVAL;
}
if ((erc = ly_out_new_clb(&pt_ly_out_clb_func, &clb_arg, &new_out))) {
return erc;
}
line_length = line_length == 0 ? SIZE_MAX : line_length;
pt_lysc_tree_ctx(node->module, new_out, line_length, &tc);
module = pt_read_module_name(&tc);
pt_print_keyword_stmt(&module, NULL, tc.out);
pt_print_parents(node, NULL, &tc);
if (!(options & LYS_PRINT_NO_SUBSTMT)) {
tc.cn = lysc_node_child(node);
wr = pt_count_depth(NULL, tc.cn);
pt_print_trees(wr, &tc);
}
ly_print_(out, "\n");
erc = pt_print_check_error(&clb_arg, &tc);
ly_out_free(new_out, NULL, 1);
return erc;
}
LY_ERR
tree_print_parsed_submodule(struct ly_out *out, const struct lysp_submodule *submodp, uint32_t UNUSED(options),
size_t line_length)
{
struct pt_tree_ctx tc;
struct ly_out *new_out;
LY_ERR erc;
struct ly_out_clb_arg clb_arg = PT_INIT_LY_OUT_CLB_ARG(PT_PRINT, out, 0, LY_SUCCESS);
assert(submodp);
LY_CHECK_ARG_RET(submodp->mod->ctx, out, LY_EINVAL);
if ((erc = ly_out_new_clb(&pt_ly_out_clb_func, &clb_arg, &new_out))) {
return erc;
}
line_length = line_length == 0 ? SIZE_MAX : line_length;
pt_lysp_tree_ctx(submodp->mod, new_out, line_length, &tc);
tc.pmod = (struct lysp_module *)submodp;
tc.pn = submodp->data;
pt_print_sections(&tc);
erc = pt_print_check_error(&clb_arg, &tc);
ly_out_free(new_out, NULL, 1);
return erc;
}