yanglint FEATURE schema mount support (#1901)

* modify existing context if provided

In ly_ctx_new_yldata(), check if *ctx is NULL.  If so, proceed as before
with allocating a new context.  Otherwise, load modules into the existing
context.

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

* add parent-reference xpath helper to schema-mount plugin

This new function produces a list of schema nodes from the expanded
parent-reference xpath expressions.

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

* add context lookup to schema-mount plugin

This function allocates a new context for a particular instance of the
yangmnt:mount-point extension.

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

* yanglint: schema-mount extension callback

Add a commandline argument "-x" that accepts a file containing extension
data, used to create a context for the schema-mount extension.  This file
has the same format as what is provided to the "-Y" option.  A callback
function for the schema-mount extenion is registered if the new option
is specified.

This allows validating instance data for models that include a schema
mount point.

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

* yanglint: print mounted schema trees

Display "mp" flag for mount point and print mounted tree.  Also display
the / and @ opts in node names.

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

* add unit test for tree mount-point flag

Test is courtesy of aPiecek <piecek@cesnet.cz>.

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

* add example data files for validation with schema-mount

From tools/lint/examples directory:

% ../../../build/yanglint \
    -f json -t config -p ../../../models -p . \
    -Y ./sm-context-main.xml -x ./sm-context-extension.xml sm-data.xml

% ../../../build/yanglint \
    -f tree -p ../../../models -p . \
    -Y ./sm-context-main.xml -x ./sm-context-extension.xml sm-main.yang

Signed-off-by: Eric Kinzie <ekinzie@labn.net>

Signed-off-by: Eric Kinzie <ekinzie@labn.net>
Co-authored-by: Eric Kinzie <ekinzie@labn.net>
diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c
index 3a9f617..bf7d203 100644
--- a/tests/utests/basic/test_context.c
+++ b/tests/utests/basic/test_context.c
@@ -744,6 +744,7 @@
     assert_non_null(ly_ctx_get_module(ctx_test, "ietf-yang-library", "2019-01-04"));
     assert_null(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01"));
     ly_ctx_destroy(ctx_test);
+    ctx_test = NULL;
 
     /* test loading module, should also import other module */
     assert_int_equal(LY_SUCCESS, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", with_netconf, LYD_XML, 0, &ctx_test));
@@ -753,6 +754,7 @@
     assert_int_equal(0, ly_ctx_get_module(ctx_test, "ietf-netconf-acm", "2018-02-14")->implemented);
     assert_int_equal(LY_ENOT, lys_feature_value(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01"), "url"));
     ly_ctx_destroy(ctx_test);
+    ctx_test = NULL;
 
     /* test loading module with feature if they are present */
     assert_int_equal(LY_SUCCESS, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", with_netconf_features, LYD_XML, 0, &ctx_test));
@@ -760,6 +762,7 @@
     assert_non_null(ly_ctx_get_module(ctx_test, "ietf-netconf-acm", "2018-02-14"));
     assert_int_equal(LY_SUCCESS, lys_feature_value(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01"), "url"));
     ly_ctx_destroy(ctx_test);
+    ctx_test = NULL;
 
     /* test with not matching revision */
     assert_int_equal(LY_EINVAL, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", garbage_revision, LYD_XML, 0, &ctx_test));