Fixed bug in inetd code. The server listened on tcp:@:9999 even
[yaz-moved-to-github.git] / ccl / cclfind.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  */
44 /* CCL find (to rpn conversion)
45  * Europagate, 1995
46  *
47  * $Log: cclfind.c,v $
48  * Revision 1.9  1997-09-29 08:56:37  adam
49  * Changed CCL parser to be thread safe. New type, CCL_parser, declared
50  * and a create/destructers ccl_parser_create/ccl_parser/destory has
51  * been added.
52  *
53  * Revision 1.8  1997/09/01 08:48:11  adam
54  * New windows NT/95 port using MSV5.0. Only a few changes made
55  * to avoid warnings.
56  *
57  * Revision 1.7  1997/05/14 06:53:26  adam
58  * C++ support.
59  *
60  * Revision 1.6  1997/04/30 08:52:06  quinn
61  * Null
62  *
63  * Revision 1.5  1996/10/11  15:00:24  adam
64  * CCL parser from Europagate Email gateway 1.0.
65  *
66  * Revision 1.16  1996/01/08  08:41:13  adam
67  * Removed unused function.
68  *
69  * Revision 1.15  1995/07/20  08:14:34  adam
70  * Qualifiers were observed too often. Instead tokens are treated as
71  * qualifiers only when separated by comma.
72  *
73  * Revision 1.14  1995/05/16  09:39:26  adam
74  * LICENSE.
75  *
76  * Revision 1.13  1995/04/17  09:31:42  adam
77  * Improved handling of qualifiers. Aliases or reserved words.
78  *
79  * Revision 1.12  1995/03/20  15:27:43  adam
80  * Minor changes.
81  *
82  * Revision 1.11  1995/02/23  08:31:59  adam
83  * Changed header.
84  *
85  * Revision 1.9  1995/02/16  13:20:06  adam
86  * Spell fix.
87  *
88  * Revision 1.8  1995/02/14  19:59:42  adam
89  * Removed a syntax error.
90  *
91  * Revision 1.7  1995/02/14  19:55:10  adam
92  * Header files ccl.h/cclp.h are gone! They have been merged an
93  * moved to ../include/ccl.h.
94  * Node kind(s) in ccl_rpn_node have changed names.
95  *
96  * Revision 1.6  1995/02/14  16:20:55  adam
97  * Qualifiers are read from a file now.
98  *
99  * Revision 1.5  1995/02/14  14:12:41  adam
100  * Ranges for ordered qualfiers implemented (e.g. pd=1980-1990).
101  *
102  * Revision 1.4  1995/02/14  13:16:29  adam
103  * Left and/or right truncation implemented.
104  *
105  * Revision 1.3  1995/02/14  10:25:56  adam
106  * The constructions 'qualifier rel term ...' implemented.
107  *
108  * Revision 1.2  1995/02/13  15:15:07  adam
109  * Added handling of qualifiers. Not finished yet.
110  *
111  * Revision 1.1  1995/02/13  12:35:20  adam
112  * First version of CCL. Qualifiers aren't handled yet.
113  *
114  */
115
116 #include <stdio.h>
117 #include <stdlib.h>
118 #include <assert.h>
119 #include <string.h>
120
121 #include <ccl.h>
122
123 /* returns type of current lookahead */
124 #define KIND (cclp->look_token->kind)
125
126 /* move one token forward */
127 #define ADVANCE cclp->look_token = cclp->look_token->next
128
129 /* 
130  * qual_val_type: test for existance of attribute type/value pair.
131  * qa:     Attribute array
132  * type:   Type of attribute to search for
133  * value:  Value of attribute to seach for
134  * return: 1 if found; 0 otherwise.
135  */
136 static int qual_val_type (struct ccl_rpn_attr **qa, int type, int value)
137 {
138     int i;
139     struct ccl_rpn_attr *q;
140
141     if (!qa)
142         return 0;
143     for (i = 0;  (q=qa[i]); i++)
144         while (q)
145         {
146             if (q->type == type && q->value == value)
147                 return 1;
148             q = q->next;
149         }
150     return 0;
151 }
152
153 /*
154  * strxcat: concatenate strings.
155  * n:      Null-terminated Destination string 
156  * src:    Source string to be appended (not null-terminated)
157  * len:    Length of source string.
158  */
159 static void strxcat (char *n, const char *src, int len)
160 {
161     while (*n)
162         n++;
163     while (--len >= 0)
164         *n++ = *src++;
165     *n = '\0';
166 }
167
168 /*
169  * copy_token_name: Return copy of CCL token name
170  * tp:      Pointer to token info.
171  * return:  malloc(3) allocated copy of token name.
172  */
173 static char *copy_token_name (struct ccl_token *tp)
174 {
175     char *str = malloc (tp->len + 1);
176     assert (str);
177     memcpy (str, tp->name, tp->len);
178     str[tp->len] = '\0';
179     return str;
180 }
181
182 /*
183  * mk_node: Create RPN node.
184  * kind:   Type of node.
185  * return: pointer to allocated node.
186  */
187 static struct ccl_rpn_node *mk_node (int kind)
188 {
189     struct ccl_rpn_node *p;
190     p = malloc (sizeof(*p));
191     assert (p);
192     p->kind = kind;
193     return p;
194 }
195
196 /*
197  * ccl_rpn_delete: Delete RPN tree.
198  * rpn:   Pointer to tree.
199  */
200 void ccl_rpn_delete (struct ccl_rpn_node *rpn)
201 {
202     struct ccl_rpn_attr *attr, *attr1;
203     if (!rpn)
204         return;
205     switch (rpn->kind)
206     {
207     case CCL_RPN_AND:
208     case CCL_RPN_OR:
209     case CCL_RPN_NOT:
210         ccl_rpn_delete (rpn->u.p[0]);
211         ccl_rpn_delete (rpn->u.p[1]);
212         break;
213     case CCL_RPN_TERM:
214         free (rpn->u.t.term);
215         for (attr = rpn->u.t.attr_list; attr; attr = attr1)
216         {
217             attr1 = attr->next;
218             free (attr);
219         }
220         break;
221     case CCL_RPN_SET:
222         free (rpn->u.setname);
223         break;
224     case CCL_RPN_PROX:
225         ccl_rpn_delete (rpn->u.p[0]);
226         ccl_rpn_delete (rpn->u.p[1]);
227         break;
228     }
229     free (rpn);
230 }
231
232 static struct ccl_rpn_node *find_spec (CCL_parser cclp,
233                                        struct ccl_rpn_attr **qa);
234 static struct ccl_rpn_node *search_terms (CCL_parser cclp,
235                                           struct ccl_rpn_attr **qa);
236
237 /*
238  * add_attr: Add attribute (type/value) to RPN term node.
239  * p:     RPN node of type term.
240  * type:  Type of attribute
241  * value: Value of attribute
242  */
243 static void add_attr (struct ccl_rpn_node *p, int type, int value)
244 {
245     struct ccl_rpn_attr *n;
246
247     n = malloc (sizeof(*n));
248     assert (n);
249     n->type = type;
250     n->value = value;
251     n->next = p->u.t.attr_list;
252     p->u.t.attr_list = n;
253 }
254
255 /*
256  * search_term: Parse CCL search term. 
257  * cclp:   CCL Parser
258  * qa:     Qualifier attributes already applied.
259  * return: pointer to node(s); NULL on error.
260  */
261 static struct ccl_rpn_node *search_term (CCL_parser cclp,
262                                          struct ccl_rpn_attr **qa)
263 {
264     struct ccl_rpn_node *p;
265     struct ccl_token *lookahead = cclp->look_token;
266     int len = 0;
267     size_t no, i;
268     int left_trunc = 0;
269     int right_trunc = 0;
270     int mid_trunc = 0;
271     int relation_value = -1;
272     int position_value = -1;
273     int structure_value = -1;
274     int truncation_value = -1;
275     int completeness_value = -1;
276
277     if (KIND != CCL_TOK_TERM)
278     {
279         cclp->error_code = CCL_ERR_TERM_EXPECTED;
280         return NULL;
281     }
282     /* create the term node, but wait a moment before adding the term */
283     p = mk_node (CCL_RPN_TERM);
284     p->u.t.attr_list = NULL;
285     p->u.t.term = NULL;
286
287     if (!qa)
288     {
289         /* no qualifier(s) applied. Use 'term' if it is defined */
290
291         qa = malloc (2*sizeof(*qa));
292         assert (qa);
293         qa[0] = ccl_qual_search (cclp, "term", 4);
294         qa[1] = NULL;
295     }
296
297     /* go through all attributes and add them to the attribute list */
298     for (i=0; qa && qa[i]; i++)
299     {
300         struct ccl_rpn_attr *attr;
301
302         for (attr = qa[i]; attr; attr = attr->next)
303             if (attr->value > 0)
304             {   /* deal only with REAL attributes (positive) */
305                 switch (attr->type)
306                 {
307                 case CCL_BIB1_REL:
308                     if (relation_value != -1)
309                         continue;
310                     relation_value = attr->value;
311                     break;
312                 case CCL_BIB1_POS:
313                     if (position_value != -1)
314                         continue;
315                     position_value = attr->value;
316                     break;
317                 case CCL_BIB1_STR:
318                     if (structure_value != -1)
319                         continue;
320                     structure_value = attr->value;
321                     break;
322                 case CCL_BIB1_TRU:
323                     if (truncation_value != -1)
324                         continue;
325                     truncation_value = attr->value;
326                     break;
327                 case CCL_BIB1_COM:
328                     if (completeness_value != -1)
329                         continue;
330                     completeness_value = attr->value;
331                     break;
332                 }
333                 add_attr (p, attr->type, attr->value);
334             }
335     }
336     /* go through each TERM token. If no truncation attribute is yet
337        met, then look for left/right truncation markers (?) and
338        set left_trunc/right_trunc/mid_trunc accordingly */
339     for (no = 0; lookahead->kind == CCL_TOK_TERM; no++)
340     {
341         for (i = 0; i<lookahead->len; i++)
342             if (truncation_value == -1 && lookahead->name[i] == '?')
343             {
344                 if (no == 0 && i == 0 && lookahead->len >= 1)
345                     left_trunc = 1;
346                 else if (lookahead->next->kind != CCL_TOK_TERM &&
347                          i == lookahead->len-1 && i >= 1)
348                     right_trunc = 1;
349                 else
350                     mid_trunc = 1;
351             }
352         len += 1+lookahead->len;
353         lookahead = lookahead->next;
354     }
355     /* len now holds the number of characters in the RPN term */
356     /* no holds the number of CCL tokens (1 or more) */
357
358     if (structure_value == -1 && 
359         qual_val_type (qa, CCL_BIB1_STR, CCL_BIB1_STR_WP))
360     {   /* no structure attribute met. Apply either structure attribute 
361            WORD or PHRASE depending on number of CCL tokens */
362         if (no == 1)
363             add_attr (p, CCL_BIB1_STR, 2);
364         else
365             add_attr (p, CCL_BIB1_STR, 1);
366     }
367
368     /* make the RPN token */
369     p->u.t.term = malloc (len);
370     assert (p->u.t.term);
371     p->u.t.term[0] = '\0';
372     for (i = 0; i<no; i++)
373     {
374         const char *src_str = cclp->look_token->name;
375         int src_len = cclp->look_token->len;
376         
377         if (i == 0 && left_trunc)
378         {
379             src_len--;
380             src_str++;
381         }
382         else if (i == no-1 && right_trunc)
383             src_len--;
384         if (i)
385             strcat (p->u.t.term, " ");
386         strxcat (p->u.t.term, src_str, src_len);
387         ADVANCE;
388     }
389     if (left_trunc && right_trunc)
390     {
391         if (!qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_BOTH))
392         {
393             cclp->error_code = CCL_ERR_TRUNC_NOT_BOTH;
394             free (qa);
395             ccl_rpn_delete (p);
396             return NULL;
397         }
398         add_attr (p, CCL_BIB1_TRU, 3);
399     }
400     else if (right_trunc)
401     {
402         if (!qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_RIGHT))
403         {
404             cclp->error_code = CCL_ERR_TRUNC_NOT_RIGHT;
405             free (qa);
406             ccl_rpn_delete (p);
407             return NULL;
408         }
409         add_attr (p, CCL_BIB1_TRU, 1);
410     }
411     else if (left_trunc)
412     {
413         if (!qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_LEFT))
414         {
415             cclp->error_code = CCL_ERR_TRUNC_NOT_LEFT;
416             free (qa);
417             ccl_rpn_delete (p);
418             return NULL;
419         }
420         add_attr (p, CCL_BIB1_TRU, 2);
421     }
422     else
423     {
424         if (qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_NONE))
425             add_attr (p, CCL_BIB1_TRU, 100);
426     }
427     return p;
428 }
429
430 /*
431  * qualifiers: Parse CCL qualifiers and search terms. 
432  * cclp:   CCL Parser
433  * la:     Token pointer to RELATION token.
434  * qa:     Qualifier attributes already applied.
435  * return: pointer to node(s); NULL on error.
436  */
437 static struct ccl_rpn_node *qualifiers (CCL_parser cclp, struct ccl_token *la,
438                                         struct ccl_rpn_attr **qa)
439 {
440     struct ccl_token *lookahead = cclp->look_token;
441     struct ccl_rpn_attr **ap;
442     int no = 0;
443     int i, rel;
444 #if 0
445     if (qa)
446     {
447         cclp->error_code = CCL_ERR_DOUBLE_QUAL;
448         return NULL;
449     }
450 #endif
451     for (lookahead = cclp->look_token; lookahead != la;
452          lookahead=lookahead->next)
453         no++;
454     if (qa)
455         for (i=0; qa[i]; i++)
456             no++;
457     ap = malloc ((no+1) * sizeof(*ap));
458     assert (ap);
459     for (i = 0; cclp->look_token != la; i++)
460     {
461         ap[i] = ccl_qual_search (cclp, cclp->look_token->name,
462                                  cclp->look_token->len);
463         if (!ap[i])
464         {
465             cclp->error_code = CCL_ERR_UNKNOWN_QUAL;
466             free (ap);
467             return NULL;
468         }
469         ADVANCE;
470         if (KIND == CCL_TOK_COMMA)
471             ADVANCE;
472     }
473     if (qa)
474         while (*qa)
475             ap[i++] = *qa++;
476     ap[i] = NULL;
477     if (!qual_val_type (ap, CCL_BIB1_REL, CCL_BIB1_REL_ORDER))
478     {                
479         /* unordered relation */
480         struct ccl_rpn_node *p;
481         if (KIND != CCL_TOK_EQ)
482         {
483             cclp->error_code = CCL_ERR_EQ_EXPECTED;
484             free (ap);
485             return NULL;
486         }
487         ADVANCE;
488         if (KIND == CCL_TOK_LP)
489         {
490             ADVANCE;
491             if (!(p = find_spec (cclp, ap)))
492             {
493                 free (ap);
494                 return NULL;
495             }
496             if (KIND != CCL_TOK_RP)
497             {
498                 cclp->error_code = CCL_ERR_RP_EXPECTED;
499                 ccl_rpn_delete (p);
500                 free (ap);
501                 return NULL;
502             }
503             ADVANCE;
504         }
505         else
506             p = search_terms (cclp, ap);
507         free (ap);
508         return p;
509     }
510     rel = 0;
511     if (cclp->look_token->len == 1)
512     {
513         if (cclp->look_token->name[0] == '<')
514             rel = 1;
515         else if (cclp->look_token->name[0] == '=')
516             rel = 3;
517         else if (cclp->look_token->name[0] == '>')
518             rel = 5;
519     }
520     else if (cclp->look_token->len == 2)
521     {
522         if (!memcmp (cclp->look_token->name, "<=", 2))
523             rel = 2;
524         else if (!memcmp (cclp->look_token->name, ">=", 2))
525             rel = 4;
526         else if (!memcmp (cclp->look_token->name, "<>", 2))
527             rel = 6;
528     }
529     if (!rel)
530         cclp->error_code = CCL_ERR_BAD_RELATION;
531     else
532     {
533         struct ccl_rpn_node *p;
534
535         ADVANCE;                      /* skip relation */
536         if (KIND == CCL_TOK_TERM &&
537             cclp->look_token->next->kind == CCL_TOK_MINUS)
538         {
539             struct ccl_rpn_node *p1;
540             if (!(p1 = search_term (cclp, ap)))
541             {
542                 free (ap);
543                 return NULL;
544             }
545             ADVANCE;                   /* skip '-' */
546             if (KIND == CCL_TOK_TERM)  /* = term - term  ? */
547             {
548                 struct ccl_rpn_node *p2;
549                 
550                 if (!(p2 = search_term (cclp, ap)))
551                 {
552                     ccl_rpn_delete (p1);
553                     free (ap);
554                     return NULL;
555                 }
556                 p = mk_node (CCL_RPN_AND);
557                 p->u.p[0] = p1;
558                 add_attr (p1, CCL_BIB1_REL, 4);
559                 p->u.p[1] = p2;
560                 add_attr (p2, CCL_BIB1_REL, 2);
561                 free (ap);
562                 return p;
563             }
564             else                       /* = term -    */
565             {
566                 add_attr (p1, CCL_BIB1_REL, 4);
567                 free (ap);
568                 return p1;
569             }
570         }
571         else if (KIND == CCL_TOK_MINUS)   /* = - term  ? */
572         {
573             ADVANCE;
574             if (!(p = search_term (cclp, ap)))
575             {
576                 free (ap);
577                 return NULL;
578             }
579             add_attr (p, CCL_BIB1_REL, 2);
580             free (ap);
581             return p;
582         }
583         else if (KIND == CCL_TOK_LP)
584         {
585             ADVANCE;
586             if (!(p = find_spec (cclp, ap)))
587             {
588                 free (ap);
589                 return NULL;
590             }
591             if (KIND != CCL_TOK_RP)
592             {
593                 cclp->error_code = CCL_ERR_RP_EXPECTED;
594                 ccl_rpn_delete (p);
595                 free (ap);
596                 return NULL;
597             }
598             ADVANCE;
599             free (ap);
600             return p;
601         }
602         else
603         {
604             if (!(p = search_terms (cclp, ap)))
605             {
606                 free (ap);
607                 return NULL;
608             }
609             add_attr (p, CCL_BIB1_REL, rel);
610             free (ap);
611             return p;
612         }
613         cclp->error_code = CCL_ERR_TERM_EXPECTED;
614     }
615     free (ap);
616     return NULL;
617 }
618
619 /*
620  * search_terms: Parse CCL search terms - including proximity.
621  * cclp:   CCL Parser
622  * qa:     Qualifier attributes already applied.
623  * return: pointer to node(s); NULL on error.
624  */
625 static struct ccl_rpn_node *search_terms (CCL_parser cclp,
626                                           struct ccl_rpn_attr **qa)
627 {
628     struct ccl_rpn_node *p1, *p2, *pn;
629     p1 = search_term (cclp, qa);
630     if (!p1)
631         return NULL;
632     while (1)
633     {
634         if (KIND == CCL_TOK_PROX)
635         {
636             ADVANCE;
637             p2 = search_term (cclp, qa);
638             if (!p2)
639             {
640                 ccl_rpn_delete (p1);
641                 return NULL;
642             }
643             pn = mk_node (CCL_RPN_PROX);
644             pn->u.p[0] = p1;
645             pn->u.p[1] = p2;
646             p1 = pn;
647         }
648         else if (KIND == CCL_TOK_TERM)
649         {
650             p2 = search_term (cclp, qa);
651             if (!p2)
652             {
653                 ccl_rpn_delete (p1);
654                 return NULL;
655             }
656             pn = mk_node (CCL_RPN_PROX);
657             pn->u.p[0] = p1;
658             pn->u.p[1] = p2;
659             p1 = pn;
660         }
661         else
662             break;
663     }
664     return p1;
665 }
666
667 /*
668  * search_elements: Parse CCL search elements
669  * cclp:   CCL Parser
670  * qa:     Qualifier attributes already applied.
671  * return: pointer to node(s); NULL on error.
672  */
673 static struct ccl_rpn_node *search_elements (CCL_parser cclp,
674                                              struct ccl_rpn_attr **qa)
675 {
676     struct ccl_rpn_node *p1;
677     struct ccl_token *lookahead;
678     if (KIND == CCL_TOK_LP)
679     {
680         ADVANCE;
681         p1 = find_spec (cclp, qa);
682         if (!p1)
683             return NULL;
684         if (KIND != CCL_TOK_RP)
685         {
686             cclp->error_code = CCL_ERR_RP_EXPECTED;
687             ccl_rpn_delete (p1);
688             return NULL;
689         }
690         ADVANCE;
691         return p1;
692     }
693     else if (KIND == CCL_TOK_SET)
694     {
695         ADVANCE;
696         if (KIND == CCL_TOK_EQ)
697             ADVANCE;
698         if (KIND != CCL_TOK_TERM)
699         {
700             cclp->error_code = CCL_ERR_SETNAME_EXPECTED;
701             return NULL;
702         }
703         p1 = mk_node (CCL_RPN_SET);
704         p1->u.setname = copy_token_name (cclp->look_token);
705         ADVANCE;
706         return p1;
707     }
708     lookahead = cclp->look_token;
709
710     while (lookahead->kind==CCL_TOK_TERM)
711     {
712         lookahead = lookahead->next;
713         if (lookahead->kind == CCL_TOK_REL || lookahead->kind == CCL_TOK_EQ)
714             return qualifiers (cclp, lookahead, qa);
715         if (lookahead->kind != CCL_TOK_COMMA)
716             break;
717         lookahead = lookahead->next;
718     }
719     return search_terms (cclp, qa);
720 }
721
722 /*
723  * find_spec: Parse CCL find specification
724  * cclp:   CCL Parser
725  * qa:     Qualifier attributes already applied.
726  * return: pointer to node(s); NULL on error.
727  */
728 static struct ccl_rpn_node *find_spec (CCL_parser cclp,
729                                        struct ccl_rpn_attr **qa)
730 {
731     struct ccl_rpn_node *p1, *p2, *pn;
732     if (!(p1 = search_elements (cclp, qa)))
733         return NULL;
734     while (1)
735     {
736         switch (KIND)
737         {
738         case CCL_TOK_AND:
739             ADVANCE;
740             p2 = search_elements (cclp, qa);
741             if (!p2)
742             {
743                 ccl_rpn_delete (p1);
744                 return NULL;
745             }
746             pn = mk_node (CCL_RPN_AND);
747             pn->u.p[0] = p1;
748             pn->u.p[1] = p2;
749             p1 = pn;
750             continue;
751         case CCL_TOK_OR:
752             ADVANCE;
753             p2 = search_elements (cclp, qa);
754             if (!p2)
755             {
756                 ccl_rpn_delete (p1);
757                 return NULL;
758             }
759             pn = mk_node (CCL_RPN_OR);
760             pn->u.p[0] = p1;
761             pn->u.p[1] = p2;
762             p1 = pn;
763             continue;
764         case CCL_TOK_NOT:
765             ADVANCE;
766             p2 = search_elements (cclp, qa);
767             if (!p2)
768             {
769                 ccl_rpn_delete (p1);
770                 return NULL;
771             }
772             pn = mk_node (CCL_RPN_NOT);
773             pn->u.p[0] = p1;
774             pn->u.p[1] = p2;
775             p1 = pn;
776             continue;
777         }
778         break;
779     }
780     return p1;
781 }
782
783 struct ccl_rpn_node *ccl_parser_find (CCL_parser cclp, struct ccl_token *list)
784 {
785     struct ccl_rpn_node *p;
786
787     cclp->look_token = list;
788     p = find_spec (cclp, NULL);
789     if (p && KIND != CCL_TOK_EOL)
790     {
791         if (KIND == CCL_TOK_RP)
792             cclp->error_code = CCL_ERR_BAD_RP;
793         else
794             cclp->error_code = CCL_ERR_OP_EXPECTED;
795         ccl_rpn_delete (p);
796         p = NULL;
797     }
798     cclp->error_pos = cclp->look_token->name;
799     if (p)
800         cclp->error_code = CCL_ERR_OK;
801     else
802         cclp->error_code = cclp->error_code;
803     return p;
804 }
805
806 /*
807  * ccl_find: Parse CCL find - token representation
808  * bibset:  Bibset to be used for the parsing
809  * list:    List of tokens
810  * error:   Pointer to integer. Holds error no. on completion.
811  * pos:     Pointer to char position. Holds approximate error position.
812  * return:  RPN tree on successful completion; NULL otherwise.
813  */
814 struct ccl_rpn_node *ccl_find (CCL_bibset bibset, struct ccl_token *list,
815                                int *error, const char **pos)
816 {
817     struct ccl_rpn_node *p;
818     CCL_parser cclp = ccl_parser_create ();
819
820     cclp->bibset = bibset;
821
822     p = ccl_parser_find (cclp, list);
823
824     *error = cclp->error_code;
825     *pos = cclp->error_pos;
826
827     ccl_parser_destroy (cclp);
828
829     return p;
830 }
831
832 /*
833  * ccl_find_str: Parse CCL find - string representation
834  * bibset:  Bibset to be used for the parsing
835  * str:     String to be parsed
836  * error:   Pointer to integer. Holds error no. on completion.
837  * pos:     Pointer to char position. Holds approximate error position.
838  * return:  RPN tree on successful completion; NULL otherwise.
839  */
840 struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
841                                    int *error, int *pos)
842 {
843     CCL_parser cclp = ccl_parser_create ();
844     struct ccl_token *list;
845     struct ccl_rpn_node *p;
846
847     cclp->bibset = bibset;
848
849     list = ccl_parser_tokenize (cclp, str);
850     p = ccl_parser_find (cclp, list);
851
852     *error = cclp->error_code;
853     if (*error)
854         *pos = cclp->error_pos - str;
855     ccl_parser_destroy (cclp);
856     return p;
857 }