X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=int.c;h=f7fe023b592f5c5538c33d003251a2494e02d86a;hb=fe8a488cd0901903cf93448366b3164c94674ac9;hp=5f0a9366362a74ac1ed0cd75ce973b8792f92282;hpb=d4bc03c024891aadf8e963736be114d4d023987f;p=umpf.git diff --git a/int.c b/int.c index 5f0a936..f7fe023 100644 --- a/int.c +++ b/int.c @@ -1,28 +1,25 @@ #include #include #include +#include #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; } @@ -34,7 +31,7 @@ get_bucket_number(char* name) unsigned char* p = name; while (*p != '\0'){ - n = n * MAGIC + *p++; + n = n * MAGIC + toupper(*p++); } n %= HASHSIZE; @@ -43,44 +40,31 @@ get_bucket_number(char* name) /* 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) { @@ -107,22 +91,18 @@ print_tree(struct tree* t, int ind) 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)); @@ -135,12 +115,11 @@ print_tree(struct tree* t, int ind) 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('$'); @@ -150,23 +129,17 @@ print_tree(struct tree* t, int ind) } 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: @@ -176,20 +149,248 @@ print_tree(struct tree* t, int ind) } } +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; iname, 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; +}