summaryrefslogtreecommitdiffstats
path: root/commands/menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'commands/menu.c')
-rw-r--r--commands/menu.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/commands/menu.c b/commands/menu.c
new file mode 100644
index 0000000..c1bd0e2
--- /dev/null
+++ b/commands/menu.c
@@ -0,0 +1,481 @@
+/*
+ * (C) Copyright 2009-2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * 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 <command.h>
+#include <readkey.h>
+#include <menu.h>
+#include <getopt.h>
+#include <errno.h>
+
+typedef enum {
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+ action_add,
+ action_remove,
+ action_select,
+#endif
+ action_list,
+ action_show,
+} menu_action;
+
+struct cmd_menu {
+ char *menu;
+ menu_action action;
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+ int entry;
+ int re_entrant;
+ char *description;
+ char *command;
+ int num;
+#endif
+};
+
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+#define OPTS "m:earlc:d:RsSn:"
+#define is_entry(x) ((x)->entry)
+#else
+#define OPTS "m:ls"
+#define is_entry(x) (0)
+#endif
+
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+/*
+ * menu -e -a -m <menu> -c <command> [-R] -d <description>
+ */
+static int do_menu_entry_add(struct cmd_menu *cm)
+{
+ struct menu_entry *me;
+ struct menu *m;
+ int len;
+ int ret = -ENOMEM;
+
+ if (!cm->menu || !cm->command || !cm->description)
+ return -EINVAL;
+
+ m = menu_get_by_name(cm->menu);
+
+ if (!m) {
+ eprintf("Menu '%s' not found\n", cm->menu);
+ return -EINVAL;
+ }
+
+ me = menu_entry_alloc();
+
+ if (!me)
+ goto free;
+
+ me->action = menu_action_run;
+
+ len = strlen(cm->command) + 1;
+
+ me->priv = calloc(len, sizeof(char));
+
+ if (!me->priv)
+ goto free;
+
+ strncpy(me->priv, cm->command, len);
+
+ len = strlen(cm->description) + 1;
+
+ me->display = calloc(len, sizeof(char));;
+
+ if (!m->display)
+ goto free;
+
+ strncpy(me->display, cm->description, len);
+
+ ret = menu_add_entry(m, me);
+
+ if (ret)
+ goto free;
+
+ me->non_re_ent = !cm->re_entrant;
+
+ return 0;
+
+free:
+ eputs("Entry add fail\n");
+
+ free(me->priv);
+
+ menu_entry_free(me);
+
+ return ret;
+}
+
+/*
+ * menu -e -r -m <name> -n <num>
+ */
+static int do_menu_entry_remove(struct cmd_menu *cm)
+{
+ struct menu *m;
+ struct menu_entry *me;
+
+ if (!cm->menu || cm->num < 0)
+ return -EINVAL;
+
+ m = menu_get_by_name(cm->menu);
+
+ if (!m) {
+ eprintf("Menu '%s' not found\n", cm->menu);
+ return -EINVAL;
+ }
+
+ me = menu_entry_get_by_num(m, cm->num);
+
+ if (!me) {
+ eprintf("Entry '%s' not found\n", cm->num);
+ return -EINVAL;
+ }
+
+ menu_remove_entry(m, me);
+
+ menu_entry_free(me);
+
+ return 0;
+}
+
+/*
+ * menu -a -m <name> -d <description>
+ */
+static int do_menu_add(struct cmd_menu *cm)
+{
+ struct menu *m;
+ int len = 0;
+ int ret = -ENOMEM;
+
+ if (!cm->menu || !cm->description)
+ return -EINVAL;
+
+ m = menu_alloc();
+
+ if (!m)
+ goto free;
+
+ len = strlen(cm->menu) + 1;
+
+ m->name = calloc(len, sizeof(char));;
+ if (!m->name)
+ goto free;
+
+ strncpy(m->name, cm->menu, len);
+
+ len = strlen(cm->description) + 1;
+
+ m->display = calloc(len, sizeof(char));;
+
+ if (!m->display)
+ goto free;
+
+ strncpy(m->display, cm->description, len);
+
+ ret = menu_add(m);
+
+ if (ret)
+ goto free;
+
+ return 0;
+
+free:
+ eprintf("Menu '%s' add fail", cm->menu);
+ if (ret == -EEXIST)
+ eputs(" already exist");
+ eputs("\n");
+
+ menu_free(m);
+
+ return ret;
+}
+/*
+ * menu -r -m <name>
+ */
+static int do_menu_remove(struct cmd_menu *cm)
+{
+ struct menu *m;
+
+ m = menu_get_by_name(cm->menu);
+
+ if (!m) {
+ eprintf("Menu '%s' not found\n", cm->menu);
+ return -EINVAL;
+ }
+
+ menu_remove(m);
+
+ menu_free(m);
+
+ return 0;
+}
+
+/*
+ * menu -m <menu> -S -n <entry num starting at 1>
+ */
+static int do_menu_select(struct cmd_menu *cm)
+{
+ struct menu *m;
+
+ if (cm->num < 0)
+ return -EINVAL;
+
+ m = menu_get_by_name(cm->menu);
+
+ if (!m) {
+ eprintf("Menu '%s' not found\n", cm->menu);
+ return -EINVAL;
+ }
+
+ if (!menu_set_selected(m, cm->num)) {
+ eprintf("Entry '%d' not found\n", cm->num);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+/*
+ * menu -s -m <menu>
+ */
+static int do_menu_show(struct cmd_menu *cm)
+{
+ struct menu *m;
+
+ if (cm->menu)
+ m = menu_get_by_name(cm->menu);
+ else
+ m = menu_get_by_name("boot");
+
+ return menu_show(m);
+}
+
+static void print_entries(struct menu *m)
+{
+ struct list_head *pos;
+ struct menu_entry *me;
+
+ list_for_each(pos, &(m->entries.list)) {
+ me = list_entry(pos, struct menu_entry, list);
+ printf("%d: %s\n", me->num, me->display);
+ }
+}
+
+/*
+ * menu -l
+ * menu -e -l [menu]
+ */
+static int do_menu_list(struct cmd_menu *cm)
+{
+ struct list_head *pos;
+ struct menu* m = NULL;
+ struct menu* menus = menu_get_menus();
+
+ if (is_entry(cm)) {
+ if (cm->menu)
+ m = menu_get_by_name(cm->menu);
+
+ if (m) {
+ print_entries(m);
+ return 0;
+ }
+ }
+
+ list_for_each(pos, &menus->list) {
+ m = list_entry(pos, struct menu, list);
+ printf("%s: %s\n", m->name, m->display? m->display : m->name);
+ if (is_entry(cm))
+ print_entries(m);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+static int do_menu_entry(struct cmd_menu *cm)
+{
+ switch(cm->action) {
+ case action_list:
+ return do_menu_list(cm);
+ case action_remove:
+ return do_menu_entry_remove(cm);
+ case action_add:
+ return do_menu_entry_add(cm);
+ case action_select:
+ case action_show:
+ break;
+ }
+ return -EINVAL;
+}
+#else
+static int do_menu_entry(struct cmd_menu *cm)
+{
+ return -EINVAL;
+}
+#endif
+
+static int do_menu(struct command *cmdtp, int argc, char *argv[])
+{
+ struct cmd_menu cm;
+ int opt;
+ int ret = -EINVAL;
+
+ if (!argc)
+ return COMMAND_ERROR_USAGE;
+
+ memset(&cm, 0, sizeof(struct cmd_menu));
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+ cm.num = -EINVAL;
+#endif
+
+ cm.action = action_show;
+
+ while((opt = getopt(argc, argv, OPTS)) > 0) {
+ switch(opt) {
+ case 'm':
+ cm.menu = optarg;
+ break;
+ case 'l':
+ cm.action = action_list;
+ break;
+ case 's':
+ cm.action = action_show;
+ break;
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+ case 'e':
+ cm.entry = 1;
+ break;
+ case 'a':
+ cm.action = action_add;
+ break;
+ case 'r':
+ cm.action = action_remove;
+ break;
+ case 'c':
+ cm.command = optarg;
+ break;
+ case 'd':
+ cm.description = optarg;
+ break;
+ case 'R':
+ cm.re_entrant = 1;
+ break;
+ case 'S':
+ cm.action = action_select;
+ break;
+ case 'n':
+ cm.num = simple_strtoul(optarg, NULL, 10);
+ break;
+#endif
+ default:
+ return 1;
+ }
+ }
+
+ if (is_entry(&cm)) {
+ ret = do_menu_entry(&cm);
+ goto end;
+ }
+
+ switch(cm.action) {
+ case action_list:
+ ret = do_menu_list(&cm);
+ break;
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+ case action_remove:
+ ret = do_menu_remove(&cm);
+ break;
+ case action_add:
+ ret = do_menu_add(&cm);
+ break;
+ case action_select:
+ ret = do_menu_select(&cm);
+ break;
+#endif
+ case action_show:
+ ret = do_menu_show(&cm);
+ break;
+ }
+
+end:
+ if (ret)
+ return 0;
+
+ return 1;
+}
+
+static const __maybe_unused char cmd_menu_help[] =
+"Usage: menu [OPTION]... \n"
+"Manage Menu\n"
+" -m menu\n"
+" -l list\n"
+" -s show\n"
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+"Advanced\n"
+" -e menu entry\n"
+" -a add\n"
+" -r remove\n"
+" -S select\n"
+#endif
+"\n"
+"How to\n"
+"\n"
+"Show menu\n"
+" menu -s -m <menu>\n"
+"\n"
+"List menu\n"
+" menu -l\n"
+"\n"
+#if defined(CONFIG_CMD_MENU_MANAGEMENT)
+"Add a menu\n"
+" menu -a -m <name> -d <description>\n"
+"\n"
+"Remove a menu\n"
+" menu -r -m <name>\n"
+"\n"
+"Add an entry\n"
+" (-R for do no exit the menu after executing the command)\n"
+" menu -e -a -m <menu> -c <command> [-R] -d <description>\n"
+"\n"
+"Remove an entry\n"
+" menu -e -r -m <name> -n <num>\n"
+"\n"
+"Select an entry\n"
+" menu -m <menu> -S -n <entry num starting at 1>\n"
+"\n"
+"List menu\n"
+" menu -e -l [menu]\n"
+"\n"
+"Menu example\n"
+"menu -a -m boot -d \"Boot Menu\"\n"
+"menu -e -a -m boot -c boot -d \"Boot\"\n"
+"menu -e -a -m boot -c reset -d \"Reset\"\n"
+"menu -s -m boot\n"
+#else
+"Menu example\n"
+"menu -s -m boot\n"
+#endif
+;
+
+BAREBOX_CMD_START(menu)
+ .cmd = do_menu,
+ .usage = "Menu Management",
+ BAREBOX_CMD_HELP(cmd_menu_help)
+BAREBOX_CMD_END