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