data1 part of zebra
[idzebra-moved-to-github.git] / data1 / d1_write.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_write.c,v 1.1 2002-10-22 12:53:33 adam Exp $
7  */
8
9 #include <string.h>
10
11 #include <data1.h>
12 #include <yaz/wrbuf.h>
13
14 #define IDSGML_MARGIN 75
15
16 #define PRETTY_FORMAT 0
17
18 static int wordlen(char *b, int max)
19 {
20     int l = 0;
21
22     while (l < max && !d1_isspace(*b))
23         l++, b++;
24     return l;
25 }
26
27 static void indent (WRBUF b, int col)
28 {
29     int i;
30     for (i = 0; i<col; i++)
31         wrbuf_putc (b, ' ');
32 }
33
34 static void wrbuf_write_cdata(WRBUF b, const char *msg, int len)
35 {
36     int i;
37
38     for (i = 0; i < len; i++)
39     {
40         switch (msg[i])
41         {
42         case '"':
43             wrbuf_puts (b, "&quot;");
44             break;
45         case '\'':
46             wrbuf_puts (b, "&apos;");
47             break;
48         case '>':
49             wrbuf_puts (b, "&gt;");
50             break;
51         case '<':
52             wrbuf_puts (b, "&lt;");
53             break;
54         case '&':
55             wrbuf_puts (b, "&amp;");
56             break;
57         default:
58             wrbuf_putc(b, msg[i]);
59         }
60     }
61 }
62
63 static void wrbuf_put_cdata(WRBUF b, const char *msg)
64 {
65     wrbuf_write_cdata (b, msg, strlen(msg));
66 }
67
68 static void wrbuf_put_xattr(WRBUF b, data1_xattr *p)
69 {
70     for (; p; p = p->next)
71     {
72         wrbuf_putc (b, ' ');
73         if (p->what == DATA1I_xmltext)
74             wrbuf_puts (b, p->name);
75         else
76             wrbuf_put_cdata (b, p->name);
77         if (p->value)
78         {
79             wrbuf_putc (b, '=');
80             wrbuf_putc (b, '"');
81             if (p->what == DATA1I_text)
82                 wrbuf_put_cdata (b, p->value);
83             else
84                 wrbuf_puts (b, p->value);
85             wrbuf_putc (b, '"');
86         }
87     }
88 }
89
90 static int nodetoidsgml(data1_node *n, int select, WRBUF b, int col,
91                         int pretty_format)
92 {
93     data1_node *c;
94
95     for (c = n->child; c; c = c->next)
96     {
97         char *tag;
98
99         if (c->which == DATA1N_preprocess)
100         {
101             data1_xattr *p;
102
103             if (pretty_format)
104                 indent (b, col);
105             wrbuf_puts (b, "<?");
106             wrbuf_put_cdata (b, c->u.preprocess.target);
107             wrbuf_put_xattr (b, c->u.preprocess.attributes);
108             if (c->child)
109                 wrbuf_puts(b, " ");
110             if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2,
111                              pretty_format) < 0)
112                 return -1;
113             wrbuf_puts (b, "?>\n");
114         }
115         else if (c->which == DATA1N_tag)
116         {
117             if (select && !c->u.tag.node_selected)
118                 continue;
119             tag = c->u.tag.tag;
120             if (!data1_matchstr(tag, "wellknown")) /* skip wellknown */
121             {
122                 if (nodetoidsgml(c, select, b, col, pretty_format) < 0)
123                     return -1;
124             }
125             else
126             {
127                 data1_xattr *p;
128
129                 if (pretty_format)
130                     indent (b, col);
131                 wrbuf_puts (b, "<");    
132                 wrbuf_put_cdata (b, tag);
133                 wrbuf_put_xattr (b, c->u.tag.attributes);
134                 wrbuf_puts(b, ">");
135                 if (pretty_format)
136                     wrbuf_puts(b, "\n");
137                 if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2,
138                                  pretty_format) < 0)
139                     return -1;
140                 if (pretty_format)
141                     indent (b, col);
142                 wrbuf_puts(b, "</");
143                 wrbuf_put_cdata(b, tag);
144                 wrbuf_puts(b, ">");
145                 if (pretty_format)
146                     wrbuf_puts (b, "\n");
147             }
148         }
149         else if (c->which == DATA1N_data || c->which == DATA1N_comment)
150         {
151             char *p = c->u.data.data;
152             int l = c->u.data.len;
153             int first = 1;
154             int lcol = col;
155
156             if (pretty_format && !c->u.data.formatted_text)
157                 indent (b, col);
158             if (c->which == DATA1N_comment)
159                 wrbuf_puts (b, "<!--");
160             switch (c->u.data.what)
161             {
162             case DATA1I_xmltext:
163                 wrbuf_write(b, c->u.data.data, c->u.data.len);
164                 break;
165             case DATA1I_text:
166                 if (!pretty_format || c->u.data.formatted_text)
167                 {
168                     wrbuf_write_cdata (b, p, l);
169                 }
170                 else
171                 {
172                     while (l)
173                     {
174                         int wlen;
175                         
176                         while (l && d1_isspace(*p))
177                             p++, l--;
178                         if (!l)
179                             break;
180                         /* break if we cross margin and word is not too long */
181                         if (lcol + (wlen = wordlen(p, l)) > IDSGML_MARGIN &&
182                             wlen < IDSGML_MARGIN)
183                         {
184                             wrbuf_puts (b, "\n");
185                             indent (b, col);
186                             lcol = col;
187                             first = 1;
188                         }
189                         if (!first)
190                         {
191                             wrbuf_putc(b, ' ');
192                             lcol++;
193                         }
194                         while (l && !d1_isspace(*p))
195                         {
196                             wrbuf_putc(b, *p);
197                             p++;
198                             l--;
199                             lcol++;
200                         }
201                         first = 0;
202                     }
203                     wrbuf_puts(b, "\n");
204                 }
205                 break;
206             case DATA1I_num:
207                 wrbuf_write_cdata(b, c->u.data.data, c->u.data.len);
208                 if (pretty_format)
209                     wrbuf_puts(b, "\n");
210                 break;
211             case DATA1I_oid:
212                 wrbuf_write_cdata(b, c->u.data.data, c->u.data.len);
213                 if (pretty_format)
214                     wrbuf_puts(b, "\n");
215             }
216             if (c->which == DATA1N_comment)
217             {
218                 wrbuf_puts(b, "-->");
219                 if (pretty_format)
220                     wrbuf_puts(b, "\n");
221             }
222         }
223     }
224     return 0;
225 }
226
227 char *data1_nodetoidsgml (data1_handle dh, data1_node *n, int select, int *len)
228 {
229     WRBUF b = data1_get_wrbuf (dh);
230     
231     wrbuf_rewind(b);
232     
233     if (!data1_is_xmlmode (dh))
234     {
235         wrbuf_puts (b, "<");
236         wrbuf_puts (b, n->u.root.type);
237         wrbuf_puts (b, ">\n");
238     }
239     if (nodetoidsgml(n, select, b, 0, 0 /* no pretty format */))
240         return 0;
241     if (!data1_is_xmlmode (dh))
242     {
243         wrbuf_puts (b, "</");
244         wrbuf_puts (b, n->u.root.type);
245         wrbuf_puts (b, ">\n");
246     }
247     *len = wrbuf_len(b);
248     return wrbuf_buf(b);
249 }