yanglint REFACTOR new yl_opt and cmd callbacks

The yanglint options were stored in non-interactive mode in the
structure named 'context'. This structure was renamed to yl_opt
and is now also used in the interactive mode, which has also been
expanded with new callbacks. These callbacks are the basis for
further refactoring commits, which aim to reduce duplicate code
between interactive and non-interactive modes to a minimum.
diff --git a/tools/lint/cmd_feature.c b/tools/lint/cmd_feature.c
index 383cf93..a2ca07e 100644
--- a/tools/lint/cmd_feature.c
+++ b/tools/lint/cmd_feature.c
@@ -1,9 +1,10 @@
 /**
  * @file cmd_feature.c
  * @author Michal Vasko <mvasko@cesnet.cz>
+ * @author Adam Piecek <piecek@cesnet.cz>
  * @brief 'feature' command of the libyang's yanglint tool.
  *
- * Copyright (c) 2015-2021 CESNET, z.s.p.o.
+ * Copyright (c) 2015-2023 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.
@@ -23,6 +24,7 @@
 #include "libyang.h"
 
 #include "common.h"
+#include "yl_opt.h"
 
 void
 cmd_feature_help(void)
@@ -37,17 +39,11 @@
             "                  Print features of all implemented modules.\n");
 }
 
-void
-cmd_feature(struct ly_ctx **ctx, const char *cmdline)
+int
+cmd_feature_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
 {
-    int argc = 0;
-    char **argv = NULL;
-    char *features_output = NULL;
-    int opt, opt_index, i;
-    ly_bool generate_features = 0, print_all = 0;
-    struct ly_set set = {0};
-    const struct lys_module *mod;
-    struct ly_out *out = NULL;
+    int rc = 0, argc = 0;
+    int opt, opt_index;
     struct option options[] = {
         {"help", no_argument, NULL, 'h'},
         {"all", no_argument, NULL, 'a'},
@@ -55,81 +51,115 @@
         {NULL, 0, NULL, 0}
     };
 
-    if (parse_cmdline(cmdline, &argc, &argv)) {
-        goto cleanup;
+    if ((rc = parse_cmdline(cmdline, &argc, &yo->argv))) {
+        return rc;
     }
 
-    while ((opt = getopt_long(argc, argv, commands[CMD_FEATURE].optstring, options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, yo->argv, commands[CMD_FEATURE].optstring, options, &opt_index)) != -1) {
         switch (opt) {
         case 'h':
             cmd_feature_help();
-            goto cleanup;
+            return 1;
         case 'a':
-            print_all = 1;
+            yo->feature_print_all = 1;
             break;
         case 'f':
-            generate_features = 1;
+            yo->feature_param_format = 1;
             break;
         default:
             YLMSG_E("Unknown option.\n");
-            goto cleanup;
+            return 1;
         }
     }
 
-    if (ly_out_new_file(stdout, &out)) {
+    *posv = &yo->argv[optind];
+    *posc = argc - optind;
+
+    return 0;
+}
+
+int
+cmd_feature_dep(struct yl_opt *yo, int posc)
+{
+    if (ly_out_new_file(stdout, &yo->out)) {
         YLMSG_E("Unable to print to the standard output.\n");
-        goto cleanup;
+        return 1;
     }
+    yo->out_stdout = 1;
 
-    if (print_all) {
-        if (print_all_features(out, *ctx, generate_features, &features_output)) {
-            YLMSG_E("Printing all features failed.\n");
-            goto cleanup;
-        }
-        if (generate_features) {
-            printf("%s\n", features_output);
-        }
-        goto cleanup;
-    }
-
-    if (argc == optind) {
+    if (yo->interactive && !yo->feature_print_all && !posc) {
         YLMSG_E("Missing modules to print.\n");
+        return 1;
+    }
+
+    if (yo->feature_print_all && posc) {
+        YLMSG_E("No positional arguments are allowed.\n");
+        return 1;
+    }
+
+    return 0;
+}
+
+int
+cmd_feature_exec(struct ly_ctx **ctx, struct yl_opt *yo, const char *posv)
+{
+    int rc = 0;
+    struct ly_set set = {0};
+    const struct lys_module *mod;
+
+    if (yo->feature_print_all) {
+        if (print_all_features(yo->out, *ctx, yo->feature_param_format, &yo->features_output)) {
+            YLMSG_E("Printing all features failed.\n");
+            rc = 1;
+            goto cleanup;
+        }
+        if (yo->feature_param_format) {
+            printf("%s\n", yo->features_output);
+        }
         goto cleanup;
     }
 
-    for (i = 0; i < argc - optind; i++) {
-        /* always erase the set, so the previous module's features don't carry over to the next module's features */
-        ly_set_erase(&set, NULL);
+    /* always erase the set, so the previous module's features don't carry over to the next module's features */
+    ly_set_erase(&set, NULL);
 
-        mod = ly_ctx_get_module_latest(*ctx, argv[optind + i]);
-        if (!mod) {
-            YLMSG_E("Module \"%s\" not found.\n", argv[optind + i]);
-            goto cleanup;
-        }
-
-        /* collect features of the module */
-        if (collect_features(mod, &set)) {
-            goto cleanup;
-        }
-
-        if (generate_features) {
-            if (generate_features_output(mod, &set, &features_output)) {
-                goto cleanup;
-            }
-            /* don't print features and their state of each module if generating features parameter */
-            continue;
-        }
-
-        print_features(out, mod, &set);
+    mod = ly_ctx_get_module_latest(*ctx, posv);
+    if (!mod) {
+        YLMSG_E("Module \"%s\" not found.\n", posv);
+        rc = 1;
+        goto cleanup;
     }
 
-    if (generate_features) {
-        printf("%s\n", features_output);
+    /* collect features of the module */
+    if (collect_features(mod, &set)) {
+        rc = 1;
+        goto cleanup;
     }
 
+    if (yo->feature_param_format) {
+        if (generate_features_output(mod, &set, &yo->features_output)) {
+            rc = 1;
+            goto cleanup;
+        }
+        /* don't print features and their state of each module if generating features parameter */
+        goto cleanup;
+    }
+
+    print_features(yo->out, mod, &set);
+
 cleanup:
-    free_cmdline(argv);
-    ly_out_free(out, NULL, 0);
     ly_set_erase(&set, NULL);
-    free(features_output);
+
+    return rc;
+}
+
+int
+cmd_feature_fin(struct ly_ctx *ctx, struct yl_opt *yo)
+{
+    (void) ctx;
+
+    if (yo->feature_param_format) {
+        printf("%s\n", yo->features_output);
+    }
+
+    return 0;
 }