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