diff options
| author | wdenk <wdenk> | 2004-04-15 18:22:41 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2004-04-15 18:22:41 +0000 | 
| commit | 04a85b3b36fdbaaac5fa95d61f59f481bbcf7520 (patch) | |
| tree | a4c6731a78805c51f43a8b195034d2036b28941b /common/command.c | |
| parent | d716b126718d874f52ffb694e6c22b7235cec483 (diff) | |
| download | olio-uboot-2014.01-04a85b3b36fdbaaac5fa95d61f59f481bbcf7520.tar.xz olio-uboot-2014.01-04a85b3b36fdbaaac5fa95d61f59f481bbcf7520.zip | |
* Patches by Pantelis Antoniou, 30 Mar 2004:
  - add auto-complete support to the U-Boot CLI
  - add support for NETTA and NETPHONE boards; fix NETVIA board
* Patch by Yuli Barcohen, 28 Mar 2004:
  - Add support for MPC8272 family including MPC8247/8248/8271/8272
  - Add support for MPC8272ADS evaluation board (another flavour of MPC8260ADS)
  - Change configuration method for MPC8260ADS family
Diffstat (limited to 'common/command.c')
| -rw-r--r-- | common/command.c | 282 | 
1 files changed, 282 insertions, 0 deletions
| diff --git a/common/command.c b/common/command.c index dfec9c138..df5d3e9bc 100644 --- a/common/command.c +++ b/common/command.c @@ -217,3 +217,285 @@ cmd_tbl_t *find_cmd (const char *cmd)  	return NULL;	/* not found or ambiguous command */  } + +#ifdef CONFIG_AUTO_COMPLETE + +int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[]) +{ +	static char tmp_buf[512]; +	int space; + +	space = last_char == '\0' || last_char == ' ' || last_char == '\t'; + +	if (space && argc == 1) +		return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf); + +	if (!space && argc == 2) +		return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf); + +	return 0; +} + +static void install_auto_complete_handler(const char *cmd, +		int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[])) +{ +	cmd_tbl_t *cmdtp; + +	cmdtp = find_cmd(cmd); +	if (cmdtp == NULL) +		return; + +	cmdtp->complete = complete; +} + +void install_auto_complete(void) +{ +	install_auto_complete_handler("printenv", var_complete); +	install_auto_complete_handler("setenv", var_complete); +#if (CONFIG_COMMANDS & CFG_CMD_RUN) +	install_auto_complete_handler("run", var_complete); +#endif +} + +/*************************************************************************************/ + +static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[]) +{ +	cmd_tbl_t *cmdtp; +	const char *p; +	int len, clen; +	int n_found = 0; +	const char *cmd; + +	/* sanity? */ +	if (maxv < 2) +		return -2; + +	cmdv[0] = NULL; + +	if (argc == 0) { +		/* output full list of commands */ +		for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { +			if (n_found >= maxv - 2) { +				cmdv[n_found++] = "..."; +				break; +			} +			cmdv[n_found++] = cmdtp->name; +		} +		cmdv[n_found] = NULL; +		return n_found; +	} + +	/* more than one arg or one but the start of the next */ +	if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) { +		cmdtp = find_cmd(argv[0]); +		if (cmdtp == NULL || cmdtp->complete == NULL) { +			cmdv[0] = NULL; +			return 0; +		} +		return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv); +	} + +	cmd = argv[0]; +	/* +	 * Some commands allow length modifiers (like "cp.b"); +	 * compare command name only until first dot. +	 */ +	p = strchr(cmd, '.'); +	if (p == NULL) +		len = strlen(cmd); +	else +		len = p - cmd; + +	/* return the partial matches */ +	for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { + +		clen = strlen(cmdtp->name); +		if (clen < len) +			continue; + +		if (memcmp(cmd, cmdtp->name, len) != 0) +			continue; + +		/* too many! */ +		if (n_found >= maxv - 2) { +			cmdv[n_found++] = "..."; +			break; +		} + +		cmdv[n_found++] = cmdtp->name; +	} + +	cmdv[n_found] = NULL; +	return n_found; +} + +static int make_argv(char *s, int argvsz, char *argv[]) +{ +	int argc = 0; + +	/* split into argv */ +	while (argc < argvsz - 1) { + +		/* skip any white space */ +		while ((*s == ' ') || (*s == '\t')) +			++s; + +		if (*s == '\0') 	/* end of s, no more args	*/ +			break; + +		argv[argc++] = s;	/* begin of argument string	*/ + +		/* find end of string */ +		while (*s && (*s != ' ') && (*s != '\t')) +			++s; + +		if (*s == '\0')		/* end of s, no more args	*/ +			break; + +		*s++ = '\0';		/* terminate current arg	 */ +	} +	argv[argc] = NULL; + +	return argc; +} + +static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[]) +{ +	int ll = leader != NULL ? strlen(leader) : 0; +	int sl = sep != NULL ? strlen(sep) : 0; +	int len, i; + +	if (banner) { +		puts("\n"); +		puts(banner); +	} + +	i = linemax;	/* force leader and newline */ +	while (*argv != NULL) { +		len = strlen(*argv) + sl; +		if (i + len >= linemax) { +			puts("\n"); +			if (leader) +				puts(leader); +			i = ll - sl; +		} else if (sep) +			puts(sep); +		puts(*argv++); +		i += len; +	} +	printf("\n"); +} + +static int find_common_prefix(char *argv[]) +{ +	int i, len; +	char *anchor, *s, *t; + +	if (*argv == NULL) +		return 0; + +	/* begin with max */ +	anchor = *argv++; +	len = strlen(anchor); +	while ((t = *argv++) != NULL) { +		s = anchor; +		for (i = 0; i < len; i++, t++, s++) { +			if (*t != *s) +				break; +		} +		len = s - anchor; +	} +	return len; +} + +static char tmp_buf[CFG_CBSIZE];	/* copy of console I/O buffer	*/ + +int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp) +{ +	int n = *np, col = *colp; +	char *argv[CFG_MAXARGS + 1];		/* NULL terminated	*/ +	char *cmdv[20]; +	char *s, *t; +	const char *sep; +	int i, j, k, len, seplen, argc; +	int cnt; +	char last_char; + +	if (strcmp(prompt, CFG_PROMPT) != 0) +		return 0;	/* not in normal console */ + +	cnt = strlen(buf); +	if (cnt >= 1) +		last_char = buf[cnt - 1]; +	else +		last_char = '\0'; + +	/* copy to secondary buffer which will be affected */ +	strcpy(tmp_buf, buf); + +	/* separate into argv */ +	argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv); + +	/* do the completion and return the possible completions */ +	i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv); + +	/* no match; bell and out */ +	if (i == 0) { +		if (argc > 1)	/* allow tab for non command */ +			return 0; +		putc('\a'); +		return 1; +	} + +	s = NULL; +	len = 0; +	sep = NULL; +	seplen = 0; +	if (i == 1) { /* one match; perfect */ +		k = strlen(argv[argc - 1]); +		s = cmdv[0] + k; +		len = strlen(s); +		sep = " "; +		seplen = 1; +	} else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) {	/* more */ +		k = strlen(argv[argc - 1]); +		j -= k; +		if (j > 0) { +			s = cmdv[0] + k; +			len = j; +		} +	} + +	if (s != NULL) { +		k = len + seplen; +		/* make sure it fits */ +		if (n + k >= CFG_CBSIZE - 2) { +			putc('\a'); +			return 1; +		} + +		t = buf + cnt; +		for (i = 0; i < len; i++) +			*t++ = *s++; +		if (sep != NULL) +			for (i = 0; i < seplen; i++) +				*t++ = sep[i]; +		*t = '\0'; +		n += k; +		col += k; +		puts(t - k); +		if (sep == NULL) +			putc('\a'); +		*np = n; +		*colp = col; +	} else { +		print_argv(NULL, "  ", " ", 78, cmdv); + +		puts(prompt); +		puts(buf); +	} +	return 1; +} + +#endif |