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