data tree FEATURE initial implementation of YANG data support
diff --git a/src/printer_schema.c b/src/printer_schema.c
new file mode 100644
index 0000000..c07ea79
--- /dev/null
+++ b/src/printer_schema.c
@@ -0,0 +1,193 @@
+/**
+ * @file printer_schema.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Generic schema printers functions.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "printer_internal.h"
+#include "tree_schema.h"
+
+/**
+ * @brief Common schema printer.
+ *
+ * @param[in] out Prepared structure defining the type and details of the printer output.
+ * @param[in] module Schema to print.
+ * @param[in] format 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, number of the printed bytes is updated in lyout::printed.
+ */
+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 ssize_t
+lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    struct lyout out;
+    LY_ERR ret;
+
+    LY_CHECK_ARG_RET(NULL, f, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_STREAM;
+    out.method.f = f;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    FILE *f;
+    ssize_t 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 ssize_t
+lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    LY_ERR ret;
+    struct lyout out;
+
+    LY_CHECK_ARG_RET(NULL, fd >= 0, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_FD;
+    out.method.fd = fd;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+
+    if (out.type == LYOUT_FDSTREAM) {
+        /* close temporary stream based on the given file descriptor */
+        fclose(out.method.f);
+        /* move the original file descriptor to the end of the output file */
+        lseek(fd, 0, SEEK_END);
+    }
+
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+    struct lyout out;
+    LY_ERR ret;
+
+    LY_CHECK_ARG_RET(NULL, strp, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_MEMORY;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+    if (ret) {
+        /* error */
+        *strp = NULL;
+        return (-1) * ret;
+    } else {
+        /* success */
+        *strp = out.method.mem.buf;
+        return (ssize_t)out.printed;
+    }
+}
+
+API ssize_t
+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)
+{
+    LY_ERR ret;
+    struct lyout out;
+
+    LY_CHECK_ARG_RET(NULL, writeclb, module, LY_EINVAL);
+
+    memset(&out, 0, sizeof out);
+    out.ctx = module->ctx;
+    out.type = LYOUT_CALLBACK;
+    out.method.clb.f = writeclb;
+    out.method.clb.arg = arg;
+
+    ret = lys_print_(&out, module, format, line_length, options);
+    if (ret) {
+        /* error */
+        return (-1) * ret;
+    } else {
+        /* success */
+        return (ssize_t)out.printed;
+    }
+}