vinyl-cache/lib/libvinyl/vsb.c
0
/*-
1
 * Copyright (c) 2000-2008 Poul-Henning Kamp <phk@FreeBSD.org>
2
 * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
3
 * All rights reserved.
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer
12
 *    in this position and unchanged.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
__FBSDID("$FreeBSD: head/sys/kern/subr_vsb.c 222004 2011-05-17 06:36:32Z phk $")
29
 */
30
31
#include "config.h"
32
33
#include <ctype.h>
34
#include <stdarg.h>
35
#include <stdio.h>
36
#include <stdint.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
41
#include "vdef.h"
42
#include "vas.h"        // XXX Flexelint "not used" - but req'ed for assert()
43
#include "vsb.h"
44
45
#define KASSERT(e, m)           assert(e)
46
#define SBMALLOC(size)          malloc(size)
47
#define SBFREE(buf)             free(buf)
48
49
#define rndup2(x, y)    (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
50
51
/*
52
 * Predicates
53
 */
54
#define VSB_ISDYNAMIC(s)        ((s)->s_flags & VSB_DYNAMIC)
55
#define VSB_ISDYNSTRUCT(s)      ((s)->s_flags & VSB_DYNSTRUCT)
56
#define VSB_HASROOM(s)          ((s)->s_len < (s)->s_size - 1L)
57
#define VSB_FREESPACE(s)        ((s)->s_size - ((s)->s_len + 1L))
58
#define VSB_CANEXTEND(s)        ((s)->s_flags & VSB_AUTOEXTEND)
59
60
/*
61
 * Set / clear flags
62
 */
63
#define VSB_SETFLAG(s, f)       do { (s)->s_flags |= (f); } while (0)
64
#define VSB_CLEARFLAG(s, f)     do { (s)->s_flags &= ~(f); } while (0)
65
66
#define VSB_MINEXTENDSIZE       16              /* Should be power of 2. */
67
68
#ifdef PAGE_SIZE
69
#define VSB_MAXEXTENDSIZE       PAGE_SIZE
70
#define VSB_MAXEXTENDINCR       PAGE_SIZE
71
#else
72
#define VSB_MAXEXTENDSIZE       4096
73
#define VSB_MAXEXTENDINCR       4096
74
#endif
75
76
/*
77
 * Debugging support
78
 */
79
#if !defined(NDEBUG)
80
static void
81 1959160326
_assert_VSB_integrity(const char *fun, const struct vsb *s)
82
{
83
84 1959160326
        (void)fun;
85 1959160326
        (void)s;
86 1959160326
        KASSERT(s != NULL,
87
            ("%s called with a NULL vsb pointer", fun));
88 1959160326
        KASSERT(s->magic == VSB_MAGIC,
89
            ("%s called with a bogus vsb pointer", fun));
90 1959160326
        KASSERT(s->s_buf != NULL,
91
            ("%s called with uninitialized or corrupt vsb", fun));
92 1959160326
        KASSERT(s->s_len < s->s_size,
93
            ("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size));
94 1959160326
}
95
96
static void
97 1844980040
_assert_VSB_state(const char *fun, const struct vsb *s, int state)
98
{
99
100 1844980040
        (void)fun;
101 1844980040
        (void)s;
102 1844980040
        (void)state;
103 1844980040
        KASSERT((s->s_flags & VSB_FINISHED) == state,
104
            ("%s called with %sfinished or corrupt vsb", fun,
105
            (state ? "un" : "")));
106 1844980040
}
107
#define assert_VSB_integrity(s) _assert_VSB_integrity(__func__, (s))
108
#define assert_VSB_state(s, i)   _assert_VSB_state(__func__, (s), (i))
109
#else
110
#define assert_VSB_integrity(s) do { } while (0)
111
#define assert_VSB_state(s, i)   do { } while (0)
112
#endif
113
114
#ifdef CTASSERT
115
CTASSERT(powerof2(VSB_MAXEXTENDSIZE));
116
CTASSERT(powerof2(VSB_MAXEXTENDINCR));
117
#endif
118
119
static ssize_t
120 92477749
VSB_extendsize(ssize_t size)
121
{
122
        ssize_t newsize;
123
124 92477749
        if (size < (int)VSB_MAXEXTENDSIZE) {
125 91519058
                newsize = VSB_MINEXTENDSIZE;
126 218290430
                while (newsize < size)
127 126771372
                        newsize *= 2;
128 91519058
        } else {
129 958691
                newsize = rndup2(size, VSB_MAXEXTENDINCR);
130
        }
131 92477749
        KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
132 92477749
        return (newsize);
133
}
134
135
/*
136
 * Extend an vsb.
137
 */
138
static ssize_t
139 53146488
VSB_extend(struct vsb *s, ssize_t addlen)
140
{
141
        char *newbuf;
142
        ssize_t newsize;
143
144 53146488
        if (!VSB_CANEXTEND(s))
145 819
                return (-1);
146 53145669
        newsize = VSB_extendsize(s->s_size + addlen);
147 53145669
        if (VSB_ISDYNAMIC(s))
148 53145669
                newbuf = realloc(s->s_buf, newsize);
149
        else
150 0
                newbuf = SBMALLOC(newsize);
151 53145669
        if (newbuf == NULL)
152 0
                return (-1);
153 53145669
        if (!VSB_ISDYNAMIC(s)) {
154 0
                vmemcpy(newbuf, s->s_buf, s->s_size);
155 0
                VSB_SETFLAG(s, VSB_DYNAMIC);
156 0
        }
157 53145669
        s->s_buf = newbuf;
158 53145669
        s->s_size = newsize;
159 53145669
        return (0);
160 53146488
}
161
162
static void
163 1619531006
_vsb_indent(struct vsb *s)
164
{
165 1622154614
        if (s->s_indent == 0 || s->s_error != 0 ||
166 2623608
            (s->s_len > 0 && s->s_buf[s->s_len - 1] != '\n'))
167 1619361139
                return;
168 169867
        if (VSB_FREESPACE(s) <= s->s_indent &&
169 364
            VSB_extend(s, s->s_indent) < 0) {
170 0
                s->s_error = ENOMEM;
171 0
                return;
172
        }
173 169867
        memset(s->s_buf + s->s_len, ' ', s->s_indent);
174 169867
        s->s_len += s->s_indent;
175 1619531006
}
176
177
/*
178
 * Initialize the internals of an vsb.
179
 * If buf is non-NULL, it points to a static or already-allocated string
180
 * big enough to hold at least length characters.
181
 */
182
static struct vsb *
183 40053137
VSB_newbuf(struct vsb *s, char *buf, int length, int flags)
184
{
185
186 40053137
        memset(s, 0, sizeof(*s));
187 40053137
        s->magic = VSB_MAGIC;
188 40053137
        s->s_flags = flags;
189 40053137
        s->s_size = length;
190 40053137
        s->s_buf = buf;
191
192 40053137
        if ((s->s_flags & VSB_AUTOEXTEND) == 0) {
193 720781
                KASSERT(s->s_size > 1,
194
                    ("attempt to create a too small vsb"));
195 720781
        }
196
197 40053137
        if (s->s_buf != NULL)
198 720781
                return (s);
199
200 39332356
        if ((flags & VSB_AUTOEXTEND) != 0)
201 39332338
                s->s_size = VSB_extendsize(s->s_size);
202
203 39332356
        s->s_buf = SBMALLOC(s->s_size);
204 39332356
        if (s->s_buf == NULL)
205 0
                return (NULL);
206 39332338
        VSB_SETFLAG(s, VSB_DYNAMIC);
207 39332338
        return (s);
208 40053119
}
209
210
struct vsb *
211 720794
VSB_init(struct vsb *s, void *buf, ssize_t length)
212
{
213 720794
        AN(s);
214 720794
        AN(buf);
215
216 720794
        KASSERT(length >= 0,
217
            ("attempt to create an vsb of negative length (%zd)", length));
218 720794
        return (VSB_newbuf(s, buf, length, VSB_FIXEDLEN));
219
}
220
221
/*
222
 * Allocate a dynamic vsb
223
 */
224
struct vsb *
225 39332338
VSB_new_auto(void)
226
{
227
        struct vsb *s;
228
229 39332338
        s = SBMALLOC(sizeof(*s));
230 39332338
        if (s == NULL)
231 0
                return (NULL);
232 39332338
        if (VSB_newbuf(s, NULL, 0, VSB_AUTOEXTEND) == NULL) {
233 0
                SBFREE(s);
234 0
                return (NULL);
235
        }
236 39332338
        VSB_SETFLAG(s, VSB_DYNSTRUCT);
237 39332338
        return (s);
238 39332338
}
239
240
/*
241
 * Clear an vsb and reset its position.
242
 */
243
void
244 53992256
VSB_clear(struct vsb *s)
245
{
246
247 53992256
        assert_VSB_integrity(s);
248
        /* don't care if it's finished or not */
249
250 53992256
        VSB_CLEARFLAG(s, VSB_FINISHED);
251 53992256
        s->s_error = 0;
252 53992256
        s->s_len = 0;
253 53992256
        s->s_indent = 0;
254 53992256
}
255
256
/*
257
 * Append a byte to an vsb.  This is the core function for appending
258
 * to an vsb and is the main place that deals with extending the
259
 * buffer and marking overflow.
260
 */
261
static void
262 1238453979
VSB_put_byte(struct vsb *s, int c)
263
{
264
265 1238453979
        assert_VSB_integrity(s);
266 1238453979
        assert_VSB_state(s, 0);
267
268 1238453979
        if (s->s_error != 0)
269 0
                return;
270 1238453979
        _vsb_indent(s);
271 1238453979
        if (VSB_FREESPACE(s) <= 0) {
272 12463649
                if (VSB_extend(s, 1) < 0)
273 0
                        s->s_error = ENOMEM;
274 12463649
                if (s->s_error != 0)
275 0
                        return;
276 12463649
        }
277 1238453979
        s->s_buf[s->s_len++] = (char)c;
278 1238453979
}
279
280
/*
281
 * Append a byte string to an vsb.
282
 */
283
int
284 78324156
VSB_bcat(struct vsb *s, const void *buf, ssize_t len)
285
{
286 78324156
        assert_VSB_integrity(s);
287 78324156
        assert_VSB_state(s, 0);
288
289 78324156
        assert(len >= 0);
290 78324156
        if (s->s_error != 0)
291 0
                return (-1);
292 78324156
        if (len == 0)
293 5095538
                return (0);
294 73228618
        _vsb_indent(s);
295 73228618
        if (len > VSB_FREESPACE(s)) {
296 14594044
                if (VSB_extend(s, len - VSB_FREESPACE(s)) < 0)
297 168
                        s->s_error = ENOMEM;
298 14594044
                if (s->s_error != 0)
299 168
                        return (-1);
300 14593876
        }
301 73228450
        vmemcpy(s->s_buf + s->s_len, buf, len);
302 73228450
        s->s_len += len;
303 73228450
        return (0);
304 78324156
}
305
306
/*
307
 * Append a string to an vsb.
308
 */
309
int
310 71488988
VSB_cat(struct vsb *s, const char *str)
311
{
312
        const char *nl;
313
        size_t l;
314
315 71488988
        assert_VSB_integrity(s);
316 71488988
        assert_VSB_state(s, 0);
317 71488988
        KASSERT(str != NULL,
318
            ("%s called with a NULL str pointer", __func__));
319
320 71488988
        if (s->s_error != 0)
321 105
                return (-1);
322
323 71513694
        while (s->s_indent > 0 && (nl = strchr(str, '\n')) != NULL) {
324 24811
                l = (nl - str) + 1;
325 24811
                if (VSB_bcat(s, str, l) < 0)
326 0
                        return (-1);
327 24811
                str += l;
328
        }
329
330 71488883
        l = vstrlen(str);
331 71488883
        return (VSB_bcat(s, str, l));
332 71488988
}
333
334
/*
335
 * Format the given argument list and append the resulting string to an vsb.
336
 */
337
int
338 308057110
VSB_vprintf(struct vsb *s, const char *fmt, va_list ap)
339
{
340
        va_list ap_copy;
341
        int len;
342
343 308057110
        assert_VSB_integrity(s);
344 308057110
        assert_VSB_state(s, 0);
345
346 308057110
        KASSERT(fmt != NULL,
347
            ("%s called with a NULL format string", __func__));
348
349 308057110
        if (s->s_error != 0)
350 0
                return (-1);
351 308057110
        _vsb_indent(s);
352
353
        /*
354
         * For the moment, there is no way to get vsnprintf(3) to hand
355
         * back a character at a time, to push everything into
356
         * VSB_putc_func() as was done for the kernel.
357
         *
358
         * In userspace, while drains are useful, there's generally
359
         * not a problem attempting to malloc(3) on out of space.  So
360
         * expand a userland vsb if there is not enough room for the
361
         * data produced by VSB_[v]printf(3).
362
         */
363
364 308057110
        do {
365 334144433
                va_copy(ap_copy, ap);
366 668288866
                len = vsnprintf(&s->s_buf[s->s_len], VSB_FREESPACE(s) + 1,
367 334144433
                    fmt, ap_copy);
368 334144433
                va_end(ap_copy);
369 334144433
                if (len < 0) {
370 0
                        s->s_error = errno;
371 0
                        return (-1);
372
                }
373 360232907
        } while (len > VSB_FREESPACE(s) &&
374 26088474
            VSB_extend(s, len - VSB_FREESPACE(s)) == 0);
375
376
        /*
377
         * s->s_len is the length of the string, without the terminating nul.
378
         * When updating s->s_len, we must subtract 1 from the length that
379
         * we passed into vsnprintf() because that length includes the
380
         * terminating nul.
381
         *
382
         * vsnprintf() returns the amount that would have been copied,
383
         * given sufficient space, so don't over-increment s_len.
384
         */
385 308057110
        s->s_len += vmin_t(ssize_t, len, VSB_FREESPACE(s));
386 308057110
        if (!VSB_HASROOM(s) && !VSB_CANEXTEND(s))
387 651
                s->s_error = ENOMEM;
388
389 308057110
        KASSERT(s->s_len < s->s_size,
390
            ("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size));
391
392 308057110
        if (s->s_error != 0)
393 638
                return (-1);
394 308056472
        return (0);
395 308057110
}
396
397
/*
398
 * Format the given arguments and append the resulting string to an vsb.
399
 */
400
int
401 163495579
VSB_printf(struct vsb *s, const char *fmt, ...)
402
{
403
        va_list ap;
404
        int result;
405
406 163495579
        va_start(ap, fmt);
407 163495579
        result = VSB_vprintf(s, fmt, ap);
408 163495579
        va_end(ap);
409 163495579
        return (result);
410
}
411
412
/*
413
 * Append a character to an vsb.
414
 */
415
int
416 1238449850
VSB_putc(struct vsb *s, int c)
417
{
418
419 1238449850
        VSB_put_byte(s, c);
420 1238449850
        if (s->s_error != 0)
421 0
                return (-1);
422 1238449850
        return (0);
423 1238449850
}
424
425
/*
426
 * Check if an vsb has an error.
427
 */
428
int
429 32416
VSB_error(const struct vsb *s)
430
{
431
432 32416
        return (s->s_error);
433
}
434
435
/*
436
 * Finish off an vsb.
437
 */
438
int
439 72594200
VSB_finish(struct vsb *s)
440
{
441
442 72594200
        assert_VSB_integrity(s);
443 72594200
        assert_VSB_state(s, 0);
444
445 72594200
        s->s_buf[s->s_len] = '\0';
446 72594200
        VSB_SETFLAG(s, VSB_FINISHED);
447 72594200
        errno = s->s_error;
448 72594200
        if (s->s_error)
449 819
                return (-1);
450 72593381
        return (0);
451 72594200
}
452
453
/*
454
 * Return a pointer to the vsb data.
455
 */
456
char *
457 74818633
VSB_data(const struct vsb *s)
458
{
459
460 74818633
        assert_VSB_integrity(s);
461 74818633
        assert_VSB_state(s, VSB_FINISHED);
462
463 74818633
        return (s->s_buf);
464
}
465
466
/*
467
 * Return the length of the vsb data.
468
 */
469
ssize_t
470 26899667
VSB_len(const struct vsb *s)
471
{
472
473 26899667
        assert_VSB_integrity(s);
474
        /* don't care if it's finished or not */
475
476 26899667
        if (s->s_error != 0)
477 0
                return (-1);
478 26899667
        return (s->s_len);
479 26899667
}
480
481
void
482 699357
VSB_fini(struct vsb *s)
483
{
484
485 699357
        assert_VSB_integrity(s);
486 699357
        assert(!VSB_ISDYNAMIC(s));
487 699357
        assert(!VSB_ISDYNSTRUCT(s));
488 699357
        memset(s, 0, sizeof(*s));
489 699357
}
490
491
void
492 32738317
VSB_destroy(struct vsb **s)
493
{
494
495 32738317
        AN(s);
496 32738317
        assert_VSB_integrity(*s);
497 32738317
        assert(VSB_ISDYNAMIC(*s));
498 32738317
        assert(VSB_ISDYNSTRUCT(*s));
499 32738317
        SBFREE((*s)->s_buf);
500 32738317
        memset(*s, 0, sizeof(**s));
501 32738317
        SBFREE(*s);
502 32738317
        *s = NULL;
503 32738317
}
504
505
/*
506
 * Quote a string
507
 */
508
509
static void
510 87360
vsb_quote_hex(struct vsb *s, const uint8_t *u, size_t len)
511
{
512
        const uint8_t *w;
513
514 87360
        VSB_cat(s, "0x");
515 211471
        for (w = u; w < u + len; w++)
516 198745
                if (*w != 0x00)
517 74634
                        break;
518 87360
        if (w == u + len && len > 4) {
519 357
                VSB_cat(s, "0...0");
520 357
        } else {
521 14328344
                for (w = u; w < u + len; w++)
522 14241341
                        VSB_printf(s, "%02x", *w);
523
        }
524 87360
}
525
526
void
527 7411951
VSB_quote_pfx(struct vsb *s, const char *pfx, const void *v, int len, int how)
528
{
529 7411951
        const uint8_t *p = v;
530
        const uint8_t *q;
531 7411951
        int quote = 0;
532
        int nl;
533
534 7411951
        nl = how &
535
            (VSB_QUOTE_JSON|VSB_QUOTE_HEX|VSB_QUOTE_CSTR|VSB_QUOTE_UNSAFE);
536 7411951
        AZ(nl & (nl - 1)); // Only one bit can be set
537
538 7411951
        if (how & VSB_QUOTE_ESCHEX)
539 3774200
                AZ(how & (VSB_QUOTE_JSON|VSB_QUOTE_HEX));
540
541 7411951
        if (how & VSB_QUOTE_UNSAFE)
542 2849297
                how |= VSB_QUOTE_NONL;
543
544 7411951
        assert(p != NULL);
545 7411951
        if (how & VSB_QUOTE_ABBREVIATE) {
546 168
                assert (len > 5);
547 168
                if (vstrlen(v) < (unsigned)len) {
548 42
                        len = vstrlen(v);
549 42
                        how &= ~VSB_QUOTE_ABBREVIATE;
550 42
                } else {
551 126
                        len -= 5;
552
                }
553 168
        }
554 7411951
        if (len == -1)
555 3371958
                len = vstrlen(v);
556
557 7411951
        if (len == 0 && (how & VSB_QUOTE_CSTR)) {
558 4347
                VSB_printf(s, "%s\"\"", pfx);
559 4347
                if ((how & VSB_QUOTE_NONL))
560 0
                        VSB_putc(s, '\n');
561 4347
        }
562
563 7411951
        if (len == 0)
564 205040
                return;
565
566 7206911
        VSB_cat(s, pfx);
567
568 7206911
        if (how & VSB_QUOTE_HEX) {
569 87360
                vsb_quote_hex(s, v, len);
570 87360
                if (how & VSB_QUOTE_NONL)
571 21
                        VSB_putc(s, '\n');
572 87360
                return;
573
        }
574
575 7119551
        if (how & VSB_QUOTE_CSTR)
576 3167390
                VSB_putc(s, '"');
577
578 175324465
        for (q = p; q < p + len; q++) {
579
                if (
580 170003182
                    *q < 0x20 ||
581 168438510
                    *q == '"' ||
582 168402765
                    *q == '\\' ||
583 168397213
                    (*q == '?' && (how & VSB_QUOTE_CSTR)) ||
584 168204914
                    (*q > 0x7e && !(how & VSB_QUOTE_JSON))
585
                ) {
586 1795517
                        quote++;
587 1795517
                        break;
588
                }
589 168204914
        }
590
591 7119551
        if (!quote) {
592 5324038
                VSB_bcat(s, p, len);
593 5324038
                if (how & VSB_QUOTE_CSTR)
594 2290275
                        VSB_putc(s, '"');
595 5324038
                if (how & VSB_QUOTE_ABBREVIATE)
596 21
                        VSB_cat(s, "[...]");
597 5324038
                if ((how & VSB_QUOTE_NONL) &&
598 1818987
                    p[len-1] != '\n')
599 1818988
                        (void)VSB_putc(s, '\n');
600 5324040
                return;
601
        }
602
603 1795513
        nl = 0;
604 439823167
        for (q = p; q < p + len; q++) {
605 438027654
                if (nl)
606 3957557
                        VSB_cat(s, pfx);
607 438027654
                nl = 0;
608 438027654
                switch (*q) {
609
                case '?':
610
                        /* Avoid C Trigraph insanity */
611 711920
                        if (how & VSB_QUOTE_CSTR && !(how & VSB_QUOTE_JSON))
612 272850
                                (void)VSB_putc(s, '\\');
613 711920
                        (void)VSB_putc(s, *q);
614 711920
                        break;
615
                case '\\':
616
                case '"':
617 4428927
                        if (!(how & VSB_QUOTE_UNSAFE))
618 3041721
                                (void)VSB_putc(s, '\\');
619 4428927
                        (void)VSB_putc(s, *q);
620 4428927
                        break;
621
                case '\n':
622 17436624
                        if (how & VSB_QUOTE_CSTR) {
623 12614021
                                VSB_printf(s, "\\n\"\n%s\"", pfx);
624 17436624
                        } else if (how & VSB_QUOTE_JSON) {
625 37002
                                VSB_cat(s, "\\n");
626 4822603
                        } else if (how & VSB_QUOTE_NONL) {
627 4772032
                                VSB_putc(s, *q);
628 4772032
                                nl = 1;
629 4772032
                        } else {
630 13569
                                VSB_cat(s, "\\n");
631
                        }
632 17436624
                        break;
633
                case '\r':
634 1997547
                        VSB_cat(s, "\\r");
635 1997547
                        break;
636
                case '\t':
637 6221808
                        VSB_cat(s, "\\t");
638 6221808
                        break;
639
                default:
640 407230828
                        if (0x20 <= *q && *q <= 0x7e)
641 407035544
                                VSB_putc(s, *q);
642 195284
                        else if (*q > 0x7e && (how & VSB_QUOTE_JSON))
643 84
                                VSB_putc(s, *q);
644 195200
                        else if (how & VSB_QUOTE_JSON)
645 147
                                VSB_printf(s, "\\u%04x", *q);
646 195053
                        else if (how & VSB_QUOTE_ESCHEX)
647 193709
                                VSB_printf(s, "\\x%02x", *q);
648
                        else
649 1344
                                VSB_printf(s, "\\%03o", *q);
650 407230828
                        break;
651
                }
652 438027654
        }
653 1795513
        if (how & VSB_QUOTE_CSTR)
654 877115
                VSB_putc(s, '"');
655 1795513
        if (how & VSB_QUOTE_ABBREVIATE)
656 105
                VSB_cat(s, "[...]");
657 1795513
        if ((how & VSB_QUOTE_NONL) && !nl)
658 64323
                VSB_putc(s, '\n');
659 7411953
}
660
661
void
662 4455683
VSB_quote(struct vsb *s, const void *v, int len, int how)
663
{
664 4455683
        VSB_quote_pfx(s, "", v, len, how);
665 4455683
}
666
667
/*
668
 * Indentation
669
 */
670
671
void
672 59634
VSB_indent(struct vsb *s, int i)
673
{
674
675 59634
        assert_VSB_integrity(s);
676 59634
        if (s->s_indent + i < 0)
677 0
                s->s_error = EINVAL;
678
        else
679 59634
                s->s_indent += i;
680 59634
}
681
682
int
683 1749808
VSB_tofile(const struct vsb *s, int fd)
684
{
685
        const char *p;
686
        ssize_t r;
687
        size_t sz;
688
689 1749808
        assert_VSB_integrity(s);
690 1749808
        assert_VSB_state(s, VSB_FINISHED);
691 1749808
        assert(s->s_len >= 0);
692 1749808
        r = 0;
693 1749808
        p = s->s_buf;
694 1749808
        sz = (typeof(sz))s->s_len;
695 3499038
        while (sz > 0) {
696 1749514
                r = write(fd, p, sz);
697 1749514
                if (r < 0)
698 284
                        return (-1);
699 1749230
                assert((typeof(sz))r <= sz);
700 1749230
                p += r;
701 1749230
                sz -= r;
702
        }
703 1749524
        return (0);
704 1749808
}