/* * (C) Copyright 2009-2010 Jean-Christophe PLAGNIOL-VILLARD * * 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 #include #include #include #include #include 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 -c [-R] -d */ 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 -n */ 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 -d */ 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 */ 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 -S -n */ 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 */ 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 \n" "\n" "List menu\n" " menu -l\n" "\n" #if defined(CONFIG_CMD_MENU_MANAGEMENT) "Add a menu\n" " menu -a -m -d \n" "\n" "Remove a menu\n" " menu -r -m \n" "\n" "Add an entry\n" " (-R for do no exit the menu after executing the command)\n" " menu -e -a -m -c [-R] -d \n" "\n" "Remove an entry\n" " menu -e -r -m -n \n" "\n" "Select an entry\n" " menu -m -S -n \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