e55a654c021791927079a9ad20e5d14a5edc135f
[yaz-moved-to-github.git] / src / cclqual.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 Index Data
3  * See the file LICENSE for details.
4  */
5 /** 
6  * \file cclqual.c
7  * \brief Implements CCL qualifier utilities
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <yaz/snprintf.h>
17 #include <yaz/tokenizer.h>
18 #include "cclp.h"
19
20 /** CCL Qualifier */
21 struct ccl_qualifier {
22     char *name;
23     int no_sub;
24     struct ccl_qualifier **sub;
25     struct ccl_rpn_attr *attr_list;
26     struct ccl_qualifier *next;
27 };
28
29
30 /** Definition of CCL_bibset pointer */
31 struct ccl_qualifiers {
32     struct ccl_qualifier *list;
33     struct ccl_qualifier_special *special;
34 };
35
36
37 /** CCL Qualifier special */
38 struct ccl_qualifier_special {
39     char *name;
40     const char **values;
41     struct ccl_qualifier_special *next;
42 };
43
44
45 static struct ccl_qualifier *ccl_qual_lookup(CCL_bibset b,
46                                              const char *n, size_t len)
47 {
48     struct ccl_qualifier *q;
49     for (q = b->list; q; q = q->next)
50         if (len == strlen(q->name) && !memcmp(q->name, n, len))
51             break;
52     return q;
53 }
54
55 void ccl_qual_add_special_ar(CCL_bibset bibset, const char *n,
56                              const char **values)
57 {
58     struct ccl_qualifier_special *p;
59     for (p = bibset->special; p && strcmp(p->name, n); p = p->next)
60         ;
61     if (p)
62     {
63         if (p->values)
64         {
65             int i;
66             for (i = 0; p->values[i]; i++)
67                 xfree((char *) p->values[i]);
68             xfree((char **)p->values);
69         }
70     }
71     else
72     {
73         p = (struct ccl_qualifier_special *) xmalloc(sizeof(*p));
74         p->name = xstrdup(n);
75         p->next = bibset->special;
76         bibset->special = p;
77     }
78     p->values = values;
79 }
80
81 void ccl_qual_add_special(CCL_bibset bibset, const char *n, const char *cp)
82 {
83     size_t no = 2;
84     char **vlist = (char **) xmalloc(no * sizeof(*vlist));
85     yaz_tok_cfg_t yt = yaz_tok_cfg_create();
86     int t;
87     size_t i = 0;
88     
89     yaz_tok_parse_t tp = yaz_tok_parse_buf(yt, cp);
90     
91     yaz_tok_cfg_destroy(yt);
92     
93     t = yaz_tok_move(tp);
94     while (t == YAZ_TOK_STRING)
95     {
96         if (i >= no-1)
97             vlist = (char **) xrealloc(vlist, (no = no * 2) * sizeof(*vlist));
98         vlist[i++] = xstrdup(yaz_tok_parse_string(tp));
99         t = yaz_tok_move(tp); 
100     }
101     vlist[i] = 0;
102     ccl_qual_add_special_ar(bibset, n, (const char **) vlist);
103     
104     yaz_tok_parse_destroy(tp);
105 }
106
107
108 /** \brief adds specifies qualifier aliases
109     
110     \param b bibset
111     \param n qualifier name
112     \param names list of qualifier aliases
113 */
114 void ccl_qual_add_combi(CCL_bibset b, const char *n, const char **names)
115 {
116     int i;
117     struct ccl_qualifier *q;
118     for (q = b->list; q && strcmp(q->name, n); q = q->next)
119         ;
120     if (q)
121         return ;
122     q = (struct ccl_qualifier *) xmalloc(sizeof(*q));
123     q->name = xstrdup(n);
124     q->attr_list = 0;
125     q->next = b->list;
126     b->list = q;
127     
128     for (i = 0; names[i]; i++)
129         ;
130     q->no_sub = i;
131     q->sub = (struct ccl_qualifier **)
132         xmalloc(sizeof(*q->sub) * (1+q->no_sub));
133     for (i = 0; names[i]; i++)
134         q->sub[i] = ccl_qual_lookup(b, names[i], strlen(names[i]));
135 }
136
137 /** \brief adds specifies attributes for qualifier
138     
139     \param b bibset
140     \param name qualifier name
141     \param no number of attribute type+value pairs
142     \param type_ar attributes type of size no
143     \param value_ar attribute value of size no
144     \param svalue_ar attribute string values ([i] only used  if != NULL)
145     \param attsets attribute sets of size no
146 */
147
148 void ccl_qual_add_set(CCL_bibset b, const char *name, int no,
149                        int *type_ar, int *value_ar, char **svalue_ar,
150                        char **attsets)
151 {
152     struct ccl_qualifier *q;
153     struct ccl_rpn_attr **attrp;
154
155     ccl_assert(b);
156     for (q = b->list; q; q = q->next)
157         if (!strcmp(name, q->name))
158             break;
159     if (!q)
160     {
161         q = (struct ccl_qualifier *)xmalloc(sizeof(*q));
162         ccl_assert(q);
163         
164         q->next = b->list;
165         b->list = q;
166         
167         q->name = xstrdup(name);
168         q->attr_list = 0;
169
170         q->no_sub = 0;
171         q->sub = 0;
172     }
173     attrp = &q->attr_list;
174     while (*attrp)
175         attrp = &(*attrp)->next;
176     while (--no >= 0)
177     {
178         struct ccl_rpn_attr *attr;
179
180         attr = (struct ccl_rpn_attr *)xmalloc(sizeof(*attr));
181         ccl_assert(attr);
182         attr->set = *attsets++;
183         attr->type = *type_ar++;
184         if (*svalue_ar)
185         {
186             attr->kind = CCL_RPN_ATTR_STRING;
187             attr->value.str = *svalue_ar;
188         }
189         else
190         {
191             attr->kind = CCL_RPN_ATTR_NUMERIC;
192             attr->value.numeric = *value_ar;
193         }
194         svalue_ar++;
195         value_ar++;
196         *attrp = attr;
197         attrp = &attr->next;
198     }
199     *attrp = NULL;
200 }
201
202 /** \brief creates Bibset
203     \returns bibset
204  */
205 CCL_bibset ccl_qual_mk(void)
206 {
207     CCL_bibset b = (CCL_bibset)xmalloc(sizeof(*b));
208     ccl_assert(b);
209     b->list = NULL;     
210     b->special = NULL;
211     return b;
212 }
213
214 /** \brief destroys Bibset
215     \param b pointer to Bibset
216     
217     *b will be set to NULL.
218  */
219 void ccl_qual_rm(CCL_bibset *b)
220 {
221     struct ccl_qualifier *q, *q1;
222     struct ccl_qualifier_special *sp, *sp1;
223
224     if (!*b)
225         return;
226     for (q = (*b)->list; q; q = q1)
227     {
228         struct ccl_rpn_attr *attr, *attr1;
229
230         for (attr = q->attr_list; attr; attr = attr1)
231         {
232             attr1 = attr->next;
233             if (attr->set)
234                 xfree(attr->set);
235             if (attr->kind == CCL_RPN_ATTR_STRING)
236                 xfree(attr->value.str);
237             xfree(attr);
238         }
239         q1 = q->next;
240         xfree(q->name);
241         if (q->sub)
242             xfree(q->sub);
243         xfree(q);
244     }
245     for (sp = (*b)->special; sp; sp = sp1)
246     {
247         sp1 = sp->next;
248         xfree(sp->name);
249         if (sp->values)
250         {
251             int i;
252             for (i = 0; sp->values[i]; i++)
253                 xfree((char*) sp->values[i]);
254             xfree((char **)sp->values);
255         }
256         xfree(sp);
257     }
258     xfree(*b);
259     *b = NULL;
260 }
261
262 CCL_bibset ccl_qual_dup(CCL_bibset b)
263 {
264     CCL_bibset n = ccl_qual_mk();
265     struct ccl_qualifier *q, **qp;
266     struct ccl_qualifier_special *s, **sp;
267
268     qp = &n->list;
269     for (q = b->list; q; q = q->next)
270     {
271         struct ccl_rpn_attr *attr, **attrp;
272         *qp = xmalloc(sizeof(**qp));
273         (*qp)->next = 0;
274         (*qp)->attr_list = 0;
275         (*qp)->name = xstrdup(q->name);
276         
277         attrp = &(*qp)->attr_list;
278         for (attr = q->attr_list; attr; attr = attr->next)
279         {
280             int i;
281             *attrp = xmalloc(sizeof(**attrp));
282             (*attrp)->next = 0;
283             (*attrp)->set = attr->set ? xstrdup(attr->set) : 0;
284             (*attrp)->type = attr->type;
285             if (attr->kind == CCL_RPN_ATTR_NUMERIC)
286                 (*attrp)->value.numeric = attr->value.numeric;
287             else if (attr->kind == CCL_RPN_ATTR_STRING)
288                 (*attrp)->value.str = xstrdup(attr->value.str);
289
290             /* fix up the sub qualifiers.. */
291             for (i = 0; q->sub[i]; i++)
292                 ;
293             (*qp)->sub = xmalloc(sizeof(*(*qp)->sub) * (i+1));
294             for (i = 0; q->sub[i]; i++)
295             {
296                 struct ccl_qualifier *q1, *q2;
297
298                 /* sweep though original and match up the corresponding ent */
299                 q2 = n->list;
300                 for (q1 = b->list; q1 && q2; q1 = q1->next, q2 = q2->next)
301                     if (q1 == q->sub[i])
302                         break;
303                 (*qp)->sub[i] = q2;
304             }
305             (*qp)->sub[i] = 0;
306
307             attrp = &(*attrp)->next;
308         }
309         qp = &(*qp)->next;
310     }
311     sp = &n->special;
312     for (s = b->special; s; s = s->next)
313     {
314         int i;
315
316         for (i = 0; s->values[i]; i++)
317             ;
318         *sp = xmalloc(sizeof(**sp));
319         (*sp)->next = 0;
320         (*sp)->name = xstrdup(s->name);
321         (*sp)->values = xmalloc(sizeof(*(*sp)->values) * (i+1));
322         for (i = 0; s->values[i]; i++)
323             (*sp)->values[i] = xstrdup(s->values[i]);
324         (*sp)->values[i] = 0;
325         sp = &(*sp)->next;
326     }
327     return n;
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[0]);
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->values;
393     return 0;
394 }
395
396 int ccl_search_stop(CCL_bibset bibset, const char *qname,
397                     const char *src_str, size_t src_len)
398 {
399     const char **slist = 0;
400     if (qname)
401     {
402         char qname_buf[80];
403         yaz_snprintf(qname_buf, sizeof(qname_buf)-1, "stop.%s",
404                      qname);
405         slist = ccl_qual_search_special(bibset, qname_buf);
406     }
407     if (!slist)
408         slist = ccl_qual_search_special(bibset, "stop.*");
409     if (slist)
410     {
411         int i;
412         for (i = 0; slist[i]; i++)
413             if (src_len == strlen(slist[i]) 
414                 && ccl_memicmp(slist[i], src_str, src_len) == 0)
415                 return 1;
416     }
417     return 0;
418 }
419
420 /*
421  * Local variables:
422  * c-basic-offset: 4
423  * c-file-style: "Stroustrup"
424  * indent-tabs-mode: nil
425  * End:
426  * vim: shiftwidth=4 tabstop=8 expandtab
427  */
428