emview_config.c from EmStar at Krugle
Show emview_config.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <emview/emview.h>
#include "emview_i.h"
#include <libmisc/misc.h>
#include <emrun/emrun.h>
struct config_mod_state {
emview_module_t *mod;
emview_device_t *dev;
};
static struct config_mod_state state = {};
#define CONFIG_INIT 0
#define CONFIG_ASSIGN 1
#define CONFIG_ENABLE 2
#define CONFIG_DONE 3
/*
* config helper API
*/
static
int emview_config_parse_enable_string(char *val, int *enable_me)
{
if (val == NULL) goto fail;
if (strcmp(val, "none") == 0)
*enable_me = 0;
else if (strcmp(val, "data") == 0)
*enable_me = EMVIEW_ENABLE;
else if (strcmp(val, "links") == 0)
*enable_me = EMVIEW_ENABLE | EMVIEW_ENABLE_LINK;
else if (strcmp(val, "all") == 0)
*enable_me = EMVIEW_ENABLE_ALL;
else
goto fail;
return 0;
fail:
elog(LOG_WARNING, "Unexpected value for enable: %s", val);
return -1;
}
emview_color_t emview_parse_color(char *color_str)
{
if (color_str == NULL) goto fail;
if (color_str[0] == 0) return EMVIEW_COLOR_NONE;
if (strcmp(color_str, "none") == 0) return EMVIEW_COLOR_NONE;
if (strcmp(color_str, "black") == 0) return EMVIEW_COLOR_BLACK;
if (strcmp(color_str, "red") == 0) return EMVIEW_COLOR_RED;
if (strcmp(color_str, "blue") == 0) return EMVIEW_COLOR_BLUE;
if (strcmp(color_str, "green") == 0) return EMVIEW_COLOR_GREEN;
if (strcmp(color_str, "yellow") == 0) return EMVIEW_COLOR_YELLOW;
if (strcmp(color_str, "magenta") == 0) return EMVIEW_COLOR_MAGENTA;
if (strcmp(color_str, "cyan") == 0) return EMVIEW_COLOR_CYAN;
if (strcmp(color_str, "burgundy") == 0) return EMVIEW_COLOR_BURGANDY;
if (strcmp(color_str, "white") == 0) return EMVIEW_COLOR_WHITE;
if (isdigit(color_str[0]))
return atoi(color_str);
fail:
elog(LOG_WARNING, "Unrecognized color string %s", color_str);
return EMVIEW_COLOR_NONE;
}
char *emview_unparse_color(emview_color_t color)
{
switch (color) {
case EMVIEW_COLOR_NONE: return "none";
case EMVIEW_COLOR_BLACK: return "black";
case EMVIEW_COLOR_RED: return "red";
case EMVIEW_COLOR_BLUE: return "blue";
case EMVIEW_COLOR_GREEN: return "green";
case EMVIEW_COLOR_YELLOW: return "yellow";
case EMVIEW_COLOR_MAGENTA: return "magenta";
case EMVIEW_COLOR_CYAN: return "cyan";
case EMVIEW_COLOR_BURGANDY: return "burgandy";
case EMVIEW_COLOR_WHITE: return "white";
default:
return "<unknown>";
}
}
char *emview_unparse_component_field(int field)
{
static char buf[50];
switch (field) {
case 0: return "all";
case EMVIEW_BOX_ABOVE: return "above";
case EMVIEW_BOX_INSIDE: return "inside";
case EMVIEW_BOX_COLOR: return "color";
case EMVIEW_BOX_BORDER: return "border";
case EMVIEW_BOX_FLAG1: return "flag1";
case EMVIEW_BOX_FLAG2: return "flag2";
case EMVIEW_BOX_FLAG3: return "flag3";
case EMVIEW_NODE_BELOW: return "below";
default: {
int i = field - EMVIEW_NODE_FIRST_COLOR_FLAG;
if ((i < 0) || (i >= EMVIEW_MAX_COLORS-2)) {
return "<unknown>";
}
sprintf(buf, "%s-flag", emview_unparse_color(i+2));
return buf;
}
}
}
char *emview_unparse_source_type(emview_source_type_t type)
{
switch (type) {
case EMVIEW_SOURCE_SIMPLE: return "data";
case EMVIEW_SOURCE_LINK : return "link";
case EMVIEW_SOURCE_LAYOUT: return "layout";
default:
return "<unknown>";
}
}
char *emview_config_unparse_enable(int enable)
{
if (enable & EMVIEW_ENABLE_LINK_NOTE) return "all";
if (enable & EMVIEW_ENABLE_LINK) return "links";
if (enable) return "data";
return "none";
}
static
void emview_config_parse_enable(parser_state_t *ps, int id, int mode)
{
/* process custom enable specs */
int enable_bit = 1;
do {
/* options? */
if (strcmp(ps->key, "option") == 0) {
if (mode == CONFIG_ENABLE) {
if (ps->value)
emview_option_class_set_enable(id, ps->value, enable_bit);
else
elog(LOG_WARNING, "enable_option, no name supplied");
}
continue;
}
/* enable? */
if (strcmp(ps->key, "enable") == 0) {
if (ps->value == NULL)
enable_bit = 1;
else {
if (ps->value[0] == '1') enable_bit = 1;
else if (ps->value[0] == '0') enable_bit = 0;
else {
elog(LOG_WARNING, "Bad argument to enable key: %s", ps->value);
}
}
continue;
}
elog(LOG_WARNING, "Unexpected key %s", ps->key);
continue;
} while (misc_parse_next_kvp(ps) >= 0);
}
static
void emview_config_parse_options(parser_state_t *ps, int id, int mode)
{
/* process custom options specs */
/* this is the name of this custom option */
char *option_name = strdup(ps->value);
while (misc_parse_next_kvp(ps) >= 0) {
int link=0;
if (strcmp(ps->key, "assign") == 0) {}
else if (strcmp(ps->key, "linkscheme") == 0) { link=1; }
else {
elog(LOG_WARNING, "Unexpected key %s", ps->key);
continue;
}
/* assign statement */
if (mode == CONFIG_ASSIGN) {
parser_state_t *ps2 = misc_parse_init(ps->value, MISC_PARSE_COMMA_SCHEME);
char *keys[4] = { "component", "field", "source", "enable_type" };
char *args[4];
int enable_me;
if (misc_parse_n_args(ps2, keys, args, 4) < 0) {
elog(LOG_WARNING, "Wrong number of arguments to assign(%s)", ps->value);
goto cleanup;
}
if (emview_config_parse_enable_string(args[3], &enable_me) < 0)
goto cleanup;
if (link) {
/* $$$ parse color field */
if (emview_assign_link_source(id, args[0], atoi(args[1]), args[2], option_name, enable_me) < 0) {
elog(LOG_WARNING, "LinkAssign(%d,%s,%d,%s,%s) failed", id, args[0], atoi(args[1]), args[2],
args[3]);
elog(LOG_DEBUG(10), "'%s'", ps->value);
}
else
elog(LOG_DEBUG(0), "Assigned link (%s)", ps->value);
}
else {
/* $$$ parse field field */
if (emview_assign_source(id, args[0], atoi(args[1]), args[2], option_name, enable_me) < 0) {
elog(LOG_WARNING, "Assign(%d,%s,%d,%s,%s) failed", id, args[0], atoi(args[1]), args[2],
args[3]);
elog(LOG_DEBUG(10), "'%s'", ps->value);
}
else
elog(LOG_DEBUG(0), "Assigned (%s)", ps->value);
}
cleanup:
misc_free_n_args(args, 4);
misc_parse_cleanup(ps2);
}
continue;
}
free(option_name);
}
static
void emview_config_parse_module(parser_state_t *ps, int id, int mode)
{
char *dev = "_";
/* search for matching module */
emview_module_t *mod = emvew_module_lookup(ps->value);
/* not found ? */
if (mod == NULL) {
elog(LOG_WARNING, "Unrecognized module '%s'.. ignoring", ps->value);
return;
}
/* this module ? */
if (mod == state.mod) {
elog(LOG_WARNING, "Not allowed to modify '%s'.. ignoring", ps->value);
return;
}
/* next parse dev.. */
while (misc_parse_next_kvp(ps) >= 0) {
if (strcmp(ps->key, "dev") == 0) {
dev = ps->value;
break;
}
elog(LOG_WARNING, "Unexpected key: %s, second key MUST be 'dev='", ps->key);
goto skip_rest;
}
{
int created=0;
emview_module_inst_t *inst = NULL;
/* separate the nickname and the device */
char *ptr;
char *device_path = NULL;
if ((ptr = strpbrk(dev, ","))) {
*ptr = 0;
device_path = ptr+1;
}
/* look up / create a new instance */
inst = emview_mod_inst_lookup_or_create(mod, dev, &created);
if (mode == CONFIG_INIT) {
/* initially config the module.. */
if (mod && mod->opts.config_new_instance) {
if (created) {
mod->opts.config_new_instance(mod, inst, device_path, id);
elog(LOG_DEBUG(0), "config'd device %s,%s", dev, device_path);
}
}
else
elog(LOG_WARNING, "Ignoring 'dev' specifier '%s'", dev);
goto skip_rest;
}
if (mode == CONFIG_ASSIGN) {
/* now do the option configuration */
if (mod && mod->opts.config_assign) {
elog(LOG_DEBUG(0), "config-ing assignments for device %s", dev);
mod->opts.config_assign(mod, inst, id, ps);
}
goto skip_rest;
}
if (mode == CONFIG_ENABLE) {
/* now do the option configuration */
if (mod && mod->opts.config_opts) {
elog(LOG_DEBUG(0), "configing options for device %s", dev);
mod->opts.config_opts(mod, inst, id, ps);
}
goto skip_rest;
}
elog(LOG_ERR, "invalid mode ??? ");
goto skip_rest;
}
skip_rest:
return;
}
/*
* parse and process the visualizer config blocks
*/
void emview_config_parse(struct config_mod_state *state, node_t *n, parser_state_t *ps, int mode)
{
/* parse the new config block */
while (misc_parse_next_kvp(ps) >= 0) {
parser_state_t *ps2 = misc_parse_init(ps->key, MISC_PARSE_COLON_SCHEME);
elog(LOG_DEBUG(10), "got kvp='%s=%s'", ps->key, ps->value);
/* re-parse for module initializer */
if (misc_parse_next_kvp(ps2) >= 0) {
/* module? */
if (strcmp(ps2->key, "module") == 0) {
emview_config_parse_module(ps2, n->id, mode);
}
/* options? */
else if (strcmp(ps2->key, "def_option") == 0) {
emview_config_parse_options(ps2, n->id, mode);
}
/* enable? */
else if (strcmp(ps2->key, "enable") == 0) {
emview_config_parse_enable(ps2, n->id, mode);
}
else
elog(LOG_WARNING, "Unexpected key: %s", ps2->key);
}
misc_parse_cleanup(ps2);
}
misc_parse_reset(ps);
}
int emview_config_global_now(void *data, int interval, g_event_t *ev)
{
node_t *n;
emview_dev_node_t *dn;
int stage;
/* set marks on each node */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n)) {
/* mark existing components */
emview_component_list_mark(&(n->display.components));
/* unmark the node component */
emview_component_register(g_quark_from_string(EMVIEW_NODE_COMPONENT), n->id, EMVIEW_COMP_TYPE_NODE);
}
/* staged parse for each node */
for (stage = CONFIG_INIT; stage < CONFIG_DONE; stage++) {
for (dn = emview_dn_top(state.dev); dn; dn = emview_dn_next(dn)) {
n = emview_node_lookup_nocreate(emview_dn_get_node_id(dn));
if (n && dn->data) {
/* set up the parse */
parser_state_t *ps = misc_parse_init(dn->data, MISC_PARSE_LF_SCHEME);
/* parse all the component declarations etc */
emview_config_parse(&state, n, ps, stage);
/* free it */
misc_parse_cleanup(ps);
}
}
}
/* prune marked components */
for (n = emview_node_top(&(_core.node_list)); n; n = emview_node_next(n)) {
emview_component_list_prune_marked(&(n->display.components));
}
/* relink */
emview_node_global_relink_display();
/* rebuild menu if needed */
emview_build_options_menu();
/* OK, done! */
return TIMER_DONE;
}
void emview_config_schedule_reconfig()
{
static g_event_t *timer = NULL;
if (timer == NULL)
g_timer_add(1000, emview_config_global_now, NULL, NULL, &timer);
}
int config_handle_data(emview_device_t *dev, emproxy_reply_hdr_t *reply,
emview_dev_node_t *node)
{
node_t *n = emview_node_lookup_nocreate(emview_dn_get_node_id(node));
elog(LOG_DEBUG(1), "Got emview config data for node %d", emview_dn_get_node_id(node));
elog(LOG_DEBUG(1), "got '%s'", reply->data);
/* check for node present */
if (n == NULL) {
elog(LOG_ERR, "Null node in config handler");
goto out;
}
/* is this new config different? */
if (node->data &&
(strncmp(reply->data, node->data, reply->data_length) == 0)) {
/* no change.. */
goto out;
}
/* save.. */
if (node->data) free(node->data);
node->data = malloc(reply->data_length+1);
memmove(node->data, reply->data, reply->data_length);
((char*)node->data)[reply->data_length]=0;
/* OK, now do a global reconfiguration */
emview_config_schedule_reconfig();
out:
return 0;
}
int config_node_timeout(emview_device_t *dev, emview_dev_node_t *node)
{
elog(LOG_DEBUG(10), "Node %d timed out!", emview_dn_get_node_id(node));
return 0;
}
void emview_config_test(node_t *n, buf_t *buf)
{
emproxy_reply_hdr_t *reply = malloc(sizeof(emproxy_reply_hdr_t) + buf->len);
memset(reply, 0, sizeof(emproxy_reply_hdr_t));
memmove(reply->data, buf->buf, buf->len);
reply->data_length = buf->len;
config_handle_data(state.dev, reply, emview_dev_node_lookup(state.dev, n->id));
}
/*
* "main" function for the config module
*/
int config_main(int *argc, char **argv)
{
emview_module_opts_t mod_opts = {
name: "__Config",
private_data: &state,
};
/* register with emview and get context structure */
state.mod = emview_register(&mod_opts);
/* add new device */
{
char buf[128];
/* register the device */
emview_device_opts_t opts = {
name: "__config",
private_data: &state,
proxy_string: buf,
data_handler: config_handle_data,
node_timeout: config_node_timeout,
parent: state.mod,
always_active: 1
};
sprintf(buf, "dev=%s:ascii", EMRUN_EMVIEW_CONFIG_DEVNAME);
/* register device */
state.dev = emview_register_device(&opts);
}
return 0;
}
/*
* Options tree
*/
typedef struct {
char *option_name;
char *usage;
char *description;
int select_state;
char **mutex_options;
GtkWidget *menu;
emview_module_t *parent;
} option_state_t;
/*
* Options menu support
*/
static int b0rken_gtk = 0;
static
int emview_option_config(void *data)
{
option_state_t *option = (option_state_t *)data;
if (!b0rken_gtk) {
/* this will set the state and call the function to set the check */
emview_option_class_set_enable(0, option->option_name, !option->select_state);
emview_reconfig();
}
return TRUE;
}
static
void emview_option_set_check(option_state_t *opt)
{
if (opt->menu) {
b0rken_gtk = 1;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(opt->menu), opt->select_state);
b0rken_gtk = 0;
}
}
/*
* globals to compute flat tree... grr..
*/
static int flat_count = 0;
static option_state_t **flat = NULL;
static
int emview_flatten(void *key, void *value, void *data)
{
flat[flat_count] = (option_state_t *)value;
flat_count++;
return 0;
}
void emview_recurse_rebuild(int *index, char *prefix, GtkWidget *parent_menu)
{
int prefix_len = strlen(prefix);
while (*index < flat_count) {
char *next_slash;
elog(LOG_DEBUG(1), "processing item '%s', prefix '%s'", flat[*index]->option_name, prefix);
/* is prefix NOT a prefix of the current string? */
if (strncmp(prefix, flat[*index]->option_name, prefix_len)) {
/* pop! */
return;
}
/* OK, prefix is a prefix. */
/* is there a '/' after prefix? */
next_slash = strpbrk(flat[*index]->option_name + prefix_len, "/");
if (next_slash) {
char *new_prefix = strdup(flat[*index]->option_name);
GtkWidget *submenu;
new_prefix[next_slash - flat[*index]->option_name + 1] = 0;
/* OK, create a submenu */
submenu = emview_sub_menu(parent_menu, new_prefix + prefix_len);
/* now start filling it. */
emview_recurse_rebuild(index, new_prefix, submenu);
/* free the prefix */
free(new_prefix);
/* retry this one */
continue;
}
/* no slash.. just add a check item */
else {
elog(LOG_DEBUG(1), "appending new menu item '%s'", flat[*index]->option_name + prefix_len);
flat[*index]->menu =
emview_menu_item
(parent_menu, gtk_check_menu_item_new_with_label(flat[*index]->option_name + prefix_len),
emview_option_config, flat[*index]);
emview_option_set_check(flat[*index]);
}
/* next.. */
(*index)++;
}
}
void emview_build_options_menu()
{
if (_core.config.rebuild_menu) {
int index;
if (!_core.nogui) {
/* destroy old */
if (_core.config.menu) {
gtk_container_remove(GTK_CONTAINER(_core.gui.menu_bar), _core.config.menu_item);
gtk_widget_destroy(_core.config.menu_item);
}
/* create new */
_core.config.menu = emview_toplevel_menu("Options", &(_core.config.menu_item));
}
/* flatten the tree -- glib types totally suck :( */
flat_count = 0;
flat = malloc(sizeof(option_state_t *)*(g_tree_nnodes(_core.config.option_tree)));
g_tree_foreach(_core.config.option_tree, emview_flatten, NULL);
/*
* OK, now we've got a flat tree, that can be iterated
* more conveniently!
*/
/* add each menu in turn */
if (!_core.nogui) {
index = 0;
emview_recurse_rebuild(&index, "", _core.config.menu);
}
/* free! */
free(flat);
flat = NULL;
flat_count = 0;
}
_core.config.rebuild_menu = 0;
}
/*
* Options tree functions
*/
static
int option_key_compare(const void *x, const void *y)
{
return strcmp((const char*)x, (const char*)y);
}
static
option_state_t *emview_option_tree_lookup(char *option_name)
{
return (option_state_t *) g_tree_lookup(_core.config.option_tree, option_name);
}
int emview_option_tree_update(char *option_name, int enable_bit)
{
option_state_t *opt = emview_option_tree_lookup(option_name);
if (opt == NULL) {
elog(LOG_WARNING, "Trying to update option tree for %s, not in tree!", option_name);
return -1;
}
opt->select_state = enable_bit;
emview_option_set_check(opt);
if (enable_bit) {
/* $$$$ add support for mutex options.. unset all mutex entries */
}
return 0;
}
void emview_document_option_class(emview_module_t *module,
char *option, char *usage, char *description,
char **mutex_options)
{
option_state_t *found;
/* stupid defaults */
if (usage == NULL)
usage = "<no usage info>";
if (description == NULL)
description = "<no description>";
/* create tree if needed */
if (_core.config.option_tree == NULL) {
_core.config.option_tree = g_tree_new(option_key_compare);
}
/* lookup this option in the tree */
if ((found = emview_option_tree_lookup(option))) {
/* already present */
if ((found->usage && strcmp(found->usage, usage)) ||
(found->description && strcmp(found->description, description))) {
elog(LOG_WARNING, "Option document call differs from existing option %s [%p]",
option, found);
elog(LOG_WARNING, "%s,%s/%s,%s", usage, found->usage, description, found->description);
}
/* $$$$ add same check for mutex list. */
return;
}
/* otherwise, add us to the options tree */
{
/* $$$$ add support for mutex options.. copy null-term array of strings */
option_state_t *opt = g_new0(option_state_t, 1);
opt->option_name = strdup(option);
opt->usage = strdup(usage);
opt->description = strdup(description);
opt->parent = module;
_core.config.rebuild_menu = 1;
g_tree_insert(_core.config.option_tree, opt->option_name, opt);
}
}
static buf_t *__buf = NULL;
static node_t *__node = NULL;
static
int emview_cd_aux(void *key, void *value, void *data)
{
option_state_t *opt = (option_state_t *)value;
emview_module_t *mod = (emview_module_t *)data;
if (opt->parent == mod) {
GQuark option_q = g_quark_from_string(opt->option_name);
bufprintf(__buf, "\n Option '%s': Usage: %s\n", opt->option_name,
opt->usage ? opt->usage : "");
bufprintf(__buf, " %s\n", opt->description);
/* $$$ dump mutex */
/* search through for component slots */
emview_slots_list_status_printable(&(__node->display.slots), __buf, option_q);
}
return 0;
}
void emview_config_dump(emview_module_t *module, node_t *n, buf_t *buf)
{
__buf = buf;
__node = n;
bufprintf(buf, "Module %s: %s\n", module->opts.name,
module->opts.description);
g_tree_foreach(_core.config.option_tree, emview_cd_aux, module);
bufprintf(buf, "\n\n");
}
See more files for this project here