e0761b8eecd5e5374ac784d10f141fdcb9ad8fad
[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             *attrp = xmalloc(sizeof(**attrp));
281             (*attrp)->next = 0;
282             (*attrp)->set = attr->set ? xstrdup(attr->set) : 0;
283             (*attrp)->type = attr->type;
284             if (attr->kind == CCL_RPN_ATTR_NUMERIC)
285                 (*attrp)->value.numeric = attr->value.numeric;
286             else if (attr->kind == CCL_RPN_ATTR_STRING)
287                 (*attrp)->value.str = xstrdup(attr->value.str);
288
289             attrp = &(*attrp)->next;
290         }
291         (*qp)->no_sub = q->no_sub;
292         if (!q->sub)
293             (*qp)->sub = 0;
294         else
295         {
296             /* fix up the sub qualifiers.. */
297             int i;
298             (*qp)->sub = xmalloc(sizeof(*q->sub) * (q->no_sub + 1));
299             for (i = 0; i < q->no_sub; i++)
300             {
301                 struct ccl_qualifier *q1, *q2;
302                 
303                 /* sweep though original and match up the corresponding ent */
304                 q2 = n->list;
305                 for (q1 = b->list; q1 && q2; q1 = q1->next, q2 = q2->next)
306                     if (q1 == q->sub[i])
307                         break;
308                 (*qp)->sub[i] = q2;
309             }
310         }
311         qp = &(*qp)->next;
312     }
313     sp = &n->special;
314     for (s = b->special; s; s = s->next)
315     {
316         int i;
317
318         for (i = 0; s->values[i]; i++)
319             ;
320         *sp = xmalloc(sizeof(**sp));
321         (*sp)->next = 0;
322         (*sp)->name = xstrdup(s->name);
323         (*sp)->values = xmalloc(sizeof(*(*sp)->values) * (i+1));
324         for (i = 0; s->values[i]; i++)
325             (*sp)->values[i] = xstrdup(s->values[i]);
326         (*sp)->values[i] = 0;
327         sp = &(*sp)->next;
328     }
329     return n;
330 }
331
332 ccl_qualifier_t ccl_qual_search(CCL_parser cclp, const char *name, 
333                                 size_t name_len, int seq)
334 {
335     struct ccl_qualifier *q = 0;
336     const char **aliases;
337     int case_sensitive = cclp->ccl_case_sensitive;
338
339     ccl_assert(cclp);
340     if (!cclp->bibset)
341         return 0;
342
343     aliases = ccl_qual_search_special(cclp->bibset, "case");
344     if (aliases)
345         case_sensitive = atoi(aliases[0]);
346
347     for (q = cclp->bibset->list; q; q = q->next)
348         if (strlen(q->name) == name_len)
349         {
350             if (case_sensitive)
351             {
352                 if (!memcmp(name, q->name, name_len))
353                     break;
354             }
355             else
356             {
357                 if (!ccl_memicmp(name, q->name, name_len))
358                     break;
359             }
360         }
361     if (q)
362     {
363         if (q->no_sub)
364         {
365             if (seq < q->no_sub)
366                 q = q->sub[seq];
367             else
368                 q = 0;
369         }
370         else if (seq)
371             q = 0;
372     }
373     return q;
374 }
375
376 struct ccl_rpn_attr *ccl_qual_get_attr(ccl_qualifier_t q)
377 {
378     return q->attr_list;
379 }
380
381 const char *ccl_qual_get_name(ccl_qualifier_t q)
382 {
383     return q->name;
384 }
385
386 const char **ccl_qual_search_special(CCL_bibset b, const char *name)
387 {
388     struct ccl_qualifier_special *q;
389     if (!b)
390         return 0;
391     for (q = b->special; q && strcmp(q->name, name); q = q->next)
392         ;
393     if (q)
394         return q->values;
395     return 0;
396 }
397
398 int ccl_search_stop(CCL_bibset bibset, const char *qname,
399                     const char *src_str, size_t src_len)
400 {
401     const char **slist = 0;
402     if (qname)
403     {
404         char qname_buf[80];
405         yaz_snprintf(qname_buf, sizeof(qname_buf)-1, "stop.%s",
406                      qname);
407         slist = ccl_qual_search_special(bibset, qname_buf);
408     }
409     if (!slist)
410         slist = ccl_qual_search_special(bibset, "stop.*");
411     if (slist)
412     {
413         int i;
414         for (i = 0; slist[i]; i++)
415             if (src_len == strlen(slist[i]) 
416                 && ccl_memicmp(slist[i], src_str, src_len) == 0)
417                 return 1;
418     }
419     return 0;
420 }
421
422 /*
423  * Local variables:
424  * c-basic-offset: 4
425  * c-file-style: "Stroustrup"
426  * indent-tabs-mode: nil
427  * End:
428  * vim: shiftwidth=4 tabstop=8 expandtab
429  */
430