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