Happy new year
[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_qualifier_t ccl_qual_search(CCL_parser cclp, const char *name, 
263                                 size_t name_len, int seq)
264 {
265     struct ccl_qualifier *q = 0;
266     const char **aliases;
267     int case_sensitive = cclp->ccl_case_sensitive;
268
269     ccl_assert(cclp);
270     if (!cclp->bibset)
271         return 0;
272
273     aliases = ccl_qual_search_special(cclp->bibset, "case");
274     if (aliases)
275         case_sensitive = atoi(aliases[0]);
276
277     for (q = cclp->bibset->list; q; q = q->next)
278         if (strlen(q->name) == name_len)
279         {
280             if (case_sensitive)
281             {
282                 if (!memcmp(name, q->name, name_len))
283                     break;
284             }
285             else
286             {
287                 if (!ccl_memicmp(name, q->name, name_len))
288                     break;
289             }
290         }
291     if (q)
292     {
293         if (q->no_sub)
294         {
295             if (seq < q->no_sub)
296                 q = q->sub[seq];
297             else
298                 q = 0;
299         }
300         else if (seq)
301             q = 0;
302     }
303     return q;
304 }
305
306 struct ccl_rpn_attr *ccl_qual_get_attr(ccl_qualifier_t q)
307 {
308     return q->attr_list;
309 }
310
311 const char *ccl_qual_get_name(ccl_qualifier_t q)
312 {
313     return q->name;
314 }
315
316 const char **ccl_qual_search_special(CCL_bibset b, const char *name)
317 {
318     struct ccl_qualifier_special *q;
319     if (!b)
320         return 0;
321     for (q = b->special; q && strcmp(q->name, name); q = q->next)
322         ;
323     if (q)
324         return q->values;
325     return 0;
326 }
327
328 int ccl_search_stop(CCL_bibset bibset, const char *qname,
329                     const char *src_str, size_t src_len)
330 {
331     const char **slist = 0;
332     if (qname)
333     {
334         char qname_buf[80];
335         yaz_snprintf(qname_buf, sizeof(qname_buf)-1, "stop.%s",
336                      qname);
337         slist = ccl_qual_search_special(bibset, qname_buf);
338     }
339     if (!slist)
340         slist = ccl_qual_search_special(bibset, "stop.*");
341     if (slist)
342     {
343         int i;
344         for (i = 0; slist[i]; i++)
345             if (src_len == strlen(slist[i]) 
346                 && ccl_memicmp(slist[i], src_str, src_len) == 0)
347                 return 1;
348     }
349     return 0;
350 }
351
352 /*
353  * Local variables:
354  * c-basic-offset: 4
355  * c-file-style: "Stroustrup"
356  * indent-tabs-mode: nil
357  * End:
358  * vim: shiftwidth=4 tabstop=8 expandtab
359  */
360