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