Added handling of qualifiers. Not finished yet.
[egate.git] / ccl / cclfind.c
1 /* CCL find (to rpn conversion)
2  * Europagate, 1995
3  *
4  * $Log: cclfind.c,v $
5  * Revision 1.2  1995/02/13 15:15:07  adam
6  * Added handling of qualifiers. Not finished yet.
7  *
8  * Revision 1.1  1995/02/13  12:35:20  adam
9  * First version of CCL. Qualifiers aren't handled yet.
10  *
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <assert.h>
16 #include <string.h>
17
18 #include "cclp.h"
19
20 static struct ccl_token *look_token;
21 static int ccl_error;
22 static CCL_bibset bibset;
23
24 #define KIND (look_token->kind)
25 #define ADVANCE look_token = look_token->next
26 #define ADVX(x) x=(x)->next
27
28 static void strxcat (char *n, const char *src, int len)
29 {
30     while (*n)
31         n++;
32     while (--len >= 0)
33         *n++ = *src++;
34     *n = '\0';
35 }
36
37 static char *copy_token_name (struct ccl_token *tp)
38 {
39     char *str = malloc (tp->len + 1);
40     assert (str);
41     memcpy (str, tp->name, tp->len);
42     str[tp->len] = '\0';
43     return str;
44 }
45
46 static struct ccl_rpn_node *mk_node (enum rpn_node_kind kind)
47 {
48     struct ccl_rpn_node *p;
49     p = malloc (sizeof(*p));
50     assert (p);
51     p->kind = kind;
52     return p;
53 }
54
55 void ccl_rpn_delete (struct ccl_rpn_node *rpn)
56 {
57     struct ccl_rpn_attr *attr, *attr1;
58     if (!rpn)
59         return;
60     switch (rpn->kind)
61     {
62     case AND:
63     case OR:
64     case NOT:
65         ccl_rpn_delete (rpn->u.p[0]);
66         ccl_rpn_delete (rpn->u.p[1]);
67         break;
68     case TERM:
69         free (rpn->u.t.term);
70         for (attr = rpn->u.t.attr_list; attr; attr = attr1)
71         {
72             attr1 = attr->next;
73             free (attr);
74         }
75         break;
76     case SET:
77         free (rpn->u.setname);
78         break;
79     case PROX:
80         ccl_rpn_delete (rpn->u.p[0]);
81         ccl_rpn_delete (rpn->u.p[1]);
82         break;
83     }
84     free (rpn);
85 }
86
87 static struct ccl_rpn_node *find_spec (struct ccl_qualifier **qa);
88 static struct ccl_rpn_node *search_terms (struct ccl_qualifier **qa);
89
90 static void add_attr (struct ccl_rpn_node *p, int type, int value)
91 {
92     struct ccl_rpn_attr *n;
93
94     n = malloc (sizeof(*n));
95     assert (n);
96     n->type = type;
97     n->value = value;
98     n->next = p->u.t.attr_list;
99     p->u.t.attr_list = n;
100 }
101
102 static struct ccl_rpn_node *search_term (struct ccl_qualifier **qa)
103 {
104     struct ccl_rpn_node *p;
105     struct ccl_token *lookahead = look_token;
106     int len = 0;
107     int no = 0;
108
109     if (KIND != CCL_TOK_TERM)
110     {
111         ccl_error = CCL_ERR_TERM_EXPECTED;
112         return NULL;
113     }
114     while (lookahead->kind == CCL_TOK_TERM)
115     {
116         no++;
117         len += 1+lookahead->len;
118         lookahead = lookahead->next;
119     }
120     p = mk_node (TERM);
121     p->u.t.term = malloc (len);
122     p->u.t.attr_list = NULL;
123     p->u.t.term[0] = '\0';
124     assert (p->u.t.term);
125     strxcat (p->u.t.term, look_token->name, look_token->len);
126     ADVANCE;
127     while (KIND == CCL_TOK_TERM)
128     {
129         strcat (p->u.t.term, " ");
130         strxcat (p->u.t.term, look_token->name, look_token->len);
131         ADVANCE;
132     }
133     if (qa)
134     {
135         int i;
136         /* use ... */
137         for (i=0; qa[i]; i++)
138         {
139             int j;
140             for (j=0; j<qa[i]->nuse; j++)
141                 add_attr (p, 1, qa[i]->use[j]);
142         }
143         /* structure ... */
144         if (qa[0]->structure == 0)
145         {
146             if (no == 1)
147                 add_attr (p, 4, 2);
148             else
149                 add_attr (p, 4, 1);
150         }
151         else if (qa[0]->structure > 0)
152             add_attr (p, 4, qa[0]->structure);
153     }
154     return p;
155 }
156
157 static struct ccl_rpn_node *qualifiers (struct ccl_token *la,
158                                         struct ccl_qualifier **qa)
159 {
160     struct ccl_token *lookahead = look_token;
161     struct ccl_qualifier **ap;
162     int no = 1;
163     int i;
164
165     if (qa)
166     {
167         ccl_error = CCL_ERR_DOBBLE_QUAL;
168         return NULL;
169     }
170     for (lookahead = look_token; lookahead != la; lookahead=lookahead->next)
171         no++;
172     ap = malloc (no * sizeof(*ap));
173     assert (ap);
174     for (i=0; look_token != la; i++)
175     {
176         ap[i] = ccl_qual_search (bibset, lookahead->name);
177         if (!ap[i])
178         {
179             ccl_error = CCL_ERR_UNKNOWN_QUAL;
180             free (ap);
181             return NULL;
182         }
183         ADVANCE;
184         if (KIND == CCL_TOK_COMMA)
185             ADVANCE;
186     }
187     ap[i] = NULL;
188     if (ap[0]->relation != 0)  
189     {                
190         /* unordered relation */
191         struct ccl_rpn_node *p;
192         if (KIND != CCL_TOK_EQ)
193         {
194             ccl_error = CCL_ERR_EQ_EXPECTED;
195             free (ap);
196             return NULL;
197         }
198         ADVANCE;
199         if (KIND == CCL_TOK_LP)
200         {
201             ADVANCE;
202             if (!(p = find_spec (ap)))
203             {
204                 free (ap);
205                 return NULL;
206             }
207             if (KIND != CCL_TOK_RP)
208             {
209                 ccl_error = CCL_ERR_RP_EXPECTED;
210                 ccl_rpn_delete (p);
211                 free (ap);
212                 return NULL;
213             }
214             ADVANCE;
215         }
216         else
217             p = search_terms (ap);
218         free (ap);
219         return p;
220     }
221     /* ordered relation ... */
222     assert (0);
223     free (ap);
224     return NULL;
225 }
226
227 static struct ccl_rpn_node *search_terms (struct ccl_qualifier **qa)
228 {
229     struct ccl_rpn_node *p1, *p2, *pn;
230     p1 = search_term (qa);
231     if (!p1)
232         return NULL;
233     while (1)
234     {
235         if (KIND == CCL_TOK_PROX)
236         {
237             ADVANCE;
238             p2 = search_term (qa);
239             if (!p2)
240             {
241                 ccl_rpn_delete (p1);
242                 return NULL;
243             }
244             pn = mk_node (PROX);
245             pn->u.p[0] = p1;
246             pn->u.p[1] = p2;
247             p1 = pn;
248         }
249         else if (KIND == CCL_TOK_TERM)
250         {
251             p2 = search_term (qa);
252             if (!p2)
253             {
254                 ccl_rpn_delete (p1);
255                 return NULL;
256             }
257             pn = mk_node (PROX);
258             pn->u.p[0] = p1;
259             pn->u.p[1] = p2;
260             p1 = pn;
261         }
262         else
263             break;
264     }
265     return p1;
266 }
267
268 static struct ccl_rpn_node *search_elements (struct ccl_qualifier **qa)
269 {
270     struct ccl_rpn_node *p1;
271     struct ccl_token *lookahead;
272     if (KIND == CCL_TOK_LP)
273     {
274         ADVANCE;
275         p1 = find_spec (qa);
276         if (!p1)
277             return NULL;
278         if (KIND != CCL_TOK_RP)
279         {
280             ccl_error = CCL_ERR_RP_EXPECTED;
281             ccl_rpn_delete (p1);
282             return NULL;
283         }
284         ADVANCE;
285         return p1;
286     }
287     else if (KIND == CCL_TOK_SET)
288     {
289         ADVANCE;
290         if (KIND != CCL_TOK_TERM)
291         {
292             ccl_error = CCL_ERR_SETNAME_EXPECTED;
293             return NULL;
294         }
295         p1 = mk_node (SET);
296         p1->u.setname = copy_token_name (look_token);
297         ADVANCE;
298         return p1;
299     }
300     lookahead = look_token;
301
302     while (lookahead->kind==CCL_TOK_TERM || lookahead->kind==CCL_TOK_COMMA)
303         lookahead = lookahead->next;
304     if (lookahead->kind == CCL_TOK_REL || lookahead->kind == CCL_TOK_EQ)
305         return qualifiers (lookahead, qa);
306     return search_terms (qa);
307 }
308
309 static struct ccl_rpn_node *find_spec (struct ccl_qualifier **qa)
310 {
311     struct ccl_rpn_node *p1, *p2, *pn;
312     if (!(p1 = search_elements (qa)))
313         return NULL;
314     while (1)
315     {
316         switch (KIND)
317         {
318         case CCL_TOK_AND:
319             ADVANCE;
320             p2 = search_elements (qa);
321             if (!p2)
322             {
323                 ccl_rpn_delete (p1);
324                 return NULL;
325             }
326             pn = mk_node (AND);
327             pn->u.p[0] = p1;
328             pn->u.p[1] = p2;
329             p1 = pn;
330             continue;
331         case CCL_TOK_OR:
332             ADVANCE;
333             p2 = search_elements (qa);
334             if (!p2)
335             {
336                 ccl_rpn_delete (p1);
337                 return NULL;
338             }
339             pn = mk_node (OR);
340             pn->u.p[0] = p1;
341             pn->u.p[1] = p2;
342             p1 = pn;
343             continue;
344         case CCL_TOK_NOT:
345             ADVANCE;
346             p2 = search_elements (qa);
347             if (!p2)
348             {
349                 ccl_rpn_delete (p1);
350                 return NULL;
351             }
352             pn = mk_node (NOT);
353             pn->u.p[0] = p1;
354             pn->u.p[1] = p2;
355             p1 = pn;
356             continue;
357         }
358         break;
359     }
360     return p1;
361 }
362
363 struct ccl_rpn_node *ccl_find (CCL_bibset abibset, struct ccl_token *list,
364                                int *error, const char **pos)
365 {
366     struct ccl_rpn_node *p;
367
368     look_token = list;
369     bibset = abibset;
370     p = find_spec (NULL);
371     if (p && KIND != CCL_TOK_EOL)
372     {
373         if (KIND == CCL_TOK_RP)
374             ccl_error = CCL_ERR_BAD_RP;
375         else
376             ccl_error = CCL_ERR_OP_EXPECTED;
377         ccl_rpn_delete (p);
378         p = NULL;
379     }
380     *pos = look_token->name;
381     if (p)
382         *error = CCL_ERR_OK;
383     else
384         *error = ccl_error;
385     return p;
386 }
387
388 static void pr_tree (struct ccl_rpn_node *rpn)
389 {
390
391     switch (rpn->kind)
392     {
393     case TERM:
394         printf ("\"%s\"", rpn->u.t.term);
395         if (rpn->u.t.attr_list)
396         {
397             struct ccl_rpn_attr *attr;
398             printf ("[ ");
399             for (attr = rpn->u.t.attr_list; attr; attr = attr->next)
400                 printf ("%d=%d ", attr->type, attr->value);
401             printf ("] ");
402         }
403         break;
404     case AND:
405         printf ("(");
406         pr_tree (rpn->u.p[0]);
407         printf (") and (");
408         pr_tree (rpn->u.p[1]);
409         printf (")");
410         break;
411     case OR:
412         printf ("(");
413         pr_tree (rpn->u.p[0]);
414         printf (") or (");
415         pr_tree (rpn->u.p[1]);
416         printf (")");
417         break;
418     case NOT:
419         printf ("(");
420         pr_tree (rpn->u.p[0]);
421         printf (") not (");
422         pr_tree (rpn->u.p[1]);
423         printf (")");
424         break;
425     case SET:
426         printf ("set=%s", rpn->u.setname);
427         break;
428     case PROX:
429         printf ("(");
430         pr_tree (rpn->u.p[0]);
431         printf (") prox (");
432         pr_tree (rpn->u.p[1]);
433         printf (")");
434         break;
435     default:
436         assert (0);
437     }
438 }
439
440 struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
441                                    int *error, int *pos)
442 {
443     struct ccl_token *list, *li;
444     struct ccl_rpn_node *rpn;
445     const char *char_pos;
446
447     list = ccl_tokenize (str);
448 #if 0
449     for (li = list; li; li = li->next)
450         printf ("kind=%d, str='%.*s'\n", li->kind, li->len, li->name);
451 #endif
452     rpn = ccl_find (bibset, list, error, &char_pos);
453     if (! *error)
454     {
455         pr_tree (rpn);
456         printf ("\n");
457     }
458     else
459     {
460         *pos = char_pos - str;
461     }
462     return rpn;
463 }