bios: add auto completion for commands

This commit is contained in:
Franck Jullien 2020-04-29 21:57:13 +02:00
parent fc2b8226c5
commit 74dc444b02
5 changed files with 216 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,174 @@
// This file is Copyright (c) 2020 Franck Jullien <franck.jullien@gmail.com>
//
// Largely inspired/copied from U-boot and Barebox projects wich are:
// Sascha Hauer, Pengutronix, <s.hauer@pengutronix.de>
// License: BSD
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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;
}

View file

@ -0,0 +1,6 @@
#ifndef __COMPLETE_H__
#define __COMPLETE_H__
int complete(char *instr, char **outstr);
#endif

View file

@ -17,6 +17,7 @@
#include <uart.h>
#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: