yanglint UPDATE support NETCONF data types

Refs #1834
diff --git a/tools/lint/cmd_data.c b/tools/lint/cmd_data.c
index 919c45e..cd023dc 100644
--- a/tools/lint/cmd_data.c
+++ b/tools/lint/cmd_data.c
@@ -316,9 +316,8 @@
     }
 
     /* parse, validate and print data */
-    if (process_data(*ctx, data_type, data_merge, outformat, out,
-            options_parse, options_validate, options_print,
-            operational, &inputs, &xpaths)) {
+    if (process_data(*ctx, data_type, data_merge, outformat, out, options_parse, options_validate, options_print,
+            operational, NULL, &inputs, &xpaths)) {
         goto cleanup;
     }
 
diff --git a/tools/lint/common.c b/tools/lint/common.c
index 8e6bd94..8819443 100644
--- a/tools/lint/common.c
+++ b/tools/lint/common.c
@@ -443,15 +443,15 @@
 
 LY_ERR
 process_data(struct ly_ctx *ctx, enum lyd_type data_type, uint8_t merge, LYD_FORMAT format, struct ly_out *out,
-        uint32_t options_parse, uint32_t options_validate, uint32_t options_print,
-        struct cmdline_file *operational_f, struct ly_set *inputs, struct ly_set *xpaths)
+        uint32_t options_parse, uint32_t options_validate, uint32_t options_print, struct cmdline_file *operational_f,
+        struct cmdline_file *rpc_f, struct ly_set *inputs, struct ly_set *xpaths)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lyd_node *tree = NULL, *merged_tree = NULL, *operational = NULL;
+    struct lyd_node *tree = NULL, *envp = NULL, *merged_tree = NULL, *oper_tree = NULL;
 
     /* additional operational datastore */
     if (operational_f && operational_f->in) {
-        ret = lyd_parse_data(ctx, NULL, operational_f->in, operational_f->format, LYD_PARSE_ONLY, 0, &operational);
+        ret = lyd_parse_data(ctx, NULL, operational_f->in, operational_f->format, LYD_PARSE_ONLY, 0, &oper_tree);
         if (ret) {
             YLMSG_E("Failed to parse operational datastore file \"%s\".\n", operational_f->path);
             goto cleanup;
@@ -469,6 +469,28 @@
         case LYD_TYPE_NOTIF_YANG:
             ret = lyd_parse_op(ctx, NULL, input_f->in, input_f->format, data_type, &tree, NULL);
             break;
+        case LYD_TYPE_RPC_NETCONF:
+        case LYD_TYPE_NOTIF_NETCONF:
+            ret = lyd_parse_op(ctx, NULL, input_f->in, input_f->format, data_type, &envp, &tree);
+            break;
+        case LYD_TYPE_REPLY_NETCONF:
+            /* parse source RPC operation */
+            assert(rpc_f && rpc_f->in);
+            ret = lyd_parse_op(ctx, NULL, rpc_f->in, rpc_f->format, LYD_TYPE_RPC_NETCONF, &envp, &tree);
+            if (ret) {
+                YLMSG_E("Failed to parse source NETCONF RPC operation file \"%s\".\n", rpc_f->path);
+                goto cleanup;
+            }
+
+            /* free input */
+            lyd_free_siblings(lyd_child(tree));
+
+            /* we do not care */
+            lyd_free_all(envp);
+            envp = NULL;
+
+            ret = lyd_parse_op(ctx, tree, input_f->in, input_f->format, data_type, &envp, NULL);
+            break;
         default:
             YLMSG_E("Internal error (%s:%d).\n", __FILE__, __LINE__);
             goto cleanup;
@@ -492,18 +514,40 @@
             }
             tree = NULL;
         } else if (format) {
-            lyd_print_all(out, tree, format, options_print);
-        } else if (operational) {
+            /* print */
+            switch (data_type) {
+            case LYD_TYPE_DATA_YANG:
+                lyd_print_all(out, tree, format, options_print);
+                break;
+            case LYD_TYPE_RPC_YANG:
+            case LYD_TYPE_REPLY_YANG:
+            case LYD_TYPE_NOTIF_YANG:
+            case LYD_TYPE_RPC_NETCONF:
+            case LYD_TYPE_NOTIF_NETCONF:
+                lyd_print_tree(out, tree, format, options_print);
+                break;
+            case LYD_TYPE_REPLY_NETCONF:
+                /* just the output */
+                lyd_print_tree(out, lyd_child(tree), format, options_print);
+                break;
+            default:
+                assert(0);
+            }
+        } else if (oper_tree) {
             /* additional validation of the RPC/Action/reply/Notification with the operational datastore */
-            ret = lyd_validate_op(tree, operational, data_type, NULL);
+            ret = lyd_validate_op(tree, oper_tree, data_type, NULL);
             if (ret) {
                 YLMSG_E("Failed to validate input data file \"%s\" with operational datastore \"%s\".\n",
                         input_f->path, operational_f->path);
                 goto cleanup;
             }
         }
+
+        /* next iter */
         lyd_free_all(tree);
         tree = NULL;
+        lyd_free_all(envp);
+        envp = NULL;
     }
 
     if (merge) {
@@ -528,7 +572,8 @@
 
 cleanup:
     lyd_free_all(tree);
+    lyd_free_all(envp);
     lyd_free_all(merged_tree);
-    lyd_free_all(operational);
+    lyd_free_all(oper_tree);
     return ret;
 }
diff --git a/tools/lint/common.h b/tools/lint/common.h
index ae37df2..0bc93c8 100644
--- a/tools/lint/common.h
+++ b/tools/lint/common.h
@@ -187,13 +187,14 @@
  * @param[in] options_print Printer options.
  * @param[in] operational_f Optional operational datastore file information for the case of an extended validation of
  * operation(s).
+ * @param[in] rpc_f Source RPC operation file information for parsing NETCONF rpc-reply.
  * @param[in] inputs Set of file informations of input data files.
  * @param[in] xpath The set of XPaths to be evaluated on the processed data tree, basic information about the resulting set
  * is printed. Alternative to data printing.
- * return LY_ERR value.
+ * @return LY_ERR value.
  */
 LY_ERR process_data(struct ly_ctx *ctx, enum lyd_type data_type, uint8_t merge, LYD_FORMAT format, struct ly_out *out,
-        uint32_t options_parse, uint32_t options_validate, uint32_t options_print,
-        struct cmdline_file *operational_f, struct ly_set *inputs, struct ly_set *xpaths);
+        uint32_t options_parse, uint32_t options_validate, uint32_t options_print, struct cmdline_file *operational_f,
+        struct cmdline_file *rpc_f, struct ly_set *inputs, struct ly_set *xpaths);
 
 #endif /* COMMON_H_ */
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index dad3450..5ff8a69 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -90,6 +90,9 @@
 
     /* storage for --operational */
     struct cmdline_file data_operational;
+
+    /* storage for --reply-rpc */
+    struct cmdline_file reply_rpc;
 };
 
 static void
@@ -120,11 +123,19 @@
 help(int shortout)
 {
 
-    printf("Usage:\n"
-            "    yanglint [Options] [-f { yang | yin | info}] <schema>...\n"
-            "        Validates the YANG module in <schema>, and all its dependencies.\n\n"
-            "    yanglint [Options] [-f { xml | json }] <schema>... <file> ...\n"
-            "        Validates the YANG modeled data in <file> according to the <schema>.\n\n"
+    printf("Example usage:\n"
+            "    yanglint [-f { yang | yin | info}] <schema>...\n"
+            "        Validates the YANG module <schema>(s) and all its dependencies, optionally printing\n"
+            "        them in the specified format.\n\n"
+            "    yanglint [-f { xml | json }] <schema>... <file>...\n"
+            "        Validates the YANG modeled data <file>(s) according to the <schema>(s) optionally\n"
+            "        printing them in the specified format.\n\n"
+            "    yanglint -t (nc-)rpc/notif [-O <operational-file>] <schema>... <file>\n"
+            "        Validates the YANG/NETCONF RPC/notification <file> according to the <schema>(s) using\n"
+            "        <operational-file> with possible references to the operational datastore data.\n\n"
+            "    yanglint -t nc-reply -R <rpc-file> [-O <operational-file>] <schema>... <file>\n"
+            "        Validates the NETCONF rpc-reply <file> of RPC <rpc-file> according to the <schema>(s)\n"
+            "        using <operational-file> with possible references to the operational datastore data.\n\n"
             "    yanglint\n"
             "        Starts interactive mode with more features.\n\n");
 
@@ -193,17 +204,23 @@
             "                Specify data tree type in the input data file(s):\n"
             "        data          - Complete datastore with status data (default type).\n"
             "        config        - Configuration datastore (without status data).\n"
-            "        get           - Result of the NETCONF <get> operation.\n"
-            "        getconfig     - Result of the NETCONF <get-config> operation.\n"
-            "        edit          - Content of the NETCONF <edit-config> operation.\n"
-            "        rpc           - Content of the NETCONF <rpc> message, defined as YANG's\n"
-            "                        RPC/Action input statement.\n"
-            "        reply         - Reply to the RPC/Action. Note that the reply data are\n"
-            "                        expected inside a container representing the original\n"
-            "                        RPC/Action. This is necessary to identify appropriate\n"
-            "                        data definitions in the schema module.\n"
-            "        notif         - Notification instance (content of the <notification>\n"
-            "                        element without <eventTime>).\n\n");
+            "        get           - Data returned by the NETCONF <get> operation.\n"
+            "        getconfig     - Data returned by the NETCONF <get-config> operation.\n"
+            "        edit          - Config content of the NETCONF <edit-config> operation.\n"
+            "        rpc           - Invocation of a YANG RPC/action, defined as input.\n"
+            "        nc-rpc        - Similar to 'rpc' but expect and check also the NETCONF\n"
+            "                        envelopes <rpc> or <action>.\n"
+            "        reply         - Reply to a YANG RPC/action, defined as output. Note that\n"
+            "                        the reply data are expected inside a container representing\n"
+            "                        the original RPC/action invocation.\n"
+            "        nc-reply      - Similar to 'reply' but expect and check also the NETCONF\n"
+            "                        envelope <rpc-reply> with output data nodes as direct\n"
+            "                        descendants. The original RPC/action invocation is expected\n"
+            "                        in a separate parameter '-R' and is parsed as 'nc-rpc'.\n"
+            "        notif         - Notification instance of a YANG notification.\n"
+            "        nc-notif      - Similar to 'notif' but expect and check also the NETCONF\n"
+            "                        envelope <notification> with element <eventTime> and its\n"
+            "                        sibling as the actual notification.\n\n");
 
     printf("  -d MODE, --default=MODE\n"
             "                Print data with default values, according to the MODE\n"
@@ -233,6 +250,10 @@
             "                the :running configuration datastore and state data\n"
             "                (operational datastore) referenced from the RPC/Notification.\n\n");
 
+    printf("  -R FILE, --reply-rpc=FILE\n"
+            "                Provide source RPC for parsing of the 'nc-reply' TYPE. The FILE\n"
+            "                is supposed to contain the source 'nc-rpc' operation of the reply.\n\n");
+
     printf("  -m, --merge   Merge input data files into a single tree and validate at\n"
             "                once. The option has effect only for 'data' and 'config' TYPEs.\n\n");
 
@@ -332,12 +353,17 @@
         }
     }
 
-    /* process the operational content if any */
+    /* process the operational and/or reply RPC content if any */
     if (c->data_operational.path) {
         if (get_input(c->data_operational.path, NULL, &c->data_operational.format, &c->data_operational.in)) {
             return -1;
         }
     }
+    if (c->reply_rpc.path) {
+        if (get_input(c->reply_rpc.path, NULL, &c->reply_rpc.format, &c->reply_rpc.in)) {
+            return -1;
+        }
+    }
 
     for (int i = 0; i < argc - optind; i++) {
         LYS_INFORMAT format_schema = LYS_IN_UNKNOWN;
@@ -474,6 +500,7 @@
         {"tree-line-length",  required_argument, NULL, 'L'},
         {"output",            required_argument, NULL, 'o'},
         {"operational",       required_argument, NULL, 'O'},
+        {"reply-rpc",         required_argument, NULL, 'R'},
         {"merge",             no_argument,       NULL, 'm'},
         {"yang-library",      no_argument,       NULL, 'y'},
         {"yang-library-file", required_argument, NULL, 'Y'},
@@ -490,9 +517,9 @@
 
     opterr = 0;
 #ifndef NDEBUG
-    while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:O:myY:G:", options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:O:R:myY:G:", options, &opt_index)) != -1) {
 #else
-    while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:O:myY:", options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:O:R:myY:", options, &opt_index)) != -1) {
 #endif
         switch (opt) {
         case 'h': /* --help */
@@ -635,12 +662,18 @@
                 c->data_parse_options |= LYD_PARSE_ONLY | LYD_PARSE_NO_STATE;
             } else if (!strcasecmp(optarg, "edit")) {
                 c->data_parse_options |= LYD_PARSE_ONLY;
-            } else if (!strcasecmp(optarg, "rpc") || !strcasecmp(optarg, "action")) {
+            } else if (!strcasecmp(optarg, "rpc")) {
                 c->data_type = LYD_TYPE_RPC_YANG;
-            } else if (!strcasecmp(optarg, "reply") || !strcasecmp(optarg, "rpcreply")) {
+            } else if (!strcasecmp(optarg, "nc-rpc")) {
+                c->data_type = LYD_TYPE_RPC_NETCONF;
+            } else if (!strcasecmp(optarg, "reply")) {
                 c->data_type = LYD_TYPE_REPLY_YANG;
-            } else if (!strcasecmp(optarg, "notif") || !strcasecmp(optarg, "notification")) {
+            } else if (!strcasecmp(optarg, "nc-reply")) {
+                c->data_type = LYD_TYPE_REPLY_NETCONF;
+            } else if (!strcasecmp(optarg, "notif")) {
                 c->data_type = LYD_TYPE_NOTIF_YANG;
+            } else if (!strcasecmp(optarg, "nc-notif")) {
+                c->data_type = LYD_TYPE_NOTIF_NETCONF;
             } else if (!strcasecmp(optarg, "data")) {
                 /* default option */
             } else {
@@ -696,6 +729,14 @@
             c->data_operational.path = optarg;
             break;
 
+        case 'R': /* --reply-rpc */
+            if (c->reply_rpc.path) {
+                YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.\n");
+                return -1;
+            }
+            c->reply_rpc.path = optarg;
+            break;
+
         case 'm': /* --merge */
             c->data_merge = 1;
             break;
@@ -762,10 +803,18 @@
     }
 
     if (c->data_operational.path && !c->data_type) {
-        YLMSG_E("Operational datastore takes effect only with RPCs/Actions/Replies/Notifications input data types.\n");
+        YLMSG_E("Operational datastore takes effect only with RPCs/Actions/Replies/Notification input data types.\n");
         c->data_operational.path = NULL;
     }
 
+    if (c->reply_rpc.path && (c->data_type != LYD_TYPE_REPLY_NETCONF)) {
+        YLMSG_E("Source RPC is needed only for NETCONF Reply input data type.\n");
+        c->data_operational.path = NULL;
+    } else if (!c->reply_rpc.path && (c->data_type == LYD_TYPE_REPLY_NETCONF)) {
+        YLMSG_E("Missing source RPC (-R) for NETCONF Reply input data type.\n");
+        return -1;
+    }
+
     if ((c->schema_out_format != LYS_OUT_TREE) && c->line_length) {
         YLMSG_E("--tree-line-length take effect only in case of the tree output format.\n");
     }
@@ -881,7 +930,7 @@
         /* do the data validation despite the schema was printed */
         if (c.data_inputs.size) {
             ret = process_data(c.ctx, c.data_type, c.data_merge, c.data_out_format, c.out, c.data_parse_options,
-                    c.data_validate_options, c.data_print_options, &c.data_operational, &c.data_inputs, NULL);
+                    c.data_validate_options, c.data_print_options, &c.data_operational, &c.reply_rpc, &c.data_inputs, NULL);
             if (ret) {
                 goto cleanup;
             }