diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2008-03-01 21:08:14 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2008-03-01 21:08:14 +0100 |
commit | df31bb46be18edbaca1adbef3dcb16d2033942b9 (patch) | |
tree | 98ca794cf8d8753c47135c9b3189a49fd5cb7ea2 /common/complete.c | |
parent | a1a747af7f7bd816af73d808e1c750f536873c3d (diff) | |
download | barebox-df31bb46be18edbaca1adbef3dcb16d2033942b9.tar.gz barebox-df31bb46be18edbaca1adbef3dcb16d2033942b9.tar.xz |
implement TAB completion
Diffstat (limited to 'common/complete.c')
-rw-r--r-- | common/complete.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/common/complete.c b/common/complete.c new file mode 100644 index 0000000000..211dc2e09d --- /dev/null +++ b/common/complete.c @@ -0,0 +1,210 @@ +/* + * complete.c - functions for TAB completion + * + * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <common.h> +#include <complete.h> +#include <xfuncs.h> +#include <list.h> +#include <malloc.h> +#include <fs.h> +#include <linux/stat.h> +#include <libgen.h> +#include <command.h> + +static int complete_push(struct complete_handle *handle, char *str) +{ + struct complete_handle *new; + + new = xmalloc(sizeof(struct complete_handle) + strlen(str) + 1); + + strcpy(new->str, str); + + list_add_tail(&new->list, &handle->list); + + return 0; +} + +static int file_complete(struct complete_handle *handle, char *instr) +{ + char *path = strdup(instr); + struct stat s; + DIR *dir; + struct dirent *d; + char tmp[PATH_MAX]; + char *base, *dirn; + + base = basename(instr); + dirn = dirname(path); + + dir = opendir(dirn); + if (!dir) + goto out; + + while ((d = readdir(dir))) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + if (!strncmp(base, d->d_name, strlen(base))) { + strcpy(tmp, instr); + strcat(tmp, d->d_name + strlen(base)); + if (!stat(tmp, &s) && S_ISDIR(s.st_mode)) + strcat(tmp, "/"); + else + strcat(tmp, " "); + complete_push(handle, tmp); + } + } + + closedir(dir); + +out: + free(path); + + return 0; +} + +static int command_complete(struct complete_handle *handle, char *instr) +{ + cmd_tbl_t *cmdtp; + char cmd[128]; + + for_each_command(cmdtp) { + if (!strncmp(instr, cmdtp->name, strlen(instr))) { + strcpy(cmd, cmdtp->name); + cmd[strlen(cmdtp->name)] = ' '; + cmd[strlen(cmdtp->name) + 1] = 0; + complete_push(handle, cmd); + } + } + + return 0; +} + +static int tab_pressed = 0; + +void complete_reset(void) +{ + tab_pressed = 0; +} + +int complete(char *instr, char **outstr) +{ + struct complete_handle c, *entry, *first_entry, *safe; + int pos; + char ch; + int changed; + static char out[256]; + int outpos = 0; + int reprint = 0; + char *t; + + INIT_LIST_HEAD(&c.list); + + /* advance to the last command */ + t = strrchr(instr, ';'); + if (!t) + t = instr; + else + t++; + + while (*t == ' ') + t++; + + instr = t; + + /* get the completion possibilities */ + if ((t = strrchr(t, ' '))) { + t++; + file_complete(&c, t); + instr = t; + } else + command_complete(&c, instr); + + pos = strlen(instr); + + *outstr = ""; + if (list_empty(&c.list)) + return reprint; + + out[0] = 0; + + first_entry = list_first_entry(&c.list, struct complete_handle, list); + + while (1) { + entry = first_entry; + ch = entry->str[pos]; + if (!ch) + break; + + changed = 0; + list_for_each_entry(entry, &c.list, list) { + if (!entry->str[pos]) + break; + if (ch != entry->str[pos]) { + changed = 1; + break; + } + } + + if (changed) + break; + out[outpos++] = ch; + pos++; + } + + if (!list_is_last(&first_entry->list, &c.list) && !outpos && tab_pressed) { + int len = 0, num, i; + + printf("\n"); + + list_for_each_entry(entry, &c.list, list) { + int l = strlen(entry->str) + 4; + if (l > len) + len = l; + } + + num = 80 / len; + if (len == 0) + len = 1; + + i = 0; + list_for_each_entry(entry, &c.list, list) { + printf("%-*s ", len, entry->str); + if (!(++i % num)) + printf("\n"); + } + if (i % num) + printf("\n"); + reprint = 1; + } + + out[outpos++] = 0; + *outstr = out; + + if (*out == 0) + tab_pressed = 1; + else + tab_pressed = 0; + + list_for_each_entry_safe(entry, safe, &c.list, list) + free(entry); + + return reprint; +} + |