input->f = f;
input->mode = mode;
input->level = 0;
+
+ nettle_buffer_init(&input->string);
}
struct sexp_output
}
}
else
- for (;;)
- {
- int c = getc(input->f);
+ {
+ int c = getc(input->f);
- if (c < 0)
- {
- if (ferror(input->f))
- return -1;
-
- input->token = SEXP_EOF;
- return 0;
- }
- }
+ if (c < 0)
+ {
+ if (ferror(input->f))
+ return -1;
+
+ input->token = SEXP_EOF;
+ return 0;
+ }
+
+ *out = c;
+ return 1;
+ }
}
static const char
for (;;)
switch (*c)
{
+ default:
+ return 1;
case '\"':
return 0;
case '\\':
sexp_get_token(struct sexp_input *input)
{
uint8_t c;
- switch (sexp_get_char(input, &c))
- {
- case -1:
- return 0;
- case 0:
- return 1;
- case 1:
- switch(c)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return sexp_get_string_length(input, c - '0');
-
- case '(':
- input->token = SEXP_LIST_START;
- return 1;
- case ')':
- input->token = SEXP_LIST_END;
- if (!input->level)
- return 0;
+ for(;;)
+ switch (sexp_get_char(input, &c))
+ {
+ case -1:
+ return 0;
+ case 0:
+ return 1;
+ case 1:
+ switch(c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return sexp_get_string_length(input, c - '0');
+
+ case '(':
+ input->token = SEXP_LIST_START;
+ return 1;
+ case ')':
+ input->token = SEXP_LIST_END;
- input->level--;
- return 1;
+ return 1;
- case '[':
- input->token = SEXP_DISPLAY_START;
- return 1;
+ case '[':
+ input->token = SEXP_DISPLAY_START;
+ return 1;
- case ']':
- input->token = SEXP_DISPLAY_END;
- return 1;
+ case ']':
+ input->token = SEXP_DISPLAY_END;
+ return 1;
- case ' ': /* SPC, TAB, LF, CR */
- case '\t':
- case '\n':
- case '\r':
- if (input->mode != SEXP_ADVANCED)
- return 0;
- break;
+ case ' ': /* SPC, TAB, LF, CR */
+ case '\t':
+ case '\n':
+ case '\r':
+ if (input->mode != SEXP_ADVANCED)
+ return 0;
+ break;
- case ';': /* Comments */
- if (input->mode != SEXP_ADVANCED)
- return 0;
+ case ';': /* Comments */
+ if (input->mode != SEXP_ADVANCED)
+ return 0;
- for (;;)
- {
- int c = getc(input->f);
- if (c < 0)
- {
- if (ferror(input->f))
- return 0;
- else
- {
- input->token = SEXP_EOF;
- return 1;
- }
- }
- if (c != '\n')
- break;
- }
- break;
+ for (;;)
+ {
+ int c = getc(input->f);
+ if (c < 0)
+ {
+ if (ferror(input->f))
+ return 0;
+ else
+ {
+ input->token = SEXP_EOF;
+ return 1;
+ }
+ }
+ if (c == '\n')
+ break;
+ }
+ break;
- default:
- /* Ought to be a string */
- return (input->mode == SEXP_ADVANCED)
- && sexp_get_string(input, c);
- }
- }
- abort();
+ default:
+ /* Ought to be a string */
+ return (input->mode == SEXP_ADVANCED)
+ && sexp_get_string(input, c);
+ }
+ }
}
done = base64_encode_final(&output->base64, encoded);
- assert(done < sizeof(encoded));
+ assert(done <= sizeof(encoded));
output->mode &= ~ SEXP_TRANSPORT;
unsigned i;
int token = (string->contents[0] < '0' || string->contents[0] > '9');
int quote_friendly = 1;
-
+ static const char escape_names[0x10] =
+ { 0,0,0,0,0,0,0,0, 'b','t','n',0,'f','r',0,0 };
+
for (i = 0; i<string->size; i++)
{
uint8_t c = string->contents[i];
if (token & !TOKEN_CHAR(c))
token = 0;
- if (quote_friendly && (c < 0x20 || c >= 0x7f))
- quote_friendly = 0;
+ if (quote_friendly)
+ {
+ if (c >= 0x7f)
+ quote_friendly = 0;
+ else if (c < 0x20 && !escape_names[c])
+ quote_friendly = 0;
+ }
}
if (token)
else if (quote_friendly)
{
- return sexp_put_char(output, indent, '"')
- && sexp_put_data(output, indent, string->size, string->contents)
- && sexp_put_char(output, indent, '"');
+ if (!sexp_put_char(output, indent, '"'))
+ return 0;
+ for (i = 0; i<string->size; i++)
+ {
+ int escape = 0;
+ uint8_t c = string->contents[i];
+
+ assert(c < 0x7f);
+
+ if (c == '\\' || c == '"')
+ escape = 1;
+ else if (c < 0x20)
+ {
+ escape = 1;
+ c = escape_names[c];
+ assert(c);
+ }
+ if (escape && !sexp_put_char(output, indent, '\\'))
+ return 0;
+
+ if (!sexp_put_char(output, indent, c))
+ return 0;
+ }
+
+ return sexp_put_char(output, indent, '"');
}
else
return (sexp_put_base64_start(output, '|')
sexp_convert_list(struct sexp_input *input, struct sexp_output *output,
unsigned indent)
{
- if (!sexp_get_token(input))
- return 0;
+ unsigned item;
- switch (sexp_convert_item(input, output, indent))
- {
- case 0:
- return 1;
- case -1:
- return 0;
- case 1:
- break;
- }
-
- indent = output->pos;
-
- for (;;)
+ for (item = 0;; item++)
{
if (!sexp_get_token(input))
return 0;
-
+
+ /* Check for end of list */
if (input->token == SEXP_LIST_END
|| input->token == SEXP_EOF
|| input->token == SEXP_TRANSPORT_END)
return 1;
- sexp_put_newline(output, indent);
- sexp_convert_item(input, output, indent);
+ if (output->mode == SEXP_ADVANCED)
+ {
+ /* FIXME: Adapt pretty printing to handle a big first
+ * element. */
+ if (item == 1)
+ {
+ if (!sexp_put_char(output, indent, ' '))
+ return 0;
+ indent = output->pos;
+ }
+ else if (item > 1 && !sexp_put_newline(output, indent))
+ return 0;
+ }
+
+ switch (sexp_convert_item(input, output, indent))
+ {
+ case 0:
+ /* Should be detected above */
+ abort();
+ case -1:
+ return 0;
+ case 1:
+ break;
+ }
}
}
+static int
+sexp_skip_token(struct sexp_input *input, enum sexp_token token)
+{
+ return sexp_get_token(input) && input->token == token;
+}
+
/* Returns 1 on success, -1 on error, and 0 at end of list/file.
*
* Should be called after getting the first token. */
case SEXP_DISPLAY_START:
return (sexp_put_display_start(output, indent)
&& sexp_convert_string(input, output, indent)
+ && sexp_skip_token(input, SEXP_DISPLAY_END)
&& sexp_put_display_end(output, indent)
&& sexp_convert_string(input, output, indent)) ? 1 : -1;