lib/util: Standardize use of st_[acm]time ns
[samba.git] / source3 / lib / cbuf.c
1 /*
2  * Samba Unix/Linux SMB client library
3  *
4  * Copyright (C) Gregor Beck 2010
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file   cbuf.c
22  * @author Gregor Beck <gb@sernet.de>
23  * @date   Aug 2010
24  *
25  * @brief  A talloced character buffer.
26  *
27  */
28
29
30 #include "replace.h"
31 #include "system/locale.h"
32 #include "cbuf.h"
33 #include <talloc.h>
34 #include <assert.h>
35 #include "lib/util/byteorder.h"
36
37
38 struct cbuf {
39         char*  buf;
40         size_t pos;
41         size_t size;
42 };
43
44
45 cbuf* cbuf_clear(cbuf* b)
46 {
47         cbuf_setpos(b, 0);
48         return b;
49 }
50
51 cbuf* cbuf_new(const void* ctx)
52 {
53         cbuf* s = talloc(ctx, cbuf);
54         if (s == NULL)
55                 return NULL;
56         s->size = 32;
57         s->buf  = (char *)talloc_size(s, s->size);
58         if (s->size && (s->buf == NULL)) {
59                 talloc_free(s);
60                 return NULL;
61         }
62         return cbuf_clear(s);
63 }
64
65 cbuf* cbuf_copy(const cbuf* b)
66 {
67         cbuf* s = talloc(talloc_parent(b), cbuf);
68         if (s == NULL) {
69                 return NULL;
70         }
71
72         s->buf = (char *)talloc_memdup(s, b->buf, b->size); /* only up to pos? */
73
74         /* XXX shallow did not work, because realloc */
75         /* fails with multiple references */
76         /* s->buf = talloc_reference(s, b->buf); */
77
78         if (s->buf == NULL) {
79                 cbuf_delete(s);
80                 return NULL;
81         }
82         s->size = b->size;
83         s->pos  = b->pos;
84         return s;
85 }
86
87 void cbuf_delete(cbuf* b)
88 {
89         talloc_free(b);
90 }
91
92 #define SWAP(A,B,T) do {                        \
93                 T tmp = A; A = B; B = tmp;      \
94         } while(0)
95
96
97 void cbuf_swap(cbuf* b1, cbuf* b2)
98 {
99         if (b1 == b2) {
100                 return;
101         }
102         talloc_reparent(b1, b2, b1->buf);
103         talloc_reparent(b2, b1, b2->buf);
104         SWAP(b1->buf,  b2->buf, char*);
105         SWAP(b1->pos,  b2->pos, size_t);
106         SWAP(b1->size, b2->size, size_t);
107 }
108
109
110
111 cbuf* cbuf_takeover(cbuf* b1, cbuf* b2)
112 {
113         talloc_reparent(b2, b1, b2->buf);
114         b1->buf = b2->buf;
115         b1->pos = b2->pos;
116         b1->size = b2->size;
117         cbuf_delete(b2);
118         return b1;
119 }
120
121 cbuf* cbuf_swapptr(cbuf* b, char** ptr, size_t len)
122 {
123         void* p = talloc_parent(*ptr);
124         SWAP(b->buf, *ptr, char*);
125         talloc_steal(b, b->buf);
126         talloc_steal(p, *ptr);
127         b->size = talloc_get_size(b->buf);
128         b->pos  = (len == -1) ? strlen(b->buf) : len;
129
130         assert(b->pos <= b->size);
131         return b;
132 }
133
134 cbuf* cbuf_resize(cbuf* b, size_t size)
135 {
136         char* save_buf = b->buf;
137         b->buf = talloc_realloc(b, b->buf, char, size);
138         if (b->buf == NULL) {
139                 talloc_free(save_buf);
140                 b->size = 0;
141         } else {
142                 b->size = size;
143         }
144         b->pos  = MIN(b->pos, b->size);
145         return b->buf ? b : NULL;
146 }
147
148 char* cbuf_reserve(cbuf* b, size_t len)
149 {
150         if(b->size < b->pos + len)
151                 cbuf_resize(b, MAX(2*b->size, b->pos + len));
152         return b->buf ? b->buf + b->pos : NULL;
153 }
154
155 int cbuf_puts(cbuf* b, const char* str, size_t len)
156 {
157         char* dst;
158
159         if (b == NULL)
160                 return 0;
161
162         if (len == -1) {
163                 len=strlen(str);
164         }
165
166         dst = cbuf_reserve(b, len+1);
167         if (dst == NULL)
168                 return -1;
169
170         memcpy(dst, str, len);
171         dst[len] = '\0'; /* just to ease debugging */
172
173         b->pos += len;
174         assert(b->pos < b->size);
175
176         return len;
177 }
178
179 int cbuf_putc(cbuf* b, char c) {
180         char* dst;
181
182         if (b == NULL)
183                 return 0;
184
185         dst = cbuf_reserve(b, 2);
186         if (dst == NULL) {
187                 return -1;
188         }
189
190         dst[0] = c;
191         dst[1] = '\0'; /* just to ease debugging */
192
193         b->pos++;
194         assert(b->pos < b->size);
195
196         return 1;
197 }
198
199 int cbuf_putdw(cbuf* b, uint32_t u) {
200         char* dst;
201         static const size_t LEN = sizeof(uint32_t);
202
203         if (b == NULL)
204                 return 0;
205
206         dst = cbuf_reserve(b, LEN);
207         if (dst == NULL) {
208                 return -1;
209         }
210
211         SIVAL(dst, 0, u);
212
213         b->pos += LEN;
214         assert(b->pos <= b->size); /* no NULL termination*/
215
216         return LEN;
217 }
218
219 size_t cbuf_getpos(const cbuf* b) {
220         assert(b->pos <= b->size);
221         return b->pos;
222 }
223
224 void cbuf_setpos(cbuf* b, size_t pos) {
225         assert(pos <= b->size);
226         b->pos = pos;
227         if (pos < b->size)
228                 b->buf[pos] = '\0'; /* just to ease debugging */
229 }
230
231 char* cbuf_gets(cbuf* b, size_t idx) {
232         assert(idx <= b->pos);
233
234         if (cbuf_reserve(b, 1) == NULL)
235                 return NULL;
236
237         b->buf[b->pos] = '\0';
238         return b->buf + idx;
239 }
240
241 int cbuf_printf(cbuf* b, const char* fmt, ...)
242 {
243         va_list args, args2;
244         int len;
245         char* dst = b->buf + b->pos;
246         const int avail = b->size - b->pos;
247         assert(avail >= 0);
248
249         va_start(args, fmt);
250         va_copy(args2, args);
251
252         len = vsnprintf(dst, avail, fmt, args);
253
254         if (len >= avail) {
255                 dst = cbuf_reserve(b, len+1);
256                 len = (dst != NULL) ? vsnprintf(dst, len+1, fmt, args2) : -1;
257         }
258
259         if (len > 0) {
260                 b->pos += len;
261         }
262
263         va_end(args);
264         va_end(args2);
265         assert(b->pos <= b->size);
266
267         return len;
268 }
269
270 int cbuf_print_quoted_string(cbuf* ost, const char* s)
271 {
272         int n = 1;
273         cbuf_putc(ost,'"');
274
275         while(true) {
276                 switch (*s) {
277                 case '\0':
278                         cbuf_putc(ost, '"');
279                         return n+1;
280
281                 case '"':
282                 case '\\':
283                         cbuf_putc(ost, '\\');
284                         n++;
285
286                         FALL_THROUGH;
287                 default:
288                         cbuf_putc(ost, *s);
289                         n++;
290                 }
291                 s++;
292         }
293 }
294
295
296 int cbuf_print_quoted(cbuf* ost, const char* s, size_t len)
297 {
298         int n = 1;
299         int ret;
300         cbuf_reserve(ost, len+2);
301
302         cbuf_putc(ost,'"');
303
304         while(len--) {
305                 switch (*s) {
306                 case '"':
307                 case '\\':
308                         ret = cbuf_printf(ost, "\\%c", *s);
309                         break;
310                 default:
311                         if (isprint(*s) && ((*s == ' ') || !isspace(*s))) {
312                                 ret = cbuf_putc(ost, *s);
313                         } else {
314                                 ret = cbuf_printf(ost,
315                                                   "\\%02x",
316                                                   (unsigned char)*s);
317                         }
318                 }
319                 s++;
320                 if (ret == -1) {
321                         return -1;
322                 }
323                 n += ret;
324         }
325         ret = cbuf_putc(ost,'"');
326
327         return (ret == -1) ? -1 : (n + ret);
328 }