]> mj.ucw.cz Git - umpf.git/blob - int.c
body can have 0 now
[umpf.git] / int.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <pcre.h>
4 #include <ctype.h>
5
6 #include "cond.tab.h"
7 #include "brum.h"
8
9 #define OVECCOUNT 3
10 #define HASHSIZE 103
11 #define MAGIC 19
12
13 struct list* 
14 new_var_hash(void)
15 {
16         struct list* res;
17         int i;
18
19         res = xmalloc (HASHSIZE * sizeof(struct list));
20         for (i = 0; i < HASHSIZE; i++)
21                 list_init(res + i);
22         
23
24         return res;
25 }
26
27 static int
28 get_bucket_number(char* name)
29 {
30         unsigned int n = 0;
31         unsigned char* p = name;
32
33         while (*p != '\0'){
34                 n = n * MAGIC + toupper(*p++);
35         }
36         n %= HASHSIZE;
37
38         return n;
39 }
40
41 /* value NULL for finding without modyfiing */
42 static struct variable*
43 find_var(char* name, char* value, struct list* hash)
44 {
45         int n;
46         struct variable *p;
47
48         n = get_bucket_number(name);
49         int nocase = isupper(*name);
50         LIST_FOREACH(p, hash + n)
51                 if (!(nocase ? strcasecmp : strcmp)(p->name,name)){
52                         if (value){
53                                 free(p->value);
54                                 p->value = value;
55                                 p->modified = 1;
56                         }
57                         return p;
58                 }
59
60         p = xmalloc(sizeof(struct variable));
61         p->name = xstrdup(name); 
62         p->value = (value? value:xstrdup(""));
63         p->modified = 1;
64         list_add_last(hash+n, &p->car);
65         return p;
66 }
67
68 static int 
69 regex_cmp(char* s, char* r)
70 {
71         pcre *brum;
72         int erroroffset;
73         const char* error;
74         int ovector[OVECCOUNT];
75         
76         brum = pcre_compile(r,0,&error,&erroroffset,NULL);
77         if (!brum)
78                 return -1;
79         
80         int res = pcre_exec(brum,NULL,s,strlen(s),0,0,ovector,OVECCOUNT);
81         pcre_free(brum);
82
83         return res;
84 }
85
86 void
87 print_tree(struct tree* t, int ind)
88 {
89         if (!t)
90                 return; 
91
92         switch (t->st){
93                 case ST_IF:
94                         printf("%*s if\n", ind, "");
95                         print_tree(t->pt.tif.c,ind+1);
96                         printf("%*s then\n", ind, "");
97                         print_tree(t->pt.tif.i,ind+1);
98                         printf("%*s else\n", ind, "");
99                         print_tree(t->pt.tif.e,ind+1);
100                         break;
101                 case ST_COND:
102 #define UPPER(a) ((a) >> 8)
103 #define LOWER(a) ((a) & 0xFF)
104                         print_tree(t->pt.cond.left, ind+1);
105                         printf("%*s", ind, "");
106                         if (UPPER(t->pt.cond.op) > 0)
107                                 putchar(UPPER(t->pt.cond.op));
108                         putchar(LOWER(t->pt.cond.op));
109                         putchar('\n'); 
110                         print_tree(t->pt.cond.right, ind+1);    
111                         break;
112                 case ST_BLOCK:
113                         print_tree(t->pt.block.head,ind);
114                         print_tree(t->pt.block.tail,ind);
115                         break;
116                 case ST_ASS:
117                         print_tree(t->pt.ass.left, ind+1);
118                         printf("%*s =\n", ind, "");
119                         print_tree(t->pt.ass.right, ind+1);
120                         break;
121                 case ST_LEAF:
122                         printf("%*s", ind, "");
123                         switch (t->pt.leaf.type){
124                                 case L_VAR:
125                                         putchar('$');
126                                 case L_CONST:
127                                         puts(t->pt.leaf.value);
128                                         break;
129                         }
130                         break;
131                 case ST_ARROW:
132                         if (t->pt.arrow.kw_left)
133                                 printf("%*s%s\n", ind+1, "", t->pt.arrow.kw_left);
134                         printf("%*s ->\n", ind, "");
135                         if (t->pt.arrow.kw_right)
136                                 printf("%*s%s\n", ind+1, "", t->pt.arrow.kw_right);
137                         if (t->pt.arrow.s)
138                                 print_tree(t->pt.arrow.s,ind+1);
139                         break;
140                 case ST_OP:
141                         print_tree(t->pt.op.left, ind+1);
142                         printf("%*s%c\n", ind, "", t->pt.op.op);
143                         print_tree(t->pt.op.right, ind+1);
144                         break;  
145                 case ST_EMPTY:
146                         break;  
147
148
149         }
150 }
151
152 static char*
153 xcat(char* left, char* right)
154 {
155         char* res = xmalloc(strlen(left) + strlen(right) + 1);
156
157         strcpy(res,left);
158         strcat(left,right);
159
160         free(left);
161         free(right);    
162
163         return res;
164 }
165
166 static char*
167 interp_ass_right(struct tree* t, struct list* hash)
168 {
169         switch (t->st){
170                 case ST_LEAF:
171                         if (t->pt.leaf.type == L_VAR)
172                                 return xstrdup(find_var(t->pt.leaf.value,NULL,hash)->value);
173                         else 
174                                 return xstrdup(t->pt.leaf.value);
175                 case ST_OP:
176                         switch (t->pt.op.op){
177                                 case '.':
178                                         return xcat(interp_ass_right(t->pt.op.left, hash),interp_ass_right(t->pt.op.right, hash));
179                         }       
180                 case ST_EMPTY:
181                         return xstrdup("");
182                 default:
183                         die("interp_ass_right: got to default");        
184                 }
185 }       
186
187 // FIXME: we would like to be able also do things like ($a & $b) == $c
188 static int
189 interp_cond(struct tree* t, struct list* hash)
190 {
191         if (t->st != ST_COND)
192                 die("Muhehehechlemst?");
193
194         if (t->pt.cond.type == OP_REL){
195                 if (t->pt.cond.left->st != ST_LEAF || t->pt.cond.right->st != ST_LEAF)
196                         die("Chlemst");
197
198                 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);
199         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);
200                 switch (t->pt.cond.op){
201                         case CC('=','='):
202                                 return !strcmp(left,right);
203                         case CC('!','='):
204                                 return strcmp(left,right);
205                         case CC('~','~'):
206                                 return regex_cmp(left,right);
207                         case CC('!','~'):
208                                 return !regex_cmp(left,right);
209                         default:
210                                 die("Brrrchlemst!");
211                 } //TODO: add numbers
212
213         } else {
214                 int left = interp_cond(t->pt.cond.left, hash);
215                 int right;
216
217                 if (t->pt.cond.op != '!')
218                         right = interp_cond(t->pt.cond.right, hash);
219
220                 switch (t->pt.cond.op){
221                         case '&':
222                                 return left && right;
223                         case '|':
224                                 return left || right;
225                         case '^':
226                                 return (left || right) && !(left && right);
227                         case '!':
228                                 return !left;
229                         default:
230                                 die("Brrrchlemst!");
231                 }
232         }
233 }
234
235 static void
236 modify_headers(struct list* headers, struct list* hash)
237 {
238         struct hlist* p;
239         struct variable* pv;
240         int i;
241
242         LIST_FOREACH(p, headers){
243                 pv = find_var(p->name,NULL,hash);
244                 if (pv->modified){
245                         pv->modified = 0;
246                         free(p->value);
247                         p->value = xstrdup(pv->value); //FIXME: fold it
248                 }
249         }
250
251         /* find new headers */
252         for (i = 0; i < HASHSIZE; i++){
253                 LIST_FOREACH(pv, hash + i){
254                         if (isupper(pv->name[0]) && pv->modified){
255                                 pv->modified = 0;
256
257                                 p = xmalloc(sizeof(struct hlist));
258                                 p->name = xstrdup(pv->name);
259                                 p->value = xstrdup(pv->value);
260
261                                 list_add_last(headers,&p->car);
262                         }
263                 }
264         }
265 }
266
267 static struct list*
268 copy_headers(struct list* orig)
269 {
270         struct list* new = xmalloc(sizeof(struct list));
271         struct hlist* po, *pn;
272
273         list_init(new);
274
275         LIST_FOREACH(po, orig){
276                 pn = xmalloc(sizeof(struct hlist));
277                 pn->name = xstrdup(po->name);
278                 pn->value = xstrdup(po->value);
279
280                 list_add_last(new, &pn->car);
281         }
282
283         return new;
284 }
285
286 static void
287 new_action(char* l, char* r, char* s, struct list* hash)
288 {
289         struct action* a;
290
291         a = xmalloc(sizeof(struct action));
292
293         modify_headers(current_headers, hash);
294         a->e.headers = copy_headers(current_headers);
295         a->e.body_len = current_body->body_len; 
296         a->e.body = xmalloc(a->e.body_len);
297         memcpy(a->e.body, current_body->body, a->e.body_len);
298         a->l = l;
299         a->r = r;
300         a->s = s;
301
302         do_action(a);
303 }
304
305 void
306 interp(struct tree* t, struct list* hash)
307 {
308         if (!t)
309                 return;
310
311         switch(t->st){
312                 case ST_BLOCK:
313                         interp(t->pt.block.head, hash);
314                         interp(t->pt.block.tail, hash);
315                         break;
316                 case ST_ASS:
317                         find_var(t->pt.ass.left->pt.leaf.value, interp_ass_right(t->pt.ass.right, hash), hash);
318                         break;
319                 case ST_IF:
320                         if (interp_cond(t->pt.tif.c, hash))
321                                 interp(t->pt.tif.i, hash);
322                         else 
323                                 interp(t->pt.tif.e, hash);
324                         break;
325                 case ST_ARROW:
326                         new_action(t->pt.arrow.kw_left, t->pt.arrow.kw_right, interp_ass_right(t->pt.arrow.s, hash),hash);
327                         break;
328                 case ST_EMPTY:
329                         break;  
330                 default:
331                         die("interp: got to default");
332         }
333
334 }
335
336 void
337 print_vars(struct list* hash)
338 {
339         int i;
340         struct variable* p;
341
342         for (i=0; i<HASHSIZE; i++){
343                 LIST_FOREACH(p, hash + i)
344                         printf("%s=%s\n",p->name, p->value);
345         }
346 }
347
348 static char*
349 unfold(char* u)
350 {
351         char* new;
352         char* pu = u; 
353         char* pn;
354
355         new = xmalloc(strlen(u)+1);
356         pn = new;
357
358 #define IS_WHITE(c) ((c) == '\t' || (c)==' ' || c=='\n')
359
360         while (IS_WHITE(*pu))
361                 pu++;
362
363         while (*pu != 0){
364                 if (IS_WHITE(*pu)){
365                         while (IS_WHITE(*pu))
366                                 pu++;
367                         if (*pu != 0)
368                                 *pn++ = ' ';
369                 } else
370                         *pn++ = *pu++;          
371         }
372         *pn = 0;
373
374         return new;
375 }
376
377 void
378 save_current_headers(struct list* hash)
379 {
380         struct hlist* p;
381         struct variable* pv;
382         char* u;
383
384         LIST_FOREACH(p, current_headers){
385                 u = unfold(p->value);
386                 pv = find_var(p->name,u,hash);
387                 pv->modified = 0;
388         }
389
390 }
391
392 void
393 get_default_mailbox(char* mb)
394 {
395         default_mailbox = mb;
396 }