Commit f16abac5 authored by Niels Möller's avatar Niels Möller
Browse files

Better "advanced" and "international" output styles.

Rev: src/sexp.c:1.3
parent 489cb80a
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include "sexp.h.x" #include "sexp.h.x"
#undef CLASS_DEFINE #undef CLASS_DEFINE
/* Defines int char_classes[0x100] */
#include "sexp_table.h"
#include "sexp.c.x" #include "sexp.c.x"
/* CLASS: /* CLASS:
...@@ -47,6 +50,101 @@ ...@@ -47,6 +50,101 @@
(contents string))) (contents string)))
*/ */
/* For advanced format */
static struct lsh_string *do_format_simple_string(struct lsh_string *s,
int style)
{
int quote_friendly = ( (~CHAR_control & ~CHAR_international)
| CHAR_escapable);
switch(style)
{
case SEXP_TRANSPORT:
fatal("Internal error!\n");
case SEXP_CANONICAL:
return ssh_format("%dS", s);
case SEXP_INTERNATIONAL:
quote_friendly |= CHAR_international;
/* Fall through */
case SEXP_ADVANCED:
{
int c;
unsigned i;
if (!s->length)
return ssh_format("\"\"");
/* Compute the set of all character classes represented in the string */
for (c = 0, i = 0; i < s->length; i++)
c |= char_classes[s->data[i]];
if (! ( (char_classes[s->data[0]] & CHAR_digit)
|| (c & ~(CHAR_alpha | CHAR_digit | CHAR_punctuation))))
/* Output token, without any quoting at all */
return lsh_string_dup(s);
if (! (c & ~quote_friendly))
{
/* Count the number of characters needing escape */
unsigned length = s->length;
unsigned i;
struct lsh_string *res;
UINT8 *dst;
for (i = 0; i<s->length; i++)
if (char_classes[s->data[i]] & CHAR_escapable)
length++;
res = ssh_format("\"%lr\"", length, &dst);
for (i=0; i<s->length; i++)
if (char_classes[s->data[i]] & CHAR_escapable)
{
*dst++ = '\\';
switch(s->data[i])
{
case '\b':
*dst++ = 'b';
break;
case '\t':
*dst++ = 't';
break;
case '\v':
*dst++ = 'v';
break;
case '\n':
*dst++ = 'n';
break;
case '\f':
*dst++ = 'f';
break;
case '\r':
*dst++ = 'r';
break;
case '\"':
*dst++ = '\"';
break;
case '\\':
*dst++ = '\\';
break;
default:
fatal("Internal error!\n");
}
}
else
*dst++ = s->data[i];
assert(dst == (res->data + 1 + length));
return res;
}
/* Base 64 string */
return encode_base64(s, "||", 0);
}
default:
fatal("do_format_sexp_string: Unknown output style.\n");
}
}
static struct lsh_string *do_format_sexp_string(struct sexp *s, int style) static struct lsh_string *do_format_sexp_string(struct sexp *s, int style)
{ {
CAST(sexp_string, self, s); CAST(sexp_string, self, s);
...@@ -56,15 +154,15 @@ static struct lsh_string *do_format_sexp_string(struct sexp *s, int style) ...@@ -56,15 +154,15 @@ static struct lsh_string *do_format_sexp_string(struct sexp *s, int style)
case SEXP_TRANSPORT: case SEXP_TRANSPORT:
fatal("Internal error!\n"); fatal("Internal error!\n");
case SEXP_ADVANCED: case SEXP_ADVANCED:
/* Special case of canonical, so we'll fal through for now. */ case SEXP_INTERNATIONAL:
case SEXP_CANONICAL: case SEXP_CANONICAL:
if (self->display) if (self->display)
return ssh_format("[%ds]%ds", return ssh_format("[%lfS]%lfS",
self->display->length, self->display->data, do_format_simple_string(self->display, style),
self->contents->length, self->contents->data); do_format_simple_string(self->contents, style));
else else
return ssh_format("%ds", return ssh_format("%lfS",
self->contents->length, self->contents->data); do_format_simple_string(self->contents, style));
default: default:
fatal("do_format_sexp_string: Unknown output style.\n"); fatal("do_format_sexp_string: Unknown output style.\n");
} }
...@@ -83,9 +181,27 @@ static struct sexp *make_sexp_string(struct lsh_string *d, struct lsh_string *c) ...@@ -83,9 +181,27 @@ static struct sexp *make_sexp_string(struct lsh_string *d, struct lsh_string *c)
return &s->super; return &s->super;
} }
static struct lsh_string *
do_format_sexp_nil(struct sexp *ignored UNUSED, int style)
{
return ssh_format("()");
}
struct sexp_cons sexp_nil =
{ { STATIC_HEADER, do_format_sexp_nil }, &sexp_nil.super, &sexp_nil };
#define SEXP_NIL (&sexp_nil.super)
int sexp_nullp(struct sexp *e)
{
return (e == SEXP_NIL);
}
static struct lsh_string *do_format_sexp_tail(struct sexp_cons *c, int style) static struct lsh_string *do_format_sexp_tail(struct sexp_cons *c, int style)
{ {
if (!c) int use_space = 0;
if (c == &sexp_nil)
return ssh_format(")"); return ssh_format(")");
switch(style) switch(style)
...@@ -93,9 +209,11 @@ static struct lsh_string *do_format_sexp_tail(struct sexp_cons *c, int style) ...@@ -93,9 +209,11 @@ static struct lsh_string *do_format_sexp_tail(struct sexp_cons *c, int style)
case SEXP_TRANSPORT: case SEXP_TRANSPORT:
fatal("Internal error!\n"); fatal("Internal error!\n");
case SEXP_ADVANCED: case SEXP_ADVANCED:
/* Special case of canonical, so we'll fall through for now. */ case SEXP_INTERNATIONAL:
use_space = 1;
/* Fall through */
case SEXP_CANONICAL: case SEXP_CANONICAL:
return ssh_format("%ls %ls", return ssh_format(use_space ? " %ls%ls" : "%ls%ls",
sexp_format(c->car, style), sexp_format(c->car, style),
do_format_sexp_tail(c->cdr, style)); do_format_sexp_tail(c->cdr, style));
default: default:
...@@ -112,7 +230,7 @@ static struct lsh_string *do_format_sexp_cons(struct sexp *s, int style) ...@@ -112,7 +230,7 @@ static struct lsh_string *do_format_sexp_cons(struct sexp *s, int style)
case SEXP_TRANSPORT: case SEXP_TRANSPORT:
fatal("Internal error!\n"); fatal("Internal error!\n");
case SEXP_ADVANCED: case SEXP_ADVANCED:
/* Special case of canonical, so we'll fal through for now. */ case SEXP_INTERNATIONAL:
case SEXP_CANONICAL: case SEXP_CANONICAL:
return ssh_format("(%ls", do_format_sexp_tail(self, style)); return ssh_format("(%ls", do_format_sexp_tail(self, style));
default: default:
...@@ -148,6 +266,7 @@ static struct lsh_string *do_format_sexp_vector(struct sexp *e, int style) ...@@ -148,6 +266,7 @@ static struct lsh_string *do_format_sexp_vector(struct sexp *e, int style)
unsigned i; unsigned i;
UINT32 size; UINT32 size;
int use_space = 0;
struct lsh_string **elements = alloca(LIST_LENGTH(v->elements) struct lsh_string **elements = alloca(LIST_LENGTH(v->elements)
* sizeof(struct lsh_string *) ); * sizeof(struct lsh_string *) );
...@@ -157,14 +276,16 @@ static struct lsh_string *do_format_sexp_vector(struct sexp *e, int style) ...@@ -157,14 +276,16 @@ static struct lsh_string *do_format_sexp_vector(struct sexp *e, int style)
case SEXP_TRANSPORT: case SEXP_TRANSPORT:
fatal("Internal error!\n"); fatal("Internal error!\n");
case SEXP_ADVANCED: case SEXP_ADVANCED:
/* Special case of canonical, so we'll fal through for now. */ case SEXP_INTERNATIONAL:
use_space = 1;
/* Fall through */
case SEXP_CANONICAL: case SEXP_CANONICAL:
{ {
struct lsh_string *res; struct lsh_string *res;
UINT8 *dst; UINT8 *dst;
assert(LIST_LENGTH(v->elements)); assert(LIST_LENGTH(v->elements));
for (i = 0, size = 0; i<LIST_LENGTH(v->elements); i++) for (i = 0, size = 2; i<LIST_LENGTH(v->elements); i++)
{ {
CAST_SUBTYPE(sexp, o, LIST(v->elements)[i]); CAST_SUBTYPE(sexp, o, LIST(v->elements)[i]);
...@@ -172,12 +293,18 @@ static struct lsh_string *do_format_sexp_vector(struct sexp *e, int style) ...@@ -172,12 +293,18 @@ static struct lsh_string *do_format_sexp_vector(struct sexp *e, int style)
size += elements[i]->length; size += elements[i]->length;
} }
res = lsh_string_alloc(size + 2); if (use_space)
size += LIST_LENGTH(v->elements) - 1;
res = lsh_string_alloc(size);
dst = res->data; dst = res->data;
*dst++ = '('; *dst++ = '(';
for (i = 0; i<LIST_LENGTH(v->elements); i++) for (i = 0; i<LIST_LENGTH(v->elements); i++)
{ {
if (i && use_space)
*dst++ = ' ';
memcpy(dst, elements[i]->data, elements[i]->length); memcpy(dst, elements[i]->data, elements[i]->length);
dst += elements[i]->length; dst += elements[i]->length;
...@@ -204,7 +331,7 @@ struct sexp *sexp_l(unsigned n, ...) ...@@ -204,7 +331,7 @@ struct sexp *sexp_l(unsigned n, ...)
{ {
assert(va_arg(args, int) == -1); assert(va_arg(args, int) == -1);
va_end(args); va_end(args);
return NULL; return SEXP_NIL;
} }
else else
{ {
...@@ -245,13 +372,12 @@ struct lsh_string *sexp_format(struct sexp *e, int style) ...@@ -245,13 +372,12 @@ struct lsh_string *sexp_format(struct sexp *e, int style)
switch(style) switch(style)
{ {
case SEXP_TRANSPORT: case SEXP_TRANSPORT:
return ssh_format("{%lfs}", return encode_base64(sexp_format(e, SEXP_CANONICAL), "{}", 1);
encode_base64(sexp_format(e, SEXP_CANONICAL), 1));
case SEXP_ADVANCED:
case SEXP_CANONICAL: case SEXP_CANONICAL:
return e case SEXP_ADVANCED:
? SEXP_FORMAT(e, style) case SEXP_INTERNATIONAL:
: ssh_format("()"); /* NOTE: Check for NULL here? I don't think so. */
return SEXP_FORMAT(e, style);
default: default:
fatal("sexp_format: Unknown output style.\n"); fatal("sexp_format: Unknown output style.\n");
} }
...@@ -271,22 +397,27 @@ static void encode_base64_group(UINT32 n, UINT8 *dest) ...@@ -271,22 +397,27 @@ static void encode_base64_group(UINT32 n, UINT8 *dest)
} }
} }
struct lsh_string *encode_base64(struct lsh_string *s, int free) struct lsh_string *encode_base64(struct lsh_string *s,
char *delimiters,
int free)
{ {
UINT32 full_groups = (s->length) / 3; UINT32 full_groups = (s->length) / 3;
unsigned last = (s->length) % 3; unsigned last = (s->length) % 3;
unsigned length = (full_groups + !!last) * 4;
struct lsh_string *res = lsh_string_alloc( (full_groups + !!last) * 4);
UINT8 *src = s->data; UINT8 *src = s->data;
UINT8 *dst = res->data; UINT8 *dst;
struct lsh_string *res
= (delimiters
? ssh_format("%c%lr%c", delimiters[0], length, &dst, delimiters[1])
: ssh_format("%lr", length, &dst));
if (full_groups) if (full_groups)
{ {
unsigned i; unsigned i;
/* Loop over all but the last group. */ /* Loop over all but the last group. */
for (i=0; i+1<full_groups; dst += 4, i++) for (i=0; i<full_groups; dst += 4, i++)
{ {
encode_base64_group( ( (*src++) << 16) encode_base64_group( ( (*src++) << 16)
| ( (*src++) << 8) | ( (*src++) << 8)
...@@ -314,7 +445,7 @@ struct lsh_string *encode_base64(struct lsh_string *s, int free) ...@@ -314,7 +445,7 @@ struct lsh_string *encode_base64(struct lsh_string *s, int free)
fatal("encode_base64: Internal error!\n"); fatal("encode_base64: Internal error!\n");
} }
assert(dst == (res->data + res->length)); assert( (dst + !!delimiters) == (res->data + res->length));
if (free) if (free)
lsh_string_free(s); lsh_string_free(s);
......
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