reworked menu definition in config file to be more elegant and more flexible

This commit is contained in:
marschap
2006-04-29 19:44:11 +00:00
parent 5963852e6c
commit c52083f2a5
4 changed files with 362 additions and 297 deletions
+215 -187
View File
@@ -1,12 +1,12 @@
/*
* lcdexec.c
* menu.c
* This file is part of lcdexec, an LCDproc client.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2002, Joris Robijn
*
* Copyright (c) 2006, Peter Marschall
*/
#include <stdio.h>
@@ -20,203 +20,231 @@
#include "menu.h"
Menu * menu_find_submenu(Menu * menu, char * submenu_id);
Menu * menu_read(char * menu_id, char * progname)
/* recursively read the menu hierarchy */
MenuEntry *menu_read(MenuEntry *parent, char *name)
{
char buf[100];
char * str;
char * parts[3];
int i;
static int id = 0;
Menu * menu;
report(RPT_DEBUG, "Reading menu: [%s]", menu_id);
menu = malloc(sizeof(Menu));
menu->num_menucmds = 0;
menu->num_submenus = 0;
/* Read the commands */
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;
}
menu->num_menucmds++;
}
}
/* Read the submenus */
str = "";
while (str && menu->num_submenus < MAX_NUM_SUBMENUS) {
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;
}
menu->num_submenus++;
}
}
/* And do the same for all submenus */
for (i = 0; i < menu->num_submenus; i++) {
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;
}
/* And do the same for all submenus */
for (i = 0; i < menu->num_submenus; i++) {
if (menu_send_to_LCDd(menu->submenu[i], menu->submenu_id[i], sock) < 0)
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);
if (config_has_section(name)) {
MenuEntry *me = calloc(1, sizeof(MenuEntry));
if (me == NULL)
return NULL;
// set common entries
me->id = id++;
me->name = strdup(name);
if (me->name == NULL) {
//menu_free(me);
return NULL;
}
me->displayname = strdup(config_get_string(name, "DisplayName", 0, name));
if (me->name == NULL) {
//menu_free(me);
return NULL;
}
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;
}
*addr = entry;
addr = &entry->next;
}
}
else if (config_get_string(name, "Exec", 0, NULL) != NULL) {
// it's a command to execute
me->type = exec;
me->command = strdup(config_get_string(name, "Exec", 0, ""));
if (me->command == NULL) {
//menu_free(me);
return NULL;
}
}
}
else {
item_id = id;
}
else {
//menu_free(me);
return NULL;
}
/* 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;
}
}
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 me;
}
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.
* The return value is the number of parts.
* 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 !
*/
/* create LCDproc commands for the menu entry hierarchy and send it to the server */
int menu_sock_send(MenuEntry *me, MenuEntry *parent, int sock)
{
char * p1 = str;
char * p2;
int part_nr = 0;
if ((me != NULL) && (sock > 0)) {
char parent_id[12];
/* Find the delim char to end the current part */
while ((part_nr < maxparts - 1) && ((p2 = strchr(p1, delim)) != NULL)) {
if (parent == NULL)
strcpy(parent_id, "");
else
sprintf(parent_id, "%d", parent->id);
/* subsequent parts... */
*p2 = '\0';
parts[part_nr] = p1;
switch (me->type) {
MenuEntry *entry;
p1 = p2 + 1; /* Just after the delim char */
part_nr++;
}
/* and the last part... */
parts[part_nr] = p1;
part_nr++;
return part_nr;
case menu:
// 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;
}
// 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 */