parsers CHANGE redesign API of all the parsers

Simplify work with different inputs by introducing ly_in handler similar
to the printers' ly_out. The input handler can be used repeatedly and
also some input data manipulation functions are added.

Add new lys_parse() as a generic function using ly_in input handler. The
current API (lys_parse_* functions) was rewritten to be a wrapper of
the generic lys_parse().

Next to the unit tests for the parsers functions, also the similar tests
for printers functions are added.
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 826e025..7bafc82 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -20,7 +20,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -37,6 +36,7 @@
 #include "tree.h"
 #include "tree_schema.h"
 #include "tree_schema_internal.h"
+#include "parser_internal.h"
 
 API const struct lysc_node *
 lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, int options)
@@ -737,7 +737,7 @@
     mod->implemented = value;
 
     /* compile the schema */
-    LY_CHECK_RET(lys_compile(mod, LYSC_OPT_INTERNAL));
+    LY_CHECK_RET(lys_compile(&mod, LYSC_OPT_INTERNAL));
 
     return LY_SUCCESS;
 }
@@ -992,165 +992,109 @@
 }
 
 API struct lys_module *
-lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
+lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format)
 {
     struct lys_module *mod;
+    char *filename, *rev, *dot;
+    size_t len;
 
-    mod = lys_parse_mem_module(ctx, data, format, 1, NULL, NULL);
+    LY_CHECK_ARG_RET(NULL, ctx, in, format > LYS_IN_UNKNOWN, NULL);
+
+    mod = lys_parse_mem_module(ctx, in->current, format, 1, NULL, NULL);
     LY_CHECK_RET(!mod, NULL);
 
-    if (lys_compile(mod, 0)) {
-        ly_set_rm(&ctx->list, mod, NULL);
-        lys_module_free(mod, NULL);
-        return NULL;
+    switch (in->type) {
+    case LY_IN_FILEPATH:
+        /* check that name and revision match filename */
+        filename = strrchr(in->method.fpath.filepath, '/');
+        if (!filename) {
+            filename = in->method.fpath.filepath;
+        } else {
+            filename++;
+        }
+        rev = strchr(filename, '@');
+        dot = strrchr(filename, '.');
+
+        /* name */
+        len = strlen(mod->name);
+        if (strncmp(filename, mod->name, len) ||
+                ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
+            LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
+        }
+        if (rev) {
+            len = dot - ++rev;
+            if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
+                LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
+                       mod->parsed->revs ? mod->parsed->revs[0].date : "none");
+            }
+        }
+
+        break;
+    case LY_IN_FD:
+    case LY_IN_FILE:
+    case LY_IN_MEMORY:
+        /* nothing special to do */
+        break;
+    default:
+        LOGINT(ctx);
+        break;
     }
+
+    lys_parser_fill_filepath(ctx, in, &mod->filepath);
+    lys_compile(&mod, 0);
+
     return mod;
 }
 
-static void
-lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
+API struct lys_module *
+lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
 {
-    char path[PATH_MAX];
+	LY_ERR ret;
+    struct ly_in *in = NULL;
+    struct lys_module *result = NULL;
 
-#ifdef __APPLE__
-    if (fcntl(fd, F_GETPATH, path) != -1) {
-        *filename = lydict_insert(ctx, path, 0);
-    }
-#else
-    int len;
-    char proc_path[32];
+    LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, NULL);
 
-    /* get URI if there is /proc */
-    sprintf(proc_path, "/proc/self/fd/%d", fd);
-    if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
-        *filename = lydict_insert(ctx, path, len);
-    }
-#endif
-}
+    LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), NULL);
 
-void *
-lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
-              lys_custom_check custom_check, void *check_data)
-{
-    void *result;
-    struct lys_module *mod = NULL;
-    struct lysp_submodule *submod = NULL;
-    size_t length;
-    char *addr;
-
-    LY_CHECK_ARG_RET(ctx, ctx, NULL);
-    if (fd < 0) {
-        LOGARG(ctx, fd);
-        return NULL;
-    }
-
-    LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
-    if (!addr) {
-        LOGERR(ctx, LY_EINVAL, "Empty schema file.");
-        return NULL;
-    }
-
-    if (main_ctx) {
-        result = submod = lys_parse_mem_submodule(ctx, addr, format, main_ctx, custom_check, check_data);
-    } else {
-        result = mod = lys_parse_mem_module(ctx, addr, format, implement, custom_check, check_data);
-        if (mod && implement && lys_compile(mod, 0)) {
-            ly_set_rm(&ctx->list, mod, NULL);
-            lys_module_free(mod, NULL);
-            result = mod = NULL;
-        }
-    }
-    ly_munmap(addr, length);
-
-    if (mod && !mod->filepath) {
-        lys_parse_set_filename(ctx, &mod->filepath, fd);
-    } else if (submod && !submod->filepath) {
-        lys_parse_set_filename(ctx, &submod->filepath, fd);
-    }
+    result = lys_parse(ctx, in, format);
+    ly_in_free(in, 0);
 
     return result;
 }
 
-struct lys_module *
-lys_parse_fd_module(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, lys_custom_check custom_check,
-                    void *check_data)
-{
-    return (struct lys_module*)lys_parse_fd_(ctx, fd, format, implement, NULL, custom_check, check_data);
-}
-
-struct lysp_submodule *
-lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
-                       lys_custom_check custom_check, void *check_data)
-{
-    assert(main_ctx);
-    return (struct lysp_submodule*)lys_parse_fd_(ctx, fd, format, 0, main_ctx, custom_check, check_data);
-}
-
 API struct lys_module *
 lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
 {
-    return lys_parse_fd_module(ctx, fd, format, 1, NULL, NULL);
-}
+	LY_ERR ret;
+    struct ly_in *in = NULL;
+    struct lys_module *result = NULL;
 
-struct lys_module *
-lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
-                lys_custom_check custom_check, void *check_data)
-{
-    int fd;
-    struct lys_module *mod;
-    const char *rev, *dot, *filename;
-    size_t len;
+    LY_CHECK_ARG_RET(ctx, fd != -1, format != LYS_IN_UNKNOWN, NULL);
 
-    LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
+    LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), NULL);
 
-    fd = open(path, O_RDONLY);
-    LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
+    result = lys_parse(ctx, in, format);
+    ly_in_free(in, 0);
 
-    mod = lys_parse_fd_module(ctx, fd, format, implement, custom_check, check_data);
-    close(fd);
-    LY_CHECK_RET(!mod, NULL);
-
-    /* check that name and revision match filename */
-    filename = strrchr(path, '/');
-    if (!filename) {
-        filename = path;
-    } else {
-        filename++;
-    }
-    rev = strchr(filename, '@');
-    dot = strrchr(filename, '.');
-
-    /* name */
-    len = strlen(mod->name);
-    if (strncmp(filename, mod->name, len) ||
-            ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
-        LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
-    }
-    if (rev) {
-        len = dot - ++rev;
-        if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
-            LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
-                   mod->parsed->revs ? mod->parsed->revs[0].date : "none");
-        }
-    }
-
-    if (!mod->filepath) {
-        /* store URI */
-        char rpath[PATH_MAX];
-        if (realpath(path, rpath) != NULL) {
-            mod->filepath = lydict_insert(ctx, rpath, 0);
-        } else {
-            mod->filepath = lydict_insert(ctx, path, 0);
-        }
-    }
-
-    return mod;
+    return result;
 }
 
 API struct lys_module *
 lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
 {
-    return lys_parse_path_(ctx, path, format, 1, NULL, NULL);
+	LY_ERR ret;
+    struct ly_in *in = NULL;
+    struct lys_module *result = NULL;
+
+    LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, NULL);
+
+    LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in), LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), NULL);
+
+    result = lys_parse(ctx, in, format);
+    ly_in_free(in, 0);
+
+    return result;
 }
 
 API LY_ERR