#include <string.h>
#include <pcre.h>
#include <ctype.h>
+#include <limits.h>
#include "cond.tab.h"
#include "umpf.h"
#define HASHSIZE 103
#define MAGIC 19
-struct list*
-new_var_hash(void)
+#define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6)
+
+static void
+clear_var(int var)
{
- struct list* res;
- int i;
+ if (var_tab[var])
+ free(var_tab[var]);
+}
- res = xmalloc (HASHSIZE * sizeof(struct list));
- for (i = 0; i < HASHSIZE; i++)
- list_init(res + i);
+static void
+set_var(int var, char* value)
+{
+ clear_var(var);
+ var_tab[var] = xstrdup(value);
-
- return res;
}
-static int
-get_bucket_number(char* name)
+static char*
+get_var(int var)
{
- unsigned int n = 0;
- unsigned char* p = name;
-
- while (*p != '\0'){
- n = n * MAGIC + toupper(*p++);
- }
- n %= HASHSIZE;
-
- return n;
+ if (var < 0)
+ return const_tab[-var];
+ return var_tab[var];
}
-/* value NULL for finding without modyfiing */
+/* return var struct or NULL if not found */
static struct variable*
-find_var(char* name, char* value, struct list* hash)
+get_var_struct(char* name, struct list* hash)
{
int n;
struct variable *p;
n = get_bucket_number(name);
int nocase = isupper(*name);
LIST_FOREACH(p, hash + n)
- if (!(nocase ? strcasecmp : strcmp)(p->name,name)){
- if (value){
- free(p->value);
- p->value = value;
- p->modified = 1;
- }
+ if (!(nocase ? strcasecmp : strcmp)(p->name,name))
return p;
- }
- p = xmalloc(sizeof(struct variable));
- p->name = xstrdup(name);
- p->value = (value? value:xstrdup(""));
- p->modified = 1;
- list_add_last(hash+n, &p->car);
- return p;
+ return NULL;
}
static int
return res;
}
-void
-print_tree(struct tree* t, int ind)
-{
- if (!t)
- return;
-
- switch (t->st){
- case ST_IF:
- printf("%*s if\n", ind, "");
- print_tree(t->pt.tif.c,ind+1);
- printf("%*s then\n", ind, "");
- print_tree(t->pt.tif.i,ind+1);
- printf("%*s else\n", ind, "");
- print_tree(t->pt.tif.e,ind+1);
- break;
- case ST_COND:
#define UPPER(a) ((a) >> 8)
#define LOWER(a) ((a) & 0xFF)
- print_tree(t->pt.cond.left, ind+1);
- printf("%*s", ind, "");
- if (UPPER(t->pt.cond.op) > 0)
- putchar(UPPER(t->pt.cond.op));
- putchar(LOWER(t->pt.cond.op));
- putchar('\n');
- print_tree(t->pt.cond.right, ind+1);
- break;
- case ST_BLOCK:
- print_tree(t->pt.block.head,ind);
- print_tree(t->pt.block.tail,ind);
- break;
- case ST_ASS:
- print_tree(t->pt.ass.left, ind+1);
- printf("%*s =\n", ind, "");
- print_tree(t->pt.ass.right, ind+1);
- break;
- case ST_LEAF:
- printf("%*s", ind, "");
- switch (t->pt.leaf.type){
- case L_VAR:
- putchar('$');
- case L_CONST:
- puts(t->pt.leaf.value);
- break;
- }
- break;
- case ST_ARROW:
- if (t->pt.arrow.kw_left)
- printf("%*s%s\n", ind+1, "", t->pt.arrow.kw_left);
- printf("%*s ->\n", ind, "");
- if (t->pt.arrow.kw_right)
- printf("%*s%s\n", ind+1, "", t->pt.arrow.kw_right);
- if (t->pt.arrow.s)
- print_tree(t->pt.arrow.s,ind+1);
- break;
- case ST_OP:
- print_tree(t->pt.op.left, ind+1);
- printf("%*s%c\n", ind, "", t->pt.op.op);
- print_tree(t->pt.op.right, ind+1);
- break;
- case ST_EMPTY:
- break;
-
-
- }
-}
static char*
xcat(char* left, char* right)
return res;
}
-static char*
-interp_ass_right(struct tree* t, struct list* hash)
-{
- switch (t->st){
- case ST_LEAF:
- if (t->pt.leaf.type == L_VAR)
- return xstrdup(find_var(t->pt.leaf.value,NULL,hash)->value);
- else
- return xstrdup(t->pt.leaf.value);
- case ST_OP:
- switch (t->pt.op.op){
- case '.':
- return xcat(interp_ass_right(t->pt.op.left, hash),interp_ass_right(t->pt.op.right, hash));
- }
- case ST_EMPTY:
- return xstrdup("");
- default:
- die("interp_ass_right: got to default");
- }
-}
-
-// FIXME: we would like to be able also do things like ($a & $b) == $c
-static int
-interp_cond(struct tree* t, struct list* hash)
-{
- if (t->st != ST_COND)
- die("Muhehehechlemst?");
-
- if (t->pt.cond.type == OP_REL){
- if (t->pt.cond.left->st != ST_LEAF || t->pt.cond.right->st != ST_LEAF)
- die("Chlemst");
-
- char* left = (t->pt.cond.left->pt.leaf.type == L_VAR ? find_var(t->pt.cond.left->pt.leaf.value,NULL,hash)->value : t->pt.cond.left->pt.leaf.value);
- char* right = (t->pt.cond.right->pt.leaf.type == L_VAR ? find_var(t->pt.cond.right->pt.leaf.value,NULL,hash)->value : t->pt.cond.right->pt.leaf.value);
- switch (t->pt.cond.op){
- case CC('=','='):
- return !strcmp(left,right);
- case CC('!','='):
- return strcmp(left,right);
- case CC('~','~'):
- return regex_cmp(left,right);
- case CC('!','~'):
- return !regex_cmp(left,right);
- default:
- die("Brrrchlemst!");
- } //TODO: add numbers
-
- } else {
- int left = interp_cond(t->pt.cond.left, hash);
- int right;
-
- if (t->pt.cond.op != '!')
- right = interp_cond(t->pt.cond.right, hash);
-
- switch (t->pt.cond.op){
- case '&':
- return left && right;
- case '|':
- return left || right;
- case '^':
- return (left || right) && !(left && right);
- case '!':
- return !left;
- default:
- die("Brrrchlemst!");
- }
- }
-}
-
static void
modify_headers(struct list* headers, struct list* hash)
{
struct hlist* p;
- struct variable* pv;
int i;
+ struct variable* pv;
+
LIST_FOREACH(p, headers){
- pv = find_var(p->name,NULL,hash);
+ pv = get_var_struct(p->name, hash);
+ if (!pv)
+ continue;
if (pv->modified){
pv->modified = 0;
free(p->value);
- p->value = xstrdup(pv->value); //FIXME: fold it
+ p->value = xstrdup(get_var(pv->varcode)); //FIXME: fold it
}
}
- /* find new headers */
+ // find new headers
for (i = 0; i < HASHSIZE; i++){
LIST_FOREACH(pv, hash + i){
if (isupper(pv->name[0]) && pv->modified){
p = xmalloc(sizeof(struct hlist));
p->name = xstrdup(pv->name);
- p->value = xstrdup(pv->value);
+ p->value = xstrdup(get_var(pv->varcode));
list_add_last(headers,&p->car);
}
pn = xmalloc(sizeof(struct hlist));
pn->name = xstrdup(po->name);
pn->value = xstrdup(po->value);
+ pn->have_var = 0;
list_add_last(new, &pn->car);
}
return new;
}
-static void
-new_action(char* l, char* r, char* s, struct list* hash)
+static struct email*
+prepare_email(struct list* hash)
{
- struct action* a;
+ struct email* em;
- a = xmalloc(sizeof(struct action));
+ em = xmalloc(sizeof(struct email));
modify_headers(current_headers, hash);
- a->e.headers = copy_headers(current_headers);
- a->e.body_len = current_body->body_len;
- a->e.body = xmalloc(a->e.body_len);
- memcpy(a->e.body, current_body->body, a->e.body_len);
- a->l = l;
- a->r = r;
- a->s = s;
-
- do_action(a);
+ em->headers = copy_headers(current_headers);
+ em->body_len = current_body->body_len;
+ em->body = xmalloc(em->body_len);
+ memcpy(em->body, current_body->body, em->body_len);
+
+ return em;
}
-void
-interp(struct tree* t, struct list* hash)
+static void
+do_string_ternary_op(struct code* p)
{
- if (!t)
- return;
+ char* l = get_var(p->u.tpop.l);
+ char* r = get_var(p->u.tpop.r);
+ char* result;
+
+ switch(p->opcode) {
+ case OPC_RE:
+ result = xmalloc(INT_TO_STRING_LEN);
+ sprintf(result, "%d", regex_cmp(l, r));
+ case OPC_NRE:
+ result = xmalloc(INT_TO_STRING_LEN);
+ sprintf(result, "%d", !regex_cmp(l, r));
+ case OPC_CAT:
+ result = xcat(l, r);
+ default:
+ break;
+ };
+
+ set_var(p->u.tpop.res, result);
+}
+
+static void
+do_num_ternary_op(struct code* p)
+{
+ int l, r, res;
+ char* result = xmalloc(INT_TO_STRING_LEN);
+
+ sscanf(get_var(p->u.tpop.l),"%d", &l);
+ sscanf(get_var(p->u.tpop.r),"%d", &r);
- switch(t->st){
- case ST_BLOCK:
- interp(t->pt.block.head, hash);
- interp(t->pt.block.tail, hash);
+ switch(p->opcode) {
+ case OPC_GT:
+ res = (l > r);
break;
- case ST_ASS:
- find_var(t->pt.ass.left->pt.leaf.value, interp_ass_right(t->pt.ass.right, hash), hash);
+ case OPC_LT:
+ res = (l < r);
break;
- case ST_IF:
- if (interp_cond(t->pt.tif.c, hash))
- interp(t->pt.tif.i, hash);
- else
- interp(t->pt.tif.e, hash);
+ case OPC_LE:
+ res = (l <= r);
break;
- case ST_ARROW:
- new_action(t->pt.arrow.kw_left, t->pt.arrow.kw_right, interp_ass_right(t->pt.arrow.s, hash),hash);
+ case OPC_GE:
+ res = (l >= r);
+ break;
+ case OPC_EQ:
+ res = (l == r);
+ break;
+ case OPC_NEQ:
+ res = (l != r);
+ break;
+ case OPC_AND:
+ res = (l && r);
+ break;
+ case OPC_OR:
+ res = (l || r);
+ break;
+ case OPC_XOR:
+ res = ((l || r) && !(l && r));
+ break;
+ case OPC_PLUS:
+ res = (l + r);
+ break;
+ case OPC_MINUS:
+ res = (l - r);
+ break;
+ case OPC_MUL:
+ res = (l * r);
+ break;
+ case OPC_DIV:
+ res = (l / r);
break;
- case ST_EMPTY:
- break;
default:
- die("interp: got to default");
+ break;
}
+ sprintf(result, "%d", res);
+ set_var(p->u.tpop.res, result);
+}
+
+static int
+eval_cond(int var)
+{
+ char* val = get_var(var);
+ int v;
+
+ if (! val)
+ return 0;
+ if (! *val)
+ return 0;
+ sscanf(val, "%d", &v);
+
+ return !!v;
+}
+
+void
+interp(struct list* ins)
+{
+ struct code* p;
+ char* result;
+ int v;
+
+ LIST_FOREACH(p, ins) {
+ switch (p->opcode) {
+ case OPC_SET:
+ set_var(p->u.set.l, get_var(p->u.set.r));
+ break;
+ case OPC_JUMP:
+ p = p->u.jump.target;
+ continue;
+ break;
+ case OPC_JUMP_IF:
+ if (eval_cond(p->u.jump_if.cond))
+ p = p->u.jump_if.target;
+ continue;
+ break;
+ case OPC_JUMP_UNLESS:
+ if (!eval_cond(p->u.jump_unless.cond))
+ p = p->u.jump_unless.target;
+ continue;
+ break;
+ case OPC_NOP:
+ continue;
+ break;
+ case OPC_GT:
+ case OPC_LT:
+ case OPC_LE:
+ case OPC_GE:
+ case OPC_EQ:
+ case OPC_NEQ:
+ case OPC_AND:
+ case OPC_OR:
+ case OPC_XOR:
+ case OPC_PLUS:
+ case OPC_MINUS:
+ case OPC_MUL:
+ case OPC_DIV:
+ do_num_ternary_op(p);
+ break;
+ case OPC_NOT:
+ result = xmalloc(INT_TO_STRING_LEN);
+ sscanf(get_var(p->u.tpop.l),"%d", &v);
+ sprintf(result, "%d", !v);
+ set_var(p->u.tpop.res, result);
+ case OPC_CAT:
+ case OPC_RE:
+ case OPC_NRE:
+ do_string_ternary_op(p);
+ break;
+ case OPC_PIPE:
+ break;
+ case OPC_MAIL:
+ break;
+ case OPC_DELIVER:
+ break;
+ case OPC_CALL_EXT:
+ break;
+ case OPC_DISCARD:
+ break;
+ }}
}
void
for (i=0; i<HASHSIZE; i++){
LIST_FOREACH(p, hash + i)
- printf("%s=%s\n",p->name, p->value);
+ printf("%s=%s\n",p->name, get_var(p->varcode));
}
}
save_current_headers(struct list* hash)
{
struct hlist* p;
- struct variable* pv;
char* u;
+ struct variable* pv;
LIST_FOREACH(p, current_headers){
+ pv = get_var_struct(p->name, hash);
+ if (!pv)
+ continue;
u = unfold(p->value);
- pv = find_var(p->name,u,hash);
+ set_var(pv->varcode, u);
pv->modified = 0;
+ p->have_var = 1;
}
}
-void
+static void
get_default_mailbox(char* mb)
{
default_mailbox = mb;