1 /* $Id: recgrs.c,v 1.71 2002-12-16 20:27:18 adam Exp $
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
5 This file is part of the Zebra server.
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 #include <sys/types.h>
36 #define GRS_MAX_WORD 512
42 struct grs_handler *next;
46 struct grs_handler *handlers;
49 static int read_grs_type (struct grs_handlers *h,
50 struct grs_read_info *p, const char *type,
53 struct grs_handler *gh = h->handlers;
54 const char *cp = strchr (type, '.');
56 if (cp == NULL || cp == type)
58 cp = strlen(type) + type;
62 strcpy (p->type, cp+1);
63 for (gh = h->handlers; gh; gh = gh->next)
65 if (!memcmp (type, gh->type->type, cp-type))
70 gh->clientData = (*gh->type->init)();
72 p->clientData = gh->clientData;
73 *root = (gh->type->read)(p);
74 gh->clientData = p->clientData;
81 static void grs_add_handler (struct grs_handlers *h, RecTypeGrs t)
83 struct grs_handler *gh = (struct grs_handler *) xmalloc (sizeof(*gh));
84 gh->next = h->handlers;
91 static void *grs_init(RecType recType)
93 struct grs_handlers *h = (struct grs_handlers *) xmalloc (sizeof(*h));
96 grs_add_handler (h, recTypeGrs_sgml);
97 grs_add_handler (h, recTypeGrs_regx);
99 grs_add_handler (h, recTypeGrs_tcl);
101 grs_add_handler (h, recTypeGrs_marc);
103 grs_add_handler (h, recTypeGrs_xml);
106 grs_add_handler (h, recTypeGrs_perl);
111 static void grs_destroy(void *clientData)
113 struct grs_handlers *h = (struct grs_handlers *) clientData;
114 struct grs_handler *gh = h->handlers, *gh_next;
119 (*gh->type->destroy)(gh->clientData);
128 New function, looking for xpath "element" definitions in abs, by
129 tagpath, using a kind of ugly regxp search.The DFA was built while
130 parsing abs, so here we just go trough them and try to match
131 against the given tagpath. The first matching entry is returned.
136 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
138 data1_absyn *abs = n->root->u.root.absyn;
139 data1_xpelement *xpe = abs->xp_elements;
140 char *pexpr = malloc(strlen(tagpath)+2);
143 sprintf (pexpr, "%s\n", tagpath);
146 struct DFA_state **dfaar = xpe->dfa->states;
147 struct DFA_state *s=dfaar[0];
154 c = *pexpr++; t = s->trans; i = s->tran_no;
155 if (c >= t->ch[0] && c <= t->ch[1]) {
158 if ((s = dfaar[t->to])->rule_no &&
159 (start_line || s->rule_nno)) {
163 for (t=s->trans, i=s->tran_no; --i >= 0; t++) {
164 if ((unsigned) *p >= t->ch[0] && (unsigned) *p <= t->ch[1])
176 return xpe->termlists;
183 1 start element (tag)
185 3 start attr (and attr-exact)
193 Now, if there is a matching xelm described in abs, for the
194 indexed element or the attribute, then the data is handled according
195 to those definitions...
197 modified by pop, 2002-12-13
200 static void index_xpath (data1_node *n, struct recExtractCtrl *p,
201 int level, RecWord *wrd, int use)
204 char tag_path_full[1024];
211 wrd->string = n->u.data.data;
212 wrd->length = n->u.data.len;
213 if (p->flagShowRecords)
215 printf("%*s data=", (level + 1) * 4, "");
216 for (i = 0; i<wrd->length && i < 8; i++)
217 fputc (wrd->string[i], stdout);
225 /* we have to fetch the whole path to the data tag */
226 for (nn = n; nn; nn = nn->parent) {
227 if (nn->which == DATA1N_tag) {
228 size_t tlen = strlen(nn->u.tag.tag);
229 if (tlen + flen > (sizeof(tag_path_full)-2)) return;
230 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
232 tag_path_full[flen++] = '/';
234 else if (nn->which == DATA1N_root) break;
237 tag_path_full[flen] = 0;
239 /* If we have a matching termlist... */
240 if (tl = xpath_termlist_by_tagpath(tag_path_full, n)) {
241 for (; tl; tl = tl->next) {
242 wrd->reg_type = *tl->structure;
243 /* this is the ! case, so structure is for the xpath index */
245 wrd->attrSet = VAL_IDXPATH;
249 /* this is just the old fashioned attribute based index */
251 wrd->attrSet = (int) (tl->att->parent->reference);
252 wrd->attrUse = tl->att->locals->local;
257 /* xpath indexing is done, if there was no termlist given,
258 or no ! attribute... */
260 wrd->attrSet = VAL_IDXPATH;
269 for (nn = n; nn; nn = nn->parent)
271 if (nn->which == DATA1N_tag)
273 size_t tlen = strlen(nn->u.tag.tag);
274 if (tlen + flen > (sizeof(tag_path_full)-2))
276 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
278 tag_path_full[flen++] = '/';
280 else if (nn->which == DATA1N_root)
286 wrd->string = tag_path_full;
288 wrd->attrSet = VAL_IDXPATH;
290 if (p->flagShowRecords)
292 printf("%*s tag=", (level + 1) * 4, "");
293 for (i = 0; i<wrd->length && i < 40; i++)
294 fputc (wrd->string[i], stdout);
302 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
305 for (xp = n->u.tag.attributes; xp; xp = xp->next)
308 /* attribute (no value) */
311 wrd->string = xp->name;
312 wrd->length = strlen(xp->name);
318 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2)
320 /* attribute value exact */
321 strcpy (comb, xp->name);
323 strcat (comb, xp->value);
328 wrd->length = strlen(comb);
334 for (xp = n->u.tag.attributes; xp; xp = xp->next)
336 char attr_tag_path_full[1024];
339 sprintf (attr_tag_path_full, "@%s/%.*s",
340 xp->name, int_len, tag_path_full);
343 wrd->string = attr_tag_path_full;
344 wrd->length = strlen(attr_tag_path_full);
349 /* the same jokes, as with the data nodes ... */
353 wrd->string = xp->value;
354 wrd->length = strlen(xp->value);
357 if (tl = xpath_termlist_by_tagpath(attr_tag_path_full,
359 for (; tl; tl = tl->next) {
360 wrd->reg_type = *tl->structure;
362 wrd->attrSet = VAL_IDXPATH;
367 wrd->attrSet = (int) (tl->att->parent->reference);
368 wrd->attrUse = tl->att->locals->local;
375 wrd->attrSet = VAL_IDXPATH;
382 wrd->attrSet = VAL_IDXPATH;
385 wrd->string = attr_tag_path_full;
386 wrd->length = strlen(attr_tag_path_full);
394 static void index_termlist (data1_node *par, data1_node *n,
395 struct recExtractCtrl *p, int level, RecWord *wrd)
397 data1_termlist *tlist = 0;
398 data1_datatype dtype = DATA1K_string;
401 * cycle up towards the root until we find a tag with an att..
402 * this has the effect of indexing locally defined tags with
403 * the attribute of their ancestor in the record.
406 while (!par->u.tag.element)
407 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
409 if (!par || !(tlist = par->u.tag.element->termlists))
411 if (par->u.tag.element->tag)
412 dtype = par->u.tag.element->tag->kind;
414 for (; tlist; tlist = tlist->next)
418 /* consider source */
421 if (!strcmp (tlist->source, "data") && n->which == DATA1N_data)
423 wrd->string = n->u.data.data;
424 wrd->length = n->u.data.len;
426 else if (!strcmp (tlist->source, "tag") && n->which == DATA1N_tag)
428 wrd->string = n->u.tag.tag;
429 wrd->length = strlen(n->u.tag.tag);
431 else if (sscanf (tlist->source, "attr(%511[^)])", xattr) == 1 &&
432 n->which == DATA1N_tag)
434 data1_xattr *p = n->u.tag.attributes;
435 while (p && strcmp (p->name, xattr))
439 wrd->string = p->value;
440 wrd->length = strlen(p->value);
445 if (p->flagShowRecords)
448 printf("%*sIdx: [%s]", (level + 1) * 4, "",
450 printf("%s:%s [%d] %s",
451 tlist->att->parent->name,
452 tlist->att->name, tlist->att->value,
455 for (i = 0; i<wrd->length && i < 8; i++)
456 fputc (wrd->string[i], stdout);
460 fputc ('\n', stdout);
464 wrd->reg_type = *tlist->structure;
465 wrd->attrSet = (int) (tlist->att->parent->reference);
466 wrd->attrUse = tlist->att->locals->local;
473 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level,
476 for (; n; n = n->next)
478 if (p->flagShowRecords) /* display element description to user */
480 if (n->which == DATA1N_root)
482 printf("%*s", level * 4, "");
483 printf("Record type: '%s'\n", n->u.root.type);
485 else if (n->which == DATA1N_tag)
489 printf("%*s", level * 4, "");
490 if (!(e = n->u.tag.element))
491 printf("Local tag: '%s'\n", n->u.tag.tag);
494 printf("Elm: '%s' ", e->name);
497 data1_tag *t = e->tag;
499 printf("TagNam: '%s' ", t->names->name);
502 printf("%s[%d],", t->tagset->name, t->tagset->type);
505 if (t->which == DATA1T_numeric)
506 printf("%d)", t->value.numeric);
508 printf("'%s')", t->value.string);
515 if (n->which == DATA1N_tag)
517 index_termlist (n, n, p, level, wrd);
518 /* index start tag */
519 assert (n->root->u.root.absyn);
521 if (!n->root->u.root.absyn)
522 index_xpath (n, p, level, wrd, 1);
523 else if (n->root->u.root.absyn->enable_xpath_indexing)
524 index_xpath (n, p, level, wrd, 1);
528 if (dumpkeys(n->child, p, level + 1, wrd) < 0)
532 if (n->which == DATA1N_data)
534 data1_node *par = get_parent_tag(p->dh, n);
536 if (p->flagShowRecords)
538 printf("%*s", level * 4, "");
540 if (n->u.data.len > 256)
541 printf("'%.240s ... %.6s'\n", n->u.data.data,
542 n->u.data.data + n->u.data.len-6);
543 else if (n->u.data.len > 0)
544 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
550 index_termlist (par, n, p, level, wrd);
551 if (!n->root->u.root.absyn)
552 index_xpath (n, p, level, wrd, 1016);
553 else if (n->root->u.root.absyn->enable_xpath_indexing)
554 index_xpath (n, p, level, wrd, 1016);
557 if (n->which == DATA1N_tag)
560 if (!n->root->u.root.absyn)
561 index_xpath (n, p, level, wrd, 2);
562 else if (n->root->u.root.absyn->enable_xpath_indexing)
563 index_xpath (n, p, level, wrd, 2);
566 if (p->flagShowRecords && n->which == DATA1N_root)
568 printf("%*s-------------\n\n", level * 4, "");
574 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
577 int oidtmp[OID_SIZE];
580 oe.proto = PROTO_Z3950;
581 oe.oclass = CLASS_SCHEMA;
584 oe.value = n->u.root.absyn->reference;
586 if ((oid_ent_to_oid (&oe, oidtmp)))
587 (*p->schemaAdd)(p, oidtmp);
591 return dumpkeys(n, p, 0, &wrd);
594 static int grs_extract_sub(struct grs_handlers *h, struct recExtractCtrl *p,
598 struct grs_read_info gri;
600 int oidtmp[OID_SIZE];
603 gri.readf = p->readf;
604 gri.seekf = p->seekf;
605 gri.tellf = p->tellf;
608 gri.offset = p->offset;
612 if (read_grs_type (h, &gri, p->subType, &n))
613 return RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER;
615 return RECCTRL_EXTRACT_EOF;
616 oe.proto = PROTO_Z3950;
617 oe.oclass = CLASS_SCHEMA;
619 if (!n->u.root.absyn)
620 return RECCTRL_EXTRACT_ERROR;
624 oe.value = n->u.root.absyn->reference;
625 if ((oid_ent_to_oid (&oe, oidtmp)))
626 (*p->schemaAdd)(p, oidtmp);
629 /* ensure our data1 tree is UTF-8 */
630 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
633 data1_pr_tree (p->dh, n, stdout);
637 if (dumpkeys(n, p, 0, &wrd) < 0)
639 data1_free_tree(p->dh, n);
640 return RECCTRL_EXTRACT_ERROR_GENERIC;
642 data1_free_tree(p->dh, n);
643 return RECCTRL_EXTRACT_OK;
646 static int grs_extract(void *clientData, struct recExtractCtrl *p)
649 NMEM mem = nmem_create ();
650 struct grs_handlers *h = (struct grs_handlers *) clientData;
652 ret = grs_extract_sub(h, p, mem);
658 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
660 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c)
662 data1_esetname *eset;
668 case Z_RecordComp_simple:
669 if (c->u.simple->which != Z_ElementSetNames_generic)
670 return 26; /* only generic form supported. Fix this later */
671 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
672 c->u.simple->u.generic)))
674 logf(LOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
675 return 25; /* invalid esetname */
677 logf(LOG_DEBUG, "Esetname '%s' in simple compspec",
678 c->u.simple->u.generic);
681 case Z_RecordComp_complex:
682 if (c->u.complex->generic)
684 /* insert check for schema */
685 if ((p = c->u.complex->generic->elementSpec))
689 case Z_ElementSpec_elementSetName:
691 data1_getesetbyname(dh, n->u.root.absyn,
692 p->u.elementSetName)))
694 logf(LOG_LOG, "Unknown esetname '%s'",
695 p->u.elementSetName);
696 return 25; /* invalid esetname */
698 logf(LOG_DEBUG, "Esetname '%s' in complex compspec",
699 p->u.elementSetName);
702 case Z_ElementSpec_externalSpec:
703 if (p->u.externalSpec->which == Z_External_espec1)
705 logf(LOG_DEBUG, "Got Espec-1");
706 espec = p->u.externalSpec-> u.espec1;
710 logf(LOG_LOG, "Unknown external espec.");
711 return 25; /* bad. what is proper diagnostic? */
722 logf (LOG_DEBUG, "Element: Espec-1 match");
723 return data1_doespec1(dh, n, espec);
727 logf (LOG_DEBUG, "Element: all match");
732 /* Add Zebra info in separate namespace ...
735 <metadata xmlns="http://www.indexdata.dk/zebra/">
737 <localnumber>447</localnumber>
738 <filename>records/genera.xml</filename>
743 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
746 const char *idzebra_ns[3];
747 const char *i2 = "\n ";
748 const char *i4 = "\n ";
751 idzebra_ns[0] = "xmlns";
752 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
755 data1_mk_text (p->dh, mem, i2, top);
757 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
759 data1_mk_text (p->dh, mem, "\n", top);
761 data1_mk_text (p->dh, mem, i4, n);
763 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
767 data1_mk_text (p->dh, mem, i4, n);
768 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
770 data1_mk_text (p->dh, mem, i4, n);
771 data1_mk_tag_data_int (p->dh, n, "localnumber", p->localno, mem);
774 data1_mk_text (p->dh, mem, i4, n);
775 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
777 data1_mk_text (p->dh, mem, i2, n);
780 static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p)
782 data1_node *node = 0, *onode = 0, *top;
785 int res, selected = 0;
787 struct grs_read_info gri;
789 struct grs_handlers *h = (struct grs_handlers *) clientData;
790 int requested_schema = VAL_NONE;
791 data1_marctab *marctab;
795 gri.readf = p->readf;
796 gri.seekf = p->seekf;
797 gri.tellf = p->tellf;
804 logf (LOG_DEBUG, "grs_retrieve");
805 if (read_grs_type (h, &gri, p->subType, &node))
817 /* ensure our data1 tree is UTF-8 */
818 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
821 data1_pr_tree (p->dh, node, stdout);
823 top = data1_get_root_tag (p->dh, node);
825 logf (LOG_DEBUG, "grs_retrieve: size");
826 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
828 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
830 dnew->u.data.what = DATA1I_text;
831 dnew->u.data.data = dnew->lbuf;
832 sprintf(dnew->u.data.data, "%d", p->recordSize);
833 dnew->u.data.len = strlen(dnew->u.data.data);
836 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
837 if (tagname && p->score >= 0 &&
838 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
840 logf (LOG_DEBUG, "grs_retrieve: %s", tagname);
841 dnew->u.data.what = DATA1I_num;
842 dnew->u.data.data = dnew->lbuf;
843 sprintf(dnew->u.data.data, "%d", p->score);
844 dnew->u.data.len = strlen(dnew->u.data.data);
847 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
848 "localControlNumber");
849 if (tagname && p->localno > 0 &&
850 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
852 logf (LOG_DEBUG, "grs_retrieve: %s", tagname);
853 dnew->u.data.what = DATA1I_text;
854 dnew->u.data.data = dnew->lbuf;
856 sprintf(dnew->u.data.data, "%d", p->localno);
857 dnew->u.data.len = strlen(dnew->u.data.data);
860 data1_pr_tree (p->dh, node, stdout);
862 if (p->comp && p->comp->which == Z_RecordComp_complex &&
863 p->comp->u.complex->generic &&
864 p->comp->u.complex->generic->schema)
866 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema);
868 requested_schema = oe->value;
871 /* If schema has been specified, map if possible, then check that
872 * we got the right one
874 if (requested_schema != VAL_NONE)
876 logf (LOG_DEBUG, "grs_retrieve: schema mapping");
877 for (map = node->u.root.absyn->maptabs; map; map = map->next)
879 if (map->target_absyn_ref == requested_schema)
882 if (!(node = data1_map_record(p->dh, onode, map, mem)))
891 if (node->u.root.absyn &&
892 requested_schema != node->u.root.absyn->reference)
900 * Does the requested format match a known syntax-mapping? (this reflects
901 * the overlap of schema and formatting which is inherent in the MARC
904 yaz_log (LOG_DEBUG, "grs_retrieve: syntax mapping");
905 if (node->u.root.absyn)
906 for (map = node->u.root.absyn->maptabs; map; map = map->next)
908 if (map->target_absyn_ref == p->input_format)
911 if (!(node = data1_map_record(p->dh, onode, map, mem)))
920 yaz_log (LOG_DEBUG, "grs_retrieve: schemaIdentifier");
921 if (node->u.root.absyn &&
922 node->u.root.absyn->reference != VAL_NONE &&
923 p->input_format == VAL_GRS1)
927 int oidtmp[OID_SIZE];
929 oe.proto = PROTO_Z3950;
930 oe.oclass = CLASS_SCHEMA;
931 oe.value = node->u.root.absyn->reference;
933 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
936 data1_handle dh = p->dh;
940 for (ii = oid; *ii >= 0; ii++)
944 sprintf(p, "%d", *ii);
947 if ((dnew = data1_mk_tag_data_wd(dh, top,
948 "schemaIdentifier", mem)))
950 dnew->u.data.what = DATA1I_oid;
951 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
952 memcpy(dnew->u.data.data, tmp, p - tmp);
953 dnew->u.data.len = p - tmp;
958 logf (LOG_DEBUG, "grs_retrieve: element spec");
959 if (p->comp && (res = process_comp(p->dh, node, p->comp)) > 0)
963 data1_free_tree(p->dh, onode);
964 data1_free_tree(p->dh, node);
968 else if (p->comp && !res)
972 data1_pr_tree (p->dh, node, stdout);
974 logf (LOG_DEBUG, "grs_retrieve: transfer syntax mapping");
975 switch (p->output_format = (p->input_format != VAL_NONE ?
976 p->input_format : VAL_SUTRS))
979 zebra_xml_metadata (p, top, mem);
982 data1_pr_tree (p->dh, node, stdout);
986 data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");
988 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
993 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
994 memcpy (new_buf, p->rec_buf, p->rec_len);
995 p->rec_buf = new_buf;
1000 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1002 p->diagnostic = 238; /* not available in requested syntax */
1004 p->rec_len = (size_t) (-1);
1007 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1009 p->diagnostic = 238;
1011 p->rec_len = (size_t) (-1);
1014 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1016 p->diagnostic = 238;
1018 p->rec_len = (size_t) (-1);
1022 data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");
1023 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1025 p->diagnostic = 238;
1028 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1029 memcpy (new_buf, p->rec_buf, p->rec_len);
1030 p->rec_buf = new_buf;
1034 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1036 p->diagnostic = 238;
1039 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1040 memcpy (new_buf, p->rec_buf, p->rec_len);
1041 p->rec_buf = new_buf;
1045 if (!node->u.root.absyn)
1047 p->diagnostic = 238;
1050 for (marctab = node->u.root.absyn->marc; marctab;
1051 marctab = marctab->next)
1052 if (marctab->reference == p->input_format)
1056 p->diagnostic = 238;
1060 data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");
1061 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1062 selected, &p->rec_len)))
1063 p->diagnostic = 238;
1066 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1067 memcpy (new_buf, p->rec_buf, p->rec_len);
1068 p->rec_buf = new_buf;
1072 data1_free_tree(p->dh, node);
1074 data1_free_tree(p->dh, onode);
1079 static struct recType grs_type =
1088 RecType recTypeGrs = &grs_type;