1 /* This file is part of the Zebra server.
2 Copyright (C) 1994-2010 Index Data
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /** \file d1_doespec.c
21 * \brief handle Z39.50 variant-1 specs
23 * See http://www.loc.gov/z3950/agency/defns/variant1.html
29 #include <yaz/proto.h>
30 #include <yaz/oid_db.h>
31 #include <idzebra/data1.h>
33 static int match_children(data1_handle dh, data1_node *n,
34 Z_Espec1 *e, int i, Z_ETagUnit **t,
38 static int match_children_wildpath(data1_handle dh, data1_node *n,
40 Z_ETagUnit **t, int num)
46 * Locate a specific triple within a variant.
47 * set is the set to look for, universal set is the set that applies to a
48 * triple with an unknown set.
50 static Z_Triple *find_triple(Z_Variant *var, const Odr_oid *universal_oid,
51 const Odr_oid *var_oid, int zclass, int type)
55 for (i = 0; i < var->num_triples; i++)
57 const Odr_oid *cur_oid = var->triples[i]->variantSetId;
59 cur_oid = var->globalVariantSetId;
60 if (cur_oid && var_oid
61 && !oid_oidcmp(var_oid, cur_oid) && *var->triples[i]->type == type)
62 return var->triples[i];
67 static void mark_subtree(data1_node *n, int make_variantlist, int no_data,
68 int get_bytes, Z_Variant *vreq, int select_flag)
73 if (n->which == DATA1N_tag)
75 if (n->which == DATA1N_tag && (!n->child || n->child->which != DATA1N_tag))
77 * This seems to cause multi-level elements to fall out when only a
78 * top-level elementRequest has been given... Problem is, I can't figure
79 * out what it was supposed to ACHIEVE.... delete when code has been
84 n->u.tag.node_selected = select_flag;
85 n->u.tag.make_variantlist = make_variantlist;
86 n->u.tag.no_data_requested = no_data;
87 n->u.tag.get_bytes = get_bytes;
90 for (c = n->child; c; c = c->next)
92 if (c->which == DATA1N_tag && (!n->child ||
93 n->child->which != DATA1N_tag))
95 c->u.tag.node_selected = select_flag;
96 c->u.tag.make_variantlist = make_variantlist;
97 c->u.tag.no_data_requested = no_data;
98 c->u.tag.get_bytes = get_bytes;
100 mark_subtree(c, make_variantlist, no_data, get_bytes, vreq,
106 static void match_triple(data1_handle dh, Z_Variant *vreq,
107 const Odr_oid *def_oid,
108 const Odr_oid *var_oid, data1_node *n)
114 if (n->which != DATA1N_variant)
122 assert ((*c)->which == DATA1N_variant);
124 if ((*c)->u.variant.type->zclass->zclass == 4 &&
125 (*c)->u.variant.type->type == 1)
127 if ((r = find_triple(vreq, def_oid, var_oid, 4, 1)) &&
128 (r->which == Z_Triple_internationalString))
130 const char *string_value =
131 r->value.internationalString;
132 if (strcmp ((*c)->u.variant.value, string_value))
142 match_triple(dh, vreq, def_oid, var_oid, *c);
148 static int match_node_and_attr (data1_node *c, const char *spec)
158 if (c->u.tag.element)
159 tag = c->u.tag.element->tag;
162 sscanf(spec, "%63[^[]%c%63[^]]", elem, &dummy_ch, predicate);
163 if (data1_matchstr(elem, tag ? tag->value.string : c->u.tag.tag))
166 if (*predicate == '\0')
168 else if (sscanf(predicate, "@%63[^=]=%63s", attr, value) == 2)
171 for (xa = c->u.tag.attributes; xa; xa = xa->next)
172 if (!strcmp(xa->name, attr) &&
173 !strcmp(xa->value, value))
177 else if (sscanf(predicate, "@%63s", attr) == 1)
180 for (xa = c->u.tag.attributes; xa; xa = xa->next)
181 if (!strcmp(xa->name, attr))
186 yaz_log(YLOG_WARN, "Bad simpleelement component: '%s'", spec);
191 static int match_children_here (data1_handle dh, data1_node *n,
193 Z_ETagUnit **t, int num,
196 int counter = 0, hits = 0;
199 Z_Occurrences *occur;
201 for (c = n->child; c ; c = c->next)
205 if (c->which != DATA1N_tag)
208 if (tp->which == Z_ETagUnit_specificTag)
210 Z_SpecificTag *want = tp->u.specificTag;
211 occur = want->occurrences;
212 if (c->u.tag.element)
213 tag = c->u.tag.element->tag;
214 if (*want->tagType != ((tag && tag->tagset) ? tag->tagset->type :
217 if (want->tagValue->which == Z_StringOrNumeric_numeric)
219 if (!tag || tag->which != DATA1T_numeric)
221 if (*want->tagValue->u.numeric != tag->value.numeric)
224 else if (want->tagValue->which == Z_StringOrNumeric_string)
226 const char *str_val = want->tagValue->u.string;
227 if (str_val[0] == '!')
232 if (tag && tag->which != DATA1T_string)
235 if (!match_node_and_attr(c, str_val))
238 if (data1_matchstr(str_val,
239 tag ? tag->value.string : c->u.tag.tag))
245 yaz_log(YLOG_WARN, "Bad SpecificTag type: %d",
246 want->tagValue->which);
250 else if (tp->which == Z_ETagUnit_wildThing)
251 occur = tp->u.wildThing;
255 * Ok, so we have a matching tag. Are we within occurrences-range?
258 if (occur && occur->which == Z_Occurrences_last)
260 yaz_log(YLOG_WARN, "Can't do occurrences=last (yet)");
263 if (!occur || occur->which == Z_Occurrences_all ||
264 (occur->which == Z_Occurrences_values && counter >=
265 *occur->u.values->start))
267 if (match_children(dh, c, e, i, t + 1, num - 1, select_flag))
269 c->u.tag.node_selected = select_flag;
271 * Consider the variant specification if this is a complete
276 int show_variantlist = 0;
281 e->elements[i]->u.simpleElement->variantRequest;
283 const Odr_oid *var_oid = yaz_oid_varset_variant_1;
285 vreq = e->defaultVariantRequest;
292 * 6,5: meta-data requested, variant list.
294 if (find_triple(vreq, e->defaultVariantSetId,
296 show_variantlist = 1;
298 * 9,1: Miscellaneous, no data requested.
300 if (find_triple(vreq, e->defaultVariantSetId,
305 if ((r = find_triple(vreq, e->defaultVariantSetId,
307 if (r->which == Z_Triple_integer)
308 get_bytes = *r->value.integer;
310 if (!show_variantlist)
311 match_triple(dh, vreq, e->defaultVariantSetId,
314 mark_subtree(c, show_variantlist, no_data, get_bytes, vreq,
319 * have we looked at enough children?
321 if (!occur || (occur->which == Z_Occurrences_values &&
322 (!occur->u.values->howMany ||
323 counter - *occur->u.values->start >=
324 *occur->u.values->howMany - 1)))
332 static int match_children(data1_handle dh, data1_node *n, Z_Espec1 *e,
333 int i, Z_ETagUnit **t, int num, int select_flag)
341 case Z_ETagUnit_wildThing:
342 case Z_ETagUnit_specificTag:
343 res = match_children_here(dh, n, e, i, t, num, select_flag);
345 case Z_ETagUnit_wildPath:
346 res = match_children_wildpath(dh, n, e, i, t, num); break;
353 int data1_doespec1 (data1_handle dh, data1_node *n, Z_Espec1 *e)
357 n = data1_get_root_tag (dh, n);
358 if (n && n->which == DATA1N_tag)
359 n->u.tag.node_selected = 1;
361 for (i = 0; i < e->num_elements; i++)
363 if (e->elements[i]->which != Z_ERequest_simpleElement)
365 match_children(dh, n, e, i,
366 e->elements[i]->u.simpleElement->path->tags,
367 e->elements[i]->u.simpleElement->path->num_tags,
368 1 /* select (include) by default */ );
375 * c-file-style: "Stroustrup"
376 * indent-tabs-mode: nil
378 * vim: shiftwidth=4 tabstop=8 expandtab