lcdexec: parameter support using widgets; hidden behind compile time option

This commit is contained in:
marschap
2007-10-11 08:17:59 +00:00
parent 0c9764bf51
commit 6ecb4854b4
6 changed files with 681 additions and 95 deletions
+1
View File
@@ -33,6 +33,7 @@ v.0.5dev (ongoing development)
* picolcd driver: overhaul USB init for more portability (M. Dolze)
+ curses driver: new option DrawBorder (Bruno Schwander)
* avoid sending duplicate "success" messages in response to menu_add_item
+ lcdexec: parameter support using widgets; hidden behind compile time option
v.0.5.2
* fix switching on/off the Load screen in lcdproc client using the menu
+146 -14
View File
@@ -40,6 +40,7 @@ typedef struct ProcInfo {
time_t starttime; /**< start time of the process */
time_t endtime; /**< finishing time of the process */
int status; /**< exit status of the process */
int feedback; /**< what info to show to the user */
int shown; /**< tell if the info has been shown to the user */
} ProcInfo;
@@ -342,8 +343,9 @@ static int process_response(char *str)
free(str2);
return -1;
}
if (strcmp(argv[1], "select") == 0) {
MenuEntry *exec;
if ((strcmp(argv[1], "select") == 0) ||
(strcmp(argv[1], "leave") == 0)) {
MenuEntry *entry;
if (argc < 3) {
report(RPT_WARNING, "Server gave invalid response");
@@ -351,16 +353,85 @@ static int process_response(char *str)
return -1;
}
/* Find the id */
exec = menu_find_by_id(main_menu, atoi(argv[2]));
if (exec == NULL) {
/* Find the entry by id */
entry = menu_find_by_id(main_menu, atoi(argv[2]));
if (entry == NULL) {
report(RPT_WARNING, "Could not find the item id given by the server");
free(str2);
return -1;
}
/* The id has been found */
exec_command(exec);
/* The id has been found.
* We trigger on the following conditions:
* - command entry without args
* - last arg of a command entry with args */
if (((entry->type == MT_EXEC) && (entry->children == NULL)) ||
((entry->type & MT_ARG_ANY) && (entry->next == NULL))) {
// last arg => get parent entry
if ((entry->type & MT_ARG_ANY) && (entry->next == NULL))
entry = entry->parent;
if (entry->type == MT_EXEC)
exec_command(entry);
}
}
#if defined(LCDEXEC_PARAMS)
else if ((strcmp(argv[1], "plus") == 0) ||
(strcmp(argv[1], "minus") == 0) ||
(strcmp(argv[1], "update") == 0)) {
MenuEntry *entry;
if (argc < 4) {
report(RPT_WARNING, "Server gave invalid response");
free(str2);
return -1;
}
/* Find the entry by id */
entry = menu_find_by_id(main_menu, atoi(argv[2]));
if (entry == NULL) {
report(RPT_WARNING, "Could not find the item id given by the server");
free(str2);
return -1;
}
switch (entry->type) {
case MT_ARG_SLIDER:
entry->data.slider.value = atoi(argv[3]);
break;
case MT_ARG_RING:
entry->data.ring.value = atoi(argv[3]);
break;
case MT_ARG_NUMERIC:
entry->data.numeric.value = atoi(argv[3]);
break;
case MT_ARG_ALPHA:
entry->data.alpha.value = realloc(entry->data.alpha.value,
strlen(argv[3]));
strcpy(entry->data.alpha.value, argv[3]);
break;
case MT_ARG_IP:
entry->data.ip.value = realloc(entry->data.ip.value,
strlen(argv[3]));
strcpy(entry->data.ip.value, argv[3]);
break;
case MT_ARG_CHECKBOX:
if ((entry->data.checkbox.allow_gray) &&
(strcasecmp(argv[3], "gray") == 0))
entry->data.checkbox.value = 2;
else if (strcasecmp(argv[3], "on") == 0)
entry->data.checkbox.value = 1;
else
entry->data.checkbox.value = 0;
break;
default:
report(RPT_WARNING, "Illegal menu entry type for event");
free(str2);
return -1;
}
}
#endif
else {
; /* Ignore other menuevents */
}
@@ -401,18 +472,64 @@ static int exec_command(MenuEntry *cmd)
const char *argv[4];
pid_t pid;
ProcInfo *p;
#if defined(LCDEXEC_PARAMS)
char *envp[cmd->numChildren+1];
MenuEntry *arg;
int i;
#endif
report(RPT_NOTICE, "Executing: %s", command);
/* set argument vector */
argv[0] = default_shell;
argv[1] = "-c";
argv[2] = command;
argv[3] = NULL;
#if defined(LCDEXEC_PARAMS)
/* set environment vector: allocate & fill contents */
for (arg = cmd->children, i = 0; arg != NULL; arg = arg->next, i++) {
char buf[1025];
switch (arg->type) {
case MT_ARG_SLIDER:
snprintf(buf, 1024, "%s=%d", arg->name, arg->data.slider.value);
break;
case MT_ARG_RING:
snprintf(buf, 1024, "%s=%s", arg->name, arg->data.ring.strings[arg->data.ring.value]);
break;
case MT_ARG_NUMERIC:
snprintf(buf, 1024, "%s=%d", arg->name, arg->data.numeric.value);
break;
case MT_ARG_ALPHA:
snprintf(buf, 1024, "%s=%s", arg->name, arg->data.alpha.value);
break;
case MT_ARG_IP:
snprintf(buf, 1024, "%s=%s", arg->name, arg->data.ip.value);
break;
case MT_ARG_CHECKBOX:
snprintf(buf, 1024, "%s=%d", arg->name, arg->data.checkbox.value);
break;
default:
/* error ? */
break;
}
buf[1024] ='\0';
envp[i] = strdup(buf);
debug(RPT_DEBUG, "Environment: %s", envp[i]);
}
envp[cmd->numChildren] = NULL;
#endif
debug(RPT_DEBUG, "Executing '%s' via Shell %s", command, default_shell);
switch (pid = fork()) {
case 0:
/* We're the child: execute the command */
#if defined(LCDEXEC_PARAMS)
execve(argv[0], (char **) argv, envp);
#else
execv(argv[0], (char **) argv);
#endif
exit(0);
break;
default:
@@ -422,15 +539,23 @@ static int exec_command(MenuEntry *cmd)
p->cmd = cmd;
p->pid = pid;
p->starttime = time(NULL);
p->feedback = cmd->data.exec.feedback;
/* prepend it to existing queue atomically */
p->next = proc_queue;
proc_queue = p;
}
break;
break;
case -1:
report(RPT_ERR, "Could not fork");
return -1;
}
#if defined(LCDEXEC_PARAMS)
/* free envp's contents */
for (i = 0; envp[i] != NULL; i++)
free(envp[i]);
#endif
return 0;
}
return -1;
@@ -441,11 +566,15 @@ static int show_procinfo_msg(ProcInfo *p)
{
if ((p != NULL) && (lcd_wid > 0) && (lcd_hgt > 0)) {
if (p->endtime > 0) {
/* nothing to do => the quick way out (successful) */
if ((p->shown) || (!p->feedback))
return 1;
sock_printf(sock, "screen_add [%u]\n", p->pid);
sock_printf(sock, "screen_set [%u] -name {lcdexec [%u]}"
" -priority alert -timeout %d"
" -heartbeat off\n",
p->pid, p->pid, 8*8);
p->pid, p->pid, 6*8);
if (lcd_hgt > 2) {
sock_printf(sock, "widget_add [%u] t title\n", p->pid);
@@ -472,8 +601,9 @@ static int show_procinfo_msg(ProcInfo *p)
p->pid, WTERMSIG(p->status));
}
sock_printf(sock, "widget_set [%u] s3 1 4 {Exec time: %lds}\n",
p->pid, p->endtime - p->starttime);
if (lcd_hgt > 3)
sock_printf(sock, "widget_set [%u] s3 1 4 {Exec time: %lds}\n",
p->pid, p->endtime - p->starttime);
}
else {
sock_printf(sock, "widget_add [%u] s1 string\n", p->pid);
@@ -496,9 +626,10 @@ static int show_procinfo_msg(ProcInfo *p)
}
}
return 1;
}
}
return 1;
return 0;
}
@@ -560,3 +691,4 @@ static int main_loop(void)
return 0;
}
/* EOF */
+68 -9
View File
@@ -38,6 +38,8 @@ Entry=MenuC
DisplayName="You can say A"
# the exec=... line tells that it is a command
Exec="echo a"
# show a temporary feedback screen upon completion [default: no; legal: yes, no]
Feedback= yes
[CmdB]
DisplayName="Or you can say B"
@@ -55,20 +57,77 @@ DisplayName=P
Exec="echo P"
[CmdQ]
DisplayName=Q
Exec="echo Q"
DisplayName="Show environment"
Exec="env"
# When lcdexec is compiled with compiler option -DLCDEXEC_PARAMS
# you can change parameters for commands within lcdexec.
# Parameters are handed to the program as environment variables;
# so they can be easily used in the Exec=... line as $XXX
# (e.g. "echo $SLIDER_ARG").
# Please note a little issue with parameters: after changing the
# last parameter of a command the command gets executed automatically.
# This is IMHO noti ideal. I'm open for ideas to improve it.
# Here's how they are defined:
#Parameter=SLIDER_ARG
#Parameter=RING_ARG
#Parameter=NUMERIC_ARG
#Parameter=ALPHA_ARG
#Parameter=CHECKBOX_ARG
#Parameter=IP_ARG
#
#[SLIDER_ARG]
#DisplayName="Slider"
## Type of argument widget [legal: Slider, Checkbox, Ring, Numeric, Alpha, IP]
#Type=Slider
## inital value of the argument
#Value=5
## options depending on the widget type
#MinValue=0
#MaxValue=10
#
#[CHECKBOX_ARG]
#DisplayName="Checkbox"
#Type=Checkbox
#Value=on
#AllowGray=no
#
#[RING_ARG]
#DisplayName="Ring"
#Type=Ring
#Value=0
## list of alternative strings
#String=Eins
#String=Zwei
#String=Drei
#
#[NUMERIC_ARG]
#DisplayName="Numeric"
#Type=Numeric
#Value=5
#MinValue=0
#MaxValue=10
#
#[ALPHA_ARG]
#DisplayName="Alpha"
#Type=Alpha
## range of characters allowed [default: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
#AllowedChars = "+-0123456789ABCDEF"
#Value=5
#MinLength=0
#MaxLength=10
#
#[IP_ARG]
#DisplayName="IP"
#Type=IP
#Value=10.230.2.2
#v6=no
# Further Extensions:
# Ideas for further extensions:
# - shell selectable in command sections
# - type definitions instead implicit depending on Exec/Entry
# (the latter only as fallback)
# - use input for parameters e.g. IP-Adresses, Sliders
# e.g. Exec="ifconfig ${IF} ${IP} netmask ${MASK} broadcast ${BCAST}"
# where
# - ${IF} is the result of a selection input screen
# - ${IP}, ${MASK}n ${BCAST} are the results of IP input screens
# - display result if a command on the display
# - display configurable result of a command on the display
# - jump to other menus depending on the output/result of a command
# EOF
+400 -63
View File
@@ -20,14 +20,21 @@
#include "menu.h"
/* names for boolean and tristate values */
static char *boolValueName[] = { "false", "true" };
#if defined(LCDEXEC_PARAMS)
static char *triGrayValueName[] = { "off", "on", "gray" };
#endif
/* recursively read the menu hierarchy */
MenuEntry *menu_read(MenuEntry *parent, const char *name)
{
static int id = 0;
if (config_has_section(name)) {
MenuEntry *me = calloc(1, sizeof(MenuEntry));
MenuEntry *me = calloc(1, sizeof(MenuEntry)); // auto-NULL elements
if (me == NULL)
return NULL;
// set common entries
@@ -36,55 +43,158 @@ MenuEntry *menu_read(MenuEntry *parent, const char *name)
if (me->name == NULL) {
//menu_free(me);
return NULL;
}
}
me->displayname = strdup(config_get_string(name, "DisplayName", 0, name));
if (me->name == NULL) {
if (me->displayname == NULL) {
//menu_free(me);
return NULL;
}
}
me->entries = NULL;
me->parent = parent;
me->next = NULL;
me->command = NULL;
me->children = NULL;
me->numChildren = 0;
if (config_get_string(name, "Entry", 0, NULL) != NULL) {
MenuEntry **addr = &me->entries;
MenuEntry **addr = &me->children;
const char *entryname;
int index = 0;
// it is a sub-menu
me->type = menu;
while ((entryname = config_get_string(name, "Entry", index++, NULL)) != NULL) {
me->type = MT_MENU;
// read menu entries
while ((entryname = config_get_string(name, "Entry", me->numChildren, NULL)) != NULL) {
MenuEntry *entry = menu_read(me, entryname);
if (entry == NULL) {
//menu_free(me);
return NULL;
}
}
me->numChildren++;
*addr = entry;
addr = &entry->next;
}
}
}
}
else if (config_get_string(name, "Exec", 0, NULL) != NULL) {
#if defined(LCDEXEC_PARAMS)
MenuEntry **addr = &me->children;
const char *entryname;
#endif
// it's a command to execute
me->type = exec;
me->type = MT_EXEC;
me->command = strdup(config_get_string(name, "Exec", 0, ""));
if (me->command == NULL) {
me->data.exec.command = strdup(config_get_string(name, "Exec", 0, ""));
if (me->data.exec.command == NULL) {
//menu_free(me);
return NULL;
}
}
me->data.exec.feedback = config_get_bool(name, "Feedback", 0, 0);
#if defined(LCDEXEC_PARAMS)
// try to read parameters
while ((entryname = config_get_string(name, "Parameter", me->numChildren, NULL)) != NULL) {
MenuEntry *entry = menu_read(me, entryname);
if (entry == NULL) {
//menu_free(me);
return NULL;
}
me->numChildren++;
*addr = entry;
addr = &entry->next;
}
#endif
}
#if defined(LCDEXEC_PARAMS)
else if (config_get_string(name, "Type", 0, NULL) != NULL) {
// it's a command parameter
const char *type;
type = config_get_string(name, "Type", 0, "");
if (strcasecmp(type, "slider") == 0) {
char buf[35];
me->type = MT_ARG_SLIDER;
me->data.slider.value = config_get_int(name, "Value", 0, 0);
me->data.slider.minval = config_get_int(name, "MinValue", 0, 0);
me->data.slider.maxval = config_get_int(name, "MaxValue", 0, 1000);
sprintf(buf, "%d", me->data.slider.minval);
me->data.slider.mintext = strdup(config_get_string(name, "MinText", 0, buf));
sprintf(buf, "%d", me->data.slider.maxval);
me->data.slider.maxtext = strdup(config_get_string(name, "MaxText", 0, buf));
me->data.slider.stepsize = config_get_int(name, "StepSize", 0, 1);
}
else if (strcasecmp(type, "ring") == 0) {
const char *tmp;
int numStrings = 0;
int i = 0;
me->type = MT_ARG_RING;
me->data.ring.value = config_get_int(name, "Value", 0, 0);
numStrings = config_has_key(name, "String");
me->data.ring.strings = calloc(sizeof(char *), numStrings+1);
me->data.ring.strings[numStrings] = NULL;
while ((tmp = config_get_string(name, "String", i, NULL)) != NULL) {
me->data.ring.strings[i] = strdup(tmp);
i++;
}
me->data.ring.strings[i] = NULL;
}
else if (strcasecmp(type, "numeric") == 0) {
me->type = MT_ARG_NUMERIC;
me->data.numeric.value = config_get_int(name, "Value", 0, 0);
me->data.numeric.minval = config_get_int(name, "MinValue", 0, 0);
me->data.numeric.maxval = config_get_int(name, "MaxValue", 0, 1000);
}
else if (strcasecmp(type, "alpha") == 0) {
me->type = MT_ARG_ALPHA;
me->data.alpha.value = strdup(config_get_string(name, "Value", 0, ""));
me->data.alpha.minlen = config_get_int(name, "MinLength", 0, 0);
me->data.alpha.maxlen = config_get_int(name, "MaxLength", 0, 100);
me->data.alpha.allowed_chars = strdup(config_get_string(name, "AllowedChars", 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
}
else if (strcasecmp(type, "ip") == 0) {
me->type = MT_ARG_IP;
me->data.ip.value = strdup(config_get_string(name, "Value", 0, ""));
me->data.ip.v6 = config_get_bool(name, "Value", 0, 0);
}
else if (strcasecmp(type, "checkbox") == 0) {
me->type = MT_ARG_CHECKBOX;
me->data.checkbox.allow_gray = config_get_bool(name, "AllowGray", 0, 0);
me->data.checkbox.value = (me->data.checkbox.allow_gray)
? config_get_tristate(name, "Value", 0, "gray", 0)
: config_get_bool(name, "Value", 0, 0);
}
else {
report(RPT_DEBUG, "illegal parameter type");
//menu_free(me);
return NULL;
}
}
#endif
else {
report(RPT_DEBUG, "unknown menu entry type");
//menu_free(me);
return NULL;
}
}
return me;
}
}
return NULL;
}
@@ -105,34 +215,169 @@ int menu_sock_send(MenuEntry *me, MenuEntry *parent, int sock)
switch (me->type) {
MenuEntry *entry;
case menu:
case MT_MENU:
// don't create a separate entry for the main menu
if ((parent != NULL) && (me->id != 0)) {
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" menu \"%s\"\n",
parent_id, me->id, me->displayname) < 0)
return -1;
}
}
// recursively do it for the menu's sub-menus
for (entry = me->entries; entry != NULL; entry = entry->next) {
for (entry = me->children; entry != NULL; entry = entry->next) {
if (menu_sock_send(entry, me, sock) < 0)
return -1;
}
}
break;
case exec:
case MT_EXEC:
#if defined(LCDEXEC_PARAMS)
if (me->children == NULL) {
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" action \"%s\"\n",
parent_id, me->id, me->displayname) < 0)
return -1;
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -menu_result quit\n",
parent_id, me->id) < 0)
return -1;
}
else {
if ((parent != NULL) && (me->id != 0)) {
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" menu \"%s\"\n",
parent_id, me->id, me->displayname) < 0)
return -1;
}
// (recursively) do it for the entry's parameters
for (entry = me->children; entry != NULL; entry = entry->next) {
if (menu_sock_send(entry, me, sock) < 0)
return -1;
}
}
#else
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" action \"%s\"\n",
parent_id, me->id, me->displayname) < 0)
return -1;
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -menu_result quit\n",
parent_id, me->id) < 0)
return -1;
#endif
break;
case unknown:
#if defined(LCDEXEC_PARAMS)
case MT_ARG_SLIDER:
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" slider -text \"%s\""
" -value %d -minvalue %d -maxvalue %d"
" -mintext \"%s\" -maxtext \"%s\" -stepsize %d\n",
parent_id, me->id, me->displayname,
me->data.slider.value,
me->data.slider.minval,
me->data.slider.maxval,
me->data.slider.mintext,
me->data.slider.maxtext,
me->data.slider.stepsize) <0)
return -1;
if (me->next == NULL) {
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -next _quit_\n",
parent_id, me->id) < 0)
return -1;
}
break;
case MT_ARG_RING:
{
int i;
char *tmp = strdup("");
// join all strings with TAB as separator
for (i = 0; me->data.ring.strings[i] != NULL; i++) {
tmp = realloc(tmp, strlen(tmp) + 1 +
strlen(me->data.ring.strings[i]) + 1);
if (tmp[0] != '\0')
strcat(tmp, "\t");
strcat(tmp, me->data.ring.strings[i]);
}
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" ring -text \"%s\""
" -value %d -strings \"%s\"\n",
parent_id, me->id, me->displayname,
me->data.ring.value,
tmp) < 0)
return -1;
}
if (me->next == NULL) {
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -next _quit_\n",
parent_id, me->id) < 0)
return -1;
}
break;
case MT_ARG_NUMERIC:
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" numeric -text \"%s\""
" -value %d -minvalue %d -maxvalue %d\n",
parent_id, me->id, me->displayname,
me->data.numeric.value,
me->data.numeric.minval,
me->data.numeric.maxval) < 0)
return -1;
if (me->next == NULL) {
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -next _quit_\n",
parent_id, me->id) < 0)
return -1;
}
break;
case MT_ARG_ALPHA:
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" alpha -text \"%s\""
" -value \"%s\" -minlength %d -maxlength %d"
" -allow_caps false -allow_noncaps false"
" -allow_numbers false -allowed_extra \"%s\"\n",
parent_id, me->id, me->displayname,
me->data.alpha.value,
me->data.alpha.minlen,
me->data.alpha.maxlen,
me->data.alpha.allowed_chars) <0)
return -1;
if (me->next == NULL) {
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -next _quit_\n",
parent_id, me->id) < 0)
return -1;
}
break;
case MT_ARG_IP:
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" ip -text \"%s\""
" -value \"%s\" -v6 %s\n",
parent_id, me->id, me->displayname,
me->data.ip.value,
boolValueName[me->data.ip.v6]) < 0)
return -1;
if (me->next == NULL) {
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -next _quit_\n",
parent_id, me->id) < 0)
return -1;
}
break;
case MT_ARG_CHECKBOX:
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" checkbox -text \"%s\""
" -value %s -allow_gray %s\n",
parent_id, me->id, me->displayname,
triGrayValueName[me->data.checkbox.value],
boolValueName[me->data.checkbox.allow_gray]) < 0)
return -1;
if (me->next == NULL) {
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -next _quit_\n",
parent_id, me->id) < 0)
return -1;
}
break;
#endif
default:
return -1;
}
return 0;
}
}
return -1;
}
@@ -144,16 +389,16 @@ MenuEntry *menu_find_by_id(MenuEntry *me, int id)
if (me->id == id)
return me;
if (me->type == menu) {
if ((me->type == MT_MENU) || (me->type == MT_EXEC)) {
MenuEntry *entry;
for (entry = me->entries; entry != NULL; entry = entry->next) {
for (entry = me->children; entry != NULL; entry = entry->next) {
MenuEntry *result = menu_find_by_id(entry, id);
if (result != NULL)
return result;
}
}
}
}
return NULL;
}
@@ -162,8 +407,8 @@ MenuEntry *menu_find_by_id(MenuEntry *me, int id)
/* return command of a menu entry */
const char *menu_command(MenuEntry *me)
{
if ((me != NULL) && (me->type == exec))
return me->command;
if ((me != NULL) && (me->type == MT_EXEC))
return me->data.exec.command;
return NULL;
}
@@ -176,22 +421,55 @@ void menu_free(MenuEntry *me)
switch (me->type) {
MenuEntry *entry;
case menu:
for (entry = me->entries; entry != NULL; ) {
case MT_EXEC:
if (me->data.exec.command != NULL)
free(me->data.exec.command);
me->data.exec.command = NULL;
/* fall through */
case MT_MENU:
for (entry = me->children; entry != NULL; ) {
MenuEntry *old = entry;
entry = entry->next;
old->next = NULL;
menu_free(old);
}
me->entries = NULL;
}
me->children = NULL;
break;
case exec:
if (me->command != NULL)
free(me->command);
me->command = NULL;
#if defined(LCDEXEC_PARAMS)
case MT_ARG_SLIDER:
if (me->data.slider.mintext != NULL)
free(me->data.slider.mintext);
me->data.slider.mintext = NULL;
if (me->data.slider.maxtext != NULL)
free(me->data.slider.maxtext);
me->data.slider.maxtext = NULL;
break;
case unknown:
case MT_ARG_RING:
if (me->data.ring.strings != NULL) {
int i;
for (i = 0; me->data.ring.strings[i] != NULL; i++)
free(me->data.ring.strings[i]);
free(me->data.ring.strings);
me->data.ring.strings = NULL;
}
break;
case MT_ARG_ALPHA:
if (me->data.alpha.value != NULL)
free(me->data.alpha.value);
me->data.alpha.value = NULL;
if (me->data.alpha.allowed_chars != NULL)
free(me->data.alpha.allowed_chars);
me->data.alpha.allowed_chars = NULL;
break;
case MT_ARG_IP:
if (me->data.ip.value != NULL)
free(me->data.ip.value);
me->data.ip.value = NULL;
break;
#endif
default:
break;
}
@@ -199,12 +477,12 @@ void menu_free(MenuEntry *me)
if (me->name != NULL)
free(me->name);
me->name = NULL;
if (me->displayname != NULL)
free(me->displayname);
me->displayname = NULL;
me->type = unknown;
me->type = MT_UNKNOWN;
free(me);
}
@@ -220,31 +498,90 @@ void menu_dump(MenuEntry *me)
report(RPT_DEBUG, "[%s]", me->name);
if (me->displayname != NULL)
report(RPT_DEBUG, "DisplayName=\"%s\"", me->displayname);
switch (me->type) {
MenuEntry *entry;
case menu:
for (entry = me->entries; entry != NULL; entry = entry->next)
case MT_MENU:
// dump menu entry references
for (entry = me->children; entry != NULL; entry = entry->next)
report(RPT_DEBUG, "Entry=%s", entry->name);
report(RPT_DEBUG, "");
// recursively walk through sub-menus
for (entry = me->children; entry != NULL; entry = entry->next)
menu_dump(entry);
break;
case exec:
report(RPT_DEBUG, "Exec=\"%s\"", me->command);
case MT_EXEC:
report(RPT_DEBUG, "Exec=\"%s\"", me->data.exec.command);
report(RPT_DEBUG, "Feedback=%s", boolValueName[me->data.exec.feedback]);
#if defined(LCDEXEC_PARAMS)
// dump entry's parameter referencess
for (entry = me->children; entry != NULL; entry = entry->next)
report(RPT_DEBUG, "Parameter=%s", entry->name);
report(RPT_DEBUG, "");
// dump entry's parameters
for (entry = me->children; entry != NULL; entry = entry->next)
menu_dump(entry);
#else
report(RPT_DEBUG, "");
#endif
break;
case unknown:
#if defined(LCDEXEC_PARAMS)
case MT_ARG_SLIDER:
report(RPT_DEBUG, "Type=slider");
report(RPT_DEBUG, "Value=%d", me->data.slider.value);
report(RPT_DEBUG, "MinValue=%d", me->data.slider.minval);
report(RPT_DEBUG, "MaxValue=%d", me->data.slider.maxval);
report(RPT_DEBUG, "Stepsize=%d", me->data.slider.stepsize);
report(RPT_DEBUG, "MinText=%s", me->data.slider.mintext);
report(RPT_DEBUG, "MaxText=%s", me->data.slider.maxtext);
report(RPT_DEBUG, "");
break;
case MT_ARG_RING:
report(RPT_DEBUG, "Type=ring");
report(RPT_DEBUG, "Value: %d", me->data.ring.value);
{
int i;
for (i = 0; me->data.ring.strings[i] != NULL; i++)
report(RPT_DEBUG, "String=\"%s\"", me->data.ring.strings[i]);
}
report(RPT_DEBUG, "");
break;
case MT_ARG_NUMERIC:
report(RPT_DEBUG, "Type=numeric");
report(RPT_DEBUG, "Value=%d", me->data.numeric.value);
report(RPT_DEBUG, "MinValue=%d", me->data.numeric.minval);
report(RPT_DEBUG, "MaxValue=%d", me->data.numeric.maxval);
report(RPT_DEBUG, "");
break;
case MT_ARG_ALPHA:
report(RPT_DEBUG, "Type:=lpha");
report(RPT_DEBUG, "Value=\"%s\"", me->data.alpha.value);
report(RPT_DEBUG, "AllowedChars=\"%s\"", me->data.alpha.allowed_chars);
report(RPT_DEBUG, "");
break;
case MT_ARG_IP:
report(RPT_DEBUG, "Type=ip");
report(RPT_DEBUG, "Value=\"%s\"", me->data.ip.value);
report(RPT_DEBUG, "V6=%s", boolValueName[me->data.ip.v6]);
report(RPT_DEBUG, "");
break;
case MT_ARG_CHECKBOX:
report(RPT_DEBUG, "Type=ip");
report(RPT_DEBUG, "Value=%s", triGrayValueName[me->data.checkbox.value]);
report(RPT_DEBUG, "AllowGray=%s", boolValueName[me->data.checkbox.allow_gray]);
report(RPT_DEBUG, "");
break;
#endif
default:
report(RPT_DEBUG, "ERROR: unknown menu entry type");
break;
}
report(RPT_DEBUG, "");
// recursively walk through sub-menus
if (me->type == menu) {
MenuEntry *entry;
for (entry = me->entries; entry != NULL; entry = entry->next)
menu_dump(entry);
}
}
}
#endif
+57 -8
View File
@@ -24,9 +24,19 @@
/** Symbolic names for the types of a MenuEntry */
typedef enum {
unknown = 0, /**< Unknown MenuEntry type. */
menu = 1, /**< MenuEntry representing a menu. */
exec = 2, /**< MenuEntry representing an executable command. */
MT_UNKNOWN = 0x00, /**< Unknown MenuEntry type. */
MT_MENU = 0x01, /**< MenuEntry representing a menu. */
MT_EXEC = 0x02, /**< MenuEntry representing an executable command. */
MT_ARG_ANY = 0x10, /**< Mask denoting a parameter of any type */
#if defined(LCDEXEC_PARAMS)
MT_ARG_SLIDER = 0x11, /**< MenuEntry representing a slider parameter. */
MT_ARG_RING = 0x12, /**< MenuEntry representing a ring parameter. */
MT_ARG_NUMERIC = 0x13, /**< MenuEntry representing a numeric input parameter. */
MT_ARG_ALPHA = 0x14, /**< MenuEntry representing a alpha input parameter. */
MT_ARG_IP = 0x15, /**< MenuEntry representing a IP input parameter. */
MT_ARG_CHECKBOX = 0x16, /**< MenuEntry representing a checkbox input parameter. */
#endif
} MenuType;
@@ -35,13 +45,52 @@ typedef struct menu_entry {
char *displayname; /**< isible name of the entry. */
int id; /**< Internal ID of the entry. */
MenuType type; /**< Type of the entry. */
struct menu_entry *parent; /**< Parent menu entry */
int numChildren; /**< # of child entries */
// variables necessary for type menu
struct menu_entry *entries; /**< Subordinate menu entries (for MenuType \c menu). */
struct menu_entry *next; /**< Next sibling menu entry (for MenuType \c menu). */
// variables necessary for multiple types
struct menu_entry *children; /**< Subordinate menu entries (for MenuType \c MT_MENU & \c MT_EXEC). */
struct menu_entry *next; /**< Next sibling menu entry (for MenuType \c MT_MENU). */
// variables necessary for type exec
char *command; /**< Command to execute (for MenuType \c exec). */
union {
struct { // elements necessary for type MT_EXEC
char *command; /**< Command to execute (for MenuType \c exec). */
int feedback; /**< Feedback option (for MenuType \c exec). */
} exec;
#if defined(LCDEXEC_PARAMS)
struct { // elements necessary for type MT_ARG_SLIDER
int value;
int minval;
int maxval;
int stepsize;
char *mintext;
char *maxtext;
} slider;
struct { // elements necessary for type MT_ARG_RING
int value;
char **strings;
} ring;
struct { // elements necessary for type MT_ARG_NUMERIC
int value;
int minval;
int maxval;
} numeric;
struct { // elements necessary for type MT_ARG_ALPHA
char *value;
int minlen;
int maxlen;
char *allowed_chars;
} alpha;
struct { // elements necessary for type MT_ARG_IP
char *value;
int v6;
} ip;
struct { // elements necessary for type MT_ARG_CHECKBOX
int value;
int allow_gray;
} checkbox;
#endif
} data;
} MenuEntry;
+9 -1
View File
@@ -94,7 +94,7 @@ is the hostname of the system \fIlcdexec\fP is running on.
Set the shell to use when executing programs.
If not given, \fBlcdexec\fP tries to read the environment variable \fISHELL\fP.
If that fails, it defaults to \fB/bin/sh\fP.
Please note that the shell given here must understand the option \fB-c\fP
Please note that the shell given here must understand the option \fB\-c\fP
followed by the command line to execute.
.PP
@@ -119,6 +119,11 @@ Sections containing an \fBExec=\fP option are command entries.
.B DisplayName=\fIname\fP
The name of the menu entry to be displayed on the LCD.
If this option is not given, the the section header name is used (without the square brackets).
.TP 8
.B Feedback=\fIbool\fP
In command entries, this option tells whether to inform the user of the completion of
commands using an alert screen on the display.
If not given, it defaults to \fBno\fB.
.PP
.SH FILES
@@ -178,14 +183,17 @@ Entry=RebootNow
[Shutdown5min]
DisplayName="Shutdown in 5 minutes"
Exec="shutdown -h +5"
Feedback=yes
[Reboot5min]
DisplayName="Reboot in 5 minutes"
Exec="shutdown -r +5"
Feedback=yes
[CanclShutdown]
DisplayName="Cancel shutdown/reboot"
Exec="shutdown -c"
Feedback=yes
[ShutdownNow]
DisplayName="Shutdown now"