Restructure qualifier handling so we can have more rules per-field -
[yaz-moved-to-github.git] / src / cclqual.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 /** 
45  * \file cclqual.c
46  * \brief Implements CCL qualifier utilities
47  */
48 /* CCL qualifiers
49  * Europagate, 1995
50  *
51  * $Id: cclqual.c,v 1.8 2007-04-30 11:33:49 adam Exp $
52  *
53  * Old Europagate Log:
54  *
55  * Revision 1.9  1995/05/16  09:39:27  adam
56  * LICENSE.
57  *
58  * Revision 1.8  1995/05/11  14:03:57  adam
59  * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
60  * New variable ccl_case_sensitive, which controls whether reserved
61  * words and field names are case sensitive or not.
62  *
63  * Revision 1.7  1995/04/17  09:31:46  adam
64  * Improved handling of qualifiers. Aliases or reserved words.
65  *
66  * Revision 1.6  1995/02/23  08:32:00  adam
67  * Changed header.
68  *
69  * Revision 1.4  1995/02/14  19:55:12  adam
70  * Header files ccl.h/cclp.h are gone! They have been merged an
71  * moved to ../include/ccl.h.
72  * Node kind(s) in ccl_rpn_node have changed names.
73  *
74  * Revision 1.3  1995/02/14  16:20:56  adam
75  * Qualifiers are read from a file now.
76  *
77  * Revision 1.2  1995/02/14  10:25:56  adam
78  * The constructions 'qualifier rel term ...' implemented.
79  *
80  * Revision 1.1  1995/02/13  15:15:07  adam
81  * Added handling of qualifiers. Not finished yet.
82  *
83  */
84
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88
89 #include "cclp.h"
90
91 /** CCL Qualifier */
92 struct ccl_qualifier {
93     char *name;
94     int no_sub;
95     struct ccl_qualifier **sub;
96     struct ccl_rpn_attr *attr_list;
97     struct ccl_qualifier *next;
98 };
99
100
101 /** Definition of CCL_bibset pointer */
102 struct ccl_qualifiers {
103     struct ccl_qualifier *list;
104     struct ccl_qualifier_special *special;
105 };
106
107
108 /** CCL Qualifier special */
109 struct ccl_qualifier_special {
110     char *name;
111     char *value;
112     struct ccl_qualifier_special *next;
113 };
114
115
116 static struct ccl_qualifier *ccl_qual_lookup(CCL_bibset b,
117                                              const char *n, size_t len)
118 {
119     struct ccl_qualifier *q;
120     for (q = b->list; q; q = q->next)
121         if (len == strlen(q->name) && !memcmp(q->name, n, len))
122             break;
123     return q;
124 }
125
126 /** \brief specifies special qualifier
127     \param bibset Bibset
128     \param n name of special (without leading @)
129     \param v value of special
130 */
131 void ccl_qual_add_special(CCL_bibset bibset, const char *n, const char *v)
132 {
133     struct ccl_qualifier_special *p;
134     const char *pe;
135
136     for (p = bibset->special; p && strcmp(p->name, n); p = p->next)
137         ;
138     if (p)
139         xfree(p->value);
140     else
141     {
142         p = (struct ccl_qualifier_special *) xmalloc(sizeof(*p));
143         p->name = xstrdup(n);
144         p->value = 0;
145         p->next = bibset->special;
146         bibset->special = p;
147     }
148     while (strchr(" \t", *v))
149         ++v;
150     for (pe = v + strlen(v); pe != v; --pe)
151         if (!strchr(" \n\r\t", pe[-1]))
152             break;
153     p->value = (char*) xmalloc(pe - v + 1);
154     if (pe - v)
155         memcpy(p->value, v, pe - v);
156     p->value[pe - v] = '\0';
157 }
158
159 static int next_token(const char **cpp, const char **dst)
160 {
161     int len = 0;
162     const char *cp = *cpp;
163     while (*cp && strchr(" \r\n\t\f", *cp))
164         cp++;
165     if (dst)
166         *dst = cp;
167     len = 0;
168     while (*cp && !strchr(" \r\n\t\f", *cp))
169     {
170         cp++;
171         len++;
172     }
173     *cpp = cp;
174     return len;
175 }
176
177 /** \brief adds specifies qualifier aliases
178     
179     \param b bibset
180     \param n qualifier name
181     \param names list of qualifier aliases
182 */
183 void ccl_qual_add_combi(CCL_bibset b, const char *n, const char *names)
184 {
185     const char *cp, *cp1;
186     int i, len;
187     struct ccl_qualifier *q;
188     for (q = b->list; q && strcmp(q->name, n); q = q->next)
189         ;
190     if (q)
191         return ;
192     q = (struct ccl_qualifier *) xmalloc(sizeof(*q));
193     q->name = xstrdup(n);
194     q->attr_list = 0;
195     q->next = b->list;
196     b->list = q;
197     
198     cp = names;
199     for (i = 0; next_token(&cp, 0); i++)
200         ;
201     q->no_sub = i;
202     q->sub = (struct ccl_qualifier **) xmalloc(sizeof(*q->sub) *
203                                               (1+q->no_sub));
204     cp = names;
205     for (i = 0; (len = next_token(&cp, &cp1)); i++)
206     {
207         q->sub[i] = ccl_qual_lookup(b, cp1, len);
208     }
209 }
210
211 /** \brief adds specifies attributes for qualifier
212     
213     \param b bibset
214     \param name qualifier name
215     \param no number of attribute type+value pairs
216     \param type_ar attributes type of size no
217     \param value_ar attribute value of size no
218     \param svalue_ar attribute string values ([i] only used  if != NULL)
219     \param attsets attribute sets of size no
220 */
221
222 void ccl_qual_add_set(CCL_bibset b, const char *name, int no,
223                        int *type_ar, int *value_ar, char **svalue_ar,
224                        char **attsets)
225 {
226     struct ccl_qualifier *q;
227     struct ccl_rpn_attr **attrp;
228
229     ccl_assert(b);
230     for (q = b->list; q; q = q->next)
231         if (!strcmp(name, q->name))
232             break;
233     if (!q)
234     {
235         q = (struct ccl_qualifier *)xmalloc(sizeof(*q));
236         ccl_assert(q);
237         
238         q->next = b->list;
239         b->list = q;
240         
241         q->name = xstrdup(name);
242         q->attr_list = 0;
243
244         q->no_sub = 0;
245         q->sub = 0;
246     }
247     attrp = &q->attr_list;
248     while (*attrp)
249         attrp = &(*attrp)->next;
250     while (--no >= 0)
251     {
252         struct ccl_rpn_attr *attr;
253
254         attr = (struct ccl_rpn_attr *)xmalloc(sizeof(*attr));
255         ccl_assert(attr);
256         attr->set = *attsets++;
257         attr->type = *type_ar++;
258         if (*svalue_ar)
259         {
260             attr->kind = CCL_RPN_ATTR_STRING;
261             attr->value.str = *svalue_ar;
262         }
263         else
264         {
265             attr->kind = CCL_RPN_ATTR_NUMERIC;
266             attr->value.numeric = *value_ar;
267         }
268         svalue_ar++;
269         value_ar++;
270         *attrp = attr;
271         attrp = &attr->next;
272     }
273     *attrp = NULL;
274 }
275
276 /** \brief creates Bibset
277     \returns bibset
278  */
279 CCL_bibset ccl_qual_mk(void)
280 {
281     CCL_bibset b = (CCL_bibset)xmalloc(sizeof(*b));
282     ccl_assert(b);
283     b->list = NULL;     
284     b->special = NULL;
285     return b;
286 }
287
288 /** \brief destroys Bibset
289     \param b pointer to Bibset
290     
291     *b will be set to NULL.
292  */
293 void ccl_qual_rm(CCL_bibset *b)
294 {
295     struct ccl_qualifier *q, *q1;
296     struct ccl_qualifier_special *sp, *sp1;
297
298     if (!*b)
299         return;
300     for (q = (*b)->list; q; q = q1)
301     {
302         struct ccl_rpn_attr *attr, *attr1;
303
304         for (attr = q->attr_list; attr; attr = attr1)
305         {
306             attr1 = attr->next;
307             if (attr->set)
308                 xfree(attr->set);
309             if (attr->kind == CCL_RPN_ATTR_STRING)
310                 xfree(attr->value.str);
311             xfree(attr);
312         }
313         q1 = q->next;
314         xfree(q->name);
315         if (q->sub)
316             xfree(q->sub);
317         xfree(q);
318     }
319     for (sp = (*b)->special; sp; sp = sp1)
320     {
321         sp1 = sp->next;
322         xfree(sp->name);
323         xfree(sp->value);
324         xfree(sp);
325     }
326     xfree(*b);
327     *b = NULL;
328 }
329
330 ccl_qualifier_t ccl_qual_search(CCL_parser cclp, const char *name, 
331                                 size_t name_len, int seq)
332 {
333     struct ccl_qualifier *q = 0;
334     const char *aliases;
335     int case_sensitive = cclp->ccl_case_sensitive;
336
337     ccl_assert(cclp);
338     if (!cclp->bibset)
339         return 0;
340
341     aliases = ccl_qual_search_special(cclp->bibset, "case");
342     if (aliases)
343         case_sensitive = atoi(aliases);
344
345     for (q = cclp->bibset->list; q; q = q->next)
346         if (strlen(q->name) == name_len)
347         {
348             if (case_sensitive)
349             {
350                 if (!memcmp(name, q->name, name_len))
351                     break;
352             }
353             else
354             {
355                 if (!ccl_memicmp(name, q->name, name_len))
356                     break;
357             }
358         }
359     if (q)
360     {
361         if (q->no_sub)
362         {
363             if (seq < q->no_sub)
364                 q = q->sub[seq];
365             else
366                 q = 0;
367         }
368         else if (seq)
369             q = 0;
370     }
371     return q;
372 }
373
374 struct ccl_rpn_attr *ccl_qual_get_attr(ccl_qualifier_t q)
375 {
376     return q->attr_list;
377 }
378
379 const char *ccl_qual_get_name(ccl_qualifier_t q)
380 {
381     return q->name;
382 }
383
384 const char *ccl_qual_search_special(CCL_bibset b, const char *name)
385 {
386     struct ccl_qualifier_special *q;
387     if (!b)
388         return 0;
389     for (q = b->special; q && strcmp(q->name, name); q = q->next)
390         ;
391     if (q)
392         return q->value;
393     return 0;
394 }
395 /*
396  * Local variables:
397  * c-basic-offset: 4
398  * indent-tabs-mode: nil
399  * End:
400  * vim: shiftwidth=4 tabstop=8 expandtab
401  */
402