Changed license of CCL module to 'Revised BSD'.
[yaz-moved-to-github.git] / src / cclqfile.c
1 /*
2  * Copyright (C) 1995-2008, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: cclqfile.c,v 1.12 2008-01-09 21:32:28 adam Exp $
6  */
7 /** 
8  * \file cclqfile.c
9  * \brief Implements parsing of CCL qualifier specs in files
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include <yaz/tokenizer.h>
17 #include <yaz/ccl.h>
18 #include <yaz/log.h>
19
20 #define MAX_QUAL 128
21
22 int ccl_qual_field2(CCL_bibset bibset, const char *cp, const char *qual_name,
23                     const char **addinfo)
24 {
25     yaz_tok_cfg_t yt = yaz_tok_cfg_create();
26
27     int type_ar[MAX_QUAL];
28     int value_ar[MAX_QUAL];
29     char *svalue_ar[MAX_QUAL];
30     char *attsets[MAX_QUAL];
31     int pair_no = 0;
32     char *type_str = 0;
33     int t;
34     yaz_tok_parse_t tp;
35
36     yaz_tok_cfg_single_tokens(yt, ",=");
37
38     tp = yaz_tok_parse_buf(yt, cp);
39
40     yaz_tok_cfg_destroy(yt);
41     *addinfo = 0;
42     
43     t = yaz_tok_move(tp);
44     while (t == YAZ_TOK_STRING)
45     {
46         /* we don't know what lead is yet */
47         char *lead_str = xstrdup(yaz_tok_parse_string(tp));
48         const char *value_str = 0;
49         int type = 0, value = 0; /* indicates attribute value UNSET  */
50
51         t = yaz_tok_move(tp);
52         if (t == ',')
53         {
54             /* full attribute spec: set, type = value */
55             /* lead is attribute set */
56             attsets[pair_no] = lead_str;
57             t = yaz_tok_move(tp);
58             if (t != YAZ_TOK_STRING)
59             {
60                 *addinfo = "token expected";
61                 goto out;
62             }
63             xfree(type_str);
64             type_str = xstrdup(yaz_tok_parse_string(tp));
65             if (yaz_tok_move(tp) != '=')
66             {
67                 *addinfo = "= expected";
68                 goto out;
69             }
70         }
71         else if (t == '=')
72         {
73             /* lead is attribute type */
74             /* attribute set omitted: type = value */
75             attsets[pair_no] = 0;
76             xfree(type_str);
77             type_str = lead_str;
78         }
79         else
80         {
81             /* lead is first of a list of qualifier aliaeses */
82             /* qualifier alias: q1 q2 ... */
83             char *qlist[10];
84             int i = 0;
85
86             qlist[i++] = lead_str;
87
88             while ((t=yaz_tok_move(tp)) == YAZ_TOK_STRING)
89             {
90                 if (i < sizeof(qlist)/sizeof(*qlist)-1)
91                     qlist[i++] = xstrdup(yaz_tok_parse_string(tp));
92             }
93             qlist[i] = 0;
94             yaz_tok_parse_destroy(tp);
95             ccl_qual_add_combi (bibset, qual_name, (const char **) qlist);
96             for (i = 0; qlist[i]; i++)
97                 xfree(qlist[i]);
98             return 0;
99         }
100         while (1) /* comma separated attribute value list */
101         {
102             t = yaz_tok_move(tp);
103             /* must have a value now */
104             if (t != YAZ_TOK_STRING)
105             {
106                 *addinfo = "value token expected";
107                 goto out;
108             }
109             value_str = yaz_tok_parse_string(tp);
110             
111             if (sscanf(type_str, "%d", &type) == 1)
112                 ;
113             else if (strlen(type_str) != 1)
114             {
115                 *addinfo = "bad attribute type";
116                 goto out;
117             }
118             else
119             {
120                 switch (*type_str)
121                 {
122                 case 'u':
123                 case 'U':
124                     type = CCL_BIB1_USE;
125                     break;
126                 case 'r':
127                 case 'R':
128                     type = CCL_BIB1_REL;
129                     if (!ccl_stricmp (value_str, "o"))
130                         value = CCL_BIB1_REL_ORDER;
131                     else if (!ccl_stricmp (value_str, "r"))
132                         value = CCL_BIB1_REL_PORDER;
133                     break;                
134                 case 'p':
135                 case 'P':
136                     type = CCL_BIB1_POS;
137                     break;
138                 case 's':
139                 case 'S':
140                     type = CCL_BIB1_STR;
141                     if (!ccl_stricmp (value_str, "pw"))
142                         value = CCL_BIB1_STR_WP;
143                     if (!ccl_stricmp (value_str, "al"))
144                         value = CCL_BIB1_STR_AND_LIST;
145                     if (!ccl_stricmp (value_str, "ol"))
146                         value = CCL_BIB1_STR_OR_LIST;
147                     break;                
148                 case 't':
149                 case 'T':
150                     type = CCL_BIB1_TRU;
151                     if (!ccl_stricmp (value_str, "l"))
152                         value = CCL_BIB1_TRU_CAN_LEFT;
153                     else if (!ccl_stricmp (value_str, "r"))
154                         value = CCL_BIB1_TRU_CAN_RIGHT;
155                     else if (!ccl_stricmp (value_str, "b"))
156                         value = CCL_BIB1_TRU_CAN_BOTH;
157                     else if (!ccl_stricmp (value_str, "n"))
158                         value = CCL_BIB1_TRU_CAN_NONE;
159                     break;                
160                 case 'c':
161                 case 'C':
162                     type = CCL_BIB1_COM;
163                     break;
164                 }
165             }
166             if (type == 0)
167             {
168                 /* type was not set in switch above */
169                 *addinfo = "bad attribute type";
170                 goto out;
171             }
172             type_ar[pair_no] = type;
173             if (value)
174             {
175                 value_ar[pair_no] = value;
176                 svalue_ar[pair_no] = 0;
177             }
178             else if (*value_str >= '0' && *value_str <= '9')
179             {
180                 value_ar[pair_no] = atoi (value_str);
181                 svalue_ar[pair_no] = 0;
182             }
183             else
184             {
185                 value_ar[pair_no] = 0;
186                 svalue_ar[pair_no] = xstrdup(value_str);
187             }
188             pair_no++;
189             if (pair_no == MAX_QUAL)
190             {
191                 *addinfo = "too many attribute values";
192                 goto out;
193             }
194             t = yaz_tok_move(tp);
195             if (t != ',')
196                 break;
197             attsets[pair_no] = attsets[pair_no-1];
198         }
199     }
200  out:
201     xfree(type_str);
202     type_str = 0;
203
204     yaz_tok_parse_destroy(tp);
205
206     if (*addinfo)
207     {
208         int i;
209         for (i = 0; i<pair_no; i++)
210         {
211             xfree(attsets[i]);
212             xfree(svalue_ar[i]);
213         }
214         return -1;
215     }
216     ccl_qual_add_set(bibset, qual_name, pair_no, type_ar, value_ar, svalue_ar,
217                      attsets);
218     return 0;
219 }
220
221 void ccl_qual_field(CCL_bibset bibset, const char *cp, const char *qual_name)
222 {
223     const char *addinfo;
224     ccl_qual_field2(bibset, cp, qual_name, &addinfo);
225     if (addinfo)
226         yaz_log(YLOG_WARN, "ccl_qual_field2 fail: %s", addinfo);
227 }
228
229 void ccl_qual_fitem (CCL_bibset bibset, const char *cp, const char *qual_name)
230 {
231     if (*qual_name == '@')
232         ccl_qual_add_special(bibset, qual_name+1, cp);
233     else
234         ccl_qual_field(bibset, cp, qual_name);
235 }
236
237 void ccl_qual_buf(CCL_bibset bibset, const char *buf)
238 {
239     const char *cp1 = buf;
240     char line[256];
241     while (1)
242     {
243         const char *cp2 = cp1;
244         int len;
245         while (*cp2 && !strchr("\r\n", *cp2))
246             cp2++;
247         len = cp2 - cp1;
248         if (len > 0)
249         {
250             if (len >= (sizeof(line)-1))
251                 len = sizeof(line)-1;
252             memcpy(line, cp1, len);
253             line[len] = '\0';
254             ccl_qual_line(bibset, line);
255         }
256         if (!*cp2)
257             break;
258         cp1 = cp2+1;
259     }
260 }
261
262 void ccl_qual_line(CCL_bibset bibset, char *line)
263 {
264     int  no_scan = 0;
265     char qual_name[128];
266     char *cp1, *cp = line;
267     
268     if (*cp == '#')
269         return;        /* ignore lines starting with # */
270     if (sscanf (cp, "%100s%n", qual_name, &no_scan) < 1)
271         return;        /* also ignore empty lines */
272     cp += no_scan;
273     cp1 = strchr(cp, '#');
274     if (cp1)
275         *cp1 = '\0';
276     ccl_qual_fitem (bibset, cp, qual_name);
277 }
278
279 /*
280  * ccl_qual_file: Read bibset definition from file.
281  * bibset:  Bibset
282  * inf:     FILE pointer.
283  *
284  * Each line format is:
285  *  <name> <t>=<v> <t>=<v> ....
286  *  Where <name> is name of qualifier;
287  *  <t>=<v> is a attribute definition pair where <t> is one of: 
288  *     u(use), r(relation), p(position), t(truncation), c(completeness) 
289  *     or plain integer.
290  *  <v> is an integer or special pseudo-value.
291  */
292 void ccl_qual_file (CCL_bibset bibset, FILE *inf)
293 {
294     char line[256];
295
296     while (fgets (line, 255, inf))
297         ccl_qual_line(bibset, line);
298 }
299
300 int ccl_qual_fname (CCL_bibset bibset, const char *fname)
301 {
302     FILE *inf;
303     inf = fopen (fname, "r");
304     if (!inf)
305         return -1;
306     ccl_qual_file (bibset, inf);
307     fclose (inf);
308     return 0;
309 }
310 /*
311  * Local variables:
312  * c-basic-offset: 4
313  * indent-tabs-mode: nil
314  * End:
315  * vim: shiftwidth=4 tabstop=8 expandtab
316  */
317