]> mj.ucw.cz Git - umpf.git/blob - int.c
cleanup
[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 hlist* headers, struct variable** hash)
240 {
241         struct hlist* p;
242         struct hlist* last = NULL;
243         struct variable* pv;
244         int i;
245
246         for(p = headers; p; p = p->next){
247                 pv = find_var(p->name,NULL,hash);
248                 if (pv->modified){
249                         pv->modified = 0;
250                         free(pv->value);
251                         pv->value = xstrdup(p->value); //FIXME: fold it
252                 }
253                 last = p;
254         }
255
256         /* find new headers */
257         for (i = 0; i < HASHSIZE; i++){
258                 for(pv = hash[i]; pv; pv = pv->next){
259                         if (isupper(pv->name[0]) && pv->modified){
260                                 pv->modified = 0;
261                                 p = xmalloc(sizeof(struct hlist));
262
263                                 last->next = p; //FIXME
264                                 p->next = NULL;
265                                 p->name = xstrdup(pv->name);
266                                 p->value = xstrdup(pv->value);
267                         }
268                 }
269         }
270 }
271
272 static struct hlist*
273 copy_headers(struct hlist* orig)
274 {
275         struct hlist* new = NULL;
276         struct hlist* po, * pn = NULL;
277
278         for (po = orig; po; po = po->next){
279                 if (!pn)
280                         pn = xmalloc(sizeof(struct hlist));
281                 pn->next = xmalloc(sizeof(struct hlist));
282                 pn = pn->next;
283                 pn->next = NULL;
284                 pn->name = xstrdup(po->name);
285                 pn->value = xstrdup(po->value);
286                 if (!new)
287                         new = pn;
288         }
289
290         return new;
291 }
292
293 static void
294 new_action(char* l, char* r, char* s, struct variable** hash)
295 {
296         struct action* a;
297
298         a = xmalloc(sizeof(struct action));
299
300         modify_headers(current_headers, hash);
301         a->e.headers = copy_headers(current_headers);
302         a->l = l;
303         a->r = r;
304         a->s = s;
305
306         do_action(a);
307 }
308
309 void
310 interp(struct tree* t, struct variable** hash)
311 {
312         if (!t)
313                 return;
314
315         switch(t->st){
316                 case ST_BLOCK:
317                         interp(t->pt.block.head, hash);
318                         interp(t->pt.block.tail, hash);
319                         break;
320                 case ST_ASS:
321                         find_var(t->pt.ass.left->pt.leaf.value, interp_ass_right(t->pt.ass.right, hash), hash);
322                         break;
323                 case ST_IF:
324                         if (interp_cond(t->pt.tif.c, hash))
325                                 interp(t->pt.tif.i, hash);
326                         else 
327                                 interp(t->pt.tif.e, hash);
328                         break;
329                 case ST_ARROW:
330                         new_action(t->pt.arrow.kw_left, t->pt.arrow.kw_right, interp_ass_right(t->pt.arrow.s, hash),hash);
331                         break;
332                 case ST_EMPTY:
333                         break;  
334                 default:
335                         die("interp: got to default");
336         }
337
338 }
339
340 void
341 print_vars(struct variable** hash)
342 {
343         int i;
344         struct variable* p;
345
346         for (i=0; i<HASHSIZE; i++){
347                 p = hash[i];
348                 while(p){
349                         printf("%s=%s\n",p->name, p->value);
350                         p = p->next;
351                 }               
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 variable** hash)
386 {
387         struct hlist* p;
388         struct variable* pv;
389         char* u;
390
391         for (p = current_headers;p;p = p->next){
392                 u = unfold(p->value);
393                 pv = find_var(p->name,u,hash);
394                 pv->modified = 0;
395         }
396
397 }