Commit 0799e0cc authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Sort out VSB quoting, add testcases and asserts on usage.

parent c749a196
...@@ -79,12 +79,52 @@ ssize_t VSB_len(const struct vsb *); ...@@ -79,12 +79,52 @@ ssize_t VSB_len(const struct vsb *);
void VSB_delete(struct vsb *) v_deprecated_; void VSB_delete(struct vsb *) v_deprecated_;
void VSB_fini(struct vsb *); void VSB_fini(struct vsb *);
void VSB_destroy(struct vsb **); void VSB_destroy(struct vsb **);
#define VSB_QUOTE_NONL 1
/*
* VSB_quote[_pfx] has four major modes, and two modifiers
*/
#define VSB_QUOTE_PLAIN 0
/*
* Basic "show me the string" mode
* All output is a single line
*/
#define VSB_QUOTE_JSON 2 #define VSB_QUOTE_JSON 2
/*
* Output suitable for inclusion between "..." in JSON
* Uses JSON \u%04x quoting.
* Anything above 0x7e had better be UTF-8
*/
#define VSB_QUOTE_HEX 4 #define VSB_QUOTE_HEX 4
/*
* Hex dump, single line.
* All zero data is compressed to "0x0...0"
*/
#define VSB_QUOTE_CSTR 8 #define VSB_QUOTE_CSTR 8
/*
* C lanuage source code literal string(s)
* Breaks strings at \n (expecting string concatenation)
*/
#define VSB_QUOTE_UNSAFE 16 #define VSB_QUOTE_UNSAFE 16
/*
* For general display applications
* " and \ are not quoted
* Splits output to new line at '\n'
* Implies VSB_QUOTE_NONL
*/
#define VSB_QUOTE_NONL 1
/*
* If the output does not end in \n, append \n
* Can be combined with all other modes.
*/
#define VSB_QUOTE_ESCHEX 32 #define VSB_QUOTE_ESCHEX 32
/*
* Use \x%02x instead of \%03o
* Not valid with VSB_QUOTE_JSON and VSB_QUOTE_HEX
*/
void VSB_quote_pfx(struct vsb *, const char*, const void *, void VSB_quote_pfx(struct vsb *, const char*, const void *,
int len, int how); int len, int how);
void VSB_quote(struct vsb *, const void *, int len, int how); void VSB_quote(struct vsb *, const void *, int len, int how);
......
...@@ -555,73 +555,102 @@ VSB_destroy(struct vsb **s) ...@@ -555,73 +555,102 @@ VSB_destroy(struct vsb **s)
/* /*
* Quote a string * Quote a string
*/ */
static void
vsb_quote_hex(struct vsb *s, const uint8_t *u, size_t len)
{
const uint8_t *w;
VSB_cat(s, "0x");
for (w = u; w < u + len; w++)
if (*w != 0x00)
break;
if (w == u + len && len > 4) {
VSB_cat(s, "0...0");
} else {
for (w = u; w < u + len; w++)
VSB_printf(s, "%02x", *w);
}
}
void void
VSB_quote_pfx(struct vsb *s, const char *pfx, const void *v, int len, int how) VSB_quote_pfx(struct vsb *s, const char *pfx, const void *v, int len, int how)
{ {
const char *p; const uint8_t *p = v;
const char *q; const uint8_t *q;
int quote = 0; int quote = 0;
int nl = 0; int nl;
const unsigned char *u, *w;
nl = how &
(VSB_QUOTE_JSON|VSB_QUOTE_HEX|VSB_QUOTE_CSTR|VSB_QUOTE_UNSAFE);
AZ(nl & (nl - 1)); // Only one bit can be set
if (how & VSB_QUOTE_ESCHEX)
AZ(how & (VSB_QUOTE_JSON|VSB_QUOTE_HEX));
if (how & VSB_QUOTE_UNSAFE)
how |= VSB_QUOTE_NONL;
assert(v != NULL); assert(p != NULL);
if (len == -1) if (len == -1)
len = strlen(v); len = strlen(v);
if (len == 0 && (how & VSB_QUOTE_CSTR)) { if (len == 0 && (how & VSB_QUOTE_CSTR)) {
VSB_printf(s, "%s\"\"", pfx); VSB_printf(s, "%s\"\"", pfx);
return; if ((how & VSB_QUOTE_NONL))
} else if (len == 0) VSB_putc(s, '\n');
}
if (len == 0)
return; return;
VSB_cat(s, pfx); VSB_cat(s, pfx);
if (how & VSB_QUOTE_HEX) { if (how & VSB_QUOTE_HEX) {
u = v; vsb_quote_hex(s, v, len);
for (w = u; w < u + len; w++) if (how & VSB_QUOTE_NONL)
if (*w != 0x00) VSB_putc(s, '\n');
break;
VSB_cat(s, "0x");
if (w == u + len && len > 4) {
VSB_cat(s, "0...0");
} else {
for (w = u; w < u + len; w++)
VSB_printf(s, "%02x", *w);
}
return; return;
} }
p = v;
if (how & VSB_QUOTE_CSTR)
VSB_putc(s, '"');
for (q = p; q < p + len; q++) { for (q = p; q < p + len; q++) {
if (!isgraph(*q) || *q == '"' || *q == '\\') { if (
*q < 0x20 ||
*q == '"' ||
*q == '\\' ||
(*q == '?' && (how & VSB_QUOTE_CSTR)) ||
(*q > 0x7e && !(how & VSB_QUOTE_JSON))
) {
quote++; quote++;
break; break;
} }
} }
if (!quote && !(how & (VSB_QUOTE_JSON|VSB_QUOTE_CSTR))) {
(void)VSB_bcat(s, p, len); if (!quote) {
if ((how & (VSB_QUOTE_UNSAFE|VSB_QUOTE_NONL)) && VSB_bcat(s, p, len);
if ((how & VSB_QUOTE_NONL) &&
p[len-1] != '\n') p[len-1] != '\n')
(void)VSB_putc(s, '\n'); (void)VSB_putc(s, '\n');
if (how & VSB_QUOTE_CSTR)
VSB_putc(s, '"');
return; return;
} }
if (how & VSB_QUOTE_CSTR) nl = 0;
(void)VSB_putc(s, '"');
for (q = p; q < p + len; q++) { for (q = p; q < p + len; q++) {
if (nl) if (nl)
VSB_cat(s, pfx); VSB_cat(s, pfx);
nl = 0; nl = 0;
switch (*q) { switch (*q) {
case '?': case '?':
if (how & VSB_QUOTE_CSTR) /* Avoid C Trigraph insanity */
if (how & VSB_QUOTE_CSTR && !(how & VSB_QUOTE_JSON))
(void)VSB_putc(s, '\\'); (void)VSB_putc(s, '\\');
(void)VSB_putc(s, *q); (void)VSB_putc(s, *q);
break; break;
case ' ':
(void)VSB_putc(s, *q);
break;
case '\\': case '\\':
case '"': case '"':
if (!(how & VSB_QUOTE_UNSAFE)) if (!(how & VSB_QUOTE_UNSAFE))
...@@ -630,38 +659,43 @@ VSB_quote_pfx(struct vsb *s, const char *pfx, const void *v, int len, int how) ...@@ -630,38 +659,43 @@ VSB_quote_pfx(struct vsb *s, const char *pfx, const void *v, int len, int how)
break; break;
case '\n': case '\n':
if (how & VSB_QUOTE_CSTR) { if (how & VSB_QUOTE_CSTR) {
(void)VSB_printf(s, "\\n\"\n%s\"", pfx); VSB_printf(s, "\\n\"\n%s\"", pfx);
} else if (how & (VSB_QUOTE_NONL|VSB_QUOTE_UNSAFE)) { } else if (how & VSB_QUOTE_JSON) {
(void)VSB_printf(s, "\n"); VSB_printf(s, "\\n");
} else if (how & VSB_QUOTE_NONL) {
VSB_putc(s, *q);
nl = 1; nl = 1;
} else { } else {
(void)VSB_printf(s, "\\n"); VSB_printf(s, "\\n");
} }
break; break;
case '\r': case '\r':
(void)VSB_cat(s, "\\r"); VSB_cat(s, "\\r");
break; break;
case '\t': case '\t':
(void)VSB_cat(s, "\\t"); VSB_cat(s, "\\t");
break; break;
case '\v': case '\v':
(void)VSB_cat(s, "\\v"); VSB_cat(s, "\\v");
break; break;
default: default:
/* XXX: Implement VSB_QUOTE_JSON */ if (0x20 <= *q && *q <= 0x7e)
if (isgraph(*q)) VSB_putc(s, *q);
(void)VSB_putc(s, *q); else if (*q > 0x7e && (how & VSB_QUOTE_JSON))
VSB_putc(s, *q);
else if (how & VSB_QUOTE_JSON)
VSB_printf(s, "\\u%04x", *q);
else if (how & VSB_QUOTE_ESCHEX) else if (how & VSB_QUOTE_ESCHEX)
(void)VSB_printf(s, "\\x%02x", *q & 0xff); VSB_printf(s, "\\x%02x", *q);
else else
(void)VSB_printf(s, "\\%03o", *q & 0xff); VSB_printf(s, "\\%03o", *q);
break; break;
} }
} }
if (how & VSB_QUOTE_CSTR) if (how & VSB_QUOTE_CSTR)
(void)VSB_putc(s, '"'); VSB_putc(s, '"');
if ((how & (VSB_QUOTE_NONL|VSB_QUOTE_UNSAFE)) && !nl) if ((how & VSB_QUOTE_NONL) && !nl)
(void)VSB_putc(s, '\n'); VSB_putc(s, '\n');
} }
void void
......
...@@ -10,13 +10,79 @@ ...@@ -10,13 +10,79 @@
struct tc { struct tc {
int how; int how;
int inlen;
const char *in; const char *in;
const char *out; const char *out;
}; };
static struct tc tcs[] = { static struct tc tcs[] = {
{ {
0, NULL, NULL VSB_QUOTE_HEX,
5, "\x00\n\x7e\x7f\xff",
"PFX0x000a7e7fff"
},
{
VSB_QUOTE_HEX,
5, "\0\0\0\0\0",
"PFX0x0...0"
},
{
VSB_QUOTE_HEX | VSB_QUOTE_NONL,
5, "\x00\n\x7e\x7f\xff",
"PFX0x000a7e7fff\n"
},
{
VSB_QUOTE_ESCHEX,
5, "\x00\n\x7e\x7f\xff",
"PFX\\x00\\n~\\x7f\\xff",
},
{
0,
5, "\x00\n\x7e\x7f\xff",
"PFX\\000\\n~\\177\\377",
},
{
VSB_QUOTE_UNSAFE,
5, "\x00\n\x7e\x7f\xff",
"PFX\\000\nPFX~\\177\\377\n",
},
{
VSB_QUOTE_UNSAFE,
-1, "\n\"\\\t",
"PFX\nPFX\"\\\\t\n"
},
{
VSB_QUOTE_CSTR | VSB_QUOTE_ESCHEX,
5, "\x00\n\x7e\x7f\xff",
"PFX\"\\x00\\n\"\nPFX\"~\\x7f\\xff\"",
},
{
VSB_QUOTE_JSON,
5, "\x00\n\x7e\x7f\xff",
"PFX\\u0000\\n~\x7f\xff",
},
{
VSB_QUOTE_JSON | VSB_QUOTE_NONL,
5, "\x00\n\x7e\x7f\xff",
"PFX\\u0000\\n~\x7f\xff\n",
},
{
VSB_QUOTE_CSTR,
-1, "",
"PFX\"\""
},
{
VSB_QUOTE_CSTR,
-1, "?",
"PFX\"\\?\""
},
{
VSB_QUOTE_NONL,
-1, "\n\t",
"PFX\nPFX\\t\n"
},
{
0, -1, NULL, NULL
} }
}; };
...@@ -26,25 +92,58 @@ main(int argc, char *argv[]) ...@@ -26,25 +92,58 @@ main(int argc, char *argv[])
int err = 0; int err = 0;
struct tc *tc; struct tc *tc;
struct vsb *vsb; struct vsb *vsb;
struct vsb *vsbo;
(void)argc; (void)argc;
(void)argv; (void)argv;
vsb = VSB_new_auto(); vsb = VSB_new_auto();
AN(vsb); AN(vsb);
vsbo = VSB_new_auto();
AN(vsbo);
for (tc = tcs; tc->in; tc++) { for (tc = tcs; tc->in; tc++) {
VSB_quote(vsb, tc->in, -1, tc->how); VSB_quote_pfx(vsb, "PFX", tc->in, tc->inlen, tc->how);
assert(VSB_finish(vsb) == 0); assert(VSB_finish(vsb) == 0);
printf("%s -> %s", tc->in, VSB_data(vsb)); VSB_clear(vsbo);
VSB_printf(vsbo, "0x%02x: ", tc->how);
VSB_quote(vsbo, tc->in, tc->inlen, VSB_QUOTE_HEX);
VSB_printf(vsbo, " -> ");
VSB_quote(vsbo, VSB_data(vsb), -1, VSB_QUOTE_HEX);
VSB_printf(vsbo, " (");
VSB_quote(vsbo, tc->out, -1, VSB_QUOTE_ESCHEX);
VSB_printf(vsbo, ")");
if (strcmp(VSB_data(vsb), tc->out)) { if (strcmp(VSB_data(vsb), tc->out)) {
printf(", but should have been %s", tc->out); VSB_printf(vsbo, "\nShould have been:\n\t");
VSB_quote(vsbo, tc->out, -1, VSB_QUOTE_HEX);
VSB_printf(vsbo, "\nThat's:\n\t");
VSB_quote(vsbo, VSB_data(vsb), -1, VSB_QUOTE_ESCHEX);
VSB_printf(vsbo, "\nvs:\n\t");
VSB_quote(vsbo, tc->out, -1, VSB_QUOTE_ESCHEX);
VSB_printf(vsbo, "\nFlags 0x%02x = ", tc->how);
if (!tc->how)
VSB_printf(vsbo, "\n\t0");
if (tc->how & VSB_QUOTE_NONL)
VSB_printf(vsbo, "\n\tVSB_QUOTE_NONL");
if (tc->how & VSB_QUOTE_JSON)
VSB_printf(vsbo, "\n\tVSB_QUOTE_JSON");
if (tc->how & VSB_QUOTE_HEX)
VSB_printf(vsbo, "\n\tVSB_QUOTE_HEX");
if (tc->how & VSB_QUOTE_CSTR)
VSB_printf(vsbo, "\n\tVSB_QUOTE_CSTR");
if (tc->how & VSB_QUOTE_UNSAFE)
VSB_printf(vsbo, "\n\tVSB_QUOTE_UNSAFE");
if (tc->how & VSB_QUOTE_ESCHEX)
VSB_printf(vsbo, "\n\tVSB_QUOTE_ESCHEX");
VSB_printf(vsbo, "\n\n");
err = 1; err = 1;
} }
printf("\n"); AZ(VSB_finish(vsbo));
printf("%s\n", VSB_data(vsbo));
VSB_clear(vsb); VSB_clear(vsb);
} }
VSB_destroy(&vsb); VSB_destroy(&vsb);
VSB_destroy(&vsbo);
printf("error is %i\n", err); printf("error is %i\n", err);
return (err); return (err);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment