Update source headers for 2008. Omit CVS ID keyword subst.
[yaz-moved-to-github.git] / src / cclqfile.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 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             int i = 0;
83
84             qlist[i++] = lead_str;
85
86             while ((t=yaz_tok_move(tp)) == YAZ_TOK_STRING)
87             {
88                 if (i < sizeof(qlist)/sizeof(*qlist)-1)
89                     qlist[i++] = xstrdup(yaz_tok_parse_string(tp));
90             }
91             qlist[i] = 0;
92             yaz_tok_parse_destroy(tp);
93             ccl_qual_add_combi (bibset, qual_name, (const char **) qlist);
94             for (i = 0; qlist[i]; i++)
95                 xfree(qlist[i]);
96             return 0;
97         }
98         while (1) /* comma separated attribute value list */
99         {
100             t = yaz_tok_move(tp);
101             /* must have a value now */
102             if (t != YAZ_TOK_STRING)
103             {
104                 *addinfo = "value token expected";
105                 goto out;
106             }
107             value_str = yaz_tok_parse_string(tp);
108             
109             if (sscanf(type_str, "%d", &type) == 1)
110                 ;
111             else if (strlen(type_str) != 1)
112             {
113                 *addinfo = "bad attribute type";
114                 goto out;
115             }
116             else
117             {
118                 switch (*type_str)
119                 {
120                 case 'u':
121                 case 'U':
122                     type = CCL_BIB1_USE;
123                     break;
124                 case 'r':
125                 case 'R':
126                     type = CCL_BIB1_REL;
127                     if (!ccl_stricmp (value_str, "o"))
128                         value = CCL_BIB1_REL_ORDER;
129                     else if (!ccl_stricmp (value_str, "r"))
130                         value = CCL_BIB1_REL_PORDER;
131                     break;                
132                 case 'p':
133                 case 'P':
134                     type = CCL_BIB1_POS;
135                     break;
136                 case 's':
137                 case 'S':
138                     type = CCL_BIB1_STR;
139                     if (!ccl_stricmp (value_str, "pw"))
140                         value = CCL_BIB1_STR_WP;
141                     if (!ccl_stricmp (value_str, "al"))
142                         value = CCL_BIB1_STR_AND_LIST;
143                     if (!ccl_stricmp (value_str, "ol"))
144                         value = CCL_BIB1_STR_OR_LIST;
145                     break;                
146                 case 't':
147                 case 'T':
148                     type = CCL_BIB1_TRU;
149                     if (!ccl_stricmp (value_str, "l"))
150                         value = CCL_BIB1_TRU_CAN_LEFT;
151                     else if (!ccl_stricmp (value_str, "r"))
152                         value = CCL_BIB1_TRU_CAN_RIGHT;
153                     else if (!ccl_stricmp (value_str, "b"))
154                         value = CCL_BIB1_TRU_CAN_BOTH;
155                     else if (!ccl_stricmp (value_str, "n"))
156                         value = CCL_BIB1_TRU_CAN_NONE;
157                     break;                
158                 case 'c':
159                 case 'C':
160                     type = CCL_BIB1_COM;
161                     break;
162                 }
163             }
164             if (type == 0)
165             {
166                 /* type was not set in switch above */
167                 *addinfo = "bad attribute type";
168                 goto out;
169             }
170             type_ar[pair_no] = type;
171             if (value)
172             {
173                 value_ar[pair_no] = value;
174                 svalue_ar[pair_no] = 0;
175             }
176             else if (*value_str >= '0' && *value_str <= '9')
177             {
178                 value_ar[pair_no] = atoi (value_str);
179                 svalue_ar[pair_no] = 0;
180             }
181             else
182             {
183                 value_ar[pair_no] = 0;
184                 svalue_ar[pair_no] = xstrdup(value_str);
185             }
186             pair_no++;
187             if (pair_no == MAX_QUAL)
188             {
189                 *addinfo = "too many attribute values";
190                 goto out;
191             }
192             t = yaz_tok_move(tp);
193             if (t != ',')
194                 break;
195             attsets[pair_no] = attsets[pair_no-1];
196         }
197     }
198  out:
199     xfree(type_str);
200     type_str = 0;
201
202     yaz_tok_parse_destroy(tp);
203
204     if (*addinfo)
205     {
206         int i;
207         for (i = 0; i<pair_no; i++)
208         {
209             xfree(attsets[i]);
210             xfree(svalue_ar[i]);
211         }
212         return -1;
213     }
214     ccl_qual_add_set(bibset, qual_name, pair_no, type_ar, value_ar, svalue_ar,
215                      attsets);
216     return 0;
217 }
218
219 void ccl_qual_field(CCL_bibset bibset, const char *cp, const char *qual_name)
220 {
221     const char *addinfo;
222     ccl_qual_field2(bibset, cp, qual_name, &addinfo);
223     if (addinfo)
224         yaz_log(YLOG_WARN, "ccl_qual_field2 fail: %s", addinfo);
225 }
226
227 void ccl_qual_fitem (CCL_bibset bibset, const char *cp, const char *qual_name)
228 {
229     if (*qual_name == '@')
230         ccl_qual_add_special(bibset, qual_name+1, cp);
231     else
232         ccl_qual_field(bibset, cp, qual_name);
233 }
234
235 void ccl_qual_buf(CCL_bibset bibset, const char *buf)
236 {
237     const char *cp1 = buf;
238     char line[256];
239     while (1)
240     {
241         const char *cp2 = cp1;
242         int len;
243         while (*cp2 && !strchr("\r\n", *cp2))
244             cp2++;
245         len = cp2 - cp1;
246         if (len > 0)
247         {
248             if (len >= (sizeof(line)-1))
249                 len = sizeof(line)-1;
250             memcpy(line, cp1, len);
251             line[len] = '\0';
252             ccl_qual_line(bibset, line);
253         }
254         if (!*cp2)
255             break;
256         cp1 = cp2+1;
257     }
258 }
259
260 void ccl_qual_line(CCL_bibset bibset, char *line)
261 {
262     int  no_scan = 0;
263     char qual_name[128];
264     char *cp1, *cp = line;
265     
266     if (*cp == '#')
267         return;        /* ignore lines starting with # */
268     if (sscanf (cp, "%100s%n", qual_name, &no_scan) < 1)
269         return;        /* also ignore empty lines */
270     cp += no_scan;
271     cp1 = strchr(cp, '#');
272     if (cp1)
273         *cp1 = '\0';
274     ccl_qual_fitem (bibset, cp, qual_name);
275 }
276
277 /*
278  * ccl_qual_file: Read bibset definition from file.
279  * bibset:  Bibset
280  * inf:     FILE pointer.
281  *
282  * Each line format is:
283  *  <name> <t>=<v> <t>=<v> ....
284  *  Where <name> is name of qualifier;
285  *  <t>=<v> is a attribute definition pair where <t> is one of: 
286  *     u(use), r(relation), p(position), t(truncation), c(completeness) 
287  *     or plain integer.
288  *  <v> is an integer or special pseudo-value.
289  */
290 void ccl_qual_file (CCL_bibset bibset, FILE *inf)
291 {
292     char line[256];
293
294     while (fgets (line, 255, inf))
295         ccl_qual_line(bibset, line);
296 }
297
298 int ccl_qual_fname (CCL_bibset bibset, const char *fname)
299 {
300     FILE *inf;
301     inf = fopen (fname, "r");
302     if (!inf)
303         return -1;
304     ccl_qual_file (bibset, inf);
305     fclose (inf);
306     return 0;
307 }
308 /*
309  * Local variables:
310  * c-basic-offset: 4
311  * indent-tabs-mode: nil
312  * End:
313  * vim: shiftwidth=4 tabstop=8 expandtab
314  */
315