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