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