You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
lighttpd2/src/actions.c

189 lines
4.3 KiB

#include "log.h"
#include "actions.h"
#include "condition.h"
struct action_stack_element;
typedef struct action_stack_element action_stack_element;
struct action_stack_element {
action_list *list;
guint pos;
};
action *action_new_setting(server *srv, GString *name, option *value) {
option_set setting;
if (!parse_option(srv, name->str, value, &setting)) {
return NULL;
}
action *a = g_slice_new(action);
a->refcount = 1;
a->type = ACTION_TSETTING;
a->value.setting = setting;
return a;
}
action *action_new_function(server *srv, const char *name, option *value) {
action *a;
action_func af;
server_action *sa;
if (NULL == (sa = (server_action*) g_hash_table_lookup(srv->actions, name))) {
ERROR(srv, "Action '%s' doesn't exist", name);
return NULL;
}
if (!sa->create_action(srv, sa->p ? sa->p->data : NULL, value, &af)) {
ERROR(srv, "Action '%s' creation failed", name);
return NULL;
}
a = g_slice_new(action);
a->refcount = 1;
a->type = ACTION_TFUNCTION;
a->value.function = af;
return a;
}
void action_release(action *a) {
assert(a->refcount > 0);
if (!(--a->refcount)) {
switch (a->type) {
case ACTION_TSETTING:
/* TODO */
break;
case ACTION_TFUNCTION:
/* TODO */
break;
case ACTION_TCONDITION:
condition_release(a->value.condition.cond);
action_list_release(a->value.condition.target);
break;
}
g_slice_free(action, a);
}
}
void action_acquire(action *a) {
assert(a->refcount > 0);
a->refcount++;
}
action_list *action_list_new() {
action_list *al;
al = g_slice_new(action_list);
al->refcount = 1;
al->actions = g_array_new(FALSE, TRUE, sizeof(action *));
return al;
}
void action_list_release(action_list *al) {
assert(al->refcount > 0);
if (!(--al->refcount)) {
guint i;
for (i = al->actions->len; i-- > 0; ) {
action_release(g_array_index(al->actions, action*, i));
}
g_array_free(al->actions, TRUE);
g_slice_free(action_list, al);
}
}
void action_list_acquire(action_list *al) {
assert(al->refcount > 0);
al->refcount++;
}
void action_stack_element_release(action_stack_element *ase) {
if (!ase || !ase->list) return;
action_list_release(ase->list);
ase->list = NULL;
}
void action_stack_init(action_stack *as) {
as->stack = g_array_sized_new(FALSE, TRUE, sizeof(action_stack_element), 15);
}
void action_stack_reset(action_stack *as) {
guint i;
for (i = as->stack->len; i-- > 0; ) {
action_stack_element_release(&g_array_index(as->stack, action_stack_element, i));
}
g_array_set_size(as->stack, 0);
}
void action_stack_clear(action_stack *as) {
guint i;
for (i = as->stack->len; i-- > 0; ) {
action_stack_element_release(&g_array_index(as->stack, action_stack_element, i));
}
g_array_free(as->stack, TRUE);
}
/** handle sublist now, remember current position (stack) */
void action_enter(connection *con, action_list *al) {
action_list_acquire(al);
action_stack_element ase = { al, 0 };
g_array_append_val(con->action_stack.stack, ase);
}
static action_stack_element *action_stack_top(action_stack* as) {
return as->stack->len > 0 ? &g_array_index(as->stack, action_stack_element, as->stack->len - 1) : NULL;
}
static void action_stack_pop(action_stack *as) {
action_stack_element_release(&g_array_index(as->stack, action_stack_element, as->stack->len - 1));
g_array_set_size(as->stack, as->stack->len - 1);
}
static action* action_stack_element_next(action_stack_element *ase) {
action_list *al = ase->list;
return ase->pos < al->actions->len ? g_array_index(al->actions, action*, ase->pos++) : NULL;
}
action_result action_execute(server *srv, connection *con) {
action *a;
action_stack *as = &con->action_stack;
action_stack_element *ase;
action_result res;
while (NULL != (ase = action_stack_top(as))) {
a = action_stack_element_next(ase);
if (!a) {
action_stack_pop(as);
continue;
}
switch (a->type) {
case ACTION_TSETTING:
/* TODO */
break;
case ACTION_TFUNCTION:
res = a->value.function.func(srv, con, a->value.function.param);
switch (res) {
case ACTION_GO_ON:
break;
case ACTION_FINISHED:
case ACTION_ERROR:
action_stack_clear(as);
return res;
case ACTION_WAIT_FOR_EVENT:
return ACTION_WAIT_FOR_EVENT;
}
break;
case ACTION_TCONDITION:
if (condition_check(srv, con, a->value.condition.cond)) {
action_enter(con, a->value.condition.target);
}
break;
}
}
return ACTION_GO_ON;
}