ac19a9f2292008d128d0212761877e2ad023303e
[yaz-moved-to-github.git] / retrieval / d1_read.c
1 /*
2  * Copyright (c) 1995-2002, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Id: d1_read.c,v 1.42 2002-05-13 14:13:37 adam Exp $
7  */
8
9 #include <assert.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #include <yaz/xmalloc.h>
14 #include <yaz/log.h>
15 #include <yaz/data1.h>
16
17 /*
18  * get the tag which is the immediate parent of this node (this may mean
19  * traversing intermediate things like variants and stuff.
20  */
21 data1_node *get_parent_tag (data1_handle dh, data1_node *n)
22 {
23     for (; n && n->which != DATA1N_root; n = n->parent)
24         if (n->which == DATA1N_tag)
25             return n;
26     return 0;
27 }
28
29 data1_node *data1_mk_node (data1_handle dh, NMEM m)
30 {
31     return data1_mk_node2 (dh, m, DATA1N_root, 0);
32 }
33
34 data1_node *data1_mk_node_type (data1_handle dh, NMEM m, int type)
35 {
36     return data1_mk_node2 (dh, m, type, 0);
37 }
38
39 data1_node *data1_mk_node2 (data1_handle dh, NMEM m, int type,
40                             data1_node *parent)
41 {
42     data1_node *r;
43     
44     r = (data1_node *)nmem_malloc(m, sizeof(*r));
45     r->next = r->child = r->last_child = 0;
46     r->destroy = 0;
47
48     if (!parent)
49     {
50         r->root = r;
51     }
52     else
53     {
54         r->root = parent->root;
55         r->parent = parent;
56         if (!parent->child)
57             parent->child = parent->last_child = r;
58         else
59             parent->last_child->next = r;
60         parent->last_child = r;
61     }
62     r->which = type;
63     switch(type)
64     {
65     case DATA1N_tag:
66         r->u.tag.tag = 0;
67         r->u.tag.element = 0;
68         r->u.tag.no_data_requested = 0;
69         r->u.tag.node_selected = 0;
70         r->u.tag.make_variantlist = 0;
71         r->u.tag.get_bytes = -1;
72         r->u.tag.attributes = 0;
73         break;
74     case DATA1N_root:
75         r->u.root.type = 0;
76         r->u.root.absyn = 0;
77         break;
78     case DATA1N_data:
79         r->u.data.data = 0;
80         r->u.data.len = 0;
81         r->u.data.what = 0;
82         r->u.data.formatted_text = 0;
83         break;
84     case DATA1N_variant:
85         r->u.variant.type = 0;
86         r->u.variant.value = 0;
87         break;
88     default:
89         logf (LOG_WARN, "data_mk_node_type. bad type = %d\n", type);
90     }
91     return r;
92 }
93
94 void data1_free_tree (data1_handle dh, data1_node *t)
95 {
96     data1_node *p = t->child, *pn;
97
98     while (p)
99     {
100         pn = p->next;
101         data1_free_tree (dh, p);
102         p = pn;
103     }
104     if (t->destroy)
105         (*t->destroy)(t);
106 }
107
108 data1_node *data1_mk_root (data1_handle dh, NMEM nmem,  const char *name)
109 {
110     data1_absyn *absyn = data1_get_absyn (dh, name);
111     data1_node *res;
112     if (!absyn)
113     {
114         yaz_log(LOG_WARN, "Unable to acquire abstract syntax " "for '%s'",
115                 name); 
116         /* It's now OK for a record not to have an absyn */
117     }
118     res = data1_mk_node2 (dh, nmem, DATA1N_root, 0);
119     res->u.root.type = data1_insert_string (dh, res, nmem, name);
120     res->u.root.absyn = absyn;
121     return res;
122 }
123
124 data1_node *data1_mk_tag_n (data1_handle dh, NMEM nmem, 
125                             const char *tag, size_t len, const char **attr,
126                             data1_node *at)
127 {
128     data1_node *partag = get_parent_tag(dh, at);
129     data1_node *res = data1_mk_node2 (dh, nmem, DATA1N_tag, at);
130     data1_element *e = NULL;
131     data1_xattr **p;
132     
133     res->u.tag.tag = data1_insert_string_n (dh, res, nmem, tag, len);
134     
135     if (partag)
136         e = partag->u.tag.element;
137     res->u.tag.element =
138         data1_getelementbytagname (dh, at->root->u.root.absyn,
139                                    e, res->u.tag.tag);
140     p = &res->u.tag.attributes;
141     while (attr && *attr)
142     {
143         *p = (data1_xattr*) nmem_malloc (nmem, sizeof(**p));
144         (*p)->name = nmem_strdup (nmem, attr[0]);
145         (*p)->value = nmem_strdup (nmem, attr[1]);
146         p = &(*p)->next;
147     }
148     *p = 0;
149     return res;
150 }
151
152 data1_node *data1_mk_tag (data1_handle dh, NMEM nmem,
153                           const char *tag, const char **attr, data1_node *at) 
154 {
155     return data1_mk_tag_n (dh, nmem, tag, strlen(tag), attr, at);
156 }
157
158 data1_node *data1_search_tag (data1_handle dh, data1_node *n,
159                               const char *tag)
160 {
161     for (; n; n = n->next)
162         if (n->which == DATA1N_tag && n->u.tag.tag &&
163             !yaz_matchstr (tag, n->u.tag.tag))
164         {
165             return n;
166         }
167     return 0;
168 }
169
170 data1_node *data1_mk_tag_uni (data1_handle dh, NMEM nmem, 
171                               const char *tag, data1_node *at)
172 {
173     data1_node *node = data1_search_tag (dh, at->child, tag);
174     if (!node)
175         node = data1_mk_tag (dh, nmem, tag, 0 /* attr */, at);
176     else
177         node->child = node->last_child = 0;
178     return node;
179 }
180
181
182 data1_node *data1_mk_text_n (data1_handle dh, NMEM mem,
183                              const char *buf, size_t len, data1_node *parent)
184 {
185     data1_node *res = data1_mk_node2 (dh, mem, DATA1N_data, parent);
186     res->u.data.what = DATA1I_text;
187     res->u.data.len = len;
188     
189     res->u.data.data = data1_insert_string_n (dh, res, mem, buf, len);
190     return res;
191 }
192
193
194 data1_node *data1_mk_text (data1_handle dh, NMEM mem,
195                            const char *buf, data1_node *parent)
196 {
197     return data1_mk_text_n (dh, mem, buf, strlen(buf), parent);
198 }
199
200 char *data1_insert_string_n (data1_handle dh, data1_node *res,
201                              NMEM m, const char *str, size_t len)
202 {
203     char *b;
204     if (len >= DATA1_LOCALDATA)
205         b = nmem_malloc (m, len+1);
206     else
207         b = res->lbuf;
208     memcpy (b, str, len);
209     b[len] = 0;
210     return b;
211 }
212
213 char *data1_insert_string (data1_handle dh, data1_node *res,
214                            NMEM m, const char *str)
215 {
216     return data1_insert_string_n (dh, res, m, str, strlen(str));
217 }
218
219 static data1_node *data1_add_insert_taggeddata(data1_handle dh,
220                                                data1_node *at,
221                                                const char *tagname, NMEM m,
222                                                int local_allowed)
223 {
224     data1_node *root = at->root;
225     data1_node *partag = get_parent_tag (dh, at);
226     data1_element *e = NULL;
227     data1_node *datn = 0;
228     data1_node *tagn = 0;
229
230     if (partag)
231         e = partag->u.tag.element;
232     e = data1_getelementbytagname (dh, root->u.root.absyn, e, tagname);
233     if (local_allowed || e)
234     {
235         tagn = data1_mk_node2 (dh, m, DATA1N_tag, at);
236         tagn->u.tag.tag = data1_insert_string (dh, tagn, m, tagname);
237         tagn->u.tag.element = e;
238         datn = data1_mk_node2 (dh, m, DATA1N_data, tagn);
239     }
240     return datn;
241 }
242
243 data1_node *data1_mk_tag_data(data1_handle dh, data1_node *at,
244                               const char *tagname, NMEM m)
245 {
246     return data1_add_insert_taggeddata (dh, at, tagname, m, 1);
247 }
248
249
250 /*
251  * Insert a tagged node into the record root as first child of the node at
252  * which should be root or tag itself). Returns pointer to the data node,
253  * which can then be modified.
254  */
255 data1_node *data1_mk_tag_data_wd(data1_handle dh, data1_node *at,
256                                  const char *tagname, NMEM m)
257 {
258     return data1_add_insert_taggeddata (dh, at, tagname, m, 0);
259 }
260
261 data1_node *data1_insert_taggeddata (data1_handle dh, data1_node *root,
262                                      data1_node *at, const char *tagname,
263                                      NMEM m)
264 {
265     return data1_add_insert_taggeddata (dh, at, tagname, m, 0);
266 }
267
268 data1_node *data1_add_taggeddata (data1_handle dh, data1_node *root,
269                                   data1_node *at, const char *tagname,
270                                   NMEM m)
271 {
272     return data1_add_insert_taggeddata (dh, at, tagname, m, 1);
273 }
274
275 data1_node *data1_mk_tag_data_int (data1_handle dh, data1_node *at,
276                                    const char *tag, int num,
277                                    NMEM nmem)
278 {
279     data1_node *node_data;
280     
281     node_data = data1_mk_tag_data (dh, at, tag, nmem);
282     if (!node_data)
283         return 0;
284     node_data->u.data.what = DATA1I_num;
285     node_data->u.data.data = node_data->lbuf;
286     sprintf (node_data->u.data.data, "%d", num);
287     node_data->u.data.len = strlen (node_data->u.data.data);
288     return node_data;
289 }
290
291 data1_node *data1_mk_tag_data_oid (data1_handle dh, data1_node *at,
292                                    const char *tag, Odr_oid *oid,
293                                    NMEM nmem)
294 {
295     data1_node *node_data;
296     char str[128], *p = str;
297     Odr_oid *ii;
298     
299     node_data = data1_mk_tag_data (dh, at, tag, nmem);
300     if (!node_data)
301         return 0;
302     
303     for (ii = oid; *ii >= 0; ii++)
304     {
305         if (ii != oid)
306             *p++ = '.';
307         sprintf (p, "%d", *ii);
308         p += strlen (p);
309     }
310     node_data->u.data.what = DATA1I_oid;
311     node_data->u.data.len = strlen (str);
312     node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
313     return node_data;
314 }
315
316
317 data1_node *data1_mk_tag_data_text (data1_handle dh, data1_node *at,
318                                     const char *tag, const char *str,
319                                     NMEM nmem)
320 {
321     data1_node *node_data;
322     
323     node_data = data1_mk_tag_data (dh, at, tag, nmem);
324     if (!node_data)
325         return 0;
326     node_data->u.data.what = DATA1I_text;
327     node_data->u.data.len = strlen (str);
328     node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
329     return node_data;
330 }
331
332
333 data1_node *data1_mk_tag_data_text_uni (data1_handle dh, data1_node *at,
334                                         const char *tag, const char *str,
335                                         NMEM nmem)
336 {
337     data1_node *node = data1_search_tag (dh, at->child, tag);
338     if (!node)
339         return data1_mk_tag_data_text (dh, at, tag, str, nmem);
340     else
341     {
342         data1_node *node_data = node->child;
343         node_data->u.data.what = DATA1I_text;
344         node_data->u.data.len = strlen (str);
345         node_data->u.data.data = data1_insert_string (dh, node_data,
346                                                       nmem, str);
347         node_data->child = node_data->last_child = 0;
348         return node_data;
349     }
350 }
351
352
353 data1_xattr *data1_read_xattr (data1_handle dh, NMEM m,
354                                int (*get_byte)(void *fh), void *fh,
355                                WRBUF wrbuf, int *ch)
356 {
357     data1_xattr *p_first = 0;
358     data1_xattr **pp = &p_first;
359     int c = *ch;
360     for (;;)
361     {
362         data1_xattr *p;
363         int len;
364         while (c && d1_isspace(c))
365             c = (*get_byte)(fh);
366         if (!c  || c == '>' || c == '/')
367             break;
368         *pp = p = (data1_xattr *) nmem_malloc (m, sizeof(*p));
369         p->next = 0;
370         pp = &p->next;
371         p->value = 0;
372         
373         wrbuf_rewind(wrbuf);
374         while (c && c != '=' && c != '>' && c != '/' && !d1_isspace(c))
375         {
376             wrbuf_putc (wrbuf, c);
377             c = (*get_byte)(fh);
378         }
379         wrbuf_putc (wrbuf, '\0');
380         len = wrbuf_len(wrbuf);
381         p->name = (char*) nmem_malloc (m, len);
382         strcpy (p->name, wrbuf_buf(wrbuf));
383         if (c == '=')
384         {
385             c = (*get_byte)(fh);
386             if (c == '"')
387             {
388                 c = (*get_byte)(fh);    
389                 wrbuf_rewind(wrbuf);
390                 while (c && c != '"')
391                 {
392                     wrbuf_putc (wrbuf, c);
393                     c = (*get_byte)(fh);
394                 }
395                 if (c)
396                     c = (*get_byte)(fh);        
397             }
398             else
399             {
400                 wrbuf_rewind(wrbuf);
401                 while (c && c != '>' && c != '/')
402                 {
403                     wrbuf_putc (wrbuf, c);
404                     c = (*get_byte)(fh);
405                 }
406             }
407             wrbuf_putc (wrbuf, '\0');
408             len = wrbuf_len(wrbuf);
409             p->value = (char*) nmem_malloc (m, len);
410             strcpy (p->value, wrbuf_buf(wrbuf));
411         }
412     }
413     *ch = c;
414     return p_first;
415 }
416
417 /*
418  * Ugh. Sometimes functions just grow and grow on you. This one reads a
419  * 'node' and its children.
420  */
421 data1_node *data1_read_nodex (data1_handle dh, NMEM m,
422                               int (*get_byte)(void *fh), void *fh, WRBUF wrbuf)
423 {
424     data1_node *d1_stack[256];
425     data1_node *res;
426     int c;
427     int level = 0;
428     int line = 1;
429
430     d1_stack[level] = 0;
431     c = (*get_byte)(fh);
432     while (1)
433     {
434         data1_node *parent = level ? d1_stack[level-1] : 0;
435         while (c != '\0' && d1_isspace(c))
436         {
437             if (c == '\n')
438                 line++;
439             c = (*get_byte)(fh);
440         }
441         if (c == '\0')
442             break;
443         
444         if (c == '<') /* beginning of tag */
445         {
446             data1_xattr *xattr;
447
448             char tag[64];
449             char args[256];
450             int null_tag = 0;
451             int end_tag = 0;
452             size_t i = 0;
453
454             c = (*get_byte)(fh);
455             if (c == '/')
456             {
457                 end_tag = 1;
458                 c = (*get_byte)(fh);
459             }
460             else if (c == '!')  /* tags/comments that we don't deal with yet */
461             {
462                 while (c && c != '>')
463                     c = (*get_byte)(fh);
464                 if (c)
465                     c = (*get_byte)(fh);
466                 continue;
467             }
468             while (c && c != '>' && c != '/' && !d1_isspace(c))
469             {
470                 if (i < (sizeof(tag)-1))
471                     tag[i++] = c;
472                 c = (*get_byte)(fh);
473             }
474             tag[i] = '\0';
475             xattr = data1_read_xattr (dh, m, get_byte, fh, wrbuf, &c);
476             args[0] = '\0';
477             if (c == '/')
478             {    /* <tag attrs/> or <tag/> */
479                 null_tag = 1;
480                 c = (*get_byte)(fh);
481             }
482             if (c != '>')
483             {
484                 yaz_log(LOG_WARN, "d1: %d: Malformed tag", line);
485                 return 0;
486             }
487             else
488                 c = (*get_byte)(fh);
489
490             /* End tag? */
491             if (end_tag)       
492             {
493                 if (*tag == '\0')
494                     --level;        /* </> */
495                 else
496                 {                   /* </tag> */
497                     int i = level;
498                     while (i > 0)
499                     {
500                         parent = d1_stack[--i];
501                         if ((parent->which == DATA1N_root &&
502                              !strcmp(tag, parent->u.root.type)) ||
503                             (parent->which == DATA1N_tag &&
504                              !strcmp(tag, parent->u.tag.tag)))
505                         {
506                             level = i;
507                             break;
508                         }
509                     }
510                     if (i != level)
511                     {
512                         yaz_log (LOG_WARN, "%d: no begin tag for %s",
513                                  line, tag);
514                         break;
515                     }
516                 }
517                 if (level == 0)
518                     return d1_stack[0];
519                 continue;
520             }   
521             if (level == 0) /* root ? */
522             {
523                 res = data1_mk_root (dh, m, tag);
524             }
525             else if (!strcmp(tag, "var"))
526             {
527                 char tclass[DATA1_MAX_SYMBOL], type[DATA1_MAX_SYMBOL];
528                 data1_vartype *tp;
529                 int val_offset;
530                 
531                 if (sscanf(args, "%s %s %n", tclass, type, &val_offset) != 2)
532                 {
533                     yaz_log(LOG_WARN, "Malformed variant triple at '%s'", tag);
534                     continue;
535                 }
536                 if (!(tp =
537                       data1_getvartypebyct(dh,
538                                            parent->root->u.root.absyn->varset,
539                                            tclass, type)))
540                     continue;
541                 /*
542                  * If we're the first variant in this group, create a parent 
543                  * variant, and insert it before the current variant.
544                  */
545                 if (parent->which != DATA1N_variant)
546                 {
547                     res = data1_mk_node2 (dh, m, DATA1N_variant, parent);
548                 }
549                 else
550                 {
551                     /*
552                      * now determine if one of our ancestor triples is of
553                      * same type. If so, we break here.
554                      */
555                     int i;
556                     for (i = level-1; d1_stack[i]->which==DATA1N_variant; --i)
557                         if (d1_stack[i]->u.variant.type == tp)
558                         {
559                             level = i;
560                             break;
561                         }
562                     res = data1_mk_node2 (dh, m, DATA1N_variant, parent);
563                     res->u.variant.type = tp;
564                     res->u.variant.value =
565                         data1_insert_string (dh, res, m, args + val_offset);
566                 }
567             }
568             else 
569             {
570                 /* tag.. acquire our element in the abstract syntax */
571                 res = data1_mk_tag (dh, m, tag, 0 /* attr */, parent);
572                 res->u.tag.attributes = xattr;
573             }
574             d1_stack[level] = res;
575             d1_stack[level+1] = 0;
576             if (level < 250 && !null_tag)
577                 ++level;
578         }
579         else /* != '<'... this is a body of text */
580         {
581             const char *src;
582             char *dst;
583             int len, prev_char = 0;
584             
585             if (level == 0)
586             {
587                 c = (*get_byte)(fh);
588                 continue;
589             }
590             res = data1_mk_node2 (dh, m, DATA1N_data, parent);
591             res->u.data.what = DATA1I_text;
592             res->u.data.formatted_text = 0;
593             d1_stack[level] = res;
594             
595             wrbuf_rewind(wrbuf);
596
597             while (c && c != '<')
598             {
599                 wrbuf_putc (wrbuf, c);
600                 c = (*get_byte)(fh);
601             }
602             len = wrbuf_len(wrbuf);
603
604             /* use local buffer of nmem if too large */
605             if (len >= DATA1_LOCALDATA)
606                 res->u.data.data = (char*) nmem_malloc (m, len);
607             else
608                 res->u.data.data = res->lbuf;
609             
610             /* read "data" and transfer while removing white space */
611             dst = res->u.data.data;
612             for (src = wrbuf_buf(wrbuf); --len >= 0; src++)
613             {
614                 if (*src == '\n')
615                     line++;
616                 if (d1_isspace (*src))
617                     prev_char = ' ';
618                 else
619                 {
620                     if (prev_char)
621                     {
622                         *dst++ = prev_char;
623                         prev_char = 0;
624                     }
625                     *dst++ = *src;
626                 }
627             }
628             res->u.data.len = dst - res->u.data.data;
629         }
630     }
631     return 0;
632 }
633
634 int getc_mem (void *fh)
635 {
636     const char **p = (const char **) fh;
637     if (**p)
638         return *(*p)++;
639     return 0;
640 }
641
642 data1_node *data1_read_node (data1_handle dh, const char **buf, NMEM m)
643 {
644     WRBUF wrbuf = wrbuf_alloc();
645     data1_node *node;
646
647     node = data1_read_nodex(dh, m, getc_mem, (void *) (buf), wrbuf);
648     wrbuf_free (wrbuf, 1);
649     return node;
650 }
651
652 /*
653  * Read a record in the native syntax.
654  */
655 data1_node *data1_read_record(data1_handle dh,
656                               int (*rf)(void *, char *, size_t), void *fh,
657                               NMEM m)
658 {
659     int *size;
660     char **buf = data1_get_read_buf (dh, &size);
661     const char *bp;
662     int rd = 0, res;
663     
664     if (!*buf)
665         *buf = (char *)xmalloc(*size = 4096);
666     
667     for (;;)
668     {
669         if (rd + 2048 >= *size && !(*buf =(char *)xrealloc(*buf, *size *= 2)))
670             abort();
671         if ((res = (*rf)(fh, *buf + rd, 2048)) <= 0)
672         {
673             if (!res)
674             {
675                 bp = *buf;
676                 (*buf)[rd] = '\0';
677                 return data1_read_node(dh, &bp, m);
678             }
679             else
680                 return 0;
681         }
682         rd += res;
683     }
684 }
685
686 data1_node *data1_read_sgml (data1_handle dh, NMEM m, const char *buf)
687 {
688     const char *bp = buf;
689     return data1_read_node (dh, &bp, m);
690 }
691