reworked menu definition in config file to be more elegant and more flexible
This commit is contained in:
+53
-40
@@ -6,23 +6,13 @@
|
|||||||
* COPYING file distributed with this package.
|
* COPYING file distributed with this package.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002, Joris Robijn
|
* Copyright (c) 2002, Joris Robijn
|
||||||
*
|
* Copyright (c) 2006, Peter Marschall
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* How to use submenus in the config file:
|
|
||||||
* [lcdexec]
|
|
||||||
* MenuCommand="Shut down,shutdown -h now"
|
|
||||||
* SubMenu="Internet,inet"
|
|
||||||
* # The inet submenu is filled as follows:
|
|
||||||
* inet_MenuCommand="open,inet open"
|
|
||||||
* inet_MenuCommand="close,inet close"
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#include "getopt.h"
|
#include "getopt.h"
|
||||||
|
|
||||||
@@ -62,15 +52,15 @@ extern int optind, optopt, opterr;
|
|||||||
/* Variables set by config */
|
/* Variables set by config */
|
||||||
#define UNSET_INT -1
|
#define UNSET_INT -1
|
||||||
#define UNSET_STR "\01"
|
#define UNSET_STR "\01"
|
||||||
char * configfile = UNSET_STR;
|
char * configfile = NULL;
|
||||||
char * address = UNSET_STR;
|
char * address = NULL;
|
||||||
int port = UNSET_INT;
|
int port = UNSET_INT;
|
||||||
int foreground_mode = UNSET_INT;
|
int foreground_mode = UNSET_INT;
|
||||||
char * appname = UNSET_STR;
|
|
||||||
static int report_level = UNSET_INT;
|
static int report_level = UNSET_INT;
|
||||||
static int report_dest = UNSET_INT;
|
static int report_dest = UNSET_INT;
|
||||||
|
char *displayname = NULL;
|
||||||
|
|
||||||
Menu * main_menu;
|
MenuEntry *main_menu;
|
||||||
|
|
||||||
/* Other variables */
|
/* Other variables */
|
||||||
int sock = -1;
|
int sock = -1;
|
||||||
@@ -78,11 +68,10 @@ int sock = -1;
|
|||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
int process_command_line(int argc, char **argv);
|
int process_command_line(int argc, char **argv);
|
||||||
int process_configfile(char * configfile);
|
int process_configfile(char * configfile);
|
||||||
int split(char * str, char delim, char * parts[], int maxparts);
|
int connect_and_setup();
|
||||||
int connect_and_setup ();
|
|
||||||
int process_response(char * str);
|
int process_response(char * str);
|
||||||
int exec_command(char * command);
|
int exec_command(MenuEntry *cmd);
|
||||||
int main_loop ();
|
int main_loop();
|
||||||
|
|
||||||
|
|
||||||
#define CHAIN(e,f) { if (e>=0) { e=(f); }}
|
#define CHAIN(e,f) { if (e>=0) { e=(f); }}
|
||||||
@@ -191,14 +180,16 @@ int process_command_line(int argc, char **argv)
|
|||||||
|
|
||||||
int process_configfile(char * configfile)
|
int process_configfile(char * configfile)
|
||||||
{
|
{
|
||||||
if (strcmp(configfile, UNSET_STR) == 0) {
|
char * tmp;
|
||||||
|
|
||||||
|
if (configfile == NULL)
|
||||||
configfile = DEFAULT_CONFIGFILE;
|
configfile = DEFAULT_CONFIGFILE;
|
||||||
}
|
|
||||||
if (config_read_file(configfile) < 0) {
|
if (config_read_file(configfile) < 0) {
|
||||||
report(RPT_WARNING, "Could not read config file: %s", configfile);
|
report(RPT_WARNING, "Could not read config file: %s", configfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(address, UNSET_STR) == 0) {
|
if (address == NULL) {
|
||||||
address = strdup(config_get_string(progname, "Address", 0, "localhost"));
|
address = strdup(config_get_string(progname, "Address", 0, "localhost"));
|
||||||
}
|
}
|
||||||
if (port == UNSET_INT) {
|
if (port == UNSET_INT) {
|
||||||
@@ -216,17 +207,24 @@ int process_configfile(char * configfile)
|
|||||||
foreground_mode = config_get_bool(progname, "Foreground", 0, 0);
|
foreground_mode = config_get_bool(progname, "Foreground", 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
main_menu = menu_read("", progname);
|
if ((tmp = config_get_string(progname, "DisplayName", 0, NULL)) != NULL)
|
||||||
|
displayname = strdup(tmp);
|
||||||
|
|
||||||
if (main_menu->num_menucmds == 0 && main_menu->num_submenus == 0) {
|
main_menu = menu_read(NULL, "MainMenu");
|
||||||
main_menu->menucmd_name[0] = "echo test";
|
#if defined(DEBUG)
|
||||||
main_menu->menucmd_exec[0] = "echo \"This is a test using the echo command.\"";
|
menu_dump(main_menu);
|
||||||
main_menu->num_menucmds ++;
|
#endif
|
||||||
|
|
||||||
|
// fail on non-existent main menu;
|
||||||
|
if (main_menu == NULL) {
|
||||||
|
report(RPT_ERR, "no main menu found in configuration");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int connect_and_setup ()
|
int connect_and_setup()
|
||||||
{
|
{
|
||||||
report(RPT_INFO, "Connecting to %s:%d", address, port);
|
report(RPT_INFO, "Connecting to %s:%d", address, port);
|
||||||
|
|
||||||
@@ -235,20 +233,31 @@ int connect_and_setup ()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create our menu */
|
/* init connection and set client name */
|
||||||
sock_send_string(sock, "hello\n");
|
sock_send_string(sock, "hello\n");
|
||||||
sock_printf(sock, "client_set -name \"%s\"\n", progname);
|
if (displayname != NULL) {
|
||||||
|
sock_printf(sock, "client_set -name {%s}\n", displayname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct utsname unamebuf;
|
||||||
|
|
||||||
if (menu_send_to_LCDd(main_menu, "", sock) < 0) {
|
if (uname(&unamebuf) == 0)
|
||||||
|
sock_printf(sock, "client_set -name {%s %s}\n", progname, unamebuf.nodename);
|
||||||
|
else
|
||||||
|
sock_printf(sock, "client_set -name {%s}\n", progname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create our menu */
|
||||||
|
if (menu_sock_send(main_menu, NULL, sock) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_response(char * str)
|
int process_response(char *str)
|
||||||
{
|
{
|
||||||
char *argv[10];
|
char *argv[15];
|
||||||
int argc;
|
int argc;
|
||||||
char *str2 = strdup(str); /* get_args modifies str2 */
|
char *str2 = strdup(str); /* get_args modifies str2 */
|
||||||
|
|
||||||
@@ -270,7 +279,7 @@ int process_response(char * str)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strcmp(argv[1], "select") == 0) {
|
if (strcmp(argv[1], "select") == 0) {
|
||||||
char *exec;
|
MenuEntry *exec;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
report(RPT_WARNING, "Server gave invalid response");
|
report(RPT_WARNING, "Server gave invalid response");
|
||||||
@@ -279,8 +288,8 @@ int process_response(char * str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find the id */
|
/* Find the id */
|
||||||
exec = menu_find_cmd_of_id(main_menu, argv[2]);
|
exec = menu_find_by_id(main_menu, atoi(argv[2]));
|
||||||
if (!exec) {
|
if (exec == NULL) {
|
||||||
report(RPT_WARNING, "Could not find the item id given by the server");
|
report(RPT_WARNING, "Could not find the item id given by the server");
|
||||||
free(str2);
|
free(str2);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -303,9 +312,11 @@ int process_response(char * str)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exec_command(char * command)
|
int exec_command(MenuEntry *cmd)
|
||||||
{
|
{
|
||||||
char *argv[4];
|
if ((cmd != NULL) && (menu_command(cmd) != NULL)) {
|
||||||
|
const char *command = menu_command(cmd);
|
||||||
|
const char *argv[4];
|
||||||
|
|
||||||
report(RPT_NOTICE, "Executing: %s", command);
|
report(RPT_NOTICE, "Executing: %s", command);
|
||||||
|
|
||||||
@@ -333,12 +344,14 @@ int exec_command(char * command)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main_loop ()
|
int main_loop ()
|
||||||
{
|
{
|
||||||
int num_bytes;
|
int num_bytes;
|
||||||
char buf[80];
|
char buf[100];
|
||||||
int w = 0;
|
int w = 0;
|
||||||
|
|
||||||
/* Continuously check if we get a menu event... */
|
/* Continuously check if we get a menu event... */
|
||||||
|
|||||||
@@ -17,41 +17,54 @@ ReportToSyslog=false
|
|||||||
# run in foreground [default: false; legal: true, false]
|
# run in foreground [default: false; legal: true, false]
|
||||||
Foreground=false
|
Foreground=false
|
||||||
|
|
||||||
# menu commands for the main menu
|
# display name for the main menu [default: lcdexec HOST]
|
||||||
# format: <text to be displayed>, <command to be executed>
|
#DisplayName=lcdexec
|
||||||
MenuCommand="You can say A, echo A"
|
|
||||||
MenuCommand="Or you can say B, echo B"
|
|
||||||
|
# main menu definition
|
||||||
# sub menu for the main menu
|
[MainMenu]
|
||||||
# format: <name to be displayed>, <menu name>
|
# the Entry=... lines (one for each menu entry) tell it is a menu definition
|
||||||
SubMenu="A menu, menu1"
|
Entry=CmdA
|
||||||
|
Entry=CmdB
|
||||||
# sub menu commands
|
Entry=MenuC
|
||||||
# option names must start with the name of a defined menu
|
|
||||||
# format: see menu commands
|
# definition of a command
|
||||||
menu1_MenuCommand="p, echo P"
|
[CmdA]
|
||||||
menu1_MenuCommand="q, echo Q"
|
# name to display in the menu instead of the section name
|
||||||
|
DisplayName="You can say A"
|
||||||
|
# the exec=... line tells that it is a command
|
||||||
|
Exec="echo a"
|
||||||
|
|
||||||
|
[CmdB]
|
||||||
|
DisplayName="Or you can say B"
|
||||||
|
Exec="echo b"
|
||||||
|
|
||||||
|
# definition of a menu
|
||||||
|
# a menu contains an Entry=... line for each menu entry
|
||||||
|
[MenuC]
|
||||||
|
DisplayName="A menu"
|
||||||
|
Entry=CmdP
|
||||||
|
Entry=CmdQ
|
||||||
|
|
||||||
|
[CmdP]
|
||||||
|
DisplayName=P
|
||||||
|
Exec="echo P"
|
||||||
|
|
||||||
|
[CmdQ]
|
||||||
|
DisplayName=Q
|
||||||
|
Exec="echo Q"
|
||||||
|
|
||||||
|
|
||||||
# Ideally lcdexec should be re-written so that menu definitions
|
|
||||||
# look somewhat like:
|
|
||||||
#
|
|
||||||
#[Menu]
|
|
||||||
#Type=Menu
|
|
||||||
#Entry=SubMenu1
|
|
||||||
#Entry=SubMenu2
|
|
||||||
#
|
|
||||||
#[SubMenu1]
|
|
||||||
#Type=Action
|
|
||||||
#Exec=/bin/program to execute with parameters
|
|
||||||
#
|
|
||||||
#[SubMenu2]
|
|
||||||
#Type=Action
|
|
||||||
#Exec=/bin/otherprogram with parameters
|
|
||||||
#
|
|
||||||
# Further Extensions:
|
# 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
|
# - use input for parameters e.g. IP-Adresses, Sliders
|
||||||
# - display result if a command on Screen
|
# 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
|
||||||
# - jump to other menus depending on the output/result of a command
|
# - jump to other menus depending on the output/result of a command
|
||||||
|
|
||||||
# EOF
|
# EOF
|
||||||
|
|||||||
+197
-169
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* lcdexec.c
|
* menu.c
|
||||||
* This file is part of lcdexec, an LCDproc client.
|
* This file is part of lcdexec, an LCDproc client.
|
||||||
*
|
*
|
||||||
* This file is released under the GNU General Public License. Refer to the
|
* This file is released under the GNU General Public License. Refer to the
|
||||||
* COPYING file distributed with this package.
|
* COPYING file distributed with this package.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002, Joris Robijn
|
* Copyright (c) 2002, Joris Robijn
|
||||||
*
|
* Copyright (c) 2006, Peter Marschall
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -20,203 +20,231 @@
|
|||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
|
||||||
Menu * menu_find_submenu(Menu * menu, char * submenu_id);
|
/* recursively read the menu hierarchy */
|
||||||
|
MenuEntry *menu_read(MenuEntry *parent, char *name)
|
||||||
Menu * menu_read(char * menu_id, char * progname)
|
|
||||||
{
|
{
|
||||||
char buf[100];
|
static int id = 0;
|
||||||
char * str;
|
|
||||||
char * parts[3];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
Menu * menu;
|
if (config_has_section(name)) {
|
||||||
|
MenuEntry *me = calloc(1, sizeof(MenuEntry));
|
||||||
|
|
||||||
report(RPT_DEBUG, "Reading menu: [%s]", menu_id);
|
if (me == NULL)
|
||||||
|
return NULL;
|
||||||
menu = malloc(sizeof(Menu));
|
// set common entries
|
||||||
menu->num_menucmds = 0;
|
me->id = id++;
|
||||||
menu->num_submenus = 0;
|
me->name = strdup(name);
|
||||||
|
if (me->name == NULL) {
|
||||||
/* Read the commands */
|
//menu_free(me);
|
||||||
str = "";
|
|
||||||
while ((str != NULL) && (menu->num_menucmds < MAX_NUM_MENUCMDS)) {
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf)-1, "%s%sMenuCommand",
|
|
||||||
menu_id, menu_id[0] ? "_" : "");
|
|
||||||
buf[sizeof(buf)-1] = 0;
|
|
||||||
str = config_get_string(progname, buf, menu->num_menucmds, NULL);
|
|
||||||
if (!str) {
|
|
||||||
; /* No more menucommands */
|
|
||||||
} else {
|
|
||||||
char * str2 = strdup(str);
|
|
||||||
if (split(str2, ',', parts, 2) == 2) {
|
|
||||||
menu->menucmd_name[menu->num_menucmds] = parts[0];
|
|
||||||
while (parts[1][0] == ' ') parts[1]++; /* Skip spaces */
|
|
||||||
menu->menucmd_exec[menu->num_menucmds] = parts[1];
|
|
||||||
report(RPT_DEBUG, "Found command: [%s] [%s]", parts[0], parts[1]);
|
|
||||||
} else {
|
|
||||||
report(RPT_ERR, "Cannot read MenuCommand: \"%s\"", str);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
menu->num_menucmds++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the submenus */
|
me->displayname = strdup(config_get_string(name, "DisplayName", 0, name));
|
||||||
str = "";
|
if (me->name == NULL) {
|
||||||
while (str && menu->num_submenus < MAX_NUM_SUBMENUS) {
|
//menu_free(me);
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf)-1, "%s%sSubmenu",
|
|
||||||
menu_id, menu_id[0]?"_":"");
|
|
||||||
buf[sizeof(buf)-1] = 0;
|
|
||||||
str = config_get_string(progname, buf, menu->num_submenus, NULL);
|
|
||||||
if (!str) {
|
|
||||||
; /* No more submenus */
|
|
||||||
} else {
|
|
||||||
char * str2 = strdup(str);
|
|
||||||
if (split(str2, ',', parts, 2) == 2) {
|
|
||||||
menu->submenu_name[menu->num_submenus] = parts[0];
|
|
||||||
while (parts[1][0] == ' ') parts[1]++; /* Skip spaces */
|
|
||||||
menu->submenu_id[menu->num_submenus] = parts[1];
|
|
||||||
report(RPT_DEBUG, "Found submenu: [%s] [%s]", parts[0], parts[1]);
|
|
||||||
} else {
|
|
||||||
report(RPT_ERR, "Cannot read Submenu: \"%s\"", str);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
menu->num_submenus++;
|
|
||||||
}
|
me->entries = NULL;
|
||||||
|
me->next = NULL;
|
||||||
|
me->command = NULL;
|
||||||
|
|
||||||
|
if (config_get_string(name, "Entry", 0, NULL) != NULL) {
|
||||||
|
MenuEntry **addr = &me->entries;
|
||||||
|
char *entryname;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
// it is a sub-menu
|
||||||
|
me->type = menu;
|
||||||
|
|
||||||
|
while ((entryname = config_get_string(name, "Entry", index++, NULL)) != NULL) {
|
||||||
|
MenuEntry *entry = menu_read(me, entryname);
|
||||||
|
|
||||||
|
if (entry == NULL) {
|
||||||
|
//menu_free(me);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And do the same for all submenus */
|
*addr = entry;
|
||||||
for (i = 0; i < menu->num_submenus; i++) {
|
addr = &entry->next;
|
||||||
menu->submenu[i] = menu_read (menu->submenu_id[i], progname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
int menu_send_to_LCDd(Menu * menu, char * id, int sock)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char buf[100];
|
|
||||||
|
|
||||||
for (i = 0; i < menu->num_menucmds; i++) {
|
|
||||||
snprintf(buf, sizeof(buf)-1,
|
|
||||||
"menu_add_item \"%s\" \"%s%s%d\" action \"%s\"\n",
|
|
||||||
id, id, id[0]?"_":"", i, menu->menucmd_name[i]);
|
|
||||||
buf[sizeof(buf)-1] = '\0';
|
|
||||||
if (sock_send_string(sock, buf) < 0)
|
|
||||||
return -1;
|
|
||||||
snprintf(buf, sizeof(buf)-1,
|
|
||||||
"menu_set_item \"%s\" \"%s%s%d\" -menu_result quit\n",
|
|
||||||
id, id, id[0]?"_":"", i);
|
|
||||||
buf[sizeof(buf)-1] = '\0';
|
|
||||||
if (sock_send_string(sock, buf) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for (i = 0; i < menu->num_submenus; i++) {
|
|
||||||
snprintf(buf, sizeof(buf)-1,
|
|
||||||
"menu_add_item \"%s\" \"%s\" menu \"%s\"\n",
|
|
||||||
id, menu->submenu_id[i], menu->submenu_name[i]);
|
|
||||||
buf[sizeof(buf)-1] = '\0';
|
|
||||||
if (sock_send_string(sock, buf) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
else if (config_get_string(name, "Exec", 0, NULL) != NULL) {
|
||||||
|
// it's a command to execute
|
||||||
|
me->type = exec;
|
||||||
|
|
||||||
/* And do the same for all submenus */
|
me->command = strdup(config_get_string(name, "Exec", 0, ""));
|
||||||
for (i = 0; i < menu->num_submenus; i++) {
|
if (me->command == NULL) {
|
||||||
if (menu_send_to_LCDd(menu->submenu[i], menu->submenu_id[i], sock) < 0)
|
//menu_free(me);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * menu_find_cmd_of_id(Menu * menu, char * id)
|
|
||||||
{
|
|
||||||
char * p;
|
|
||||||
char * submenu_id;
|
|
||||||
char * item_id;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Find the submenu_id part of the id */
|
|
||||||
submenu_id = strdup(id);
|
|
||||||
p = strrchr(submenu_id, '_');
|
|
||||||
|
|
||||||
/* Do we need to search the submenus ? */
|
|
||||||
if (p) {
|
|
||||||
/* There is a menu id prepended to the id */
|
|
||||||
*p = '\0'; /* Crop the submenu_id string */
|
|
||||||
item_id = p + 1;
|
|
||||||
menu = menu_find_submenu(menu, submenu_id);
|
|
||||||
if (!menu) {
|
|
||||||
report(RPT_WARNING, "Server reported an unknown id: %s", id);
|
|
||||||
free(submenu_id);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
item_id = id;
|
//menu_free(me);
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the number at the end of the id */
|
|
||||||
i = strtol(item_id, &p, 10);
|
|
||||||
if (*item_id != '\0' && *p == '\0'
|
|
||||||
&& i >= 0 && i < menu->num_menucmds) {
|
|
||||||
/* OK */
|
|
||||||
free(submenu_id);
|
|
||||||
return menu->menucmd_exec[i];
|
|
||||||
} else {
|
|
||||||
report(RPT_WARNING, "Server reported an unknown id: %s", id);
|
|
||||||
free(submenu_id);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return me;
|
||||||
|
|
||||||
Menu * menu_find_submenu(Menu * menu, char * submenu_id)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Menu * found;
|
|
||||||
|
|
||||||
/* Search for the submenu in this menu and all submenus */
|
|
||||||
for (i = 0; i < menu->num_submenus; i++) {
|
|
||||||
if (strcmp(menu->submenu_id[i], submenu_id) == 0)
|
|
||||||
return menu->submenu[i];
|
|
||||||
found = menu_find_submenu(menu->submenu[i], submenu_id);
|
|
||||||
if (found)
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int split(char * str, char delim, char * parts[], int maxparts)
|
|
||||||
/* Splits a string into parts, to which pointers will be returned in &parts.
|
/* create LCDproc commands for the menu entry hierarchy and send it to the server */
|
||||||
* The return value is the number of parts.
|
int menu_sock_send(MenuEntry *me, MenuEntry *parent, int sock)
|
||||||
* maxparts is the maximum number of parts returned. If more parts exist
|
|
||||||
* they are (unsplit) in the last part.
|
|
||||||
* The parts are split at the character delim.
|
|
||||||
* No new space will be allocated, the string str will be mutated !
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
char * p1 = str;
|
if ((me != NULL) && (sock > 0)) {
|
||||||
char * p2;
|
char parent_id[12];
|
||||||
int part_nr = 0;
|
|
||||||
|
|
||||||
/* Find the delim char to end the current part */
|
if (parent == NULL)
|
||||||
while ((part_nr < maxparts - 1) && ((p2 = strchr(p1, delim)) != NULL)) {
|
strcpy(parent_id, "");
|
||||||
|
else
|
||||||
|
sprintf(parent_id, "%d", parent->id);
|
||||||
|
|
||||||
/* subsequent parts... */
|
switch (me->type) {
|
||||||
*p2 = '\0';
|
MenuEntry *entry;
|
||||||
parts[part_nr] = p1;
|
|
||||||
|
|
||||||
p1 = p2 + 1; /* Just after the delim char */
|
case menu:
|
||||||
part_nr++;
|
// don't create a separate entry fro the main menu
|
||||||
|
if (parent != NULL) {
|
||||||
|
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" menu \"%s\"\n",
|
||||||
|
parent_id, me->id, me->displayname) < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
/* and the last part... */
|
|
||||||
parts[part_nr] = p1;
|
|
||||||
part_nr++;
|
|
||||||
|
|
||||||
return part_nr;
|
// recursively do it for the menu's sub-menus
|
||||||
|
for (entry = me->entries; entry != NULL; entry = entry->next) {
|
||||||
|
if (menu_sock_send(entry, (parent != NULL) ? me : NULL, sock) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case exec:
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
case unknown:
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* find menu entry by its id */
|
||||||
|
MenuEntry *menu_find_by_id(MenuEntry *me, int id)
|
||||||
|
{
|
||||||
|
if (me != NULL) {
|
||||||
|
if (me->id == id)
|
||||||
|
return me;
|
||||||
|
|
||||||
|
if (me->type == menu) {
|
||||||
|
MenuEntry *entry;
|
||||||
|
|
||||||
|
for (entry = me->entries; entry != NULL; entry = entry->next) {
|
||||||
|
MenuEntry *result = menu_find_by_id(entry, id);
|
||||||
|
|
||||||
|
if (result != NULL)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* return command of a menu entry */
|
||||||
|
const char *menu_command(MenuEntry *me)
|
||||||
|
{
|
||||||
|
if ((me != NULL) && (me->type == exec))
|
||||||
|
return me->command;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* free menu entry hierarchy */
|
||||||
|
void menu_free(MenuEntry *me)
|
||||||
|
{
|
||||||
|
if (me != NULL) {
|
||||||
|
switch (me->type) {
|
||||||
|
MenuEntry *entry;
|
||||||
|
|
||||||
|
case menu:
|
||||||
|
for (entry = me->entries; entry != NULL; ) {
|
||||||
|
MenuEntry *old = entry;
|
||||||
|
|
||||||
|
entry = entry->next;
|
||||||
|
old->next = NULL;
|
||||||
|
menu_free(old);
|
||||||
|
}
|
||||||
|
me->entries = NULL;
|
||||||
|
break;
|
||||||
|
case exec:
|
||||||
|
if (me->command != NULL)
|
||||||
|
free(me->command);
|
||||||
|
me->command = NULL;
|
||||||
|
break;
|
||||||
|
case unknown:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me->name != NULL)
|
||||||
|
free(me->name);
|
||||||
|
me->name = NULL;
|
||||||
|
|
||||||
|
if (me->displayname != NULL)
|
||||||
|
free(me->displayname);
|
||||||
|
me->displayname = NULL;
|
||||||
|
|
||||||
|
me->type = unknown;
|
||||||
|
|
||||||
|
free(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
/* dump menu entry hierarchy to screen */
|
||||||
|
void menu_dump(MenuEntry *me)
|
||||||
|
{
|
||||||
|
if (me != NULL) {
|
||||||
|
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)
|
||||||
|
report(RPT_DEBUG, "Entry=%s", entry->name);
|
||||||
|
break;
|
||||||
|
case exec:
|
||||||
|
report(RPT_DEBUG, "Exec=\"%s\"", me->command);
|
||||||
|
break;
|
||||||
|
case unknown:
|
||||||
|
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
|
||||||
|
|
||||||
|
/* EOF */
|
||||||
|
|||||||
+26
-15
@@ -18,21 +18,32 @@
|
|||||||
#include "shared/configfile.h"
|
#include "shared/configfile.h"
|
||||||
#include "shared/sockets.h"
|
#include "shared/sockets.h"
|
||||||
|
|
||||||
#define MAX_NUM_MENUCMDS 40
|
|
||||||
#define MAX_NUM_SUBMENUS 20
|
|
||||||
|
|
||||||
typedef struct Menu {
|
typedef enum {
|
||||||
char * menucmd_name[MAX_NUM_MENUCMDS];
|
unknown = 0,
|
||||||
char * menucmd_exec[MAX_NUM_MENUCMDS];
|
menu = 1,
|
||||||
int num_menucmds;
|
exec = 2,
|
||||||
char * submenu_name[MAX_NUM_SUBMENUS];
|
} MenuType;
|
||||||
char * submenu_id[MAX_NUM_SUBMENUS];
|
|
||||||
struct Menu * submenu[MAX_NUM_SUBMENUS];
|
|
||||||
int num_submenus;
|
|
||||||
} Menu;
|
|
||||||
|
|
||||||
Menu * menu_read (char * menu_id, char * progname);
|
|
||||||
int menu_send_to_LCDd( Menu * menu, char * id, int sock );
|
|
||||||
char * menu_find_cmd_of_id( Menu * menu, char * id );
|
|
||||||
|
|
||||||
int split( char * str, char delim, char * parts[], int maxparts );
|
typedef struct menu_entry {
|
||||||
|
char *name;
|
||||||
|
char *displayname;
|
||||||
|
int id;
|
||||||
|
MenuType type;
|
||||||
|
|
||||||
|
// variables necessary for type menu
|
||||||
|
struct menu_entry *entries;
|
||||||
|
struct menu_entry *next;
|
||||||
|
|
||||||
|
// variables necessary for type exec
|
||||||
|
char *command;
|
||||||
|
} MenuEntry;
|
||||||
|
|
||||||
|
|
||||||
|
MenuEntry *menu_read(MenuEntry *parent, char *name);
|
||||||
|
int menu_sock_send(MenuEntry *me, MenuEntry *parent, int sock);
|
||||||
|
MenuEntry *menu_find_by_id(MenuEntry *me, int id);
|
||||||
|
const char *menu_command(MenuEntry *me);
|
||||||
|
void menu_free(MenuEntry *me);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user