First version of CCL. Qualifiers aren't handled yet.
[egate.git] / ccl / cclfind.c
1 /* CCL find (to rpn conversion)
2  * Europagate, 1995
3  *
4  * $Log: cclfind.c,v $
5  * Revision 1.1  1995/02/13 12:35:20  adam
6  * First version of CCL. Qualifiers aren't handled yet.
7  *
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <assert.h>
13 #include <string.h>
14
15 #include "cclp.h"
16
17 static struct ccl_token *look_token;
18 static int ccl_error;
19
20 #define KIND (look_token->kind)
21 #define ADVANCE look_token = look_token->next
22 #define ADVX(x) x=(x)->next
23
24 static void strxcat (char *n, const char *src, int len)
25 {
26     while (*n)
27         n++;
28     while (--len >= 0)
29         *n++ = *src++;
30     *n = '\0';
31 }
32
33 static char *copy_token_name (struct ccl_token *tp)
34 {
35     char *str = malloc (tp->len + 1);
36     memcpy (str, tp->name, tp->len);
37     str[tp->len] = '\0';
38     return str;
39 }
40
41 static struct ccl_rpn_node *mk_node (enum rpn_node_kind kind)
42 {
43     struct ccl_rpn_node *p;
44     p = malloc (sizeof(*p));
45     assert (p);
46     p->kind = kind;
47     return p;
48 }
49
50 void ccl_rpn_delete (struct ccl_rpn_node *rpn)
51 {
52     if (!rpn)
53         return;
54     switch (rpn->kind)
55     {
56     case AND:
57     case OR:
58     case NOT:
59         ccl_rpn_delete (rpn->u.p[0]);
60         ccl_rpn_delete (rpn->u.p[1]);
61         break;
62     case TERM:
63         free (rpn->u.t.term);
64         /* attr list */
65         break;
66     case SET:
67         free (rpn->u.setname);
68         break;
69     case PROX:
70         ccl_rpn_delete (rpn->u.p[0]);
71         ccl_rpn_delete (rpn->u.p[1]);
72         break;
73     }
74     free (rpn);
75 }
76
77 static struct ccl_rpn_node *find_spec (void);
78
79 static struct ccl_rpn_node *search_term (void)
80 {
81     struct ccl_rpn_node *p;
82     struct ccl_token *lookahead = look_token;
83     int len = 0;
84
85     if (KIND != CCL_TOK_TERM)
86     {
87         ccl_error = CCL_ERR_TERM_EXPECTED;
88         return NULL;
89     }
90     while (lookahead->kind == CCL_TOK_TERM)
91     {
92         len += 1+lookahead->len;
93         lookahead = lookahead->next;
94     }
95     p = mk_node (TERM);
96     p->u.t.term = malloc (len);
97     p->u.t.attr_list = NULL;
98     p->u.t.term[0] = '\0';
99     assert (p->u.t.term);
100     strxcat (p->u.t.term, look_token->name, look_token->len);
101     ADVANCE;
102     while (KIND == CCL_TOK_TERM)
103     {
104         strcat (p->u.t.term, " ");
105         strxcat (p->u.t.term, look_token->name, look_token->len);
106         ADVANCE;
107     }
108     return p;
109 }
110
111 static struct ccl_rpn_node *qualifiers (struct ccl_token *la)
112 {
113     assert (0);
114     return NULL;
115 }
116
117 static struct ccl_rpn_node *search_terms (void)
118 {
119     struct ccl_rpn_node *p1, *p2, *pn;
120     p1 = search_term ();
121     if (!p1)
122         return NULL;
123     while (1)
124     {
125         if (KIND == CCL_TOK_PROX)
126         {
127             ADVANCE;
128             p2 = search_term ();
129             if (!p2)
130             {
131                 ccl_rpn_delete (p1);
132                 return NULL;
133             }
134             pn = mk_node (PROX);
135             pn->u.p[0] = p1;
136             pn->u.p[1] = p2;
137             p1 = pn;
138         }
139         else if (KIND == CCL_TOK_TERM)
140         {
141             p2 = search_term ();
142             if (!p2)
143             {
144                 ccl_rpn_delete (p1);
145                 return NULL;
146             }
147             pn = mk_node (PROX);
148             pn->u.p[0] = p1;
149             pn->u.p[1] = p2;
150             p1 = pn;
151         }
152         else
153             break;
154     }
155     return p1;
156 }
157
158 static struct ccl_rpn_node *search_elements (void)
159 {
160     struct ccl_rpn_node *p1;
161     struct ccl_token *lookahead;
162     if (KIND == CCL_TOK_LP)
163     {
164         ADVANCE;
165         p1 = find_spec ();
166         if (!p1)
167             return NULL;
168         if (KIND != CCL_TOK_RP)
169         {
170             ccl_error = CCL_ERR_RP_EXPECTED;
171             ccl_rpn_delete (p1);
172             return NULL;
173         }
174         ADVANCE;
175         return p1;
176     }
177     else if (KIND == CCL_TOK_SET)
178     {
179         ADVANCE;
180         if (KIND != CCL_TOK_TERM)
181         {
182             ccl_error = CCL_ERR_SETNAME_EXPECTED;
183             return NULL;
184         }
185         p1 = mk_node (SET);
186         p1->u.setname = copy_token_name (look_token);
187         ADVANCE;
188         return p1;
189     }
190     lookahead = look_token;
191
192     while (lookahead->kind==CCL_TOK_TERM || lookahead->kind==CCL_TOK_COMMA)
193         lookahead = lookahead->next;
194     if (lookahead->kind == CCL_TOK_REL || lookahead->kind == CCL_TOK_EQ)
195         return qualifiers (lookahead);
196     return search_terms ();
197 }
198
199 static struct ccl_rpn_node *find_spec (void)
200 {
201     struct ccl_rpn_node *p1, *p2, *pn;
202     if (!(p1 = search_elements ()))
203         return NULL;
204     while (1)
205     {
206         switch (KIND)
207         {
208         case CCL_TOK_AND:
209             ADVANCE;
210             p2 = search_elements ();
211             if (!p2)
212             {
213                 ccl_rpn_delete (p1);
214                 return NULL;
215             }
216             pn = mk_node (AND);
217             pn->u.p[0] = p1;
218             pn->u.p[1] = p2;
219             p1 = pn;
220             continue;
221         case CCL_TOK_OR:
222             ADVANCE;
223             p2 = search_elements ();
224             if (!p2)
225             {
226                 ccl_rpn_delete (p1);
227                 return NULL;
228             }
229             pn = mk_node (OR);
230             pn->u.p[0] = p1;
231             pn->u.p[1] = p2;
232             p1 = pn;
233             continue;
234         case CCL_TOK_NOT:
235             ADVANCE;
236             p2 = search_elements ();
237             if (!p2)
238             {
239                 ccl_rpn_delete (p1);
240                 return NULL;
241             }
242             pn = mk_node (NOT);
243             pn->u.p[0] = p1;
244             pn->u.p[1] = p2;
245             p1 = pn;
246             continue;
247         }
248         break;
249     }
250     return p1;
251 }
252
253 struct ccl_rpn_node *ccl_find (struct ccl_token *list,
254                                int *error, const char **pos)
255 {
256     struct ccl_rpn_node *p;
257
258     look_token = list;
259     p = find_spec ();
260     if (p && KIND != CCL_TOK_EOL)
261     {
262         if (KIND == CCL_TOK_RP)
263             ccl_error = CCL_ERR_BAD_RP;
264         else
265             ccl_error = CCL_ERR_OP_EXPECTED;
266         ccl_rpn_delete (p);
267         p = NULL;
268     }
269     *pos = look_token->name;
270     if (p)
271         *error = CCL_ERR_OK;
272     else
273         *error = ccl_error;
274     return p;
275 }
276
277 static void pr_tree (struct ccl_rpn_node *rpn)
278 {
279     switch (rpn->kind)
280     {
281     case TERM:
282         printf ("\"%s\"", rpn->u.t.term);
283         break;
284     case AND:
285         printf ("(");
286         pr_tree (rpn->u.p[0]);
287         printf (") and (");
288         pr_tree (rpn->u.p[1]);
289         printf (")");
290         break;
291     case OR:
292         printf ("(");
293         pr_tree (rpn->u.p[0]);
294         printf (") or (");
295         pr_tree (rpn->u.p[1]);
296         printf (")");
297         break;
298     case NOT:
299         printf ("(");
300         pr_tree (rpn->u.p[0]);
301         printf (") not (");
302         pr_tree (rpn->u.p[1]);
303         printf (")");
304         break;
305     case SET:
306         printf ("set=%s", rpn->u.setname);
307         break;
308     case PROX:
309         printf ("(");
310         pr_tree (rpn->u.p[0]);
311         printf (") prox (");
312         pr_tree (rpn->u.p[1]);
313         printf (")");
314         break;
315     default:
316         assert (0);
317     }
318 }
319
320 void ccl_find_str (const char *str, int *error, int *pos)
321 {
322     struct ccl_token *list, *li;
323     struct ccl_rpn_node *rpn;
324     const char *char_pos;
325
326     list = ccl_tokenize (str);
327 #if 0
328     for (li = list; li; li = li->next)
329         printf ("kind=%d, str='%.*s'\n", li->kind, li->len, li->name);
330 #endif
331     rpn = ccl_find (list, error, &char_pos);
332     if (! *error)
333     {
334         pr_tree (rpn);
335         printf ("\n");
336     }
337     else
338     {
339         *pos = char_pos - str;
340     }
341 }