2013-09-22 22:41:22 +00:00
|
|
|
/*
|
|
|
|
* 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>
|
2014-07-30 08:43:51 +00:00
|
|
|
#include <libfile.h>
|
2013-09-22 22:41:22 +00:00
|
|
|
|
|
|
|
#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;
|
|
|
|
}
|