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