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