CCL: slight reformat
[yaz-moved-to-github.git] / src / cclqual.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 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 static struct ccl_qualifier *ccl_qual_new(CCL_bibset b, const char *name)
108 {
109     struct ccl_qualifier *q;
110     q = (struct ccl_qualifier *)xmalloc(sizeof(*q));
111     ccl_assert(q);
112     q->next = b->list;
113     b->list = q;
114     q->name = xstrdup(name);
115     q->attr_list = 0;
116     q->no_sub = 0;
117     q->sub = 0;
118     return q;
119 }
120
121 /** \brief adds specifies qualifier aliases
122
123     \param b bibset
124     \param n qualifier name
125     \param names list of qualifier aliases
126 */
127 void ccl_qual_add_combi(CCL_bibset b, const char *n, const char **names)
128 {
129     int i;
130     struct ccl_qualifier *q;
131     for (q = b->list; q && strcmp(q->name, n); q = q->next)
132         ;
133     if (q)
134         return ;
135     q = (struct ccl_qualifier *) xmalloc(sizeof(*q));
136     q->name = xstrdup(n);
137     q->attr_list = 0;
138     q->next = b->list;
139     b->list = q;
140
141     for (i = 0; names[i]; i++)
142         ;
143     q->no_sub = i;
144     q->sub = (struct ccl_qualifier **)
145         xmalloc(sizeof(*q->sub) * (1+q->no_sub));
146     for (i = 0; names[i]; i++)
147     {
148         q->sub[i] = ccl_qual_lookup(b, names[i], strlen(names[i]));
149         if (!q->sub[i])
150             q->sub[i] = ccl_qual_new(b, names[i]);
151     }
152 }
153
154 /** \brief adds specifies attributes for qualifier
155
156     \param b bibset
157     \param name qualifier name
158     \param no number of attribute type+value pairs
159     \param type_ar attributes type of size no
160     \param value_ar attribute value of size no
161     \param svalue_ar attribute string values ([i] only used  if != NULL)
162     \param attsets attribute sets of size no
163 */
164
165 void ccl_qual_add_set(CCL_bibset b, const char *name, int no,
166                        int *type_ar, int *value_ar, char **svalue_ar,
167                        char **attsets)
168 {
169     struct ccl_qualifier *q;
170     struct ccl_rpn_attr **attrp;
171
172     ccl_assert(b);
173     for (q = b->list; q; q = q->next)
174         if (!strcmp(name, q->name))
175             break;
176     if (!q)
177         q = ccl_qual_new(b, name);
178     attrp = &q->attr_list;
179     while (*attrp)
180         attrp = &(*attrp)->next;
181     while (--no >= 0)
182     {
183         struct ccl_rpn_attr *attr;
184
185         attr = (struct ccl_rpn_attr *)xmalloc(sizeof(*attr));
186         ccl_assert(attr);
187         attr->set = *attsets++;
188         attr->type = *type_ar++;
189         if (*svalue_ar)
190         {
191             attr->kind = CCL_RPN_ATTR_STRING;
192             attr->value.str = *svalue_ar;
193         }
194         else
195         {
196             attr->kind = CCL_RPN_ATTR_NUMERIC;
197             attr->value.numeric = *value_ar;
198         }
199         svalue_ar++;
200         value_ar++;
201         *attrp = attr;
202         attrp = &attr->next;
203     }
204     *attrp = NULL;
205 }
206
207 /** \brief creates Bibset
208     \returns bibset
209  */
210 CCL_bibset ccl_qual_mk(void)
211 {
212     CCL_bibset b = (CCL_bibset)xmalloc(sizeof(*b));
213     ccl_assert(b);
214     b->list = NULL;
215     b->special = NULL;
216     return b;
217 }
218
219 /** \brief destroys Bibset
220     \param b pointer to Bibset
221
222     *b will be set to NULL.
223  */
224 void ccl_qual_rm(CCL_bibset *b)
225 {
226     struct ccl_qualifier *q, *q1;
227     struct ccl_qualifier_special *sp, *sp1;
228
229     if (!*b)
230         return;
231     for (q = (*b)->list; q; q = q1)
232     {
233         struct ccl_rpn_attr *attr, *attr1;
234
235         for (attr = q->attr_list; attr; attr = attr1)
236         {
237             attr1 = attr->next;
238             if (attr->set)
239                 xfree(attr->set);
240             if (attr->kind == CCL_RPN_ATTR_STRING)
241                 xfree(attr->value.str);
242             xfree(attr);
243         }
244         q1 = q->next;
245         xfree(q->name);
246         if (q->sub)
247             xfree(q->sub);
248         xfree(q);
249     }
250     for (sp = (*b)->special; sp; sp = sp1)
251     {
252         sp1 = sp->next;
253         xfree(sp->name);
254         if (sp->values)
255         {
256             int i;
257             for (i = 0; sp->values[i]; i++)
258                 xfree((char*) sp->values[i]);
259             xfree((char **)sp->values);
260         }
261         xfree(sp);
262     }
263     xfree(*b);
264     *b = NULL;
265 }
266
267 CCL_bibset ccl_qual_dup(CCL_bibset b)
268 {
269     CCL_bibset n = ccl_qual_mk();
270     struct ccl_qualifier *q, **qp;
271     struct ccl_qualifier_special *s, **sp;
272
273     qp = &n->list;
274     for (q = b->list; q; q = q->next)
275     {
276         struct ccl_rpn_attr *attr, **attrp;
277         *qp = xmalloc(sizeof(**qp));
278         (*qp)->next = 0;
279         (*qp)->attr_list = 0;
280         (*qp)->name = xstrdup(q->name);
281
282         attrp = &(*qp)->attr_list;
283         for (attr = q->attr_list; attr; attr = attr->next)
284         {
285             *attrp = xmalloc(sizeof(**attrp));
286             (*attrp)->next = 0;
287             (*attrp)->set = attr->set ? xstrdup(attr->set) : 0;
288             (*attrp)->type = attr->type;
289             (*attrp)->kind = attr->kind;
290             if (attr->kind == CCL_RPN_ATTR_NUMERIC)
291                 (*attrp)->value.numeric = attr->value.numeric;
292             else if (attr->kind == CCL_RPN_ATTR_STRING)
293                 (*attrp)->value.str = xstrdup(attr->value.str);
294
295             attrp = &(*attrp)->next;
296         }
297         (*qp)->no_sub = q->no_sub;
298         if (!q->sub)
299             (*qp)->sub = 0;
300         else
301         {
302             /* fix up the sub qualifiers.. */
303             int i;
304             (*qp)->sub = xmalloc(sizeof(*q->sub) * (q->no_sub + 1));
305             for (i = 0; i < q->no_sub; i++)
306             {
307                 struct ccl_qualifier *q1, *q2;
308
309                 /* sweep though original and match up the corresponding ent */
310                 q2 = n->list;
311                 for (q1 = b->list; q1 && q2; q1 = q1->next, q2 = q2->next)
312                     if (q1 == q->sub[i])
313                         break;
314                 (*qp)->sub[i] = q2;
315             }
316         }
317         qp = &(*qp)->next;
318     }
319     sp = &n->special;
320     for (s = b->special; s; s = s->next)
321     {
322         int i;
323
324         for (i = 0; s->values[i]; i++)
325             ;
326         *sp = xmalloc(sizeof(**sp));
327         (*sp)->next = 0;
328         (*sp)->name = xstrdup(s->name);
329         (*sp)->values = xmalloc(sizeof(*(*sp)->values) * (i+1));
330         for (i = 0; s->values[i]; i++)
331             (*sp)->values[i] = xstrdup(s->values[i]);
332         (*sp)->values[i] = 0;
333         sp = &(*sp)->next;
334     }
335     return n;
336 }
337
338 ccl_qualifier_t ccl_qual_search(CCL_parser cclp, const char *name,
339                                 size_t name_len, int seq)
340 {
341     struct ccl_qualifier *q = 0;
342     const char **aliases;
343     int case_sensitive = cclp->ccl_case_sensitive;
344
345     ccl_assert(cclp);
346     if (!cclp->bibset)
347         return 0;
348
349     aliases = ccl_qual_search_special(cclp->bibset, "case");
350     if (aliases)
351         case_sensitive = atoi(aliases[0]);
352
353     for (q = cclp->bibset->list; q; q = q->next)
354         if (strlen(q->name) == name_len)
355         {
356             if (case_sensitive)
357             {
358                 if (!memcmp(name, q->name, name_len))
359                     break;
360             }
361             else
362             {
363                 if (!ccl_memicmp(name, q->name, name_len))
364                     break;
365             }
366         }
367     if (q)
368     {
369         if (q->no_sub)
370         {
371             if (seq < q->no_sub)
372                 q = q->sub[seq];
373             else
374                 q = 0;
375         }
376         else if (seq)
377             q = 0;
378     }
379     return q;
380 }
381
382 struct ccl_rpn_attr *ccl_qual_get_attr(ccl_qualifier_t q)
383 {
384     return q->attr_list;
385 }
386
387 struct ccl_rpn_attr *ccl_parser_qual_search(CCL_parser cclp, const char *name,
388                                             size_t name_len)
389 {
390     ccl_qualifier_t q = ccl_qual_search(cclp, name, name_len, 0);
391     if (q)
392         return q->attr_list;
393     return 0;
394 }
395
396 const char *ccl_qual_get_name(ccl_qualifier_t q)
397 {
398     return q->name;
399 }
400
401 const char **ccl_qual_search_special(CCL_bibset b, const char *name)
402 {
403     struct ccl_qualifier_special *q;
404     if (!b)
405         return 0;
406     for (q = b->special; q && strcmp(q->name, name); q = q->next)
407         ;
408     if (q)
409         return q->values;
410     return 0;
411 }
412
413 int ccl_search_stop(CCL_bibset bibset, const char *qname,
414                     const char *src_str, size_t src_len)
415 {
416     const char **slist = 0;
417     if (qname)
418     {
419         char qname_buf[80];
420         yaz_snprintf(qname_buf, sizeof(qname_buf)-1, "stop.%s",
421                      qname);
422         slist = ccl_qual_search_special(bibset, qname_buf);
423     }
424     if (!slist)
425         slist = ccl_qual_search_special(bibset, "stop.*");
426     if (slist)
427     {
428         int i;
429         for (i = 0; slist[i]; i++)
430             if (src_len == strlen(slist[i])
431                 && ccl_memicmp(slist[i], src_str, src_len) == 0)
432                 return 1;
433     }
434     return 0;
435 }
436
437 /*
438  * Local variables:
439  * c-basic-offset: 4
440  * c-file-style: "Stroustrup"
441  * indent-tabs-mode: nil
442  * End:
443  * vim: shiftwidth=4 tabstop=8 expandtab
444  */
445