File size: 2,424 Bytes
d601f7c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | // Buffer di stringa crescente con escaping JSON.
#pragma once
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { char *p; size_t n, cap; } SBuf;
static inline void sb_reserve(SBuf *s, size_t extra) {
if (s->n + extra + 1 <= s->cap) return;
size_t cap = s->cap ? s->cap : 256;
while (cap < s->n + extra + 1) cap *= 2;
s->p = realloc(s->p, cap);
s->cap = cap;
}
static inline void sb_putn(SBuf *s, const char *str, size_t n) {
sb_reserve(s, n);
memcpy(s->p + s->n, str, n);
s->n += n;
s->p[s->n] = 0;
}
static inline void sb_puts(SBuf *s, const char *str) { sb_putn(s, str, strlen(str)); }
static inline void sb_printf(SBuf *s, const char *fmt, ...) {
va_list ap, ap2;
va_start(ap, fmt);
va_copy(ap2, ap);
int n = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (n > 0) {
sb_reserve(s, (size_t)n);
vsnprintf(s->p + s->n, (size_t)n + 1, fmt, ap2);
s->n += (size_t)n;
}
va_end(ap2);
}
// Lunghezza di una sequenza UTF-8 valida che inizia in c (0 se non valida o incompleta).
static inline int utf8_len(const unsigned char *c) {
int n = c[0] < 0x80 ? 1 : (c[0] >> 5) == 6 ? 2 : (c[0] >> 4) == 14 ? 3 : (c[0] >> 3) == 30 ? 4 : 0;
for (int i = 1; i < n; i++) if ((c[i] & 0xC0) != 0x80) return 0;
return n;
}
// Stringa JSON tra virgolette, con escaping. I byte UTF-8 non validi diventano U+FFFD:
// un solo byte sbagliato farebbe chiudere la connessione al browser.
static inline void sb_json_str(SBuf *s, const char *str) {
sb_putn(s, "\"", 1);
for (const unsigned char *c = (const unsigned char *)str; *c; c++) {
if (*c >= 0x80) {
int n = utf8_len(c);
if (n) { sb_putn(s, (const char *)c, (size_t)n); c += n - 1; }
else sb_putn(s, "\\ufffd", 6);
continue;
}
switch (*c) {
case '"': sb_putn(s, "\\\"", 2); break;
case '\\': sb_putn(s, "\\\\", 2); break;
case '\n': sb_putn(s, "\\n", 2); break;
case '\r': sb_putn(s, "\\r", 2); break;
case '\t': sb_putn(s, "\\t", 2); break;
default:
if (*c < 0x20) sb_printf(s, "\\u%04x", *c);
else sb_putn(s, (const char *)c, 1);
}
}
sb_putn(s, "\"", 1);
}
static inline void sb_free(SBuf *s) { free(s->p); s->p = NULL; s->n = s->cap = 0; }
|