Allow range to be specified in termlist, e.g. title:w:range(data,2,4)
[idzebra-moved-to-github.git] / data1 / d1_write.c
1 /* $Id: d1_write.c,v 1.3 2003-02-25 21:50:27 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             if (pretty_format)
118                 indent (b, col);
119             wrbuf_puts (b, "<?");
120             wrbuf_put_cdata (b, c->u.preprocess.target);
121             wrbuf_put_xattr (b, c->u.preprocess.attributes);
122             if (c->child)
123                 wrbuf_puts(b, " ");
124             if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2,
125                              pretty_format) < 0)
126                 return -1;
127             wrbuf_puts (b, "?>\n");
128         }
129         else if (c->which == DATA1N_tag)
130         {
131             if (select && !c->u.tag.node_selected)
132                 continue;
133             tag = c->u.tag.tag;
134             if (!data1_matchstr(tag, "wellknown")) /* skip wellknown */
135             {
136                 if (nodetoidsgml(c, select, b, col, pretty_format) < 0)
137                     return -1;
138             }
139             else
140             {
141                 if (pretty_format)
142                     indent (b, col);
143                 wrbuf_puts (b, "<");    
144                 wrbuf_put_cdata (b, tag);
145                 wrbuf_put_xattr (b, c->u.tag.attributes);
146                 wrbuf_puts(b, ">");
147                 if (pretty_format)
148                     wrbuf_puts(b, "\n");
149                 if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2,
150                                  pretty_format) < 0)
151                     return -1;
152                 if (pretty_format)
153                     indent (b, col);
154                 wrbuf_puts(b, "</");
155                 wrbuf_put_cdata(b, tag);
156                 wrbuf_puts(b, ">");
157                 if (pretty_format)
158                     wrbuf_puts (b, "\n");
159             }
160         }
161         else if (c->which == DATA1N_data || c->which == DATA1N_comment)
162         {
163             char *p = c->u.data.data;
164             int l = c->u.data.len;
165             int first = 1;
166             int lcol = col;
167
168             if (pretty_format && !c->u.data.formatted_text)
169                 indent (b, col);
170             if (c->which == DATA1N_comment)
171                 wrbuf_puts (b, "<!--");
172             switch (c->u.data.what)
173             {
174             case DATA1I_xmltext:
175                 wrbuf_write(b, c->u.data.data, c->u.data.len);
176                 break;
177             case DATA1I_text:
178                 if (!pretty_format || c->u.data.formatted_text)
179                 {
180                     wrbuf_write_cdata (b, p, l);
181                 }
182                 else
183                 {
184                     while (l)
185                     {
186                         int wlen;
187                         
188                         while (l && d1_isspace(*p))
189                             p++, l--;
190                         if (!l)
191                             break;
192                         /* break if we cross margin and word is not too long */
193                         if (lcol + (wlen = wordlen(p, l)) > IDSGML_MARGIN &&
194                             wlen < IDSGML_MARGIN)
195                         {
196                             wrbuf_puts (b, "\n");
197                             indent (b, col);
198                             lcol = col;
199                             first = 1;
200                         }
201                         if (!first)
202                         {
203                             wrbuf_putc(b, ' ');
204                             lcol++;
205                         }
206                         while (l && !d1_isspace(*p))
207                         {
208                             wrbuf_putc(b, *p);
209                             p++;
210                             l--;
211                             lcol++;
212                         }
213                         first = 0;
214                     }
215                     wrbuf_puts(b, "\n");
216                 }
217                 break;
218             case DATA1I_num:
219                 wrbuf_write_cdata(b, c->u.data.data, c->u.data.len);
220                 if (pretty_format)
221                     wrbuf_puts(b, "\n");
222                 break;
223             case DATA1I_oid:
224                 wrbuf_write_cdata(b, c->u.data.data, c->u.data.len);
225                 if (pretty_format)
226                     wrbuf_puts(b, "\n");
227             }
228             if (c->which == DATA1N_comment)
229             {
230                 wrbuf_puts(b, "-->");
231                 if (pretty_format)
232                     wrbuf_puts(b, "\n");
233             }
234         }
235     }
236     return 0;
237 }
238
239 char *data1_nodetoidsgml (data1_handle dh, data1_node *n, int select, int *len)
240 {
241     WRBUF b = data1_get_wrbuf (dh);
242     
243     wrbuf_rewind(b);
244     
245     if (!data1_is_xmlmode (dh))
246     {
247         wrbuf_puts (b, "<");
248         wrbuf_puts (b, n->u.root.type);
249         wrbuf_puts (b, ">\n");
250     }
251     if (nodetoidsgml(n, select, b, 0, 0 /* no pretty format */))
252         return 0;
253     if (!data1_is_xmlmode (dh))
254     {
255         wrbuf_puts (b, "</");
256         wrbuf_puts (b, n->u.root.type);
257         wrbuf_puts (b, ">\n");
258     }
259     *len = wrbuf_len(b);
260     return wrbuf_buf(b);
261 }