#include <stdio.h>
#include <string.h>
#include <pcre.h>
+#include <ctype.h>
#include "cond.tab.h"
-#include "brum.h"
+#include "umpf.h"
#define OVECCOUNT 3
-
#define HASHSIZE 103
#define MAGIC 19
-struct variable {
- char* name;
- char* value;
- struct variable* next;
-};
-
-struct variable**
+struct list*
new_var_hash(void)
{
- struct variable** res;
+ struct list* res;
+ int i;
- res = xmalloc (HASHSIZE * sizeof(struct variable*));
- memset(res, 0, sizeof(struct variable*)*HASHSIZE);
+ res = xmalloc (HASHSIZE * sizeof(struct list));
+ for (i = 0; i < HASHSIZE; i++)
+ list_init(res + i);
+
return res;
}
unsigned char* p = name;
while (*p != '\0'){
- n = n * MAGIC + *p++;
+ n = n * MAGIC + toupper(*p++);
}
n %= HASHSIZE;
/* value NULL for finding without modyfiing */
static struct variable*
-find_var(char* name, char* value, struct variable** hash)
+find_var(char* name, char* value, 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;
+ }
+ return p;
+ }
- p = hash[n];
- while(p && strcmp(p->name,name))
- p = p->next;
-
- if (!value)
- return p;
- if (p)
- free(p->value);
- else {
- p = xmalloc(sizeof(struct variable));
- p->next = hash[n]->next;
- hash[n]->next = p;
- p->name = xstrdup(name);
- }
-
- p->value = xstrdup(value);
-
+ 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;
}
-static void
-print_ind(int num, char c)
-{
- int i;
-
- for (i = 0; i < num; i++){
- putchar(c);
- }
-//printf("%*s", num, "");
-}
-
static int
regex_cmp(char* s, char* r)
{
switch (t->st){
case ST_IF:
- print_ind(ind,' ');
- puts("if");
+ printf("%*s if\n", ind, "");
print_tree(t->pt.tif.c,ind+1);
- print_ind(ind,' ');
- puts("then");
+ printf("%*s then\n", ind, "");
print_tree(t->pt.tif.i,ind+1);
- print_ind(ind,' ');
- puts("else");
+ 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);
- print_ind(ind,' ');
-
+ printf("%*s", ind, "");
if (UPPER(t->pt.cond.op) > 0)
putchar(UPPER(t->pt.cond.op));
putchar(LOWER(t->pt.cond.op));
break;
case ST_ASS:
print_tree(t->pt.ass.left, ind+1);
- print_ind(ind,' ');
- puts("=");
+ printf("%*s =\n", ind, "");
print_tree(t->pt.ass.right, ind+1);
break;
case ST_LEAF:
- print_ind(ind, ' ');
+ printf("%*s", ind, "");
switch (t->pt.leaf.type){
case L_VAR:
putchar('$');
}
break;
case ST_ARROW:
- if (t->pt.arrow.kw_left){
- print_ind(ind+1, ' ');
- puts(t->pt.arrow.kw_left);
- }
- print_ind(ind, ' ');
- printf("->\n");
- if (t->pt.arrow.kw_right){
- print_ind(ind+1, ' ');
- puts(t->pt.arrow.kw_right);
- }
- print_tree(t->pt.arrow.s,ind+1);
+ 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);
- print_ind(ind,' ');
- putchar(t->pt.op.op);
- putchar('\n');
+ printf("%*s%c\n", ind, "", t->pt.op.op);
print_tree(t->pt.op.right, ind+1);
break;
case ST_EMPTY:
}
}
+static char*
+xcat(char* left, char* right)
+{
+ char* res = xmalloc(strlen(left) + strlen(right) + 1);
+
+ strcpy(res,left);
+ strcat(left,right);
+
+ free(left);
+ free(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;
+
+ LIST_FOREACH(p, headers){
+ pv = find_var(p->name,NULL,hash);
+ if (pv->modified){
+ pv->modified = 0;
+ free(p->value);
+ p->value = xstrdup(pv->value); //FIXME: fold it
+ }
+ }
+
+ /* find new headers */
+ for (i = 0; i < HASHSIZE; i++){
+ LIST_FOREACH(pv, hash + i){
+ if (isupper(pv->name[0]) && pv->modified){
+ pv->modified = 0;
+
+ p = xmalloc(sizeof(struct hlist));
+ p->name = xstrdup(pv->name);
+ p->value = xstrdup(pv->value);
+
+ list_add_last(headers,&p->car);
+ }
+ }
+ }
+}
+
+static struct list*
+copy_headers(struct list* orig)
+{
+ struct list* new = xmalloc(sizeof(struct list));
+ struct hlist* po, *pn;
+
+ list_init(new);
+
+ LIST_FOREACH(po, orig){
+ pn = xmalloc(sizeof(struct hlist));
+ pn->name = xstrdup(po->name);
+ pn->value = xstrdup(po->value);
+
+ list_add_last(new, &pn->car);
+ }
+
+ return new;
+}
+
+static void
+new_action(char* l, char* r, char* s, struct list* hash)
+{
+ struct action* a;
+
+ a = xmalloc(sizeof(struct action));
+
+ 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);
+}
+
void
-interp(struct tree* t)
+interp(struct tree* t, struct list* hash)
{
if (!t)
return;
switch(t->st){
case ST_BLOCK:
- interp(t->pt.block.head);
- interp(t->pt.block.tail);
- break;
+ interp(t->pt.block.head, hash);
+ interp(t->pt.block.tail, hash);
+ break;
case ST_ASS:
- // find_name(t->pt.ass.left->pt.leaf.value.s, interp_ass_right(t->pt.ass.right), var_hash);
- break;
+ find_var(t->pt.ass.left->pt.leaf.value, interp_ass_right(t->pt.ass.right, hash), hash);
+ 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);
+ 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);
+ break;
+ case ST_EMPTY:
+ break;
+ default:
+ die("interp: got to default");
+ }
+
+}
+
+void
+print_vars(struct list* hash)
+{
+ int i;
+ struct variable* p;
+
+ for (i=0; i<HASHSIZE; i++){
+ LIST_FOREACH(p, hash + i)
+ printf("%s=%s\n",p->name, p->value);
+ }
+}
+
+static char*
+unfold(char* u)
+{
+ char* new;
+ char* pu = u;
+ char* pn;
+
+ new = xmalloc(strlen(u)+1);
+ pn = new;
+
+#define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
+
+ while (IS_WHITE(*pu))
+ pu++;
+
+ while (*pu != 0){
+ if (IS_WHITE(*pu)){
+ while (IS_WHITE(*pu))
+ pu++;
+ if (*pu != 0)
+ *pn++ = ' ';
+ } else
+ *pn++ = *pu++;
}
+ *pn = 0;
+
+ return new;
+}
-};
+void
+save_current_headers(struct list* hash)
+{
+ struct hlist* p;
+ struct variable* pv;
+ char* u;
+
+ LIST_FOREACH(p, current_headers){
+ u = unfold(p->value);
+ pv = find_var(p->name,u,hash);
+ pv->modified = 0;
+ }
+
+}
+
+void
+get_default_mailbox(char* mb)
+{
+ default_mailbox = mb;
+}