summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/com32/hdt/hdt-cli.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/com32/hdt/hdt-cli.c')
-rw-r--r--contrib/syslinux-4.02/com32/hdt/hdt-cli.c1121
1 files changed, 1121 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/hdt/hdt-cli.c b/contrib/syslinux-4.02/com32/hdt/hdt-cli.c
new file mode 100644
index 0000000..639bcdb
--- /dev/null
+++ b/contrib/syslinux-4.02/com32/hdt/hdt-cli.c
@@ -0,0 +1,1121 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Erwan Velu - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslinux/config.h>
+#include <getkey.h>
+#include "hdt-cli.h"
+#include "hdt-common.h"
+
+struct cli_mode_descr *list_modes[] = {
+ &hdt_mode,
+ &dmi_mode,
+ &syslinux_mode,
+ &pxe_mode,
+ &kernel_mode,
+ &cpu_mode,
+ &pci_mode,
+ &vesa_mode,
+ &disk_mode,
+ &vpd_mode,
+ &memory_mode,
+ NULL,
+};
+
+/*
+ * .aliases = {"q", "quit"} won't work since it is an array of pointers, not an
+ * array of variables. There is no easy way around it besides declaring the arrays of
+ * strings first.
+ */
+const char *exit_aliases[] = { "q", "quit" };
+const char *help_aliases[] = { "h", "?" };
+
+/* List of aliases */
+struct cli_alias hdt_aliases[] = {
+ {
+ .command = CLI_EXIT,
+ .nb_aliases = 2,
+ .aliases = exit_aliases,
+ },
+ {
+ .command = CLI_HELP,
+ .nb_aliases = 2,
+ .aliases = help_aliases,
+ },
+};
+
+struct cli_mode_descr *current_mode;
+int autocomplete_backlog;
+
+struct autocomplete_list {
+ char autocomplete_token[MAX_LINE_SIZE];
+ struct autocomplete_list *next;
+};
+struct autocomplete_list *autocomplete_head = NULL;
+struct autocomplete_list *autocomplete_tail = NULL;
+struct autocomplete_list *autocomplete_last_seen = NULL;
+
+static void autocomplete_add_token_to_list(const char *token)
+{
+ struct autocomplete_list *new = malloc(sizeof(struct autocomplete_list));
+
+ strlcpy(new->autocomplete_token, token, sizeof(new->autocomplete_token));
+ new->next = NULL;
+ autocomplete_backlog++;
+
+ if (autocomplete_tail != NULL)
+ autocomplete_tail->next = new;
+ if (autocomplete_head == NULL)
+ autocomplete_head = new;
+ autocomplete_tail = new;
+}
+
+static void autocomplete_destroy_list(void)
+{
+ struct autocomplete_list *tmp = NULL;
+
+ while (autocomplete_head != NULL) {
+ tmp = autocomplete_head->next;
+ free(autocomplete_head);
+ autocomplete_head = tmp;
+ }
+ autocomplete_backlog = 0;
+ autocomplete_tail = NULL;
+ autocomplete_last_seen = NULL;
+}
+
+/**
+ * set_mode - set the current mode of the cli
+ * @mode: mode to set
+ *
+ * Unlike cli_set_mode, this function is not used by the cli directly.
+ **/
+void set_mode(cli_mode_t mode, struct s_hardware *hardware)
+{
+ int i = 0;
+
+ switch (mode) {
+ case EXIT_MODE:
+ hdt_cli.mode = mode;
+ break;
+ case HDT_MODE:
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_HDT);
+ break;
+ case PXE_MODE:
+ if (hardware->sv->filesystem != SYSLINUX_FS_PXELINUX) {
+ printf("You are not currently using PXELINUX\n");
+ break;
+ }
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_PXE);
+ break;
+ case KERNEL_MODE:
+ detect_pci(hardware);
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_KERNEL);
+ break;
+ case SYSLINUX_MODE:
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_SYSLINUX);
+ break;
+ case VESA_MODE:
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_VESA);
+ break;
+ case PCI_MODE:
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_PCI);
+ if (!hardware->pci_detection)
+ cli_detect_pci(hardware);
+ break;
+ case CPU_MODE:
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_CPU);
+ if (!hardware->dmi_detection)
+ detect_dmi(hardware);
+ if (!hardware->cpu_detection)
+ cpu_detect(hardware);
+ break;
+ case DMI_MODE:
+ detect_dmi(hardware);
+ if (!hardware->is_dmi_valid) {
+ printf("No valid DMI table found, exiting.\n");
+ break;
+ }
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_DMI);
+ break;
+ case DISK_MODE:
+ detect_disks(hardware);
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_DISK);
+ break;
+ case VPD_MODE:
+ detect_vpd(hardware);
+ if (!hardware->is_vpd_valid) {
+ printf("No valid VPD table found, exiting.\n");
+ break;
+ }
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_VPD);
+ break;
+ case MEMORY_MODE:
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_MEMORY);
+ break;
+ default:
+ /* Invalid mode */
+ printf("Unknown mode, please choose among:\n");
+ while (list_modes[i]) {
+ printf("\t%s\n", list_modes[i]->name);
+ i++;
+ }
+ }
+
+ find_cli_mode_descr(hdt_cli.mode, &current_mode);
+ /* There is not cli_mode_descr struct for the exit mode */
+ if (current_mode == NULL && hdt_cli.mode != EXIT_MODE) {
+ /* Shouldn't get here... */
+ printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
+ }
+}
+
+/**
+ * mode_s_to_mode_t - given a mode string, return the cli_mode_t representation
+ **/
+cli_mode_t mode_s_to_mode_t(char *name)
+{
+ int i = 0;
+
+ while (list_modes[i]) {
+ if (!strncmp(name, list_modes[i]->name, sizeof(list_modes[i]->name)))
+ break;
+ i++;
+ }
+
+ if (!list_modes[i])
+ return INVALID_MODE;
+ else
+ return list_modes[i]->mode;
+}
+
+/**
+ * find_cli_mode_descr - find the cli_mode_descr struct associated to a mode
+ * @mode: mode to look for
+ * @mode_found: store the mode if found, NULL otherwise
+ *
+ * Given a mode name, return a pointer to the associated cli_mode_descr
+ * structure.
+ * Note: the current mode name is stored in hdt_cli.mode.
+ **/
+void find_cli_mode_descr(cli_mode_t mode, struct cli_mode_descr **mode_found)
+{
+ int i = 0;
+
+ while (list_modes[i] && list_modes[i]->mode != mode)
+ i++;
+
+ /* Shouldn't get here... */
+ if (!list_modes[i])
+ *mode_found = NULL;
+ else
+ *mode_found = list_modes[i];
+}
+
+/**
+ * expand_aliases - resolve aliases mapping
+ * @line: command line to parse
+ * @command: first token in the line
+ * @module: second token in the line
+ * @argc: number of arguments
+ * @argv: array of arguments
+ *
+ * We maintain a small list of static alises to enhance user experience.
+ * Only commands can be aliased (first token). Otherwise it can become really hairy...
+ **/
+static void expand_aliases(char *line __unused, char **command, char **module,
+ int *argc, char **argv)
+{
+ struct cli_mode_descr *mode;
+ int i, j;
+
+ find_cli_mode_descr(mode_s_to_mode_t(*command), &mode);
+ if (mode != NULL && *module == NULL) {
+ /*
+ * The user specified a mode instead of `set mode...', e.g.
+ * `dmi' instead of `set mode dmi'
+ */
+
+ /* *argv is NULL since *module is NULL */
+ *argc = 1;
+ *argv = malloc(*argc * sizeof(char *));
+ argv[0] = malloc((sizeof(*command) + 1) * sizeof(char));
+ strlcpy(argv[0], *command, sizeof(*command) + 1);
+ dprintf("CLI DEBUG: ALIAS %s ", *command);
+
+ strlcpy(*command, CLI_SET, sizeof(CLI_SET)); /* set */
+
+ *module = malloc(sizeof(CLI_MODE) * sizeof(char));
+ strlcpy(*module, CLI_MODE, sizeof(CLI_MODE)); /* mode */
+
+ dprintf("--> %s %s %s\n", *command, *module, argv[0]);
+ goto out;
+ }
+
+ /* Simple aliases mapping a single command to another one */
+ for (i = 0; i < MAX_ALIASES; i++) {
+ for (j = 0; j < hdt_aliases[i].nb_aliases; j++) {
+ if (!strncmp(*command, hdt_aliases[i].aliases[j],
+ sizeof(hdt_aliases[i].aliases[j]))) {
+ dprintf("CLI DEBUG: ALIAS %s ", *command);
+ strlcpy(*command, hdt_aliases[i].command,
+ sizeof(hdt_aliases[i].command) + 1);
+ dprintf("--> %s\n", *command);
+ goto out; /* Don't allow chaining aliases */
+ }
+ }
+ }
+ return;
+
+out:
+ dprintf("CLI DEBUG: New parameters:\n");
+ dprintf("CLI DEBUG: command = %s\n", *command);
+ dprintf("CLI DEBUG: module = %s\n", *module);
+ dprintf("CLI DEBUG: argc = %d\n", *argc);
+ for (i = 0; i < *argc; i++)
+ dprintf("CLI DEBUG: argv[%d] = %s\n", i, argv[0]);
+ return;
+}
+
+/**
+ * parse_command_line - low level parser for the command line
+ * @line: command line to parse
+ * @command: first token in the line
+ * @module: second token in the line
+ * @argc: number of arguments
+ * @argv: array of arguments
+ *
+ * The format of the command line is:
+ * <main command> [<module on which to operate> [<args>]]
+ * command is always malloc'ed (even for an empty line)
+ **/
+static void parse_command_line(char *line, char **command, char **module,
+ int *argc, char **argv)
+{
+ int argc_iter = 0, args_pos = 0, token_found = 0, token_len = 0;
+ int args_len = 0;
+ char *pch = NULL, *pch_next = NULL, *tmp_pch_next = NULL;
+
+ *command = NULL;
+ *module = NULL;
+ *argc = 0;
+
+ pch = line;
+ while (pch != NULL) {
+ pch_next = strchr(pch + 1, ' ');
+ tmp_pch_next = pch_next;
+
+ /*
+ * Skip whitespaces if the user entered
+ * 'set mode foo' for 'set mode foo'
+ * ^ ^
+ * |___|___ pch
+ * |___ pch_next <- wrong!
+ *
+ * We still keep the position into tmp_pch_next to compute
+ * the lenght of the current token.
+ */
+ while (pch_next != NULL && !strncmp(pch_next, CLI_SPACE, 1))
+ pch_next++;
+
+ /* End of line guaranteed to be zeroed */
+ if (pch_next == NULL) {
+ token_len = (int)(strchr(pch + 1, '\0') - pch);
+ args_len = token_len;
+ } else {
+ token_len = (int)(tmp_pch_next - pch);
+ args_len = (int)(pch_next - pch);
+ }
+
+ if (token_found == 0) {
+ /* Main command to execute */
+ *command = malloc((token_len + 1) * sizeof(char));
+ strlcpy(*command, pch, token_len);
+ (*command)[token_len] = '\0';
+ dprintf("CLI DEBUG: command = %s\n", *command);
+ args_pos += args_len;
+ } else if (token_found == 1) {
+ /* Module */
+ *module = malloc((token_len + 1) * sizeof(char));
+ strlcpy(*module, pch, token_len);
+ (*module)[token_len] = '\0';
+ dprintf("CLI DEBUG: module = %s\n", *module);
+ args_pos += args_len;
+ } else
+ (*argc)++;
+
+ token_found++;
+ pch = pch_next;
+ }
+ dprintf("CLI DEBUG: argc = %d\n", *argc);
+
+ /* Skip arguments handling if none is supplied */
+ if (!*argc)
+ return;
+
+ /* Transform the arguments string into an array */
+ *argv = malloc(*argc * sizeof(char *));
+ pch = strtok(line + args_pos, CLI_SPACE);
+ while (pch != NULL) {
+ dprintf("CLI DEBUG: argv[%d] = %s\n", argc_iter, pch);
+ argv[argc_iter] = malloc(sizeof(pch) * sizeof(char));
+ strlcpy(argv[argc_iter], pch, sizeof(pch));
+ argc_iter++;
+ pch = strtok(NULL, CLI_SPACE);
+ /*
+ * strtok(NULL, CLI_SPACE) over a stream of spaces
+ * will return an empty string
+ */
+ while (pch != NULL && !strncmp(pch, "", 1))
+ pch = strtok(NULL, CLI_SPACE);
+ }
+}
+
+/**
+ * find_cli_callback_descr - find a callback in a list of modules
+ * @module_name: Name of the module to find
+ * @modules_list: Lits of modules among which to find @module_name
+ * @module_found: Pointer to the matched module, NULL if not found
+ *
+ * Given a module name and a list of possible modules, find the corresponding
+ * module structure that matches the module name and store it in @module_found.
+ **/
+void find_cli_callback_descr(const char *module_name,
+ struct cli_module_descr *modules_list,
+ struct cli_callback_descr **module_found)
+{
+ int modules_iter = 0;
+
+ if (modules_list == NULL)
+ goto not_found;
+
+ /* Find the callback to execute */
+ while (modules_list->modules[modules_iter].name &&
+ strcmp(module_name, modules_list->modules[modules_iter].name) != 0)
+ modules_iter++;
+
+ if (modules_list->modules[modules_iter].name) {
+ *module_found = &(modules_list->modules[modules_iter]);
+ dprintf("CLI DEBUG: module %s found\n", (*module_found)->name);
+ return;
+ }
+
+not_found:
+ *module_found = NULL;
+ return;
+}
+
+/**
+ * autocomplete_command - print matching commands
+ * @command: Beginning of the command
+ *
+ * Given a string @command, print all availables commands starting with
+ * @command. Commands are found within the list of commands for the current
+ * mode and the hdt mode (if the current mode is not hdt).
+ **/
+static void autocomplete_command(char *command)
+{
+ int j = 0;
+ struct cli_callback_descr *associated_module = NULL;
+
+ /* First take care of the two special commands: 'show' and 'set' */
+ if (strncmp(CLI_SHOW, command, strlen(command)) == 0) {
+ printf("%s\n", CLI_SHOW);
+ autocomplete_add_token_to_list(CLI_SHOW);
+ }
+ if (strncmp(CLI_SET, command, strlen(command)) == 0) {
+ printf("%s\n", CLI_SET);
+ autocomplete_add_token_to_list(CLI_SET);
+ }
+
+ /*
+ * Then, go through the modes for the special case
+ * '<mode>' -> 'set mode <mode>'
+ */
+ while (list_modes[j]) {
+ if (strncmp(list_modes[j]->name, command, strlen(command)) == 0) {
+ printf("%s\n", list_modes[j]->name);
+ autocomplete_add_token_to_list(list_modes[j]->name);
+ }
+ j++;
+ }
+
+ /*
+ * Let's go now through the list of default_modules for the current mode
+ * (single token commands for the current_mode)
+ */
+ j = 0;
+ if (current_mode->default_modules && current_mode->default_modules->modules) {
+ while (current_mode->default_modules->modules[j].name) {
+ if (strncmp(current_mode->default_modules->modules[j].name,
+ command, strlen(command)) == 0) {
+ printf("%s\n", current_mode->default_modules->modules[j].name);
+ autocomplete_add_token_to_list(current_mode->default_modules->
+ modules[j].name);
+ }
+ j++;
+ }
+ }
+
+ /*
+ * Finally, if the current_mode is not hdt, list the available
+ * default_modules of hdt (these are always available from any mode).
+ */
+ if (current_mode->mode == HDT_MODE)
+ return;
+
+ if (!hdt_mode.default_modules || !hdt_mode.default_modules->modules)
+ return;
+
+ j = 0;
+ while (hdt_mode.default_modules &&
+ hdt_mode.default_modules->modules[j].name) {
+ /*
+ * Any default command that is present in hdt mode but
+ * not in the current mode is available. A default
+ * command can be redefined in the current mode though.
+ * This next call tests this use case: if it is
+ * overwritten, do not print it again.
+ */
+ find_cli_callback_descr(hdt_mode.default_modules->modules[j].name,
+ current_mode->default_modules,
+ &associated_module);
+ if (associated_module == NULL &&
+ strncmp(command,
+ hdt_mode.default_modules->modules[j].name,
+ strlen(command)) == 0) {
+ printf("%s\n", hdt_mode.default_modules->modules[j].name);
+ autocomplete_add_token_to_list(hdt_mode.default_modules->modules[j].
+ name);
+ }
+ j++;
+ }
+}
+
+/**
+ * autocomplete_module - print matching modules
+ * @command: Command on the command line (not NULL)
+ * @module: Beginning of the module
+ *
+ * Given a command @command and a string @module, print all availables modules
+ * starting with @module for command @command. Commands are found within the
+ * list of commands for the current mode and the hdt mode (if the current mode
+ * is not hdt).
+ **/
+static void autocomplete_module(char *command, char *module)
+{
+ int j = 0;
+ char autocomplete_full_line[MAX_LINE_SIZE];
+
+ if (strncmp(CLI_SHOW, command, strlen(command)) == 0) {
+ if (!current_mode->show_modules || !current_mode->show_modules->modules)
+ return;
+
+ while (current_mode->show_modules->modules[j].name) {
+ if (strncmp(current_mode->show_modules->modules[j].name,
+ module, strlen(module)) == 0) {
+ printf("%s\n", current_mode->show_modules->modules[j].name);
+ sprintf(autocomplete_full_line, "%s %s",
+ CLI_SHOW, current_mode->show_modules->modules[j].name);
+ autocomplete_add_token_to_list(autocomplete_full_line);
+ }
+ j++;
+ }
+ } else if (strncmp(CLI_SET, command, strlen(command)) == 0) {
+ j = 0;
+ if (!current_mode->set_modules || !current_mode->set_modules->modules)
+ return;
+
+ while (current_mode->set_modules->modules[j].name) {
+ if (strncmp(current_mode->set_modules->modules[j].name,
+ module, strlen(module)) == 0) {
+ printf("%s\n", current_mode->set_modules->modules[j].name);
+ sprintf(autocomplete_full_line, "%s %s",
+ CLI_SET, current_mode->set_modules->modules[j].name);
+ autocomplete_add_token_to_list(autocomplete_full_line);
+ }
+ j++;
+ }
+ }
+}
+
+/**
+ * autocomplete - find possible matches for a command line
+ * @line: command line to parse
+ **/
+static void autocomplete(char *line)
+{
+ int i;
+ int argc = 0;
+ char *command = NULL, *module = NULL;
+ char **argv = NULL;
+
+ parse_command_line(line, &command, &module, &argc, argv);
+
+ /* If the user specified arguments, there is nothing we can complete */
+ if (argc != 0)
+ goto out;
+
+ /* No argument, (the start of) a module has been specified */
+ if (module != NULL) {
+ autocomplete_module(command, module);
+ free(module);
+ goto out;
+ }
+
+ /* No argument, no module, (the start of) a command has been specified */
+ if (command != NULL) {
+ autocomplete_command(command);
+ free(command);
+ goto out;
+ }
+
+out:
+ /* Let's not forget to clean ourselves */
+ for (i = 0; i < argc; i++)
+ free(argv[i]);
+ if (argc > 0)
+ free(argv);
+ return;
+}
+
+/**
+ * exec_command - main logic to map the command line to callbacks
+ **/
+static void exec_command(char *line, struct s_hardware *hardware)
+{
+ int argc, i = 0;
+ char *command = NULL, *module = NULL;
+ char **argv = NULL;
+ struct cli_callback_descr *current_module = NULL;
+
+ /* This will allocate memory for command and module */
+ parse_command_line(line, &command, &module, &argc, argv);
+
+ /*
+ * Expand shortcuts, if needed
+ * This will allocate memory for argc/argv
+ */
+ expand_aliases(line, &command, &module, &argc, argv);
+
+ if (module == NULL) {
+ dprintf("CLI DEBUG: single command detected\n");
+ /*
+ * A single word was specified: look at the list of default
+ * commands in the current mode to see if there is a match.
+ * If not, it may be a generic function (exit, help, ...). These
+ * are stored in the list of default commands of the hdt mode.
+ */
+ find_cli_callback_descr(command, current_mode->default_modules,
+ &current_module);
+ if (current_module != NULL)
+ current_module->exec(argc, argv, hardware);
+ else if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1) &&
+ current_mode->show_modules != NULL &&
+ current_mode->show_modules->default_callback != NULL)
+ current_mode->show_modules->default_callback(argc, argv, hardware);
+ else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1) &&
+ current_mode->set_modules != NULL &&
+ current_mode->set_modules->default_callback != NULL)
+ current_mode->set_modules->default_callback(argc, argv, hardware);
+ else {
+ find_cli_callback_descr(command, hdt_mode.default_modules,
+ &current_module);
+ if (current_module != NULL)
+ current_module->exec(argc, argv, hardware);
+ else
+ printf("unknown command: '%s'\n", command);
+ }
+ } else {
+ /*
+ * A module has been specified! We now need to find the type of command.
+ *
+ * The syntax of the cli is the following:
+ * <type of command> <module on which to operate> <args>
+ * e.g.
+ * dmi> show system
+ * dmi> show bank 1
+ * dmi> show memory 0 1
+ * pci> show device 12
+ * hdt> set mode dmi
+ */
+ if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1)) {
+ dprintf("CLI DEBUG: %s command detected\n", CLI_SHOW);
+ /* Look first for a 'show' callback in the current mode */
+ find_cli_callback_descr(module, current_mode->show_modules,
+ &current_module);
+ /* Execute the callback, if found */
+ if (current_module != NULL)
+ current_module->exec(argc, argv, hardware);
+ else {
+ /* Look now for a 'show' callback in the hdt mode */
+ find_cli_callback_descr(module, hdt_mode.show_modules,
+ &current_module);
+ /* Execute the callback, if found */
+ if (current_module != NULL)
+ current_module->exec(argc, argv, hardware);
+ else
+ printf("unknown module: '%s'\n", module);
+ }
+ } else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1)) {
+ dprintf("CLI DEBUG: %s command detected\n", CLI_SET);
+ /* Look now for a 'set' callback in the hdt mode */
+ find_cli_callback_descr(module, current_mode->set_modules,
+ &current_module);
+ /* Execute the callback, if found */
+ if (current_module != NULL)
+ current_module->exec(argc, argv, hardware);
+ else {
+ /* Look now for a 'set' callback in the hdt mode */
+ find_cli_callback_descr(module, hdt_mode.set_modules,
+ &current_module);
+ /* Execute the callback, if found */
+ if (current_module != NULL)
+ current_module->exec(argc, argv, hardware);
+ else
+ printf("unknown module: '%s'\n", module);
+ }
+ }
+ }
+
+ /* Let's not forget to clean ourselves */
+ if (command != NULL)
+ free(command);
+ if (module != NULL)
+ free(module);
+ for (i = 0; i < argc; i++)
+ free(argv[i]);
+ if (argc > 0)
+ free(argv);
+}
+
+static void reset_prompt(void)
+{
+ /* No need to display the prompt if we exit */
+ if (hdt_cli.mode != EXIT_MODE) {
+ printf("%s", hdt_cli.prompt);
+ /* Reset the line */
+ hdt_cli.cursor_pos = 0;
+ }
+}
+
+void start_auto_mode(struct s_hardware *hardware)
+{
+ char *mypch;
+ int nb_commands = 0;
+ char *commands[MAX_NB_AUTO_COMMANDS];
+
+ if (!quiet)
+ more_printf("\nEntering Auto mode\n");
+
+ /* Protecting the auto_label from the strtok modifications */
+ char *temp = strdup(hardware->auto_label);
+
+ /* Searching & saving all commands */
+ mypch = strtok(temp, AUTO_SEPARATOR);
+ while (mypch != NULL) {
+ if ((strlen(remove_spaces(mypch)) > 0) &&
+ (remove_spaces(mypch)[0] != AUTO_SEPARATOR[0])) {
+ nb_commands++;
+ if ((commands[nb_commands] = malloc(AUTO_COMMAND_SIZE)) != NULL) {
+ sprintf(commands[nb_commands], "%s", remove_spaces(mypch));
+ } else
+ nb_commands--;
+ }
+ mypch = strtok(NULL, AUTO_SEPARATOR);
+ }
+
+ /* Executing found commands */
+ for (int i = 1; i <= nb_commands; i++) {
+ if (commands[i]) {
+ if (!quiet)
+ more_printf("%s%s\n", hdt_cli.prompt, commands[i]);
+ exec_command(commands[i], hardware);
+ free(commands[i]);
+ }
+ }
+
+ if (!quiet)
+ more_printf("\nExiting Auto mode\n");
+
+ more_printf("\n");
+}
+
+void print_history(int argc, char **argv, struct s_hardware * hardware)
+{
+ (void)argc;
+ (void)argv;
+ (void)hardware;
+
+ reset_more_printf();
+ for (int i = 1; i <= MAX_HISTORY_SIZE; i++) {
+ if (i == hdt_cli.history_pos) {
+ more_printf("*%d:'%s'\n", i, hdt_cli.history[i]);
+ continue;
+ }
+ if (strlen(hdt_cli.history[i]) == 0)
+ continue;
+ more_printf(" %d:'%s'\n", i, hdt_cli.history[i]);
+ }
+}
+
+/* Code that manages the cli mode */
+void start_cli_mode(struct s_hardware *hardware)
+{
+ int current_key = 0;
+ int future_history_pos = 1; /* position of the next position in the history */
+ int current_future_history_pos = 1; /* Temp variable */
+ bool display_history = true; /* Temp Variable */
+ char temp_command[MAX_LINE_SIZE];
+
+ hdt_cli.cursor_pos = 0;
+ memset(hdt_cli.history, 0, sizeof(hdt_cli.history));
+ hdt_cli.history_pos = 1;
+ hdt_cli.max_history_pos = 1;
+
+ /* Find the mode selected */
+ set_mode(HDT_MODE, hardware);
+ find_cli_mode_descr(hdt_cli.mode, &current_mode);
+ if (current_mode == NULL) {
+ /* Shouldn't get here... */
+ printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
+ return;
+ }
+
+ /* Start the auto mode if the command line is set */
+ if (strlen(hardware->auto_label) > 0) {
+ start_auto_mode(hardware);
+ }
+
+ printf("Entering CLI mode\n");
+
+ reset_prompt();
+
+ while (hdt_cli.mode != EXIT_MODE) {
+
+ /* Display the cursor */
+ display_cursor(true);
+
+ /* Let's put the cursor blinking until we get an input */
+ set_cursor_blink(true);
+
+ /* We wait endlessly for a keyboard input */
+ current_key = get_key(stdin, 0);
+
+ /* We have to cancel the blinking mode to prevent
+ * input text to blink */
+ set_cursor_blink(false);
+
+ /* Reset autocomplete buffer unless TAB is pressed */
+ if (current_key != KEY_TAB)
+ autocomplete_destroy_list();
+
+ switch (current_key) {
+ /* clear until then end of line */
+ case KEY_CTRL('k'):
+ /* Clear the end of the line */
+ clear_end_of_line();
+ memset(&INPUT[hdt_cli.cursor_pos], 0,
+ strlen(INPUT) - hdt_cli.cursor_pos);
+ break;
+
+ case KEY_CTRL('c'):
+ printf("\n");
+ reset_prompt();
+ break;
+
+ case KEY_LEFT:
+ if (hdt_cli.cursor_pos > 0) {
+ move_cursor_left(1);
+ hdt_cli.cursor_pos--;
+ }
+ break;
+
+ case KEY_RIGHT:
+ if (hdt_cli.cursor_pos < (int)strlen(INPUT)) {
+ move_cursor_right(1);
+ hdt_cli.cursor_pos++;
+ }
+ break;
+
+ case KEY_CTRL('e'):
+ case KEY_END:
+ /* Calling with a 0 value will make the cursor move */
+ /* So, let's move the cursor only if needed */
+ if ((strlen(INPUT) - hdt_cli.cursor_pos) > 0) {
+ /* Return to the begining of line */
+ move_cursor_right(strlen(INPUT) - hdt_cli.cursor_pos);
+ hdt_cli.cursor_pos = strlen(INPUT);
+ }
+ break;
+
+ case KEY_CTRL('a'):
+ case KEY_HOME:
+ /* Calling with a 0 value will make the cursor move */
+ /* So, let's move the cursor only if needed */
+ if (hdt_cli.cursor_pos > 0) {
+ /* Return to the begining of line */
+ move_cursor_left(hdt_cli.cursor_pos);
+ hdt_cli.cursor_pos = 0;
+ }
+ break;
+
+ case KEY_UP:
+
+ /* Saving future position */
+ current_future_history_pos = future_history_pos;
+
+ /* We have to compute the next position */
+ if (future_history_pos == 1) {
+ future_history_pos = MAX_HISTORY_SIZE;
+ } else {
+ future_history_pos--;
+ }
+
+ /* Does the next position is valid */
+ if (strlen(hdt_cli.history[future_history_pos]) == 0) {
+ /* Position is invalid, restoring position */
+ future_history_pos = current_future_history_pos;
+ break;
+ }
+
+ /* Let's make that future position the one we use */
+ memset(INPUT, 0, sizeof(INPUT));
+ strlcpy(INPUT, hdt_cli.history[future_history_pos], sizeof(INPUT));
+
+ /* Clear the line */
+ clear_line();
+
+ /* Move to the begining of line */
+ move_cursor_to_column(0);
+
+ reset_prompt();
+ printf("%s", INPUT);
+ hdt_cli.cursor_pos = strlen(INPUT);
+ break;
+
+ case KEY_DOWN:
+ display_history = true;
+
+ /* Saving future position */
+ current_future_history_pos = future_history_pos;
+
+ if (future_history_pos == MAX_HISTORY_SIZE) {
+ future_history_pos = 1;
+ } else {
+ future_history_pos++;
+ }
+
+ /* Does the next position is valid */
+ if (strlen(hdt_cli.history[future_history_pos]) == 0)
+ display_history = false;
+
+ /* An exception is made to reach the last empty line */
+ if (future_history_pos == hdt_cli.max_history_pos)
+ display_history = true;
+
+ if (display_history == false) {
+ /* Position is invalid, restoring position */
+ future_history_pos = current_future_history_pos;
+ break;
+ }
+
+ /* Let's make that future position the one we use */
+ memset(INPUT, 0, sizeof(INPUT));
+ strlcpy(INPUT, hdt_cli.history[future_history_pos], sizeof(INPUT));
+
+ /* Clear the line */
+ clear_line();
+
+ /* Move to the begining of line */
+ move_cursor_to_column(0);
+
+ reset_prompt();
+ printf("%s", INPUT);
+ hdt_cli.cursor_pos = strlen(INPUT);
+ break;
+
+ case KEY_TAB:
+ if (autocomplete_backlog) {
+ clear_line();
+ /* Move to the begining of line */
+ move_cursor_to_column(0);
+ reset_prompt();
+ printf("%s", autocomplete_last_seen->autocomplete_token);
+ strlcpy(INPUT,
+ autocomplete_last_seen->autocomplete_token,
+ sizeof(INPUT));
+ hdt_cli.cursor_pos = strlen(INPUT);
+
+ /* Cycle through the list */
+ autocomplete_last_seen = autocomplete_last_seen->next;
+ if (autocomplete_last_seen == NULL)
+ autocomplete_last_seen = autocomplete_head;
+ } else {
+ printf("\n");
+ autocomplete(skip_spaces(INPUT));
+ autocomplete_last_seen = autocomplete_head;
+
+ printf("%s%s", hdt_cli.prompt, INPUT);
+ }
+ break;
+
+ case KEY_ENTER:
+ printf("\n");
+ if (strlen(remove_spaces(INPUT)) < 1) {
+ reset_prompt();
+ break;
+ }
+ exec_command(remove_spaces(INPUT), hardware);
+ hdt_cli.history_pos++;
+
+ /* Did we reach the end of the history ?*/
+ if (hdt_cli.history_pos > MAX_HISTORY_SIZE) {
+ /* Let's return at the beginning */
+ hdt_cli.history_pos = 1;
+ }
+
+ /* Does the next position is already used ?
+ * If yes, we are cycling in history */
+ if (strlen(INPUT) > 0) {
+ /* Let's clean that entry */
+ memset(&INPUT,0,sizeof(INPUT));
+ }
+
+ future_history_pos = hdt_cli.history_pos;
+ if (hdt_cli.history_pos > hdt_cli.max_history_pos)
+ hdt_cli.max_history_pos = hdt_cli.history_pos;
+ reset_prompt();
+ break;
+
+ case KEY_CTRL('d'):
+ case KEY_DELETE:
+ /* No need to delete when input is empty */
+ if (strlen(INPUT) == 0)
+ break;
+ /* Don't delete when cursor is at the end of the line */
+ if (hdt_cli.cursor_pos >= strlen(INPUT))
+ break;
+
+ for (int c = hdt_cli.cursor_pos; c < (int)strlen(INPUT) - 1; c++)
+ INPUT[c] = INPUT[c + 1];
+ INPUT[strlen(INPUT) - 1] = '\0';
+
+ /* Clear the end of the line */
+ clear_end_of_line();
+
+ /* Print the resulting buffer */
+ printf("%s", INPUT + hdt_cli.cursor_pos);
+
+ /* Replace the cursor at the proper place */
+ if (strlen(INPUT + hdt_cli.cursor_pos) > 0)
+ move_cursor_left(strlen(INPUT + hdt_cli.cursor_pos));
+ break;
+
+ case KEY_DEL:
+ case KEY_BACKSPACE:
+ /* Don't delete prompt */
+ if (hdt_cli.cursor_pos == 0)
+ break;
+
+ for (int c = hdt_cli.cursor_pos - 1;
+ c < (int)strlen(INPUT) - 1; c++)
+ INPUT[c] = INPUT[c + 1];
+ INPUT[strlen(INPUT) - 1] = '\0';
+
+ /* Get one char back */
+ move_cursor_left(1);
+
+ /* Clear the end of the line */
+ clear_end_of_line();
+
+ /* Print the resulting buffer */
+ printf("%s", INPUT + hdt_cli.cursor_pos - 1);
+
+ /* Realing to a char before the place we were */
+ hdt_cli.cursor_pos--;
+ move_cursor_to_column(strlen(hdt_cli.prompt) + hdt_cli.cursor_pos +
+ 1);
+
+ break;
+
+ case KEY_F1:
+ printf("\n");
+ exec_command(CLI_HELP, hardware);
+ reset_prompt();
+ break;
+
+ default:
+ if ((current_key < 0x20) || (current_key > 0x7e))
+ break;
+ /* Prevent overflow */
+ if (hdt_cli.cursor_pos > MAX_LINE_SIZE - 2)
+ break;
+ /* If we aren't at the end of the input line, let's insert */
+ if (hdt_cli.cursor_pos < (int)strlen(INPUT)) {
+ char key[2];
+ int trailing_chars = strlen(INPUT) - hdt_cli.cursor_pos;
+ memset(temp_command, 0, sizeof(temp_command));
+ strlcpy(temp_command, INPUT, hdt_cli.cursor_pos);
+ sprintf(key, "%c", current_key);
+ strncat(temp_command, key, 1);
+ strncat(temp_command,
+ INPUT + hdt_cli.cursor_pos, trailing_chars);
+ memset(INPUT, 0, sizeof(INPUT));
+ snprintf(INPUT, sizeof(INPUT), "%s", temp_command);
+
+ /* Clear the end of the line */
+ clear_end_of_line();
+
+ /* Print the resulting buffer */
+ printf("%s", INPUT + hdt_cli.cursor_pos);
+
+ /* Return where we must put the new char */
+ move_cursor_left(trailing_chars);
+
+ } else {
+ putchar(current_key);
+ INPUT[hdt_cli.cursor_pos] = current_key;
+ }
+ hdt_cli.cursor_pos++;
+ break;
+ }
+ }
+}