Implemented XML/SGML attributes for data1 so that d1_read reads them
[yaz-moved-to-github.git] / retrieval / d1_write.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_write.c,v $
7  * Revision 1.9  2000-11-29 14:22:47  adam
8  * Implemented XML/SGML attributes for data1 so that d1_read reads them
9  * and d1_write generates proper attributes for XML/SGML records. Added
10  * register locking for threaded version.
11  *
12  * Revision 1.8  1999/11/30 13:47:12  adam
13  * Improved installation. Moved header files to include/yaz.
14  *
15  * Revision 1.7  1999/10/21 12:06:29  adam
16  * Retrieval module no longer uses ctype.h - functions.
17  *
18  * Revision 1.6  1999/07/06 12:16:00  adam
19  * Improved layout generated record in SGML/XML format.
20  *
21  * Revision 1.5  1998/06/05 08:57:43  adam
22  * Fixed problem with function wordlen.
23  *
24  * Revision 1.4  1998/05/18 13:07:08  adam
25  * Changed the way attribute sets are handled by the retriaval module.
26  * Extended Explain conversion / schema.
27  * Modified server and client to work with ASN.1 compiled protocol handlers.
28  *
29  * Revision 1.3  1997/09/17 12:10:39  adam
30  * YAZ version 1.4.
31  *
32  * Revision 1.2  1995/12/13 17:14:27  quinn
33  * *** empty log message ***
34  *
35  * Revision 1.1  1995/12/13  15:38:43  quinn
36  * Added SGML-output filter.
37  *
38  *
39  */
40
41 #include <string.h>
42
43 #include <yaz/data1.h>
44 #include <yaz/wrbuf.h>
45
46 #define IDSGML_MARGIN 75
47
48 static int wordlen(char *b, int max)
49 {
50     int l = 0;
51
52     while (l < max && !d1_isspace(*b))
53         l++, b++;
54     return l;
55 }
56
57 static int nodetoidsgml(data1_node *n, int select, WRBUF b, int col)
58 {
59     data1_node *c;
60     char line[1024];
61
62     for (c = n->child; c; c = c->next)
63     {
64         char *tag;
65
66         if (c->which == DATA1N_tag)
67         {
68             if (select && c->u.tag.node_selected)
69                 continue;
70             if (c->u.tag.element && c->u.tag.element->tag)
71                 tag = c->u.tag.element->tag->names->name; /* first name */
72             else
73                 tag = c->u.tag.tag; /* local string tag */
74             if (!data1_matchstr(tag, "wellknown")) /* skip wellknown */
75             {
76                 if (nodetoidsgml(c, select, b, col) < 0)
77                     return -1;
78             }
79             else
80             {
81 #if DATA1_USING_XATTR
82                 data1_xattr *p;
83 #endif
84                 sprintf (line, "%*s<", col, "");
85                 wrbuf_puts (b, line);
86                 wrbuf_puts (b, tag);
87 #if DATA1_USING_XATTR
88                 for (p = c->u.tag.attributes; p; p = p->next)
89                 {
90                     wrbuf_putc (b, ' ');
91                     wrbuf_puts (b, p->name);
92                     wrbuf_putc (b, '=');
93                     wrbuf_putc (b, '"');
94                     wrbuf_puts (b, p->value);
95                     wrbuf_putc (b, '"');
96                 }
97 #endif
98                 wrbuf_puts(b, ">\n");
99                 if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2) < 0)
100                     return -1;
101                 sprintf (line, "%*s</%s>\n", col, "", tag);
102                 wrbuf_write(b, line, strlen(line));
103             }
104         }
105         else if (c->which == DATA1N_data)
106         {
107             char *p = c->u.data.data;
108             int l = c->u.data.len;
109             int first = 1;
110             int lcol = col;
111
112             sprintf(line, "%*s", col, "");
113             wrbuf_write(b, line, strlen(line));
114             switch (c->u.data.what)
115             {
116             case DATA1I_text:
117                 while (l)
118                 {
119                     int wlen;
120                     
121                     while (l && d1_isspace(*p))
122                         p++, l--;
123                     if (!l)
124                         break;
125                     /* break if we'll cross margin and word is not too long */
126                     if (lcol + (wlen = wordlen(p, l)) > IDSGML_MARGIN && wlen <
127                         IDSGML_MARGIN)
128                     {
129                         sprintf(line, "\n%*s", col, "");
130                         lcol = col;
131                         wrbuf_write(b, line, strlen(line));
132                         first = 1;
133                     }
134                     if (!first)
135                     {
136                         wrbuf_putc(b, ' ');
137                         lcol++;
138                     }
139                     while (l && !d1_isspace(*p))
140                     {
141                         wrbuf_putc(b, *p);
142                         p++;
143                         l--;
144                         lcol++;
145                     }
146                     first = 0;
147                 }
148                 wrbuf_write(b, "\n", 1);
149                 break;
150             case DATA1I_num:
151                 wrbuf_write(b, c->u.data.data, c->u.data.len);
152                 break;
153             case DATA1I_oid:
154                 wrbuf_write(b, c->u.data.data, c->u.data.len);
155             }
156         }
157     }
158     return 0;
159 }
160
161 char *data1_nodetoidsgml (data1_handle dh, data1_node *n, int select, int *len)
162 {
163     WRBUF b = data1_get_wrbuf (dh);
164     char line[1024];
165     
166     wrbuf_rewind(b);
167     
168     sprintf(line, "<%s>\n", n->u.root.type);
169     wrbuf_write(b, line, strlen(line));
170     if (nodetoidsgml(n, select, b, 0))
171         return 0;
172     sprintf(line, "</%s>\n", n->u.root.type);
173     wrbuf_write(b, line, strlen(line));
174     *len = wrbuf_len(b);
175     return wrbuf_buf(b);
176 }