8247e6255502eaf30c8f42f49c32e6eefc2ba362
[idzebra-moved-to-github.git] / data1 / d1_read.c
1 /* $Id: d1_read.c,v 1.24 2007-03-20 22:07:35 adam Exp $
2    Copyright (C) 1995-2007
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
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
10 version.
11
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
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23
24 /*
25  * This module reads "loose" SGML and converts it to data1 tree 
26  */
27
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include <yaz/yaz-util.h>
33 #include <d1_absyn.h>
34
35 data1_node *data1_get_root_tag (data1_handle dh, data1_node *n)
36 {
37     if (!n)
38         return 0;
39     if (data1_is_xmlmode(dh))
40     {
41         n = n->child;
42         while (n && n->which != DATA1N_tag)
43             n = n->next;
44     }
45     return n;
46 }
47         
48 /*
49  * get the tag which is the immediate parent of this node (this may mean
50  * traversing intermediate things like variants and stuff.
51  */
52 data1_node *get_parent_tag (data1_handle dh, data1_node *n)
53 {
54     if (data1_is_xmlmode(dh))
55     {
56         for (; n && n->which != DATA1N_root; n = n->parent)
57             if (n->which == DATA1N_tag && n->parent &&
58                 n->parent->which != DATA1N_root)
59                 return n;
60     }
61     else
62     {
63         for (; n && n->which != DATA1N_root; n = n->parent)
64             if (n->which == DATA1N_tag)
65                 return n;
66     }
67     return 0;
68 }
69
70 data1_node *data1_mk_node (data1_handle dh, NMEM m)
71 {
72     return data1_mk_node2 (dh, m, DATA1N_root, 0);
73 }
74
75 data1_node *data1_mk_node_type (data1_handle dh, NMEM m, int type)
76 {
77     return data1_mk_node2 (dh, m, type, 0);
78 }
79
80 static void data1_init_node (data1_handle dh, data1_node *r, int type)
81 {
82     r->which = type;
83     switch(type)
84     {
85     case DATA1N_tag:
86         r->u.tag.tag = 0;
87         r->u.tag.element = 0;
88         r->u.tag.no_data_requested = 0;
89         r->u.tag.node_selected = 0;
90         r->u.tag.make_variantlist = 0;
91         r->u.tag.get_bytes = -1;
92         r->u.tag.attributes = 0;
93         break;
94     case DATA1N_root:
95         r->u.root.type = 0;
96         r->u.root.absyn = 0;
97         break;
98     case DATA1N_data:
99         r->u.data.data = 0;
100         r->u.data.len = 0;
101         r->u.data.what = 0;
102         r->u.data.formatted_text = 0;
103         break;
104     case DATA1N_comment:
105         r->u.data.data = 0;
106         r->u.data.len = 0;
107         r->u.data.what = 0;
108         r->u.data.formatted_text = 1;
109         break;
110     case DATA1N_variant:
111         r->u.variant.type = 0;
112         r->u.variant.value = 0;
113         break;
114     case DATA1N_preprocess:
115         r->u.preprocess.target = 0;
116         r->u.preprocess.attributes = 0;
117         break;
118     default:
119         yaz_log (YLOG_WARN, "data_mk_node_type. bad type = %d\n", type);
120     }
121 }
122
123 data1_node *data1_append_node (data1_handle dh, NMEM m, int type,
124                                data1_node *parent)
125 {
126     data1_node *r = (data1_node *)nmem_malloc(m, sizeof(*r));
127     r->next = r->child = r->last_child = 0;
128
129     r->parent = parent;
130     if (!parent)
131         r->root = r;
132     else
133     {
134         r->root = parent->root;
135         if (!parent->child)
136             parent->child = parent->last_child = r;
137         else
138             parent->last_child->next = r;
139         parent->last_child = r;
140     }
141     data1_init_node(dh, r, type);
142     return r;
143 }
144
145 data1_node *data1_mk_node2 (data1_handle dh, NMEM m, int type,
146                             data1_node *parent)
147 {
148     return data1_append_node (dh, m, type, parent);
149 }
150
151 data1_node *data1_insert_node (data1_handle dh, NMEM m, int type,
152                                data1_node *parent)
153 {
154     data1_node *r = (data1_node *)nmem_malloc(m, sizeof(*r));
155     r->next = r->child = r->last_child = 0;
156     
157     if (!parent)
158         r->root = r;
159     else
160     {
161         r->root = parent->root;
162         r->parent = parent;
163         if (!parent->child)
164             parent->last_child = r;
165         else
166             r->next = parent->child;
167         parent->child = r;
168     }
169     data1_init_node(dh, r, type);
170     return r;
171 }
172
173 data1_node *data1_mk_root (data1_handle dh, NMEM nmem, const char *name)
174 {
175     data1_absyn *absyn = data1_get_absyn(dh, name, 1);
176     data1_node *res;
177     if (!absyn)
178     {
179         yaz_log(YLOG_WARN, "Unable to acquire abstract syntax " "for '%s'",
180                 name); 
181         /* It's now OK for a record not to have an absyn */
182     }
183     res = data1_mk_node2 (dh, nmem, DATA1N_root, 0);
184     res->u.root.type = data1_insert_string (dh, res, nmem, name);
185     res->u.root.absyn = absyn;
186     return res;
187 }
188
189 void data1_set_root(data1_handle dh, data1_node *res,
190                     NMEM nmem, const char *name)
191 {
192     data1_absyn *absyn = data1_get_absyn(
193         dh, name, DATA1_XPATH_INDEXING_ENABLE);
194
195     res->u.root.type = data1_insert_string (dh, res, nmem, name);
196     res->u.root.absyn = absyn;
197 }
198
199 void data1_add_attrs(data1_handle dh, NMEM nmem, const char **attr,
200                      data1_xattr **p)
201 {
202     while (*p)
203         p = &(*p)->next;
204
205     while (attr && *attr)
206     {
207         *p = (data1_xattr*) nmem_malloc (nmem, sizeof(**p));
208         (*p)->name = nmem_strdup (nmem, *attr++);
209         (*p)->value = nmem_strdup (nmem, *attr++);
210         (*p)->what = DATA1I_text;
211
212         p = &(*p)->next;
213     }
214     *p = 0;
215 }
216                      
217 data1_node *data1_mk_preprocess (data1_handle dh, NMEM nmem,
218                                  const char *target,
219                                  const char **attr, data1_node *at)
220 {
221     return data1_mk_preprocess_n (dh, nmem, target, strlen(target),
222                                   attr, at);
223 }
224
225 data1_node *data1_mk_preprocess_n (data1_handle dh, NMEM nmem,
226                                    const char *target, size_t len,
227                                    const char **attr, data1_node *at)
228 {
229     data1_node *res = data1_mk_node2 (dh, nmem, DATA1N_preprocess, at);
230     res->u.preprocess.target = data1_insert_string_n (dh, res, nmem,
231                                                       target, len);
232     
233     data1_add_attrs(dh, nmem, attr, &res->u.preprocess.attributes);
234     return res;
235 }
236
237 data1_node *data1_insert_preprocess (data1_handle dh, NMEM nmem,
238                                  const char *target,
239                                  const char **attr, data1_node *at)
240 {
241     return data1_insert_preprocess_n (dh, nmem, target, strlen(target),
242                                       attr, at);
243 }
244
245 data1_node *data1_insert_preprocess_n (data1_handle dh, NMEM nmem,
246                                    const char *target, size_t len,
247                                    const char **attr, data1_node *at)
248 {
249     data1_node *res = data1_insert_node (dh, nmem, DATA1N_preprocess, at);
250     res->u.preprocess.target = data1_insert_string_n (dh, res, nmem,
251                                                       target, len);
252     
253     data1_add_attrs(dh, nmem, attr, &res->u.preprocess.attributes);
254     return res;
255 }
256
257 data1_node *data1_mk_tag_n (data1_handle dh, NMEM nmem, 
258                             const char *tag, size_t len, const char **attr,
259                             data1_node *at)
260 {
261     data1_node *partag = get_parent_tag(dh, at);
262     data1_node *res = data1_mk_node2 (dh, nmem, DATA1N_tag, at);
263     data1_element *e = 0;
264     
265     res->u.tag.tag = data1_insert_string_n (dh, res, nmem, tag, len);
266     
267     if (!partag)  /* top tag? */
268         e  = data1_getelementbytagname (dh, at->root->u.root.absyn,
269                                         0 /* index as local */,
270                                         res->u.tag.tag);
271     else
272     {
273         /* only set element for known tags */
274         e = partag->u.tag.element;
275         if (e)
276             e = data1_getelementbytagname (dh, at->root->u.root.absyn,
277                                            e, res->u.tag.tag);
278     }
279     res->u.tag.element = e;
280     data1_add_attrs(dh, nmem, attr, &res->u.tag.attributes);
281     return res;
282 }
283
284 void data1_tag_add_attr (data1_handle dh, NMEM nmem,
285                          data1_node *res, const char **attr)
286 {
287     if (res->which != DATA1N_tag)
288         return;
289
290     data1_add_attrs(dh, nmem, attr, &res->u.tag.attributes);
291 }
292
293 data1_node *data1_mk_tag (data1_handle dh, NMEM nmem,
294                           const char *tag, const char **attr, data1_node *at) 
295 {
296     return data1_mk_tag_n (dh, nmem, tag, strlen(tag), attr, at);
297 }
298
299 data1_node *data1_search_tag (data1_handle dh, data1_node *n,
300                               const char *tag)
301 {
302     if (*tag == '/')
303     {
304         n = data1_get_root_tag (dh, n);
305         if (n)
306             n = n->child;
307         tag++;
308     }
309     for (; n; n = n->next)
310         if (n->which == DATA1N_tag && n->u.tag.tag &&
311             !yaz_matchstr (n->u.tag.tag, tag))
312         {
313             return n;
314         }
315     return 0;
316 }
317
318 data1_node *data1_mk_tag_uni (data1_handle dh, NMEM nmem, 
319                               const char *tag, data1_node *at)
320 {
321     data1_node *node = data1_search_tag (dh, at->child, tag);
322     if (!node)
323         node = data1_mk_tag (dh, nmem, tag, 0 /* attr */, at);
324     else
325         node->child = node->last_child = 0;
326     return node;
327 }
328
329 data1_node *data1_mk_text_n (data1_handle dh, NMEM mem,
330                              const char *buf, size_t len, data1_node *parent)
331 {
332     data1_node *res = data1_mk_node2 (dh, mem, DATA1N_data, parent);
333     res->u.data.what = DATA1I_text;
334     res->u.data.len = len;
335     
336     res->u.data.data = data1_insert_string_n (dh, res, mem, buf, len);
337     return res;
338 }
339
340 data1_node *data1_mk_text_nf (data1_handle dh, NMEM mem,
341                               const char *buf, size_t len, data1_node *parent)
342 {
343     data1_node *res = data1_mk_text_n (dh, mem, buf, len, parent);
344     res->u.data.formatted_text = 1;
345     return res;
346 }
347
348 data1_node *data1_mk_text (data1_handle dh, NMEM mem,
349                            const char *buf, data1_node *parent)
350 {
351     return data1_mk_text_n (dh, mem, buf, strlen(buf), parent);
352 }
353
354 data1_node *data1_mk_comment_n (data1_handle dh, NMEM mem,
355                                 const char *buf, size_t len,
356                                 data1_node *parent)
357 {
358     data1_node *res = data1_mk_node2 (dh, mem, DATA1N_comment, parent);
359     res->u.data.what = DATA1I_text;
360     res->u.data.len = len;
361     
362     res->u.data.data = data1_insert_string_n (dh, res, mem, buf, len);
363     return res;
364 }
365
366 data1_node *data1_mk_comment (data1_handle dh, NMEM mem,
367                               const char *buf, data1_node *parent)
368 {
369     return data1_mk_comment_n (dh, mem, buf, strlen(buf), parent);
370 }
371
372 char *data1_insert_string_n (data1_handle dh, data1_node *res,
373                              NMEM m, const char *str, size_t len)
374 {
375     char *b;
376     if (len >= DATA1_LOCALDATA)
377         b = (char *) nmem_malloc (m, len+1);
378     else
379         b = res->lbuf;
380     memcpy (b, str, len);
381     b[len] = 0;
382     return b;
383 }
384
385 char *data1_insert_string (data1_handle dh, data1_node *res,
386                            NMEM m, const char *str)
387 {
388     return data1_insert_string_n (dh, res, m, str, strlen(str));
389 }
390
391 static data1_node *data1_add_insert_taggeddata(data1_handle dh,
392                                                data1_node *at,
393                                                const char *tagname, NMEM m,
394                                                int local_allowed,
395                                                int insert_mode)
396 {
397     data1_node *root = at->root;
398     data1_node *partag = get_parent_tag (dh, at);
399     data1_element *e = NULL;
400     data1_node *datn = 0;
401     data1_node *tagn = 0;
402
403     if (!partag)
404         e = data1_getelementbytagname (dh, root->u.root.absyn, 0, tagname);
405     else 
406     {
407         e = partag->u.tag.element;
408         if (e)
409             e = data1_getelementbytagname (dh, root->u.root.absyn, e, tagname);
410     }
411     if (local_allowed || e)
412     {
413         if (insert_mode)
414             tagn = data1_insert_node (dh, m, DATA1N_tag, at);
415         else
416             tagn = data1_append_node (dh, m, DATA1N_tag, at);
417         tagn->u.tag.tag = data1_insert_string (dh, tagn, m, tagname);
418         tagn->u.tag.element = e;
419         datn = data1_mk_node2 (dh, m, DATA1N_data, tagn);
420     }
421     return datn;
422 }
423
424 data1_node *data1_mk_tag_data(data1_handle dh, data1_node *at,
425                               const char *tagname, NMEM m)
426 {
427     return data1_add_insert_taggeddata (dh, at, tagname, m, 1, 0);
428 }
429
430
431 /*
432  * Insert a tagged node into the record root as first child of the node at
433  * which should be root or tag itself). Returns pointer to the data node,
434  * which can then be modified.
435  */
436 data1_node *data1_mk_tag_data_wd(data1_handle dh, data1_node *at,
437                                  const char *tagname, NMEM m)
438 {
439     return data1_add_insert_taggeddata (dh, at, tagname, m, 0, 1);
440 }
441
442 data1_node *data1_insert_taggeddata (data1_handle dh, data1_node *root,
443                                      data1_node *at, const char *tagname,
444                                      NMEM m)
445 {
446     return data1_add_insert_taggeddata (dh, at, tagname, m, 0, 1);
447 }
448
449 data1_node *data1_add_taggeddata (data1_handle dh, data1_node *root,
450                                   data1_node *at, const char *tagname,
451                                   NMEM m)
452 {
453     return data1_add_insert_taggeddata (dh, at, tagname, m, 1, 0);
454 }
455
456 data1_node *data1_mk_tag_data_zint (data1_handle dh, data1_node *at,
457                                    const char *tag, zint num,
458                                    NMEM nmem)
459 {
460     data1_node *node_data;
461     
462     node_data = data1_mk_tag_data (dh, at, tag, nmem);
463     if (!node_data)
464         return 0;
465     node_data->u.data.what = DATA1I_num;
466     node_data->u.data.data = node_data->lbuf;
467     sprintf (node_data->u.data.data, ZINT_FORMAT, num);
468     node_data->u.data.len = strlen (node_data->u.data.data);
469     return node_data;
470 }
471
472 data1_node *data1_mk_tag_data_int (data1_handle dh, data1_node *at,
473                                    const char *tag, int num,
474                                    NMEM nmem)
475 {
476     return data1_mk_tag_data_zint(dh, at, tag, num, nmem);
477 }
478
479 data1_node *data1_mk_tag_data_oid (data1_handle dh, data1_node *at,
480                                    const char *tag, Odr_oid *oid,
481                                    NMEM nmem)
482 {
483     data1_node *node_data;
484     char str[128], *p = str;
485     Odr_oid *ii;
486     
487     node_data = data1_mk_tag_data (dh, at, tag, nmem);
488     if (!node_data)
489         return 0;
490     
491     for (ii = oid; *ii >= 0; ii++)
492     {
493         if (ii != oid)
494             *p++ = '.';
495         sprintf (p, "%d", *ii);
496         p += strlen (p);
497     }
498     node_data->u.data.what = DATA1I_oid;
499     node_data->u.data.len = strlen (str);
500     node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
501     return node_data;
502 }
503
504
505 data1_node *data1_mk_tag_data_text (data1_handle dh, data1_node *at,
506                                     const char *tag, const char *str,
507                                     NMEM nmem)
508 {
509     data1_node *node_data;
510     
511     node_data = data1_mk_tag_data (dh, at, tag, nmem);
512     if (!node_data)
513         return 0;
514     node_data->u.data.what = DATA1I_text;
515     node_data->u.data.len = strlen (str);
516     node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
517     return node_data;
518 }
519
520
521 data1_node *data1_mk_tag_data_text_uni (data1_handle dh, data1_node *at,
522                                         const char *tag, const char *str,
523                                         NMEM nmem)
524 {
525     data1_node *node = data1_search_tag (dh, at->child, tag);
526     if (!node)
527         return data1_mk_tag_data_text (dh, at, tag, str, nmem);
528     else
529     {
530         data1_node *node_data = node->child;
531         node_data->u.data.what = DATA1I_text;
532         node_data->u.data.len = strlen (str);
533         node_data->u.data.data = data1_insert_string (dh, node_data,
534                                                       nmem, str);
535         node_data->child = node_data->last_child = 0;
536         return node_data;
537     }
538 }
539
540 static int ampr (int (*get_byte)(void *fh), void *fh, int *amp)
541 {
542 #if 1
543     int c = (*get_byte)(fh);
544     *amp = 0;
545     return c;
546 #else
547     int c = (*get_byte)(fh);
548     *amp = 0;
549     if (c == '&')
550     {
551         char ent[20];
552         int i = 0;
553        
554         while (1)
555         {
556             c = (*get_byte)(fh);
557             if (c == ';')
558             {
559                 ent[i] = 0;
560                 
561                 c = ' ';
562                 if (!strcmp (ent, "quot"))
563                     c = '"';
564                 if (!strcmp (ent, "apos"))
565                     c = '\'';
566                 if (!strcmp (ent, "gt"))
567                     c = '>';
568                 if (!strcmp (ent, "lt"))
569                     c = '<';
570                 if (!strcmp (ent, "amp"))
571                     c = '&';
572                 *amp = 1;
573                 break;
574             }
575             else if (c == 0 || d1_isspace(c))
576                 break;
577             if (i < 19)
578                 ent[i++] = c;
579         }
580     }
581     return c;
582 #endif
583 }
584
585 data1_xattr *data1_read_xattr (data1_handle dh, NMEM m,
586                                int (*get_byte)(void *fh), void *fh,
587                                WRBUF wrbuf, int *ch, int *amp)
588 {
589     data1_xattr *p_first = 0;
590     data1_xattr **pp = &p_first;
591     int c = *ch;
592     for (;;)
593     {
594         data1_xattr *p;
595         while (*amp || (c && d1_isspace(c)))
596             c = ampr (get_byte, fh, amp);
597         if (*amp == 0 && (c == 0 || c == '>' || c == '/'))
598             break;
599         *pp = p = (data1_xattr *) nmem_malloc (m, sizeof(*p));
600         p->next = 0;
601         pp = &p->next;
602         p->value = 0;
603         p->what = DATA1I_xmltext;
604         
605         wrbuf_rewind(wrbuf);
606         while (c && c != '=' && c != '>' && c != '/' && !d1_isspace(c))
607         {
608             wrbuf_putc (wrbuf, c);
609             c = ampr (get_byte, fh, amp);
610         }
611         p->name = nmem_strdup (m, wrbuf_cstr(wrbuf));
612         if (c == '=')
613         {
614             c = ampr (get_byte, fh, amp);
615             if (*amp == 0 && c == '"')
616             {
617                 c = ampr (get_byte, fh, amp);   
618                 wrbuf_rewind(wrbuf);
619                 while (*amp || (c && c != '"'))
620                 {
621                     wrbuf_putc (wrbuf, c);
622                     c = ampr (get_byte, fh, amp);
623                 }
624                 if (c)
625                     c = ampr (get_byte, fh, amp);
626             }
627             else if (*amp == 0 && c == '\'')
628             {
629                 c = ampr (get_byte, fh, amp);   
630                 wrbuf_rewind(wrbuf);
631                 while (*amp || (c && c != '\''))
632                 {
633                     wrbuf_putc (wrbuf, c);
634                     c = ampr (get_byte, fh, amp);
635                 }
636                 if (c)
637                     c = ampr (get_byte, fh, amp);
638             }
639             else
640             {
641                 wrbuf_rewind(wrbuf);
642                 while (*amp || (c && c != '>' && c != '/'))
643                 {
644                     wrbuf_putc (wrbuf, c);
645                     c = ampr (get_byte, fh, amp);
646                 }
647             }
648             p->value = nmem_strdup(m, wrbuf_cstr(wrbuf));
649         }
650     }
651     *ch = c;
652     return p_first;
653 }
654
655 /*
656  * Ugh. Sometimes functions just grow and grow on you. This one reads a
657  * 'node' and its children.
658  */
659 data1_node *data1_read_nodex (data1_handle dh, NMEM m,
660                               int (*get_byte)(void *fh), void *fh, WRBUF wrbuf)
661 {
662     data1_node *d1_stack[256];
663     data1_node *res;
664     int c, amp;
665     int level = 0;
666     int line = 1;
667
668     d1_stack[level] = 0;
669     c = ampr (get_byte, fh, &amp);
670     while (c != '\0')
671     {
672         data1_node *parent = level ? d1_stack[level-1] : 0;
673
674         if (amp == 0 && c == '<') /* beginning of tag */
675         {
676             data1_xattr *xattr;
677
678             char tag[256];
679             int null_tag = 0;
680             int end_tag = 0;
681             size_t i = 0;
682
683             c = ampr (get_byte, fh, &amp);
684             if (amp == 0 && c == '/')
685             {
686                 end_tag = 1;
687                 c = ampr (get_byte, fh, &amp);
688             }
689             else if (amp == 0 && c == '?')
690             {
691                 int quote_mode = 0;
692                 while ((c = ampr(get_byte, fh, &amp)))
693                 {
694                     if (amp)
695                         continue;
696                     if (quote_mode == 0)
697                     {
698                         if (c == '"')
699                             quote_mode = c;
700                         else if (c == '\'')
701                             quote_mode = c;
702                         else if (c == '>')
703                         {
704                             c = ampr(get_byte, fh, &amp);
705                             break;
706                         }
707                     }
708                     else 
709                     {
710                         if (amp == 0 && c == quote_mode)
711                             quote_mode = 0;
712                     }
713                 }
714                 continue;
715             }
716             else if (amp == 0 && c == '!')
717             {
718                 int c0, amp0;
719               
720                 wrbuf_rewind(wrbuf);
721                 
722                 c0 = ampr (get_byte, fh, &amp0);
723                 if (amp0 == 0 && c0 == '\0')
724                     break;
725                 c = ampr (get_byte, fh, &amp);
726                 
727                 if (amp0 == 0 && c0 == '-' && amp == 0 && c == '-')
728                 {
729                     /* COMMENT: <!-- ... --> */
730                     int no_dash = 0;
731                     
732                     c = ampr (get_byte, fh, &amp);
733                     while (amp || c)
734                     {
735                         if (amp == 0 && c == '-')
736                             no_dash++;
737                         else if (amp == 0 && c == '>' && no_dash >= 2)
738                         {
739                             if (level > 0)
740                                 d1_stack[level] = 
741                                     data1_mk_comment_n (
742                                         dh, m,
743                                         wrbuf_buf(wrbuf), wrbuf_len(wrbuf)-2,
744                                         d1_stack[level-1]);
745                             c = ampr (get_byte, fh, &amp); /* skip > */
746                             break;
747                         }
748                         else
749                             no_dash = 0;
750                         wrbuf_putc (wrbuf, c);
751                         c = ampr (get_byte, fh, &amp);
752                     }
753                     continue;
754                 }
755                 else
756                 {   /* DIRECTIVE: <! .. > */
757         
758                     int blevel = 0;
759                     while (amp || c)
760                     {
761                         if (amp == 0 && c == '>' && blevel == 0)
762                         {
763                             c = ampr (get_byte, fh, &amp);
764                             break;
765                         }
766                         if (amp == 0 && c == '[')
767                             blevel++;
768                         if (amp == 0 && c == ']' && blevel > 0)
769                             blevel--;
770                         c = ampr (get_byte, fh, &amp);
771                     }
772                     continue;
773                 }
774             }
775             while (amp || (c && c != '>' && c != '/' && !d1_isspace(c)))
776             {
777                 if (i < (sizeof(tag)-1))
778                     tag[i++] = c;
779                 c = ampr (get_byte, fh, &amp);
780             }
781             tag[i] = '\0';
782             xattr = data1_read_xattr (dh, m, get_byte, fh, wrbuf, &c, &amp);
783             if (amp == 0 && c == '/')
784             {    /* <tag attrs/> or <tag/> */
785                 null_tag = 1;
786                 c = ampr (get_byte, fh, &amp);
787             }
788             if (amp || c != '>')
789             {
790                 yaz_log(YLOG_WARN, "d1: %d: Malformed tag", line);
791                 return 0;
792             }
793             else
794                 c = ampr (get_byte, fh, &amp);
795
796             /* End tag? */
797             if (end_tag)       
798             {
799                 if (*tag == '\0')
800                     --level;        /* </> */
801                 else
802                 {                   /* </tag> */
803                     int i = level;
804                     while (i > 0)
805                     {
806                         parent = d1_stack[--i];
807                         if ((parent->which == DATA1N_root &&
808                              !strcmp(tag, parent->u.root.type)) ||
809                             (parent->which == DATA1N_tag &&
810                              !strcmp(tag, parent->u.tag.tag)))
811                         {
812                             level = i;
813                             break;
814                         }
815                     }
816                     if (i != level)
817                     {
818                         yaz_log (YLOG_WARN, "%d: no begin tag for %s",
819                                  line, tag);
820                         break;
821                     }
822                 }
823                 if (data1_is_xmlmode(dh))
824                 {
825                     if (level <= 1)
826                         return d1_stack[0];
827                 }
828                 else
829                 {
830                     if (level <= 0)
831                         return d1_stack[0];
832                 }
833                 continue;
834             }   
835             else if (!strcmp(tag, "var") 
836                      && xattr && xattr->next && xattr->next->next
837                      && xattr->value == 0 
838                      && xattr->next->value == 0
839                      && xattr->next->next->value == 0)
840             {
841                 /* <var class type value> */
842                 const char *tclass = xattr->name;
843                 const char *type = xattr->next->name;
844                 const char *value = xattr->next->name;
845                 data1_vartype *tp;
846                 
847                 yaz_log(YLOG_LOG, "Variant class=%s type=%s value=%s",
848                         tclass, type, value);
849                 if (!(tp =
850                       data1_getvartypebyct(dh,
851                                            parent->root->u.root.absyn->varset,
852                                            tclass, type)))
853                     continue;
854                 /*
855                  * If we're the first variant in this group, create a parent 
856                  * variant, and insert it before the current variant.
857                  */
858                 if (parent->which != DATA1N_variant)
859                 {
860                     res = data1_mk_node2 (dh, m, DATA1N_variant, parent);
861                 }
862                 else
863                 {
864                     /*
865                      * now determine if one of our ancestor triples is of
866                      * same type. If so, we break here.
867                      */
868                     int i;
869                     for (i = level-1; d1_stack[i]->which==DATA1N_variant; --i)
870                         if (d1_stack[i]->u.variant.type == tp)
871                         {
872                             level = i;
873                             break;
874                         }
875                     res = data1_mk_node2 (dh, m, DATA1N_variant, parent);
876                     res->u.variant.type = tp;
877                     res->u.variant.value =
878                         data1_insert_string (dh, res, m, value);
879                 }
880             }
881             else 
882             {
883                 
884                 /* tag .. acquire our element in the abstract syntax */
885                 if (level == 0)
886                 {
887                     parent = data1_mk_root (dh, m, tag);
888                     res = d1_stack[level] = parent;
889
890                     if (data1_is_xmlmode(dh))
891                     {
892                         level++;
893                         res = data1_mk_tag (dh, m, tag, 0 /* attr */, parent);
894                         res->u.tag.attributes = xattr;
895                     }
896                 }
897                 else
898                 {
899                     res = data1_mk_tag (dh, m, tag, 0 /* attr */, parent);
900                     res->u.tag.attributes = xattr;
901                 }
902             }
903             d1_stack[level] = res;
904             d1_stack[level+1] = 0;
905             if (level < 250 && !null_tag)
906                 ++level;
907         }
908         else /* != '<'... this is a body of text */
909         {
910             int len;
911             
912             if (level == 0)
913             {
914                 c = ampr (get_byte, fh, &amp);
915                 continue;
916             }
917             res = data1_mk_node2 (dh, m, DATA1N_data, parent);
918             res->u.data.what = DATA1I_xmltext;
919             res->u.data.formatted_text = 0;
920             d1_stack[level] = res;
921             
922             wrbuf_rewind(wrbuf);
923
924             while (amp || (c && c != '<'))
925             {
926                 wrbuf_putc (wrbuf, c);
927                 c = ampr (get_byte, fh, &amp);
928             }
929             len = wrbuf_len(wrbuf);
930
931             /* use local buffer of nmem if too large */
932             if (len >= DATA1_LOCALDATA)
933                 res->u.data.data = (char*) nmem_malloc (m, len);
934             else
935                 res->u.data.data = res->lbuf;
936         
937             if (len)
938                 memcpy (res->u.data.data, wrbuf_buf(wrbuf), len);
939             else
940                 res->u.data.data = 0;
941             res->u.data.len = len;
942         }
943     }
944     return 0;
945 }
946
947 int getc_mem (void *fh)
948 {
949     const char **p = (const char **) fh;
950     if (**p)
951         return *(*p)++;
952     return 0;
953 }
954
955 data1_node *data1_read_node (data1_handle dh, const char **buf, NMEM m)
956 {
957     WRBUF wrbuf = wrbuf_alloc();
958     data1_node *node;
959
960     node = data1_read_nodex(dh, m, getc_mem, (void *) (buf), wrbuf);
961     wrbuf_destroy(wrbuf);
962     return node;
963 }
964
965 /*
966  * Read a record in the native syntax.
967  */
968 data1_node *data1_read_record(data1_handle dh,
969                               int (*rf)(void *, char *, size_t), void *fh,
970                               NMEM m)
971 {
972     int *size;
973     char **buf = data1_get_read_buf (dh, &size);
974     const char *bp;
975     int rd = 0, res;
976     
977     if (!*buf)
978         *buf = (char *)xmalloc(*size = 4096);
979     
980     for (;;)
981     {
982         if (rd + 2048 >= *size && !(*buf =(char *)xrealloc(*buf, *size *= 2)))
983             abort();
984         if ((res = (*rf)(fh, *buf + rd, 2048)) <= 0)
985         {
986             if (!res)
987             {
988                 bp = *buf;
989                 (*buf)[rd] = '\0';
990                 return data1_read_node(dh, &bp, m);
991             }
992             else
993                 return 0;
994         }
995         rd += res;
996     }
997 }
998
999 data1_node *data1_read_sgml (data1_handle dh, NMEM m, const char *buf)
1000 {
1001     const char *bp = buf;
1002     return data1_read_node (dh, &bp, m);
1003 }
1004
1005
1006 static int conv_item (NMEM m, yaz_iconv_t t, 
1007                       WRBUF wrbuf, char *inbuf, size_t inlen)
1008 {
1009     wrbuf_rewind (wrbuf);
1010     if (wrbuf->size < 10)
1011         wrbuf_grow (wrbuf, 10);
1012     for (;;)
1013     {
1014         char *outbuf = wrbuf->buf + wrbuf->pos;
1015         size_t outlen = wrbuf->size - wrbuf->pos;
1016         if (yaz_iconv(t, &inbuf, &inlen, &outbuf, &outlen) ==
1017             (size_t)(-1) && yaz_iconv_error(t) != YAZ_ICONV_E2BIG)
1018         {
1019             /* bad data. stop and skip conversion entirely */
1020             return -1;
1021         }
1022         else if (inlen == 0)
1023         {   /* finished converting, flush it */
1024             yaz_iconv(t, 0, 0, &outbuf, &outlen);
1025             wrbuf->pos = wrbuf->size - outlen;
1026             break;
1027         }
1028         else
1029         {
1030             /* buffer too small: make sure we expand buffer */
1031             wrbuf->pos = wrbuf->size - outlen;
1032             wrbuf_grow(wrbuf, 20);
1033         }
1034     }
1035     return 0;
1036 }
1037
1038 static void data1_iconv_s (data1_handle dh, NMEM m, data1_node *n,
1039                            yaz_iconv_t t, WRBUF wrbuf, const char *tocode)
1040 {
1041     for (; n; n = n->next)
1042     {
1043         switch (n->which)
1044         {
1045         case DATA1N_data:
1046         case DATA1N_comment:
1047             if (conv_item (m, t, wrbuf, n->u.data.data, n->u.data.len) == 0)
1048             {
1049                 n->u.data.data =
1050                     data1_insert_string_n (dh, n, m, wrbuf->buf,
1051                                            wrbuf->pos);
1052                 n->u.data.len = wrbuf->pos;
1053             }
1054             break;
1055         case DATA1N_tag:
1056             if (conv_item (m, t, wrbuf, n->u.tag.tag, strlen(n->u.tag.tag))
1057                 == 0)
1058             {
1059                 n->u.tag.tag =
1060                     data1_insert_string_n (dh, n, m, 
1061                                            wrbuf->buf, wrbuf->pos);
1062             }
1063             if (n->u.tag.attributes)
1064             {
1065                 data1_xattr *p;
1066                 for (p = n->u.tag.attributes; p; p = p->next)
1067                 {
1068                     if (p->value &&
1069                         conv_item(m, t, wrbuf, p->value, strlen(p->value))
1070                         == 0)
1071                     {
1072                         p->value = nmem_strdup(m, wrbuf_cstr(wrbuf));
1073                     }
1074                 }
1075             }
1076             break;
1077         case DATA1N_preprocess:
1078             if (strcmp(n->u.preprocess.target, "xml") == 0)
1079             {
1080                 data1_xattr *p = n->u.preprocess.attributes;
1081                 for (; p; p = p->next)
1082                     if (strcmp (p->name, "encoding") == 0)
1083                         p->value = nmem_strdup (m, tocode);
1084             }
1085             break;
1086         }
1087         data1_iconv_s (dh, m, n->child, t, wrbuf, tocode);
1088     }
1089 }
1090
1091 const char *data1_get_encoding (data1_handle dh, data1_node *n)
1092 {
1093     /* see if we have an xml header that specifies encoding */
1094     if (n && n->child && n->child->which == DATA1N_preprocess &&
1095         strcmp (n->child->u.preprocess.target, "xml") == 0)
1096     {
1097         data1_xattr *xp = n->child->u.preprocess.attributes;
1098         for (; xp; xp = xp->next)
1099             if (!strcmp (xp->name, "encoding") == 0)
1100                 return xp->value;
1101     }
1102     /* no encoding in header, so see if "encoding" was specified for abs */
1103     if (n && n->which == DATA1N_root &&
1104         n->u.root.absyn && n->u.root.absyn->encoding)
1105         return n->u.root.absyn->encoding;
1106     /* none of above, return a hard coded default */
1107     return "ISO-8859-1";
1108 }
1109
1110 int data1_iconv (data1_handle dh, NMEM m, data1_node *n,
1111                   const char *tocode, 
1112                   const char *fromcode)
1113 {
1114     if (yaz_matchstr (tocode, fromcode))
1115     {
1116         WRBUF wrbuf = wrbuf_alloc();
1117         yaz_iconv_t t = yaz_iconv_open(tocode, fromcode);
1118         if (!t)
1119         {
1120             wrbuf_destroy(wrbuf);
1121             return -1;
1122         }
1123         data1_iconv_s(dh, m, n, t, wrbuf, tocode);
1124         yaz_iconv_close(t);
1125         wrbuf_destroy(wrbuf);
1126     }
1127     return 0;
1128 }
1129
1130 void data1_concat_text(data1_handle dh, NMEM m, data1_node *n)
1131 {
1132     for (; n; n = n->next)
1133     {
1134         if (n->which == DATA1N_data && n->next && 
1135             n->next->which == DATA1N_data)
1136         {
1137             int sz = 0;
1138             int off = 0;
1139             char *ndata;
1140             data1_node *np;
1141             for (np = n; np && np->which == DATA1N_data; np=np->next)
1142                 sz += np->u.data.len;
1143             ndata = nmem_malloc(m, sz);
1144             for (np = n; np && np->which == DATA1N_data; np=np->next)
1145             {
1146                 memcpy(ndata+off, np->u.data.data, np->u.data.len);
1147                 off += np->u.data.len;
1148             }
1149             n->u.data.data = ndata;
1150             n->u.data.len = sz;
1151             n->next = np;
1152             if (!np && n->parent)
1153                 n->parent->last_child = n;
1154                 
1155         }
1156         data1_concat_text(dh, m, n->child);
1157     }
1158 }
1159 /*
1160  * Local variables:
1161  * c-basic-offset: 4
1162  * indent-tabs-mode: nil
1163  * End:
1164  * vim: shiftwidth=4 tabstop=8 expandtab
1165  */
1166