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

* examples/sexp-conv.c (sexp_convert_list): New function.

(sexp_convert_item): New function.
(main): New function. Compiles and runs now, but doesn't work.

* examples/sexp-conv.c: Added output functions.

Rev: src/nettle/examples/sexp-conv.c:1.2
parent 70dfb647
......@@ -4,19 +4,24 @@
* syntax. */
#include "base64.h"
#include "buffer.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
enum sexp_mode
{
SEXP_CANONICAL = 0,
SEXP_ADVANCED = 1,
/* OR:ed with SEXP_CANONICAL or SEXP_ADVANCED when reading
* transport data. */
* transport data */
SEXP_TRANSPORT = 2,
};
enum sexp_token
{
SEXP_LIST,
SEXP_STRING,
SEXP_DISPLAY_START,
SEXP_DISPLAY_END,
......@@ -45,17 +50,38 @@ struct sexp_input
unsigned level;
};
static void
sexp_input_init(struct sexp_input *input, FILE *f, enum sexp_mode mode)
{
input->f = f;
input->mode = mode;
input->level = 0;
}
struct sexp_output
{
FILE *f;
enum sexp_mode mode;
struct base64_encode_ctx base64;
unsigned indent;
/* Items at the head of the list */
unsigned items;
unsigned pos;
};
static void
sexp_output_init(struct sexp_output *output, FILE *f, enum sexp_mode mode)
{
output->f = f;
output->mode = mode;
output->pos = 0;
}
/* Input */
/* Returns 1 on success. On failure, return -1. For special tokens,
* return 0 and set input->token accordingly. */
static int
......@@ -73,7 +99,7 @@ sexp_get_char(struct sexp_input *input, uint8_t *out)
if (c == '}')
{
if (base64_decode_status(&input->ctx))
if (base64_decode_status(&input->base64))
{
input->token = SEXP_TRANSPORT_END;
return 0;
......@@ -82,7 +108,7 @@ sexp_get_char(struct sexp_input *input, uint8_t *out)
return -1;
}
done = base64_decode_single(&input->ctx, out, c);
done = base64_decode_single(&input->base64, out, c);
if (done)
return 1;
}
......@@ -133,7 +159,7 @@ sexp_get_token_char(struct sexp_input *input)
if (c >= 0 && TOKEN_CHAR(c))
return c;
ungetc(input->f, c);
ungetc(c, input->f);
return 0;
}
......@@ -145,14 +171,13 @@ sexp_unget_char(struct sexp_input *input, uint8_t c)
assert(input->mode == SEXP_ADVANCED);
ungetc(c, input->f);
}
#endif
static int
sexp_get_string_char(struct sexp_input *input)
{
assert(input->mode == SEXP_ADVANCED);
}
#endif
static int
sexp_get_quoted_char(struct sexp_input *input, uint8_t *c)
......@@ -252,7 +277,7 @@ sexp_get_base64_string(struct sexp_input *input)
}
static int
sexp_get_atom_string(struct sexp_input *input, uint8_t c)
sexp_get_token_string(struct sexp_input *input, uint8_t c)
{
assert(input->mode == SEXP_ADVANCED);
......@@ -313,7 +338,7 @@ sexp_get_string_length(struct sexp_input *input, unsigned length)
if (sexp_get_char(input, &c) <= 0)
return 0;
if (c < 0 || < > 9)
if (c < '0' || c > '9')
break;
/* FIXME: Check for overflow? */
......@@ -371,10 +396,15 @@ sexp_get_token(struct sexp_input *input)
return sexp_get_string_length(input, c - '0');
case '(':
input->token = SEXP_START_LIST;
input->token = SEXP_LIST_START;
return 1;
case ')':
input->token = SEXP_END_LIST;
input->token = SEXP_LIST_END;
if (!input->level)
return 0;
input->level--;
return 1;
case '[':
......@@ -420,69 +450,158 @@ sexp_get_token(struct sexp_input *input)
return (input->mode == SEXP_ADVANCED)
&& sexp_get_string(input, c);
}
}
}
abort();
}
/* Output routines */
#define LINE_WIDTH 60
static int
sexp_put_newline(struct sexp_output *output)
sexp_put_newline(struct sexp_output *output,
unsigned indent)
{
unsigned i;
if (putc('\n', output->f) < 0)
return 0;
for(i = 0; i<output->indent)
for(i = 0; i < indent; i++)
if (putc(' ', output->f) < 0)
return 0;
output->pos = output->indent;
output->pos = indent;
return 1;
}
static int
sexp_put_char(struct sexp_output *output,
sexp_put_char(struct sexp_output *output, unsigned indent,
uint8_t c)
{
output->pos++;
return fputc(c, output->file) >= 0;
}
static int
sexp_put_data(struct sexp_output *output,
unsigned length, uint8_t data)
{
if (fwrite(data, 1, length, output->f)
== length)
if (output->mode & SEXP_TRANSPORT)
{
output->pos += length;
uint8_t encoded[2];
unsigned done;
unsigned i;
done = base64_encode_single(&output->base64, encoded, c);
assert(done <= sizeof(encoded));
for (i = 0; i<done; i++)
{
if (indent &&
output->pos > LINE_WIDTH
&& output->pos > (indent + 10))
if (!sexp_put_newline(output, indent))
return 0;
if (putc(encoded[i], output->f) < 0)
return 0;
output->pos++;
}
return 1;
}
else
{
output->pos++;
return putc(c, output->f) >= 0;
}
}
static int
sexp_put_data(struct sexp_output *output, unsigned indent,
unsigned length, const uint8_t *data)
{
unsigned i;
for (i = 0; i<length; i++)
if (!sexp_put_char(output, indent, data[i]))
return 0;
return 1;
}
static int
sexp_puts(struct sexp_output *output, unsigned indent,
const uint8_t *s)
{
while (*s)
if (!sexp_put_char(output, indent, *s++))
return 0;
return 1;
}
static int
sexp_put_length(struct sexp_output *output, unsigned indent,
unsigned length)
{
unsigned digit = 1;
while (digit < length)
digit *= 10;
for (; digit; length %= digit, digit /= 10)
if (!sexp_put_char(output, indent, '0' + length / digit))
return 0;
return 1;
}
static int
sexp_put_base64_start(struct sexp_output *output, uint8_t c)
{
assert(! (output->mode & SEXP_TRANSPORT));
if (!sexp_put_char(output, 0, c))
return 0;
base64_encode_init(&output->base64);
output->mode |= SEXP_TRANSPORT;
return 1;
}
static int
sexp_put_base64_end(struct sexp_output *output, uint8_t c)
{
uint8_t encoded[BASE64_ENCODE_FINAL_LENGTH];
unsigned done;
assert(output->mode & SEXP_TRANSPORT);
done = base64_encode_final(&output->base64, encoded);
assert(done < sizeof(encoded));
output->mode &= ~ SEXP_TRANSPORT;
return sexp_put_data(output, 0, done, encoded)
&& sexp_put_char(output, 0, c);
}
static int
sexp_put_string(struct sexp_output *output,
sexp_put_string(struct sexp_output *output, unsigned indent,
struct nettle_buffer *string)
{
if (!string->size)
{
const char *s = (output->mode == SEXP_ADVANCED) ? "\"\"": "0:";
output->pos += 2;
return 2 == fputs(s , output->f);
}
return sexp_puts(output, indent,
(output->mode == SEXP_ADVANCED) ? "\"\"": "0:");
if (output->mode == SEXP_ADVANCED)
{
unsigned i;
int token = (string.buffer[0] < '0' || string.buffer[0] > '9');
int token = (string->contents[0] < '0' || string->contents[0] > '9');
int quote_friendly = 1;
for (i = 0; i<string.size; i++)
for (i = 0; i<string->size; i++)
{
uint8_t c = string.buffer[i];
uint8_t c = string->contents[i];
if (token & !TOKEN_CHAR(c))
token = 0;
......@@ -492,64 +611,186 @@ sexp_put_string(struct sexp_output *output,
}
if (token)
return sexp_put_buffer(output, string.size, string.buffer);
return sexp_put_data(output, indent, string->size, string->contents);
else if (quote_friendly)
{
output->pos += 2;
return sexp_put_char(output, '"')
&& sexp_put_buffer(output, string.size, string.buffer)
&& sexp_put_char(output, '"');
return sexp_put_char(output, indent, '"')
&& sexp_put_data(output, indent, string->size, string->contents)
&& sexp_put_char(output, indent, '"');
}
else
{
#define DATA_PER_LINE 40
uint8_t line[BASE64_ENCODE_LENGTH(DATA_PER_LINE)
+ BASE64_ENCODE_FINAL_LENGTH];
struct base64_encode_ctx ctx;
return (sexp_put_base64_start(output, '|')
&& sexp_put_data(output, output->pos,
string->size, string->contents)
&& sexp_put_base64_end(output, '|'));
}
else
return sexp_put_length(output, indent, string->size)
&& sexp_put_char(output, indent, ':')
&& sexp_put_data(output, indent, string->size, string->contents);
}
unsigned old_indent = output->indent;
unsigned i;
output->indent = output->pos + 1;
if (!sexp_put_char(output, '|'))
return 0;
base64_encode_init(&ctx);
for (i = 0; i + DATA_PER_LINE < string.size)
static int
sexp_put_list_start(struct sexp_output *output, unsigned indent)
{
if (!sexp_put_char(output, indent, '('))
return 0;
output->items = 0;
return 1;
}
static int
sexp_put_list_end(struct sexp_output *output, unsigned indent)
{
return sexp_put_char(output, indent, ')') ;
}
static int
sexp_put_display_start(struct sexp_output *output, unsigned indent)
{
return sexp_put_char(output, indent, '[');
}
static int
sexp_put_display_end(struct sexp_output *output, unsigned indent)
{
return sexp_put_char(output, indent, ']') ;
}
static int
sexp_convert_string(struct sexp_input *input, struct sexp_output *output,
unsigned indent)
{
return (sexp_get_token(input)
&& input->token == SEXP_STRING
&& sexp_put_string(output, indent, &input->string));
}
static int
sexp_convert_item(struct sexp_input *input, struct sexp_output *output,
unsigned indent);
static int
sexp_convert_list(struct sexp_input *input, struct sexp_output *output,
unsigned indent)
{
if (!sexp_get_token(input))
return 0;
switch (sexp_convert_item(input, output, indent))
{
case 0:
return 1;
case -1:
return 0;
case 1:
break;
}
indent = output->pos;
for (;;)
{
if (!sexp_get_token(input))
return 0;
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);
}
}
/* Returns 1 on success, -1 on error, and 0 at end of list/file.
*
* Should be called after getting the first token. */
static int
sexp_convert_item(struct sexp_input *input, struct sexp_output *output,
unsigned indent)
{
switch(input->token)
{
case SEXP_LIST_START:
input->level++;
if (sexp_put_list_start(output, indent)
&& sexp_convert_list(input, output, indent)
&& sexp_put_list_end(output, indent))
{
if (input->level)
{
unsigned done = base64_encode_update(&ctx,
line,
DATA_PER_LINE,
string->buffer + i);
assert(done <= BASE64_ENCODE_LENGTH(DATA_PER_LINE));
sexp_put_data(output, done, line);
sexp_put_newline(output);
input->level--;
if (input->token == SEXP_LIST_END)
return 1;
}
else if (input->token == SEXP_EOF)
return 1;
}
return -1;
case SEXP_LIST_END:
if (!input->level)
return -1;
input->level--;
return 1;
output->indent = old_indent;
done = base64_encode_update(&ctx, line,
string.size - i, string->buffer + i);
done += base64_encode_final(&ctx, line + done);
assert(done <= sizeof(line));
case SEXP_EOF:
return input->level ? -1 : 1;
case SEXP_STRING:
return sexp_put_string(output, indent, &input->string) ? 1 : -1;
case SEXP_DISPLAY_START:
return (sexp_put_display_start(output, indent)
&& sexp_convert_string(input, output, indent)
&& sexp_put_display_end(output, indent)
&& sexp_convert_string(input, output, indent)) ? 1 : -1;
return sexp_put_data(output, done, line)
&& sexp_put_char(output, '}');
case SEXP_TRANSPORT_START:
if (input->mode != SEXP_ADVANCED)
return -1;
else
{
unsigned old_level = input->level;
input->mode = SEXP_TRANSPORT;
input->level = 0;
base64_decode_init(&input->base64);
if (!sexp_convert_list(input, output, indent))
return -1;
input->mode = SEXP_ADVANCED;
input->level = old_level;
return 1;
}
case SEXP_TRANSPORT_END:
if (input->mode != SEXP_TRANSPORT
|| input->level || !base64_decode_status(&input->base64))
return -1;
return 0;
default:
return -1;
}
else
/* FIXME: Support transport mode */
return fprintf(output->f, "%d:", string.length) > 0
&& sexp_put_string(output, string.size, string.buffer);
abort();
}
static void
sexp_put_start_list(struct sexp_output *output)
int
main(int argc, char **argv)
{
}
struct sexp_input input;
struct sexp_output output;
sexp_input_init(&input, stdin, SEXP_ADVANCED);
sexp_output_init(&output, stdout, SEXP_ADVANCED);
return sexp_convert_list(&input, &output, 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
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