9caf93cf3a4c0ce6738280f2e376e984fb2a84f2
[yaz-moved-to-github.git] / src / wrbuf.c
1 /*
2  * Copyright (c) 1995-2004, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: wrbuf.c,v 1.6 2004-10-15 00:19:01 adam Exp $
6  */
7
8 /**
9  * \file wrbuf.c
10  * \brief Implements WRBUF (growing buffer)
11  */
12
13 #if HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdarg.h>
21
22 #include <yaz/wrbuf.h>
23 #include <yaz/yaz-iconv.h>
24
25 WRBUF wrbuf_alloc(void)
26 {
27     WRBUF n;
28
29     if (!(n = (WRBUF)xmalloc(sizeof(*n))))
30         abort();
31     n->buf = 0;
32     n->size = 0;
33     n->pos = 0;
34     return n;
35 }
36
37 void wrbuf_free(WRBUF b, int free_buf)
38 {
39     if (free_buf && b->buf)
40         xfree(b->buf);
41     xfree(b);
42 }
43
44 void wrbuf_rewind(WRBUF b)
45 {
46     b->pos = 0;
47 }
48
49 int wrbuf_grow(WRBUF b, int minsize)
50 {
51     int togrow;
52
53     if (!b->size)
54         togrow = 1024;
55     else
56         togrow = b->size;
57     if (togrow < minsize)
58         togrow = minsize;
59     if (b->size && !(b->buf =(char *)xrealloc(b->buf, b->size += togrow)))
60         abort();
61     else if (!b->size && !(b->buf = (char *)xmalloc(b->size = togrow)))
62         abort();
63     return 0;
64 }
65
66 int wrbuf_write(WRBUF b, const char *buf, int size)
67 {
68     if (size <= 0)
69         return 0;
70     if (b->pos + size >= b->size)
71         wrbuf_grow(b, size);
72     memcpy(b->buf + b->pos, buf, size);
73     b->pos += size;
74     return 0;
75 }
76
77 int wrbuf_puts(WRBUF b, const char *buf)
78 {
79     wrbuf_write(b, buf, strlen(buf)+1);  /* '\0'-terminate as well */
80     (b->pos)--;                          /* don't include '\0' in count */
81     return 0;
82 }
83
84 int wrbuf_xmlputs(WRBUF b, const char *cp)
85 {
86     return wrbuf_xmlputs_n(b, cp, strlen(cp));
87 }
88
89 int wrbuf_xmlputs_n(WRBUF b, const char *cp, int size)
90 {
91     while (--size >= 0)
92     {
93         /* only TAB,CR,LF of ASCII CTRL are allowed in XML 1.0! */
94         if (*cp >= 0 && *cp <= 31)
95             if (*cp != 9 && *cp != 10 && *cp != 13)
96             {
97                 cp++;  /* we silently ignore (delete) these.. */
98                 continue;
99             }
100         switch(*cp)
101         {
102         case '<':
103             wrbuf_puts(b, "&lt;");
104             break;
105         case '>':
106             wrbuf_puts(b, "&gt;");
107             break;
108         case '&':
109             wrbuf_puts(b, "&amp;");
110             break;
111         case '"':
112             wrbuf_puts(b, "&quot;");
113             break;
114         case '\'':
115             wrbuf_puts(b, "&apos;");
116             break;
117         default:
118             wrbuf_putc(b, *cp);
119         }
120         cp++;
121     }
122     wrbuf_putc(b, 0);
123     (b->pos)--;
124     return 0;
125 }
126
127 void wrbuf_printf(WRBUF b, const char *fmt, ...)
128 {
129     va_list ap;
130     char buf[4096];
131
132     va_start(ap, fmt);
133 #ifdef WIN32
134     _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
135 #else
136 /* !WIN32 */
137 #if HAVE_VSNPRINTF
138     vsnprintf(buf, sizeof(buf)-1, fmt, ap);
139 #else
140     vsprintf(buf, fmt, ap);
141 #endif
142 #endif
143     wrbuf_puts (b, buf);
144
145     va_end(ap);
146 }
147
148 static int wrbuf_iconv_write_x(WRBUF b, yaz_iconv_t cd, const char *buf,
149                                int size, int cdata)
150 {
151     if (cd)
152     {
153         char outbuf[12];
154         size_t inbytesleft = size;
155         const char *inp = buf;
156         while (inbytesleft)
157         {
158             size_t outbytesleft = sizeof(outbuf);
159             char *outp = outbuf;
160             size_t r = yaz_iconv(cd, (char**) &inp,  &inbytesleft,
161                                  &outp, &outbytesleft);
162             if (r == (size_t) (-1))
163             {
164                 int e = yaz_iconv_error(cd);
165                 if (e != YAZ_ICONV_E2BIG)
166                     break;
167             }
168             if (cdata)
169                 wrbuf_xmlputs_n(b, outbuf, outp - outbuf);
170             else
171                 wrbuf_write(b, outbuf, outp - outbuf);
172         }
173     }
174     else
175     {
176         if (cdata)
177             wrbuf_xmlputs_n(b, buf, size);
178         else
179             wrbuf_write(b, buf, size);
180     }
181     return wrbuf_len(b);
182 }
183
184 int wrbuf_iconv_write(WRBUF b, yaz_iconv_t cd, const char *buf, int size)
185 {
186     return wrbuf_iconv_write_x(b, cd, buf, size, 0);
187 }
188
189 int wrbuf_iconv_write_cdata(WRBUF b, yaz_iconv_t cd, const char *buf, int size)
190 {
191     return wrbuf_iconv_write_x(b, cd, buf, size, 1);
192 }
193