Directive s=pw sets structure to phrase if term includes blank(s).
[yaz-moved-to-github.git] / retrieval / d1_doespec.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_doespec.c,v $
7  * Revision 1.14  1999-11-30 13:47:12  adam
8  * Improved installation. Moved header files to include/yaz.
9  *
10  * Revision 1.13  1999/08/27 09:40:32  adam
11  * Renamed logf function to yaz_log. Removed VC++ project files.
12  *
13  * Revision 1.12  1999/04/23 13:34:33  adam
14  * Fixed bug in match_triple. Thanks to Franck Falcoz <franck@dtv.dk>.
15  *
16  * Revision 1.11  1997/11/06 11:36:44  adam
17  * Implemented variant match on simple elements -data1 tree and Espec-1.
18  *
19  * Revision 1.10  1997/10/02 12:10:24  quinn
20  * Attempt to fix bug in especs
21  *
22  * Revision 1.9  1997/09/17 12:10:35  adam
23  * YAZ version 1.4.
24  *
25  * Revision 1.8  1997/05/14 06:54:02  adam
26  * C++ support.
27  *
28  * Revision 1.7  1997/04/30 08:52:11  quinn
29  * Null
30  *
31  * Revision 1.6  1996/10/11  11:57:22  quinn
32  * Smallish
33  *
34  * Revision 1.5  1996/07/06  19:58:34  quinn
35  * System headerfiles gathered in yconfig
36  *
37  * Revision 1.4  1996/06/07  11:04:32  quinn
38  * Fixed tag->tagset dependency
39  *
40  * Revision 1.3  1995/11/13  09:27:33  quinn
41  * Fiddling with the variant stuff.
42  *
43  * Revision 1.2  1995/11/01  13:54:45  quinn
44  * Minor adjustments
45  *
46  * Revision 1.1  1995/11/01  11:56:07  quinn
47  * Added Retrieval (data management) functions en masse.
48  *
49  *
50  */
51
52
53 #include <assert.h>
54
55 #include <yaz/oid.h>
56 #include <yaz/log.h>
57 #include <yaz/proto.h>
58 #include <yaz/data1.h>
59
60 static int match_children(data1_handle dh, data1_node *n,
61                           Z_Espec1 *e, int i, Z_ETagUnit **t,
62     int num);
63
64 static int match_children_wildpath(data1_handle dh, data1_node *n,
65                                    Z_Espec1 *e, int i,
66                                    Z_ETagUnit **t, int num)
67 {
68     return 0;
69 }
70
71 /*
72  * Locate a specific triple within a variant.
73  * set is the set to look for, universal set is the set that applies to a
74  * triple with an unknown set.
75  */
76 static Z_Triple *find_triple(Z_Variant *var, oid_value universalset,
77     oid_value set, int zclass, int type)
78 {
79     int i;
80     oident *defaultsetent = oid_getentbyoid(var->globalVariantSetId);
81     oid_value defaultset = defaultsetent ? defaultsetent->value :
82         universalset;
83
84     for (i = 0; i < var->num_triples; i++)
85     {
86         oident *cursetent =
87             oid_getentbyoid(var->triples[i]->variantSetId);
88         oid_value curset = cursetent ? cursetent->value : defaultset;
89
90         if (set == curset &&
91             *var->triples[i]->zclass == zclass &&
92             *var->triples[i]->type == type)
93             return var->triples[i];
94     }
95     return 0;
96 }
97
98 static void mark_subtree(data1_node *n, int make_variantlist, int no_data,
99     int get_bytes, Z_Variant *vreq)
100 {
101     data1_node *c;
102
103 #if 1
104     if (n->which == DATA1N_tag)
105 #else
106     if (n->which == DATA1N_tag && (!n->child || n->child->which != DATA1N_tag))
107     /*
108      * This seems to cause multi-level elements to fall out when only a
109      * top-level elementRequest has been given... Problem is, I can't figure
110      * out what it was supposed to ACHIEVE.... delete when code has been
111      * verified.
112      */
113 #endif
114     {
115         n->u.tag.node_selected = 1;
116         n->u.tag.make_variantlist = make_variantlist;
117         n->u.tag.no_data_requested = no_data;
118         n->u.tag.get_bytes = get_bytes;
119     }
120
121     for (c = n->child; c; c = c->next)
122     {
123         if (c->which == DATA1N_tag && (!n->child ||
124             n->child->which != DATA1N_tag))
125         {
126             c->u.tag.node_selected = 1;
127             c->u.tag.make_variantlist = make_variantlist;
128             c->u.tag.no_data_requested = no_data;
129             c->u.tag.get_bytes = get_bytes;
130         }
131         mark_subtree(c, make_variantlist, no_data, get_bytes, vreq);
132     }
133 }
134
135
136 static void match_triple (data1_handle dh, Z_Variant *vreq,
137                           oid_value defsetval,
138                           oid_value var1, data1_node *n)
139 {
140     data1_node **c;
141
142     if (!(n = n->child))
143         return;
144     if (n->which != DATA1N_variant)
145         return;
146     c = &n->child;
147     while (*c)
148     {
149         int remove_flag = 0;
150         Z_Triple *r;
151         
152         assert ((*c)->which == DATA1N_variant);
153         
154         if ((*c)->u.variant.type->zclass->zclass == 4 &&
155             (*c)->u.variant.type->type == 1)
156         {
157             if ((r = find_triple(vreq, defsetval, var1, 4, 1)) &&
158                 (r->which == Z_Triple_internationalString))
159             {
160                 const char *string_value =
161                     r->value.internationalString;
162                 if (strcmp ((*c)->u.variant.value, string_value))
163                     remove_flag = 1;
164             }
165         }
166         if (remove_flag)
167         {
168             data1_free_tree (dh, *c);
169             *c = (*c)->next;
170         }
171         else
172         {
173             match_triple (dh, vreq, defsetval, var1, *c);
174             c = &(*c)->next;
175         }
176     }
177 }
178                                 
179 static int match_children_here (data1_handle dh, data1_node *n,
180                                 Z_Espec1 *e, int i,
181                                 Z_ETagUnit **t, int num)
182 {
183     int counter = 0, hits = 0;
184     data1_node *c;
185     Z_ETagUnit *tp = *t;
186     Z_Occurrences *occur;
187
188     for (c = n->child; c ; c = c->next)
189     {
190         data1_tag *tag = 0;
191         if (c->which != DATA1N_tag)
192             return 0;
193
194         if (tp->which == Z_ETagUnit_specificTag)
195         {
196             Z_SpecificTag *want = tp->u.specificTag;
197             occur = want->occurrences;
198             if (c->u.tag.element)
199                 tag = c->u.tag.element->tag;
200             if (*want->tagType != ((tag && tag->tagset) ? tag->tagset->type :
201                 3))
202                 continue;
203             if (want->tagValue->which == Z_StringOrNumeric_numeric)
204             {
205                 if (!tag || tag->which != DATA1T_numeric)
206                     continue;
207                 if (*want->tagValue->u.numeric != tag->value.numeric)
208                     continue;
209             }
210             else
211             {
212                 assert(want->tagValue->which == Z_StringOrNumeric_string);
213                 if (tag && tag->which != DATA1T_string)
214                     continue;
215                 if (data1_matchstr(want->tagValue->u.string,
216                     tag ? tag->value.string : c->u.tag.tag))
217                     continue;
218             }
219         }
220         else
221             occur = tp->u.wildThing;
222
223         /*
224          * Ok, so we have a matching tag. Are we within occurrences-range?
225          */
226         counter++;
227         if (occur && occur->which == Z_Occurrences_last)
228         {
229             yaz_log(LOG_WARN, "Can't do occurrences=last (yet)");
230             return 0;
231         }
232         if (!occur || occur->which == Z_Occurrences_all ||
233             (occur->which == Z_Occurrences_values && counter >=
234             *occur->u.values->start))
235         {
236             if (match_children(dh, c, e, i, t + 1, num - 1))
237             {
238                 c->u.tag.node_selected = 1;
239                 /*
240                  * Consider the variant specification if this is a complete
241                  * match.
242                  */
243                 if (num == 1)
244                 {
245                     int show_variantlist = 0;
246                     int no_data = 0;
247                     int get_bytes = -1;
248
249                     Z_Variant *vreq =
250                         e->elements[i]->u.simpleElement->variantRequest;
251                     oident *defset = oid_getentbyoid(e->defaultVariantSetId);
252                     oid_value defsetval = defset ? defset->value : VAL_NONE;
253                     oid_value var1 = oid_getvalbyname("Variant-1");
254
255                     if (!vreq)
256                         vreq = e->defaultVariantRequest;
257
258                     if (vreq)
259                     {
260                         Z_Triple *r;
261
262                         /*
263                          * 6,5: meta-data requested, variant list.
264                          */
265                         if (find_triple(vreq, defsetval, var1, 6, 5))
266                             show_variantlist = 1;
267                         /*
268                          * 9,1: Miscellaneous, no data requested.
269                          */
270                         if (find_triple(vreq, defsetval, var1, 9, 1))
271                             no_data = 1;
272
273                         /* howmuch */
274                         if ((r = find_triple(vreq, defsetval, var1, 5, 5)))
275                             if (r->which == Z_Triple_integer)
276                                 get_bytes = *r->value.integer;
277
278                         if (!show_variantlist)
279                             match_triple (dh, vreq, defsetval, var1, c);
280                     }
281                     mark_subtree(c, show_variantlist, no_data, get_bytes, vreq);
282                 }
283                 hits++;
284                 /*
285                  * have we looked at enough children?
286                  */
287                 if (!occur || (occur->which == Z_Occurrences_values &&
288                     (!occur->u.values->howMany ||
289                     counter - *occur->u.values->start >=
290                     *occur->u.values->howMany - 1)))
291                     return hits;
292             }
293         }
294     }
295     return hits;
296 }
297
298 static int match_children(data1_handle dh, data1_node *n, Z_Espec1 *e,
299                           int i, Z_ETagUnit **t, int num)
300 {
301     int res;
302
303     if (!num)
304         return 1;
305     switch (t[0]->which)
306     {
307         case Z_ETagUnit_wildThing:
308         case Z_ETagUnit_specificTag:
309             res = match_children_here(dh, n, e, i, t, num); break;
310         case Z_ETagUnit_wildPath:
311             res = match_children_wildpath(dh, n, e, i, t, num); break;
312         default:
313             abort();
314     }
315     return res;
316 }
317
318 int data1_doespec1 (data1_handle dh, data1_node *n, Z_Espec1 *e)
319 {
320     int i;
321
322     for (i = 0; i < e->num_elements; i++)
323     {
324         if (e->elements[i]->which != Z_ERequest_simpleElement)
325             return 100;
326         match_children(dh, n, e, i,
327                        e->elements[i]->u.simpleElement->path->tags,
328                        e->elements[i]->u.simpleElement->path->num_tags);
329     }
330     return 0;
331 }