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