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