From 74dc444b02ec437d13eae26aeb4939ee6bd6282b Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Wed, 29 Apr 2020 21:57:13 +0200 Subject: [PATCH] bios: add auto completion for commands --- litex/soc/software/bios/Makefile | 6 + litex/soc/software/bios/command.h | 2 + litex/soc/software/bios/complete.c | 174 +++++++++++++++++++++++++++++ litex/soc/software/bios/complete.h | 6 + litex/soc/software/bios/readline.c | 28 +++++ 5 files changed, 216 insertions(+) create mode 100644 litex/soc/software/bios/complete.c create mode 100644 litex/soc/software/bios/complete.h diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index c80e0a13..4b8c6a51 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -26,6 +26,12 @@ OBJECTS = isr.o \ cmd_spi_flash.o \ cmd_usddrphy.o +ifneq "$(or $(TERM_NO_COMPLETE),$(TERM_MINI))" "" +CFLAGS += -DTERM_NO_COMPLETE +else +OBJECTS += complete.o +endif + ifdef TERM_NO_HIST CFLAGS += -DTERM_NO_HIST endif diff --git a/litex/soc/software/bios/command.h b/litex/soc/software/bios/command.h index 24704389..693d7982 100644 --- a/litex/soc/software/bios/command.h +++ b/litex/soc/software/bios/command.h @@ -7,6 +7,8 @@ #define MAX_PARAM 8 +#define HIST_DEPTH 10 /* Used in string list, complete.c */ + #define MISC_CMDS 0 #define SYSTEM_CMDS 1 #define CACHE_CMDS 2 diff --git a/litex/soc/software/bios/complete.c b/litex/soc/software/bios/complete.c new file mode 100644 index 00000000..e4283297 --- /dev/null +++ b/litex/soc/software/bios/complete.c @@ -0,0 +1,174 @@ +// This file is Copyright (c) 2020 Franck Jullien +// +// Largely inspired/copied from U-boot and Barebox projects wich are: +// Sascha Hauer, Pengutronix, + +// License: BSD + +#include +#include +#include + +#include "readline.h" +#include "helpers.h" +#include "command.h" +#include "complete.h" + +static int tab_pressed = 0; + +char sl[HIST_DEPTH][CMD_LINE_BUFFER_SIZE]; +int sl_idx = 0; + +char out[CMD_LINE_BUFFER_SIZE]; + +static void string_list_init(void) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) + sl[i][0] = 0; +} + +static int string_list_add(const char *string) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) { + if (sl[i][0] == 0) { + strncpy(&sl[i][0], string, CMD_LINE_BUFFER_SIZE); + return 0; + } + } + return -1; +} + +static int string_list_empty(void) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) + if (sl[i][0] != 0) + return 0; + return 1; +} + +static int string_list_count(void) +{ + int i, count = 0; + for (i = 0; i < HIST_DEPTH; i++) + if (sl[i][0] != 0) + count++; + return count; +} + +static char *list_first_entry(void) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) + if (sl[i][0] != 0) + return &sl[i][0]; + return NULL; +} + +static void string_list_print_by_column(void) +{ + int len = 0, num, i, j; + + for (i = 0; i < HIST_DEPTH; i++) { + if (sl[i][0] != 0) { + int l = strlen(&sl[i][0]) + 4; + if (l > len) + len = l; + } + } + + if (!len) + return; + + num = 80 / (len + 1); + + for (j = 0; j < HIST_DEPTH; j++) { + if (sl[j][0] != 0) { + if (!(++i % num)) + printf("%s\n", &sl[j][0]); + else + printf("%-*s", len, &sl[j][0]); + } + } + if (i % num) + printf("\n"); +} + +static void command_complete(char *instr) +{ + struct command_struct * const *cmd; + + for (cmd = __bios_cmd_start; cmd != __bios_cmd_end; cmd++) + if (!strncmp(instr, (*cmd)->name, strlen(instr))) + string_list_add((*cmd)->name); +} + +int complete(char *instr, char **outstr) +{ + int pos; + char ch; + int changed; + int outpos = 0; + int reprint = 0; + char *first_entry; + char *entry; + int i; + + string_list_init(); + command_complete(instr); + + pos = strlen(instr); + + *outstr = ""; + if (string_list_empty()) + reprint = 0; + else + { + out[0] = 0; + + first_entry = list_first_entry(); + + while (1) { + entry = first_entry; + ch = entry[pos]; + if (!ch) + break; + + changed = 0; + for (i = 0; i < HIST_DEPTH; i++) { + if (sl[i][0] != 0) { + if (!sl[i][pos]) + break; + if (ch != sl[i][pos]) { + changed = 1; + break; + } + } + } + + if (changed) + break; + out[outpos++] = ch; + pos++; + } + + if ((string_list_count() != 1) && !outpos && tab_pressed) { + printf("\n"); + string_list_print_by_column(); + reprint = 1; + tab_pressed = 0; + } + + out[outpos++] = 0; + *outstr = out; + + if (*out == 0) + tab_pressed = 1; + else + tab_pressed = 0; + } + + return reprint; +} diff --git a/litex/soc/software/bios/complete.h b/litex/soc/software/bios/complete.h new file mode 100644 index 00000000..b615df76 --- /dev/null +++ b/litex/soc/software/bios/complete.h @@ -0,0 +1,6 @@ +#ifndef __COMPLETE_H__ +#define __COMPLETE_H__ + +int complete(char *instr, char **outstr); + +#endif diff --git a/litex/soc/software/bios/readline.c b/litex/soc/software/bios/readline.c index 998ebc0e..48d8f1a6 100644 --- a/litex/soc/software/bios/readline.c +++ b/litex/soc/software/bios/readline.c @@ -17,6 +17,7 @@ #include #include "readline.h" +#include "complete.h" #ifndef TERM_NO_HIST static int hist_max = 0; @@ -191,6 +192,12 @@ int readline(char *buf, int len) int insert = 1; char ichar; +#ifndef TERM_NO_COMPLETE + char tmp; + int reprint, i; + char *completestr; +#endif + while (1) { ichar = read_key(); @@ -200,6 +207,27 @@ int readline(char *buf, int len) switch (ichar) { case '\t': +#ifndef TERM_NO_COMPLETE + buf[eol_num] = 0; + tmp = buf[num]; + + buf[num] = 0; + reprint = complete(buf, &completestr); + buf[num] = tmp; + + if (reprint) { + printf("%s%s", PROMPT, buf); + + if (tmp) + for (i = 0; i < eol_num - num; i++) + getcmd_putch(CTL_BACKSPACE); + } + + i = 0; + while (completestr[i]) + cread_add_char(completestr[i++], insert, &num, + &eol_num, buf, len); +#endif break; case KEY_HOME: -- 2.30.2