Added wrbuf_destroy(w), equivalent to wrbuf_free(w,1)
[yaz-moved-to-github.git] / src / wrbuf.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: wrbuf.c,v 1.14 2007-01-06 15:32:46 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_destroy(WRBUF b)
45 {
46     wrbuf_free(b, 1);
47 }
48
49 void wrbuf_rewind(WRBUF b)
50 {
51     b->pos = 0;
52 }
53
54 int wrbuf_grow(WRBUF b, int minsize)
55 {
56     int togrow;
57
58     if (!b->size)
59         togrow = 1024;
60     else
61         togrow = b->size;
62     if (togrow < minsize)
63         togrow = minsize;
64     if (b->size && !(b->buf =(char *)xrealloc(b->buf, b->size += togrow)))
65         abort();
66     else if (!b->size && !(b->buf = (char *)xmalloc(b->size = togrow)))
67         abort();
68     return 0;
69 }
70
71 int wrbuf_write(WRBUF b, const char *buf, int size)
72 {
73     if (size <= 0)
74         return 0;
75     if (b->pos + size >= b->size)
76         wrbuf_grow(b, size);
77     memcpy(b->buf + b->pos, buf, size);
78     b->pos += size;
79     return 0;
80 }
81
82 int wrbuf_puts(WRBUF b, const char *buf)
83 {
84     wrbuf_write(b, buf, strlen(buf)+1);  /* '\0'-terminate as well */
85     (b->pos)--;                          /* don't include '\0' in count */
86     return 0;
87 }
88
89 int wrbuf_puts_replace_char(WRBUF b, const char *buf, 
90                             const char from, const char to)
91 {
92     while(*buf){
93         if (*buf == from)
94             wrbuf_putc(b, to);
95         else
96             wrbuf_putc(b, *buf);
97         buf++;
98     }
99     wrbuf_putc(b, 0);
100     (b->pos)--;                          /* don't include '\0' in count */
101     return 0;
102 }
103
104 void wrbuf_chop_right(WRBUF b)
105 {
106     while (b->pos && b->buf[b->pos-1] == ' ')
107     {
108         (b->pos)--;
109         b->buf[b->pos] = '\0';
110     }
111 }
112
113 int wrbuf_xmlputs(WRBUF b, const char *cp)
114 {
115     return wrbuf_xmlputs_n(b, cp, strlen(cp));
116 }
117
118 int wrbuf_xmlputs_n(WRBUF b, const char *cp, int size)
119 {
120     while (--size >= 0)
121     {
122         /* only TAB,CR,LF of ASCII CTRL are allowed in XML 1.0! */
123         if (*cp >= 0 && *cp <= 31)
124             if (*cp != 9 && *cp != 10 && *cp != 13)
125             {
126                 cp++;  /* we silently ignore (delete) these.. */
127                 continue;
128             }
129         switch(*cp)
130         {
131         case '<':
132             wrbuf_puts(b, "&lt;");
133             break;
134         case '>':
135             wrbuf_puts(b, "&gt;");
136             break;
137         case '&':
138             wrbuf_puts(b, "&amp;");
139             break;
140         case '"':
141             wrbuf_puts(b, "&quot;");
142             break;
143         case '\'':
144             wrbuf_puts(b, "&apos;");
145             break;
146         default:
147             wrbuf_putc(b, *cp);
148         }
149         cp++;
150     }
151     wrbuf_putc(b, 0);
152     (b->pos)--;
153     return 0;
154 }
155
156 void wrbuf_printf(WRBUF b, const char *fmt, ...)
157 {
158     va_list ap;
159     char buf[4096];
160
161     va_start(ap, fmt);
162 #ifdef WIN32
163     _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
164 #else
165 /* !WIN32 */
166 #if HAVE_VSNPRINTF
167     vsnprintf(buf, sizeof(buf)-1, fmt, ap);
168 #else
169     vsprintf(buf, fmt, ap);
170 #endif
171 #endif
172     wrbuf_puts (b, buf);
173
174     va_end(ap);
175 }
176
177 static int wrbuf_iconv_write_x(WRBUF b, yaz_iconv_t cd, const char *buf,
178                                int size, int cdata)
179 {
180     if (cd)
181     {
182         char outbuf[12];
183         size_t inbytesleft = size;
184         const char *inp = buf;
185         while (inbytesleft)
186         {
187             size_t outbytesleft = sizeof(outbuf);
188             char *outp = outbuf;
189             size_t r = yaz_iconv(cd, (char**) &inp,  &inbytesleft,
190                                  &outp, &outbytesleft);
191             if (r == (size_t) (-1))
192             {
193                 int e = yaz_iconv_error(cd);
194                 if (e != YAZ_ICONV_E2BIG)
195                     break;
196             }
197             if (cdata)
198                 wrbuf_xmlputs_n(b, outbuf, outp - outbuf);
199             else
200                 wrbuf_write(b, outbuf, outp - outbuf);
201         }
202     }
203     else
204     {
205         if (cdata)
206             wrbuf_xmlputs_n(b, buf, size);
207         else
208             wrbuf_write(b, buf, size);
209     }
210     return wrbuf_len(b);
211 }
212
213 int wrbuf_iconv_write(WRBUF b, yaz_iconv_t cd, const char *buf, int size)
214 {
215     return wrbuf_iconv_write_x(b, cd, buf, size, 0);
216 }
217
218 int wrbuf_iconv_puts(WRBUF b, yaz_iconv_t cd, const char *strz)
219 {
220     return wrbuf_iconv_write(b, cd, strz, strlen(strz));
221 }
222
223 int wrbuf_iconv_putchar(WRBUF b, yaz_iconv_t cd, int ch)
224 {
225     char buf[1];
226     buf[0] = ch;
227     return wrbuf_iconv_write(b, cd, buf, 1);
228 }
229
230 int wrbuf_iconv_write_cdata(WRBUF b, yaz_iconv_t cd, const char *buf, int size)
231 {
232     return wrbuf_iconv_write_x(b, cd, buf, size, 1);
233 }
234
235 /*
236  * Local variables:
237  * c-basic-offset: 4
238  * indent-tabs-mode: nil
239  * End:
240  * vim: shiftwidth=4 tabstop=8 expandtab
241  */
242