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