add menutree command
Creating menus from the shell using the regular 'menu' command is rather complicated. This adds a 'menutree' command which creates a menu from a directory structure. In the directory structure each directory corresponds to a single menu entry. The directory contains the following files: title - A file containing the title of the entry as shown in the menu box - If present, the entry is a 'bool' entry. The file contains a variable name from which the current state of the bool is taken from and saved to. action - if present this file contains a shell script which is executed when when the entry is selected. If neither 'box' or 'action' are present this entry is considered a submenu containing more entries. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
45693e0265
commit
ca8edb3b65
|
@ -90,6 +90,14 @@ config CMD_MENU_MANAGEMENT
|
|||
depends on CMD_MENU
|
||||
prompt "menu scripts management"
|
||||
|
||||
config CMD_MENUTREE
|
||||
bool
|
||||
depends on MENU
|
||||
select MENUTREE
|
||||
prompt "menutree"
|
||||
help
|
||||
The menutree command allows to create a menu from a directory structure
|
||||
|
||||
config CMD_LOGIN
|
||||
tristate
|
||||
select PASSWORD
|
||||
|
|
|
@ -94,3 +94,4 @@ obj-$(CONFIG_CMD_DETECT) += detect.o
|
|||
obj-$(CONFIG_CMD_BOOT) += boot.o
|
||||
obj-$(CONFIG_CMD_DEVINFO) += devinfo.o
|
||||
obj-$(CONFIG_CMD_READF) += readf.o
|
||||
obj-$(CONFIG_CMD_MENUTREE) += menutree.o
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include <command.h>
|
||||
#include <common.h>
|
||||
#include <getopt.h>
|
||||
#include <menu.h>
|
||||
|
||||
static int do_menutree(int argc, char *argv[])
|
||||
{
|
||||
int opt, ret;
|
||||
char *path = "/env/menu";
|
||||
|
||||
while ((opt = getopt(argc, argv, "m:")) > 0) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
path = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = menutree(path, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BAREBOX_CMD_HELP_START(menutree)
|
||||
BAREBOX_CMD_HELP_USAGE("menutree [OPTIONS]\n")
|
||||
"\n"
|
||||
"Create a menu from a directory structure\n"
|
||||
"Each menu entry is described by a subdirectory. Each subdirectory\n"
|
||||
"can contain the following files which further describe the entry:\n"
|
||||
"\n"
|
||||
"title - A file containing the title of the entry as shown in the menu\n"
|
||||
"box - If present, the entry is a 'bool' entry. The file contains a variable\n"
|
||||
" name from which the current state of the bool is taken from and saved\n"
|
||||
" to.\n"
|
||||
"action - if present this file contains a shell script which is executed when\n"
|
||||
" when the entry is selected.\n"
|
||||
"If neither 'box' or 'action' are present this entry is considered a submenu\n"
|
||||
"containing more entries.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -m <dir> directory where the menu starts (/env/menu)\n"
|
||||
|
||||
BAREBOX_CMD_HELP_END
|
||||
|
||||
|
||||
BAREBOX_CMD_START(menutree)
|
||||
.cmd = do_menutree,
|
||||
.usage = "create a menu from a directory structure",
|
||||
BAREBOX_CMD_HELP(cmd_menutree_help)
|
||||
BAREBOX_CMD_END
|
|
@ -62,6 +62,9 @@ config STDDEV
|
|||
config BAREBOX_UPDATE
|
||||
bool
|
||||
|
||||
config MENUTREE
|
||||
bool
|
||||
|
||||
menu "General Settings"
|
||||
|
||||
config LOCALVERSION
|
||||
|
|
|
@ -43,6 +43,7 @@ obj-$(CONFIG_RESET_SOURCE) += reset_source.o
|
|||
obj-$(CONFIG_SHELL_HUSH) += hush.o
|
||||
obj-$(CONFIG_SHELL_SIMPLE) += parser.o
|
||||
obj-$(CONFIG_UIMAGE) += image.o uimage.o
|
||||
obj-$(CONFIG_MENUTREE) += menutree.o
|
||||
|
||||
quiet_cmd_pwd_h = PWDH $@
|
||||
ifdef CONFIG_PASSWORD
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <environment.h>
|
||||
#include <libbb.h>
|
||||
#include <common.h>
|
||||
#include <glob.h>
|
||||
#include <menu.h>
|
||||
#include <fs.h>
|
||||
|
||||
#include <linux/stat.h>
|
||||
|
||||
struct menutree {
|
||||
char *action;
|
||||
struct menu_entry me;
|
||||
};
|
||||
|
||||
static void menutree_action_subdir(struct menu *m, struct menu_entry *me)
|
||||
{
|
||||
struct menutree *mt = container_of(me, struct menutree, me);
|
||||
|
||||
menutree(mt->action, 0);
|
||||
}
|
||||
|
||||
static void menutree_action(struct menu *m, struct menu_entry *me)
|
||||
{
|
||||
struct menutree *mt = container_of(me, struct menutree, me);
|
||||
|
||||
run_command(mt->action);
|
||||
}
|
||||
|
||||
static void setenv_bool(const char *var, bool val)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
if (val)
|
||||
str = "1";
|
||||
else
|
||||
str = "0";
|
||||
|
||||
setenv(var, str);
|
||||
}
|
||||
|
||||
static void menutree_box(struct menu *m, struct menu_entry *me)
|
||||
{
|
||||
struct menutree *mt = container_of(me, struct menutree, me);
|
||||
|
||||
setenv_bool(mt->action, me->box_state);
|
||||
}
|
||||
|
||||
static void menutree_entry_free(struct menu_entry *me)
|
||||
{
|
||||
struct menutree *mt = container_of(me, struct menutree, me);
|
||||
|
||||
free(mt->action);
|
||||
free(mt->me.display);
|
||||
free(mt);
|
||||
}
|
||||
|
||||
/*
|
||||
* menutree - show a menu constructed from a directory structure
|
||||
* @path: the path to the directory structure
|
||||
*
|
||||
* Each menu entry is described by a subdirectory. Each subdirectory
|
||||
* can contain the following files which further describe the entry:
|
||||
*
|
||||
* title - A file containing the title of the entry as shown in the menu
|
||||
* box - If present, the entry is a 'bool' entry. The file contains a variable
|
||||
* name from which the current state of the bool is taken from and saved
|
||||
* to.
|
||||
* action - if present this file contains a shell script which is executed when
|
||||
* when the entry is selected.
|
||||
*
|
||||
* If neither 'box' or 'action' are present this entry is considered a submenu
|
||||
* containing more entries.
|
||||
*/
|
||||
int menutree(const char *path, int toplevel)
|
||||
{
|
||||
int ret;
|
||||
struct menu *menu;
|
||||
struct stat s;
|
||||
char *box;
|
||||
struct menutree *mt;
|
||||
glob_t g;
|
||||
int i;
|
||||
char *globpath, *display;
|
||||
|
||||
menu = menu_alloc();
|
||||
|
||||
globpath = asprintf("%s/*", path);
|
||||
ret = glob(globpath, 0, NULL, &g);
|
||||
free(globpath);
|
||||
if (ret == GLOB_NOMATCH) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
display = read_file_line("%s/title", path);
|
||||
if (!display) {
|
||||
eprintf("no title found in %s/title\n", path);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
menu->display = shell_expand(display);
|
||||
free(display);
|
||||
|
||||
for (i = 0; i < g.gl_pathc; i++) {
|
||||
ret = stat(g.gl_pathv[i], &s);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!S_ISDIR(s.st_mode))
|
||||
continue;
|
||||
|
||||
mt = xzalloc(sizeof(*mt));
|
||||
|
||||
display = read_file_line("%s/title", g.gl_pathv[i]);
|
||||
if (!display) {
|
||||
eprintf("no title found in %s/title\n", g.gl_pathv[i]);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mt->me.display = shell_expand(display);
|
||||
free(display);
|
||||
mt->me.free = menutree_entry_free;
|
||||
|
||||
box = read_file_line("%s/box", g.gl_pathv[i]);
|
||||
if (box) {
|
||||
mt->me.type = MENU_ENTRY_BOX;
|
||||
mt->me.action = menutree_box;
|
||||
mt->action = box;
|
||||
getenv_bool(box, &mt->me.box_state);
|
||||
menu_add_entry(menu, &mt->me);
|
||||
continue;
|
||||
}
|
||||
|
||||
mt->me.type = MENU_ENTRY_NORMAL;
|
||||
|
||||
mt->action = asprintf("%s/action", g.gl_pathv[i]);
|
||||
|
||||
ret = stat(mt->action, &s);
|
||||
if (ret) {
|
||||
mt->me.action = menutree_action_subdir;
|
||||
free(mt->action);
|
||||
mt->action = xstrdup(g.gl_pathv[i]);
|
||||
} else {
|
||||
mt->me.action = menutree_action;
|
||||
}
|
||||
|
||||
menu_add_entry(menu, &mt->me);
|
||||
}
|
||||
|
||||
if (!toplevel) {
|
||||
mt = xzalloc(sizeof(*mt));
|
||||
mt->me.display = xstrdup("back");
|
||||
mt->me.type = MENU_ENTRY_NORMAL;
|
||||
mt->me.non_re_ent = 1;
|
||||
mt->me.free = menutree_entry_free;
|
||||
menu_add_entry(menu, &mt->me);
|
||||
}
|
||||
|
||||
menu_show(menu);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
menu_free(menu);
|
||||
|
||||
globfree(&g);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -106,4 +106,6 @@ struct menu_entry* menu_entry_get_by_num(struct menu* m, int num);
|
|||
*/
|
||||
void menu_action_exit(struct menu *m, struct menu_entry *me);
|
||||
|
||||
int menutree(const char *path, int toplevel);
|
||||
|
||||
#endif /* __MENU_H__ */
|
||||
|
|
Loading…
Reference in New Issue