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/main.c b/tools/lint/main.c
index b3d985a..987ea10 100644
--- a/tools/lint/main.c
+++ b/tools/lint/main.c
@@ -1,9 +1,10 @@
 /**
  * @file main.c
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Adam Piecek <piecek@cesnet.cz>
  * @brief libyang's yanglint tool
  *
- * Copyright (c) 2015-2020 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.
@@ -27,6 +28,7 @@
 #include "completion.h"
 #include "configuration.h"
 #include "linenoise/linenoise.h"
+#include "yl_opt.h"
 
 int done;
 struct ly_ctx *ctx = NULL;
@@ -37,13 +39,17 @@
 int
 main(int argc, char *argv[])
 {
-    char *cmdline;
-    int cmdlen;
+    int cmdlen, posc, i, j;
+    struct yl_opt yo = {0};
+    char *empty = NULL, *cmdline;
+    char **posv;
+    uint8_t cmd_found;
 
     if (argc > 1) {
         /* run in non-interactive mode */
         return main_ni(argc, argv);
     }
+    yo.interactive = 1;
 
     /* continue in interactive mode */
     linenoiseSetCompletionCallback(complete_cmd);
@@ -55,7 +61,10 @@
     }
 
     while (!done) {
-        uint8_t executed = 0;
+        cmd_found = 0;
+
+        posv = &empty;
+        posc = 0;
 
         /* get the command from user */
         cmdline = linenoise(PROMPT);
@@ -76,23 +85,43 @@
         for (cmdlen = 0; cmdline[cmdlen] && (cmdline[cmdlen] != ' '); cmdlen++) {}
 
         /* execute the command if any valid specified */
-        for (uint16_t i = 0; commands[i].name; i++) {
+        for (i = 0; commands[i].name; i++) {
             if (strncmp(cmdline, commands[i].name, (size_t)cmdlen) || (commands[i].name[cmdlen] != '\0')) {
                 continue;
             }
 
-            commands[i].func(&ctx, cmdline);
-            executed = 1;
+            cmd_found = 1;
+            if (commands[i].opt_func && commands[i].opt_func(&yo, cmdline, &posv, &posc)) {
+                break;
+            }
+            if (commands[i].dep_func && commands[i].dep_func(&yo, posc)) {
+                break;
+            }
+            if (posc) {
+                for (j = 0; j < posc; j++) {
+                    yo.last_one = (j + 1) == posc;
+                    if (commands[i].exec_func(&ctx, &yo, posv[j])) {
+                        break;
+                    }
+                }
+            } else {
+                commands[i].exec_func(&ctx, &yo, NULL);
+            }
+            if (commands[i].fin_func) {
+                commands[i].fin_func(ctx, &yo);
+            }
+
             break;
         }
 
-        if (!executed) {
+        if (!cmd_found) {
             /* if unknown command specified, tell it to user */
             YLMSG_E("Unknown command \"%.*s\", type 'help' for more information.\n", cmdlen, cmdline);
         }
 
         linenoiseHistoryAdd(cmdline);
         free(cmdline);
+        yl_opt_erase(&yo);
     }
 
     /* Global variables in commands are freed. */