Coverage Report

Created: 2025-12-26 06:07

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