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