Added conversions for ', &
[yaz-moved-to-github.git] / retrieval / 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.17 2002-08-23 14:25:07 adam Exp $
7  */
8
9 #include <string.h>
10
11 #include <yaz/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 int nodetoidsgml(data1_node *n, int select, WRBUF b, int col,
69                         int pretty_format)
70 {
71     data1_node *c;
72
73     for (c = n->child; c; c = c->next)
74     {
75         char *tag;
76
77         if (c->which == DATA1N_preprocess)
78         {
79             data1_xattr *p;
80
81             if (pretty_format)
82                 indent (b, col);
83             wrbuf_puts (b, "<?");
84             wrbuf_put_cdata (b, c->u.preprocess.target);
85             for (p = c->u.preprocess.attributes; p; p = p->next)
86             {
87                 wrbuf_putc (b, ' ');
88                 wrbuf_put_cdata (b, p->name);
89                 wrbuf_putc (b, '=');
90                 wrbuf_putc (b, '"');
91                 wrbuf_put_cdata (b, p->value);
92                 wrbuf_putc (b, '"');
93             }
94             if (c->child)
95                 wrbuf_puts(b, " ");
96             if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2,
97                              pretty_format) < 0)
98                 return -1;
99             wrbuf_puts (b, "?>\n");
100         }
101         else if (c->which == DATA1N_tag)
102         {
103             if (select && c->u.tag.node_selected)
104                 continue;
105             tag = c->u.tag.tag;
106             if (!data1_matchstr(tag, "wellknown")) /* skip wellknown */
107             {
108                 if (nodetoidsgml(c, select, b, col, pretty_format) < 0)
109                     return -1;
110             }
111             else
112             {
113                 data1_xattr *p;
114
115                 if (pretty_format)
116                     indent (b, col);
117                 wrbuf_puts (b, "<");    
118                 wrbuf_put_cdata (b, tag);
119                 for (p = c->u.tag.attributes; p; p = p->next)
120                 {
121                     wrbuf_putc (b, ' ');
122                     wrbuf_put_cdata (b, p->name);
123                     wrbuf_putc (b, '=');
124                     wrbuf_putc (b, '"');
125                     wrbuf_put_cdata (b, p->value);
126                     wrbuf_putc (b, '"');
127                 }
128                 wrbuf_puts(b, ">");
129                 if (pretty_format)
130                     wrbuf_puts(b, "\n");
131                 if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2,
132                                  pretty_format) < 0)
133                     return -1;
134                 if (pretty_format)
135                     indent (b, col);
136                 wrbuf_puts(b, "</");
137                 wrbuf_put_cdata(b, tag);
138                 wrbuf_puts(b, ">");
139                 if (pretty_format)
140                     wrbuf_puts (b, "\n");
141             }
142         }
143         else if (c->which == DATA1N_data || c->which == DATA1N_comment)
144         {
145             char *p = c->u.data.data;
146             int l = c->u.data.len;
147             int first = 1;
148             int lcol = col;
149
150             if (pretty_format && !c->u.data.formatted_text)
151                 indent (b, col);
152             if (c->which == DATA1N_comment)
153                 wrbuf_puts (b, "<!--");
154             switch (c->u.data.what)
155             {
156             case DATA1I_text:
157                 if (!pretty_format || c->u.data.formatted_text)
158                 {
159                     wrbuf_write_cdata (b, p, l);
160                 }
161                 else
162                 {
163                     while (l)
164                     {
165                         int wlen;
166                         
167                         while (l && d1_isspace(*p))
168                             p++, l--;
169                         if (!l)
170                             break;
171                         /* break if we cross margin and word is not too long */
172                         if (lcol + (wlen = wordlen(p, l)) > IDSGML_MARGIN &&
173                             wlen < IDSGML_MARGIN)
174                         {
175                             wrbuf_puts (b, "\n");
176                             indent (b, col);
177                             lcol = col;
178                             first = 1;
179                         }
180                         if (!first)
181                         {
182                             wrbuf_putc(b, ' ');
183                             lcol++;
184                         }
185                         while (l && !d1_isspace(*p))
186                         {
187                             wrbuf_putc(b, *p);
188                             p++;
189                             l--;
190                             lcol++;
191                         }
192                         first = 0;
193                     }
194                     wrbuf_puts(b, "\n");
195                 }
196                 break;
197             case DATA1I_num:
198                 wrbuf_write_cdata(b, c->u.data.data, c->u.data.len);
199                 if (pretty_format)
200                     wrbuf_puts(b, "\n");
201                 break;
202             case DATA1I_oid:
203                 wrbuf_write_cdata(b, c->u.data.data, c->u.data.len);
204                 if (pretty_format)
205                     wrbuf_puts(b, "\n");
206             }
207             if (c->which == DATA1N_comment)
208             {
209                 wrbuf_puts(b, "-->");
210                 if (pretty_format)
211                     wrbuf_puts(b, "\n");
212             }
213         }
214     }
215     return 0;
216 }
217
218 char *data1_nodetoidsgml (data1_handle dh, data1_node *n, int select, int *len)
219 {
220     WRBUF b = data1_get_wrbuf (dh);
221     
222     wrbuf_rewind(b);
223     
224     if (!data1_is_xmlmode (dh))
225     {
226         wrbuf_puts (b, "<");
227         wrbuf_puts (b, n->u.root.type);
228         wrbuf_puts (b, ">\n");
229     }
230     if (nodetoidsgml(n, select, b, 0, 0 /* no pretty format */))
231         return 0;
232     if (!data1_is_xmlmode (dh))
233     {
234         wrbuf_puts (b, "</");
235         wrbuf_puts (b, n->u.root.type);
236         wrbuf_puts (b, ">\n");
237     }
238     *len = wrbuf_len(b);
239     return wrbuf_buf(b);
240 }