X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=int.c;h=e1c906f058342ada6c8d264876d5f4fcc48bed35;hb=f7469b506efca7aa155899a9398b7ce490dd4ba1;hp=5f0a9366362a74ac1ed0cd75ce973b8792f92282;hpb=d4bc03c024891aadf8e963736be114d4d023987f;p=umpf.git diff --git a/int.c b/int.c index 5f0a936..e1c906f 100644 --- a/int.c +++ b/int.c @@ -1,84 +1,83 @@ #include #include #include +#include +#include +#include +#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; -}; +#define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6) -struct variable** -new_var_hash(void) +void __attribute__ ((noreturn)) +bye(int code, char* msg, ...) { - struct variable** res; + va_list args; - res = xmalloc (HASHSIZE * sizeof(struct variable*)); - memset(res, 0, sizeof(struct variable*)*HASHSIZE); + if (current_body->tmpfile) + unlink(current_body->tmpfile); + + if (msg) { + va_start(args, msg); + vfprintf(stderr, msg, args); + fputc('\n', stderr); + va_end(args); + } + exit(code); +} - return res; +void +free_string(char* c) +{ + if (c != empty) + free(c); } -static int -get_bucket_number(char* name) +static void +clear_var(int var) { - unsigned int n = 0; - unsigned char* p = name; + if ((var_tab[var] != NULL)) + free_string(var_tab[var]); +} - while (*p != '\0'){ - n = n * MAGIC + *p++; - } - n %= HASHSIZE; +static void +set_var(int var, char* value) +{ + clear_var(var); + var_tab[var] = xstrdup(value); +} - return n; +static char* +get_var(int var) +{ + if (var < 0) + return xstrdup(const_tab[-var]); + return xstrdup(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 variable** 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)) + 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); - - return p; -} - -static void -print_ind(int num, char c) -{ - int i; - - for (i = 0; i < num; i++){ - putchar(c); - } -//printf("%*s", num, ""); + return NULL; } static int @@ -99,97 +98,441 @@ regex_cmp(char* s, char* r) return res; } -void -print_tree(struct tree* t, int ind) -{ - if (!t) - return; - - switch (t->st){ - case ST_IF: - print_ind(ind,' '); - puts("if"); - print_tree(t->pt.tif.c,ind+1); - print_ind(ind,' '); - puts("then"); - print_tree(t->pt.tif.i,ind+1); - print_ind(ind,' '); - puts("else"); - 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,' '); - - 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); - print_ind(ind,' '); - puts("="); - print_tree(t->pt.ass.right, ind+1); - break; - case ST_LEAF: - print_ind(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){ - 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); + +static char* +xcat(char* left, char* right) +{ + char* res = xmalloc(strlen(left) + strlen(right) + 1); + + strcpy(res, left); + strcat(res, right); + + free_string(left); + free_string(right); + + return res; +} + +static char* +fold(const char* value, int taken) +{ + int i; + char* ret; + int len = strlen(value); + int newlines[len / 78 + 5]; + int newl = 0; + int curr_ws = -1; + int pos = 0; + int newl_done = 0; + + if (len + taken <= 78) + return xstrdup(value); + for(i = 0; i < len; i++) { + if (value[i] == ' ' || value[i]=='\t') + curr_ws = i; + taken++; + if (taken >= 78) { + if (curr_ws > 0){ + newlines[newl++] = curr_ws; + i = curr_ws; + while(value[i] && (value[i] == '\t' + || value[i] == ' ')) + i++; + taken = i - curr_ws; + curr_ws = -1; } - 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'); - print_tree(t->pt.op.right, ind+1); - break; - case ST_EMPTY: + } + } + ret = xmalloc(2*newl + len + 1); + for (i = 0; i < len; i++) { + if (newl_done == newl) { + strcpy(ret + pos, value + i); break; + } + if(i != newlines[newl_done]) + ret[pos++] = value[i]; + else { + newl++; + ret[pos++] = '\n'; + ret[pos++] = ' '; + } + } + return ret; +} + +static char* +unfold(const char* u) +{ + char* new; + const 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; +} + +static void +modify_headers(struct list* headers, struct list* hash) +{ + struct hlist* p; + int i; + struct variable* pv; + char* u, * value; + + + LIST_FOREACH(p, headers){ + pv = get_var_struct(p->name, hash); + if (!pv) + continue; + u = unfold(p->value); + value = get_var(pv->varcode); + if (strcmp(u, value)){ + pv->modified = 0; + free_string(p->value); + p->value = fold(value, + strlen(p->name) + 2); + } + free_string(u); + free_string(value); + } + + // 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 = get_var(pv->varcode); + 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); + pn->have_var = 0; + + list_add_last(new, &pn->car); + } + + return new; +} + +static struct email +prepare_email(struct list* hash) +{ + struct email em; + + modify_headers(current_headers, hash); + em.headers = copy_headers(current_headers); + em.body_len = current_body->body_len; + em.fd = current_body->fd; + if (current_body->body) { + em.body = xmalloc(em.body_len); + memcpy(em.body, current_body->body, em.body_len); + em.tmpfile = NULL; + } else { + em.tmpfile = xstrdup(current_body->tmpfile); + em.body = NULL; + } + + return em; +} + +static void +destroy_email(struct email em) +{ + if (em.body) + free_string(em.body); + if(em.tmpfile) + free_string(em.tmpfile); +} + +static void +do_string_ternary_op(struct code* p) +{ + 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)); + break; + case OPC_NRE: + result = xmalloc(INT_TO_STRING_LEN); + sprintf(result, "%d", !regex_cmp(l, r)); + break; + case OPC_CAT: + result = xcat(l, r); + break; + 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(p->opcode) { + case OPC_GT: + res = (l > r); + break; + case OPC_LT: + res = (l < r); + break; + case OPC_LE: + res = (l <= r); + break; + 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; + 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; +} + +static void +deliver(char* where, int copy, struct list* hash) +{ + int res = 0; + struct email em = prepare_email(hash); + + res = deliver_local_email(where, &em); + + destroy_email(em); + + if (!copy) { + if (res) + bye(EX_TEMPFAIL, "%m"); + else + bye(0, NULL); + } +} + +static void +send_mail(char* where, int copy, struct list* hash) +{ + int pd[2]; + int pid, status; + int res; + struct email em = prepare_email(hash); + + res = pipe(pd); + if (res < 0) + goto end; + + if ((pid = fork()) < 0) + goto end; + else if (pid == 0) { + close(0); + dup(pd[0]); + close(pd[0]); + //FIXME From? + res = execl("/usr/lib/sendmail", "sendmail", where, NULL); + } + close(pd[0]); + write_email_to_fd(pd[1], &em); + close(pd[1]); + wait(&status); +end: + destroy_email(em); + if (!copy) { + if (res) + bye(EX_TEMPFAIL, "%m"); + else + bye(0, NULL); } } void -interp(struct tree* t) -{ - if (!t) - return; - - switch(t->st){ - case ST_BLOCK: - interp(t->pt.block.head); - interp(t->pt.block.tail); - break; - case ST_ASS: - // find_name(t->pt.ass.left->pt.leaf.value.s, interp_ass_right(t->pt.ass.right), var_hash); - break; +interp(struct list* ins, struct list* hash) +{ + 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: + send_mail(get_var(p->u.arrow.what), + p->u.arrow.copy, hash); + break; + case OPC_DELIVER: + deliver(get_var(p->u.arrow.what), + p->u.arrow.copy, hash); + break; + case OPC_CALL_EXT: + break; + case OPC_DISCARD: + bye(0, NULL); + break; + }} + deliver(default_mailbox, 0, hash); +} + +void +print_vars(struct list* hash) +{ + int i; + struct variable* p; + + for (i=0; iname, get_var(p->varcode)); } +} -}; +void +save_current_headers(struct list* hash) +{ + struct hlist* p; + char* u; + struct variable* pv; + + LIST_FOREACH(p, current_headers){ + pv = get_var_struct(p->name, hash); + if (!pv) + continue; + u = unfold(p->value); + set_var(pv->varcode, u); + free_string(u); + pv->modified = 0; + p->have_var = 1; + } +}