| /** |
| * @file cmd.c |
| * @author Michal Vasko <mvasko@cesnet.cz> |
| * @author Radek Krejci <rkrejci@cesnet.cz> |
| * @brief libyang's yanglint tool general commands |
| * |
| * Copyright (c) 2015-2020 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. |
| * You may obtain a copy of the License at |
| * |
| * https://opensource.org/licenses/BSD-3-Clause |
| */ |
| |
| #define _GNU_SOURCE |
| |
| #include "cmd.h" |
| |
| #include <getopt.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <strings.h> |
| |
| #include "common.h" |
| #include "compat.h" |
| #include "libyang.h" |
| |
| COMMAND commands[]; |
| extern int done; |
| |
| #ifndef NDEBUG |
| |
| void |
| cmd_debug_help(void) |
| { |
| printf("Usage: debug (dict | xpath | dep-sets)+\n"); |
| } |
| |
| void |
| cmd_debug(struct ly_ctx **UNUSED(ctx), const char *cmdline) |
| { |
| int argc = 0; |
| char **argv = NULL; |
| int opt, opt_index; |
| struct option options[] = { |
| {"help", no_argument, NULL, 'h'}, |
| {NULL, 0, NULL, 0} |
| }; |
| uint32_t dbg_groups = 0; |
| |
| if (parse_cmdline(cmdline, &argc, &argv)) { |
| goto cleanup; |
| } |
| |
| while ((opt = getopt_long(argc, argv, commands[CMD_DEBUG].optstring, options, &opt_index)) != -1) { |
| switch (opt) { |
| case 'h': |
| cmd_debug_help(); |
| goto cleanup; |
| default: |
| YLMSG_E("Unknown option.\n"); |
| goto cleanup; |
| } |
| } |
| if (argc == optind) { |
| /* no argument */ |
| cmd_debug_help(); |
| goto cleanup; |
| } |
| |
| for (int i = 0; i < argc - optind; i++) { |
| if (!strcasecmp("dict", argv[optind + i])) { |
| dbg_groups |= LY_LDGDICT; |
| } else if (!strcasecmp("xpath", argv[optind + i])) { |
| dbg_groups |= LY_LDGXPATH; |
| } else if (!strcasecmp("dep-sets", argv[optind + i])) { |
| dbg_groups |= LY_LDGDEPSETS; |
| } else { |
| YLMSG_E("Unknown debug group \"%s\"\n", argv[optind + 1]); |
| goto cleanup; |
| } |
| } |
| |
| ly_log_dbg_groups(dbg_groups); |
| |
| cleanup: |
| free_cmdline(argv); |
| } |
| |
| #endif |
| |
| void |
| cmd_free(void) |
| { |
| uint16_t i; |
| |
| for (i = 0; commands[i].name; i++) { |
| if (commands[i].free_func) { |
| commands[i].free_func(); |
| } |
| } |
| } |
| |
| void |
| cmd_verb_help(void) |
| { |
| printf("Usage: verb (error | warning | verbose | debug)\n"); |
| } |
| |
| void |
| cmd_verb(struct ly_ctx **UNUSED(ctx), const char *cmdline) |
| { |
| int argc = 0; |
| char **argv = NULL; |
| int opt, opt_index; |
| struct option options[] = { |
| {"help", no_argument, NULL, 'h'}, |
| {NULL, 0, NULL, 0} |
| }; |
| |
| if (parse_cmdline(cmdline, &argc, &argv)) { |
| goto cleanup; |
| } |
| |
| while ((opt = getopt_long(argc, argv, commands[CMD_VERB].optstring, options, &opt_index)) != -1) { |
| switch (opt) { |
| case 'h': |
| cmd_verb_help(); |
| goto cleanup; |
| default: |
| YLMSG_E("Unknown option.\n"); |
| goto cleanup; |
| } |
| } |
| |
| if (argc - optind > 1) { |
| YLMSG_E("Only a single verbosity level can be set.\n"); |
| cmd_verb_help(); |
| goto cleanup; |
| } else if (argc == optind) { |
| /* no argument - print current value */ |
| LY_LOG_LEVEL level = ly_log_level(LY_LLERR); |
| |
| ly_log_level(level); |
| printf("Current verbosity level: "); |
| if (level == LY_LLERR) { |
| printf("error\n"); |
| } else if (level == LY_LLWRN) { |
| printf("warning\n"); |
| } else if (level == LY_LLVRB) { |
| printf("verbose\n"); |
| } else if (level == LY_LLDBG) { |
| printf("debug\n"); |
| } |
| goto cleanup; |
| } |
| |
| if (!strcasecmp("error", argv[optind]) || !strcmp("0", argv[optind])) { |
| ly_log_level(LY_LLERR); |
| } else if (!strcasecmp("warning", argv[optind]) || !strcmp("1", argv[optind])) { |
| ly_log_level(LY_LLWRN); |
| } else if (!strcasecmp("verbose", argv[optind]) || !strcmp("2", argv[optind])) { |
| ly_log_level(LY_LLVRB); |
| } else if (!strcasecmp("debug", argv[optind]) || !strcmp("3", argv[optind])) { |
| ly_log_level(LY_LLDBG); |
| } else { |
| YLMSG_E("Unknown verbosity \"%s\"\n", argv[optind]); |
| goto cleanup; |
| } |
| |
| cleanup: |
| free_cmdline(argv); |
| } |
| |
| void |
| cmd_quit(struct ly_ctx **UNUSED(ctx), const char *UNUSED(cmdline)) |
| { |
| done = 1; |
| return; |
| } |
| |
| void |
| cmd_help_help(void) |
| { |
| printf("Usage: help [cmd ...]\n"); |
| } |
| |
| void |
| cmd_help(struct ly_ctx **UNUSED(ctx), const char *cmdline) |
| { |
| int argc = 0; |
| char **argv = NULL; |
| int opt, opt_index; |
| struct option options[] = { |
| {"help", no_argument, NULL, 'h'}, |
| {NULL, 0, NULL, 0} |
| }; |
| |
| if (parse_cmdline(cmdline, &argc, &argv)) { |
| goto cleanup; |
| } |
| |
| while ((opt = getopt_long(argc, argv, commands[CMD_HELP].optstring, options, &opt_index)) != -1) { |
| switch (opt) { |
| case 'h': |
| cmd_help_help(); |
| goto cleanup; |
| default: |
| YLMSG_E("Unknown option.\n"); |
| goto cleanup; |
| } |
| } |
| |
| if (argc == optind) { |
| generic_help: |
| printf("Available commands:\n"); |
| for (uint16_t i = 0; commands[i].name; i++) { |
| if (commands[i].helpstring != NULL) { |
| printf(" %-15s %s\n", commands[i].name, commands[i].helpstring); |
| } |
| } |
| } else { |
| /* print specific help for the selected command(s) */ |
| |
| for (int c = 0; c < argc - optind; ++c) { |
| int8_t match = 0; |
| |
| /* get the command of the specified name */ |
| for (uint16_t i = 0; commands[i].name; i++) { |
| if (strcmp(argv[optind + c], commands[i].name) == 0) { |
| match = 1; |
| if (commands[i].help_func != NULL) { |
| commands[i].help_func(); |
| } else { |
| printf("%s: %s\n", argv[optind + c], commands[i].helpstring); |
| } |
| break; |
| } |
| } |
| if (!match) { |
| /* if unknown command specified, print the list of commands */ |
| printf("Unknown command \'%s\'\n", argv[optind + c]); |
| goto generic_help; |
| } |
| } |
| } |
| |
| cleanup: |
| free_cmdline(argv); |
| } |
| |
| /* Also keep enum COMMAND_INDEX updated. */ |
| COMMAND commands[] = { |
| {"help", cmd_help, cmd_help_help, NULL, "Display commands description", "h"}, |
| {"add", cmd_add, cmd_add_help, NULL, "Add a new module from a specific file", "DF:hiX"}, |
| {"load", cmd_load, cmd_load_help, NULL, "Load a new schema from the searchdirs", "F:hiX"}, |
| {"print", cmd_print, cmd_print_help, NULL, "Print a module", "f:hL:o:P:q"}, |
| {"data", cmd_data, cmd_data_help, NULL, "Load, validate and optionally print instance data", "d:ef:F:hmo:O:R:r:nt:x:"}, |
| {"list", cmd_list, cmd_list_help, NULL, "List all the loaded modules", "f:h"}, |
| {"feature", cmd_feature, cmd_feature_help, NULL, "Print all features of module(s) with their state", "haf"}, |
| {"searchpath", cmd_searchpath, cmd_searchpath_help, NULL, "Print/set the search path(s) for schemas", "ch"}, |
| {"extdata", cmd_extdata, cmd_extdata_help, cmd_extdata_free, "Set the specific data required by an extension", "ch"}, |
| {"clear", cmd_clear, cmd_clear_help, NULL, "Clear the context - remove all the loaded modules", "iyhY:"}, |
| {"verb", cmd_verb, cmd_verb_help, NULL, "Change verbosity", "h"}, |
| #ifndef NDEBUG |
| {"debug", cmd_debug, cmd_debug_help, NULL, "Display specific debug message groups", "h"}, |
| #endif |
| {"quit", cmd_quit, NULL, NULL, "Quit the program", "h"}, |
| /* synonyms for previous commands */ |
| {"?", cmd_help, NULL, NULL, "Display commands description", "h"}, |
| {"exit", cmd_quit, NULL, NULL, "Quit the program", "h"}, |
| {NULL, NULL, NULL, NULL, NULL, NULL} |
| }; |