diff --git a/examples/sexp-conv-test b/examples/sexp-conv-test deleted file mode 100755 index a0f58812a82c70c8f0c05524e9201d54de83bc3f..0000000000000000000000000000000000000000 --- a/examples/sexp-conv-test +++ /dev/null @@ -1,95 +0,0 @@ -#! /bin/sh - -if [ -z "$srcdir" ] ; then - srcdir=`pwd` -fi - -# echo -n is not portable - -if [ "`echo -n ''`" = "" ]; then - n='-n'; c='' -elif [ "`echo '\c'`" = "" ]; then - n=''; c='\c' -else - echo >&2 'Neither echo -n nor echo \c seems to work.' - exit 1 -fi - -test_advanced () { - echo "$1" > test.in - if ./sexp-conv -s advanced <test.in >test1.out ; then - true - else - exit 1 - fi - echo "$2" > test2.out - - if cmp test1.out test2.out ; then - true - else - exit 1; - fi -} - -test_transport () { - echo "$1" > test.in - if ./sexp-conv -s transport <test.in >test1.out ; then - true - else - exit 1 - fi - echo "$2" > test2.out - - if cmp test1.out test2.out ; then - true - else - exit 1; - fi -} - -test_canonical () { - echo "$1" > test.in - if ./sexp-conv -s canonical <test.in >test1.out ; then - true - else - exit 1 - fi - echo $n "$2$c" > test2.out - - if cmp test1.out test2.out ; then - true - else - exit 1; - fi -} - -test_advanced '0:' '""' -test_advanced '3:foo' 'foo' -test_advanced '12:fooooooooooo' 'fooooooooooo' -test_advanced '10:fooooooooo' 'fooooooooo' -test_advanced '4:3des' '"3des"' -test_advanced '"foo"' 'foo' -test_advanced '4:foo -' '"foo\n"' -test_advanced '2:"\' '"\"\\"' -test_advanced '()' '()' -test_advanced '(foo bar baz)' '(foo bar - baz)' -test_advanced '; comment -()' '()' - -test_advanced '(foo[bar]foo)' '(foo [bar]foo)' - -test_transport '0:' '{MDo=}' -test_transport '()' '{KCk=}' -test_transport 'foo' '{Mzpmb28=}' -test_transport '(foo bar baz)' '{KDM6Zm9vMzpiYXIzOmJheik=}' - -test_canonical '""' '0:' -test_canonical 'foo' '3:foo' -test_canonical 'fooooooooooo' '12:fooooooooooo' -test_canonical 'fooooooooo' '10:fooooooooo' -test_canonical '(foo bar baz)' '(3:foo3:bar3:baz)' -test_canonical '{KDM6Zm9vMzpiYXIzOmJheik=}' '(3:foo3:bar3:baz)' - -exit 0 diff --git a/examples/sexp-conv.c b/examples/sexp-conv.c deleted file mode 100644 index a3484ee56a211f3549378244110d78ae3ef379cb..0000000000000000000000000000000000000000 --- a/examples/sexp-conv.c +++ /dev/null @@ -1,927 +0,0 @@ -/* sexp-conv.c - * - * Conversion tool for handling the different flavours of sexp - * syntax. */ - -#include "base16.h" -#include "base64.h" -#include "buffer.h" -#include "nettle-meta.h" - -#include <assert.h> -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -/* For getopt */ -#include <unistd.h> - -void -die(const char *format, ...) -#if __GNUC___ - __attribute__((__format__ (__printf__,1, 2))) - __attribute__((__noreturn__)) -#endif - ; - -void -die(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - - exit(EXIT_FAILURE); -} - -enum sexp_mode - { - SEXP_CANONICAL = 0, - SEXP_ADVANCED = 1, - SEXP_TRANSPORT = 2, - }; - -/* Special marks in the input stream */ -enum sexp_char_type - { - SEXP_NORMAL_CHAR = 0, - SEXP_EOF_CHAR, SEXP_END_CHAR, - }; - -enum sexp_token - { - SEXP_STRING, - SEXP_DISPLAY_START, - SEXP_DISPLAY_END, - SEXP_LIST_START, - SEXP_LIST_END, - SEXP_TRANSPORT_START, - SEXP_CODING_END, - SEXP_EOF, - }; - - -/* Input */ - -struct sexp_input -{ - FILE *f; - - /* Character stream, consisting of ordinary characters, - * SEXP_EOF_CHAR, and SEXP_END_CHAR. */ - enum sexp_char_type ctype; - uint8_t c; - - const struct nettle_armor *coding; - - union { - struct base64_decode_ctx base64; - struct base16_decode_ctx hex; - } state; - - /* Terminator for current coding */ - uint8_t terminator; - - /* Type of current token */ - enum sexp_token token; - - /* Current token */ - struct nettle_buffer string; -}; - -static void -sexp_input_init(struct sexp_input *input, FILE *f) -{ - input->f = f; - input->coding = NULL; - - nettle_buffer_init(&input->string); -} - - -static void -sexp_get_raw_char(struct sexp_input *input) -{ - int c = getc(input->f); - - if (c < 0) - { - if (ferror(input->f)) - die("Read error: %s\n", strerror(errno)); - - input->ctype = SEXP_EOF_CHAR; - } - else - { - input->ctype = SEXP_NORMAL_CHAR; - input->c = c; - } -} - -static void -sexp_get_char(struct sexp_input *input) -{ - if (input->coding) - for (;;) - { - int done; - - sexp_get_raw_char(input); - if (input->ctype == SEXP_EOF_CHAR) - die("Unexpected end of file in coded data.\n"); - - if (input->c == input->terminator) - { - input->ctype = SEXP_END_CHAR; - return; - } - - done = 1; - - /* Decodes in place. Should always work, when we decode one - * character at a time. */ - if (!input->coding->decode_update(&input->state, - &done, &input->c, - 1, &input->c)) - die("Invalid coded data.\n"); - - if (done) - return; - } - else - sexp_get_raw_char(input); -} - -static uint8_t -sexp_next_char(struct sexp_input *input) -{ - sexp_get_char(input); - if (input->ctype != SEXP_NORMAL_CHAR) - die("Unexpected end of file.\n"); - - return input->c; -} - -static void -sexp_push_char(struct sexp_input *input) -{ - assert(input->ctype == SEXP_NORMAL_CHAR); - - if (!NETTLE_BUFFER_PUTC(&input->string, input->c)) - die("Virtual memory exhasuted.\n"); -} - -static void -sexp_input_start_coding(struct sexp_input *input, - const struct nettle_armor *coding, - uint8_t terminator) -{ - assert(!input->coding); - - input->coding = coding; - input->coding->decode_init(&input->state); - input->terminator = terminator; -} - -static void -sexp_input_end_coding(struct sexp_input *input) -{ - assert(input->coding); - - if (!input->coding->decode_final(&input->state)) - die("Invalid coded data.\n"); - - input->coding = NULL; -} - - -/* Return 0 at end-of-string */ -static int -sexp_get_quoted_char(struct sexp_input *input) -{ - sexp_next_char(input); - - for (;;) - switch (input->c) - { - default: - return 1; - case '\"': - return 0; - case '\\': - sexp_next_char(input); - - switch (input->c) - { - case 'b': input->c = '\b'; return 1; - case 't': input->c = '\t'; return 1; - case 'n': input->c = '\n'; return 1; - case 'f': input->c = '\f'; return 1; - case 'r': input->c = '\r'; return 1; - case '\\': input->c = '\\'; return 1; - case 'o': - case 'x': - /* FIXME: Not implemnted */ - abort(); - case '\n': - if (sexp_next_char(input) == '\r') - sexp_next_char(input); - - break; - case '\r': - if (sexp_next_char(input) == '\n') - sexp_next_char(input); - - break; - } - return 1; - } -} - - -static const char -token_chars[0x80] = - { - /* 0, ... 0x1f */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, -/* SPC ! " # $ % & ' ( ) * + , - . / */ - 0,0,0,0,0,0,0,0, 0,0,1,1,0,1,1,1, - /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ - 1,1,1,1,1,1,1,1, 1,1,1,0,0,1,0,0, - /* @ A ... O */ - 0,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, - /* P ... Z [ \ ] ^ _ */ - 1,1,1,1,1,1,1,1, 1,1,1,0,0,0,0,1, - /* ` a, ... o */ - 0,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, - /* p ... z { | } ~ DEL */ - 1,1,1,1,1,1,1,1, 1,1,1,0,0,0,0,0, - }; - -#define TOKEN_CHAR(c) ((c) < 0x80 && token_chars[(c)]) - -static void -sexp_get_token_string(struct sexp_input *input) -{ - assert(!input->coding); - assert(input->ctype == SEXP_NORMAL_CHAR); - - if (!TOKEN_CHAR(input->c)) - die("Invalid token.\n"); - - do - { - sexp_push_char(input); - sexp_get_char(input); - } - while (TOKEN_CHAR(input->c)); - - assert (input->string.size); -} - -static void -sexp_get_string(struct sexp_input *input) -{ - input->string.size = 0; - input->token = SEXP_STRING; - - switch (input->c) - { - case '\"': - while (sexp_get_quoted_char(input)) - sexp_push_char(input); - - sexp_get_char(input); - break; - - case '#': - sexp_input_start_coding(input, &nettle_base16, '#'); - goto decode; - - case '|': - sexp_input_start_coding(input, &nettle_base64, '|'); - - decode: - for (;;) - { - sexp_get_char(input); - switch (input->ctype) - { - case SEXP_NORMAL_CHAR: - sexp_push_char(input); - break; - case SEXP_EOF_CHAR: - die("Unexpected end of file in coded string.\n"); - case SEXP_END_CHAR: - sexp_input_end_coding(input); - sexp_get_char(input); - return; - } - } - - break; - - default: - sexp_get_token_string(input); - break; - } -} - -static void -sexp_get_string_length(struct sexp_input *input, enum sexp_mode mode) -{ - unsigned length; - - input->string.size = 0; - input->token = SEXP_STRING; - - length = input->c - '0'; - - if (!length) - /* There must be no more digits */ - sexp_next_char(input); - - else - { - assert(length < 10); - /* Get rest of digits */ - for (;;) - { - sexp_next_char(input); - - if (input->c < '0' || input->c > '9') - break; - - /* FIXME: Check for overflow? */ - length = length * 10 + input->c - '0'; - } - } - - switch(input->c) - { - case ':': - /* Verbatim */ - for (; length; length--) - { - sexp_next_char(input); - sexp_push_char(input); - } - - break; - - case '"': - if (mode != SEXP_ADVANCED) - die("Encountered quoted string in canonical mode.\n"); - - for (; length; length--) - if (sexp_get_quoted_char(input)) - sexp_push_char(input); - else - die("Unexpected end of string.\n"); - - if (sexp_get_quoted_char(input)) - die("Quoted string longer than expected.\n"); - - break; - - case '#': - sexp_input_start_coding(input, &nettle_base16, '#'); - goto decode; - - case '|': - sexp_input_start_coding(input, &nettle_base64, '|'); - - decode: - for (; length; length--) - { - sexp_next_char(input); - sexp_push_char(input); - } - sexp_get_char(input); - if (input->ctype != SEXP_END_CHAR) - die("Coded string too long.\n"); - - sexp_input_end_coding(input); - - break; - - default: - die("Invalid string.\n"); - } - - /* Skip the ending character. */ - sexp_get_char(input); -} - -/* When called, input->c should be the first character of the current - * token. - * - * When returning, input->c should be the first character of the next - * token. */ -static void -sexp_get_token(struct sexp_input *input, enum sexp_mode mode) -{ - for(;;) - switch(input->ctype) - { - case SEXP_EOF_CHAR: - input->token = SEXP_EOF; - return; - - case SEXP_END_CHAR: - input->token = SEXP_CODING_END; - sexp_input_end_coding(input); - sexp_next_char(input); - return; - - case SEXP_NORMAL_CHAR: - switch(input->c) - { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - sexp_get_string_length(input, mode); - return; - - case '(': - input->token = SEXP_LIST_START; - sexp_get_char(input); - return; - - case ')': - input->token = SEXP_LIST_END; - sexp_get_char(input); - return; - - case '[': - input->token = SEXP_DISPLAY_START; - sexp_get_char(input); - return; - - case ']': - input->token = SEXP_DISPLAY_END; - sexp_get_char(input); - return; - - case '{': - if (mode == SEXP_CANONICAL) - die("Unexpected transport data in canonical mode.\n"); - - sexp_input_start_coding(input, &nettle_base64, '}'); - sexp_get_char(input); - - input->token = SEXP_TRANSPORT_START; - - return; - - case ' ': /* SPC, TAB, LF, CR */ - case '\t': - case '\n': - case '\r': - if (mode == SEXP_CANONICAL) - die("Whitespace encountered in canonical mode.\n"); - - sexp_get_char(input); - break; - - case ';': /* Comments */ - if (mode == SEXP_CANONICAL) - die("Comment encountered in canonical mode.\n"); - - do - { - sexp_get_raw_char(input); - if (input->ctype != SEXP_NORMAL_CHAR) - return; - } - while (input->c != '\n'); - - break; - - default: - /* Ought to be a string */ - if (mode != SEXP_ADVANCED) - die("Encountered advanced string in canonical mode.\n"); - - sexp_get_string(input); - return; - } - } -} - - - -/* Output routines */ - -struct sexp_output -{ - FILE *f; - - const struct nettle_armor *coding; - unsigned coding_indent; - - union { - struct base64_decode_ctx base64; - /* NOTE: There's no context for hex encoding */ - } state; - - unsigned pos; -}; - -static void -sexp_output_init(struct sexp_output *output, FILE *f) -{ - output->f = f; - output->coding = NULL; - - output->pos = 0; -} - -#define LINE_WIDTH 60 - -static void -sexp_put_raw_char(struct sexp_output *output, uint8_t c) -{ - output->pos++; - if (putc(c, output->f) < 0) - die("Write failed: %s\n", strerror(errno)); -} - -static void -sexp_put_newline(struct sexp_output *output, - unsigned indent) -{ - unsigned i; - - sexp_put_raw_char(output, '\n'); - output->pos = 0; - - for(i = 0; i < indent; i++) - sexp_put_raw_char(output, ' '); - - output->pos = indent; -} - -static void -sexp_put_char(struct sexp_output *output, uint8_t c) -{ - if (output->coding) - { - /* Two is enough for both hex and base64. */ - uint8_t encoded[2]; - unsigned done; - - unsigned i; - - done = output->coding->encode_update(&output->state, encoded, - 1, &c); - assert(done <= sizeof(encoded)); - - for (i = 0; i<done; i++) - { - if (output->pos > LINE_WIDTH - && output->pos > (output->coding_indent + 10)) - sexp_put_newline(output, output->coding_indent); - - sexp_put_raw_char(output, encoded[i]); - } - } - else - sexp_put_raw_char(output, c); -} - -static void -sexp_put_data(struct sexp_output *output, - unsigned length, const uint8_t *data) -{ - unsigned i; - - for (i = 0; i<length; i++) - sexp_put_char(output, data[i]); -} - -static void -sexp_put_length(struct sexp_output *output, - unsigned length) -{ - unsigned digit = 1; - - for (;;) - { - unsigned next = digit * 10; - if (next > length) - break; - digit = next; - } - - for (; digit; length %= digit, digit /= 10) - sexp_put_char(output, '0' + length / digit); -} - -static void -sexp_put_code_start(struct sexp_output *output, - const struct nettle_armor *coding, - uint8_t c) -{ - assert(!output->coding); - - sexp_put_raw_char(output, c); - output->coding_indent = output->pos; - - output->coding = coding; - output->coding->encode_init(&output->state); -} - -static void -sexp_put_code_end(struct sexp_output *output, uint8_t c) -{ - /* Enough for both hex and base64 */ - uint8_t encoded[BASE64_ENCODE_FINAL_LENGTH]; - unsigned done; - - assert(output->coding); - - done = output->coding->encode_final(&output->state, encoded); - - assert(done <= sizeof(encoded)); - - output->coding = NULL; - - sexp_put_data(output, done, encoded); - sexp_put_char(output, c); -} - -static void -sexp_put_string(struct sexp_output *output, enum sexp_mode mode, - struct nettle_buffer *string) -{ - if (!string->size) - sexp_put_data(output, 2, - (mode == SEXP_ADVANCED) ? "\"\"": "0:"); - - else if (mode == SEXP_ADVANCED) - { - 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) - { - if (c >= 0x7f) - quote_friendly = 0; - else if (c < 0x20 && !escape_names[c]) - quote_friendly = 0; - } - } - - if (token) - sexp_put_data(output, string->size, string->contents); - - else if (quote_friendly) - { - sexp_put_char(output, '"'); - - 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, '\\'); - - sexp_put_char(output, c); - } - - sexp_put_char(output, '"'); - } - else - { - sexp_put_code_start(output, &nettle_base64, '|'); - sexp_put_data(output, string->size, string->contents); - sexp_put_code_end(output, '|'); - } - } - else - { - sexp_put_length(output, string->size); - sexp_put_char(output, ':'); - sexp_put_data(output, string->size, string->contents); - } -} - - -/* Parsing and conversion functions. */ - -static void -sexp_convert_string(struct sexp_input *input, enum sexp_mode mode_in, - struct sexp_output *output, enum sexp_mode mode_out) -{ - sexp_get_token(input, mode_in); - if (input->token == SEXP_STRING) - sexp_put_string(output, mode_out, &input->string); - else - die("Invalid string.\n"); -} - - -static void -sexp_convert_list(struct sexp_input *input, enum sexp_mode mode_in, - struct sexp_output *output, enum sexp_mode mode_out, - unsigned indent); - -static void -sexp_skip_token(struct sexp_input *input, enum sexp_mode mode, - enum sexp_token token) -{ - sexp_get_token(input, mode); - - if (input->token != token) - die("Syntax error.\n"); -} - -/* Should be called with input->token being the first token of the - * expression, to be converted, and return with input->token being the - * last token of the expression. */ -static void -sexp_convert_item(struct sexp_input *input, enum sexp_mode mode_in, - struct sexp_output *output, enum sexp_mode mode_out, - unsigned indent) -{ - if (mode_out == SEXP_TRANSPORT) - { - sexp_put_code_start(output, &nettle_base64, '{'); - sexp_convert_item(input, mode_in, output, SEXP_CANONICAL, 0); - sexp_put_code_end(output, '}'); - } - else switch(input->token) - { - case SEXP_LIST_END: - die("Unmatched end of list.\n"); - case SEXP_EOF: - die("Unexpected end of file.\n"); - case SEXP_CODING_END: - die("Unexpected end of coding.\n"); - - case SEXP_LIST_START: - sexp_convert_list(input, mode_in, output, mode_out, indent); - break; - - case SEXP_STRING: - sexp_put_string(output, mode_out, &input->string); - break; - - case SEXP_DISPLAY_START: - sexp_put_char(output, '['); - sexp_convert_string(input, mode_in, output, mode_out); - sexp_skip_token(input, mode_in, SEXP_DISPLAY_END); - sexp_put_char(output, ']'); - sexp_convert_string(input, mode_in, output, mode_out); - break; - - case SEXP_TRANSPORT_START: - if (mode_in == SEXP_CANONICAL) - die("Base64 not allowed in canonical mode.\n"); - else - { - sexp_get_token(input, SEXP_CANONICAL); - sexp_convert_item(input, SEXP_CANONICAL, output, mode_out, indent); - sexp_skip_token(input, SEXP_CANONICAL, SEXP_CODING_END); - - break; - } - - default: - die("Syntax error.\n"); - } -} - -static void -sexp_convert_list(struct sexp_input *input, enum sexp_mode mode_in, - struct sexp_output *output, enum sexp_mode mode_out, - unsigned indent) -{ - unsigned item; - - sexp_put_char(output, '('); - - for (item = 0;; item++) - { - sexp_get_token(input, mode_in); - - if (input->token == SEXP_LIST_END) - { - sexp_put_char(output, ')'); - return; - } - - if (mode_out == SEXP_ADVANCED) - { - /* FIXME: Adapt pretty printing to handle a big first - * element. */ - if (item == 1) - { - sexp_put_char(output, ' '); - indent = output->pos; - } - else if (item > 1) - sexp_put_newline(output, indent); - } - - sexp_convert_item(input, mode_in, output, mode_out, indent); - } -} - -static void -sexp_convert_file(struct sexp_input *input, enum sexp_mode mode_in, - struct sexp_output *output, enum sexp_mode mode_out) -{ - sexp_get_char(input); - sexp_get_token(input, mode_in); - - while (input->token != SEXP_EOF) - { - sexp_convert_item(input, mode_in, output, mode_out, 0); - if (mode_out != SEXP_CANONICAL) - sexp_put_newline(output, 0); - - sexp_get_token(input, mode_in); - } - - if (fflush(output->f) < 0) - die("Final fflush failed: %s.\n", strerror(errno)); -} - - - -/* Argument parsing and main program */ - -static int -match_argument(const char *given, const char *name) -{ - /* FIXME: Allow abbreviations */ - return !strcmp(given, name); -} - -int -main(int argc, char **argv) -{ - struct sexp_input input; - struct sexp_output output; - enum sexp_mode mode = SEXP_ADVANCED; - unsigned width; - - int c; - while ( (c = getopt(argc, argv, "s:w:")) != -1) - switch (c) - { - case 's': - if (match_argument(optarg, "advanced")) - mode = SEXP_ADVANCED; - else if (match_argument(optarg, "transport")) - mode = SEXP_TRANSPORT; - else if (match_argument(optarg, "canonical")) - mode = SEXP_CANONICAL; - else - die("Available syntax variants: advanced, transport, canonical\n"); - break; - - case 'w': - die("Option -w not yet implemented.\n"); - - case '?': - printf("Usage: sexp-conv [-m syntax]\n" - "Available syntax variants: advanced, transport, canonical\n"); - return EXIT_FAILURE; - - default: abort(); - } - - sexp_input_init(&input, stdin); - sexp_output_init(&output, stdout); - - sexp_convert_file(&input, SEXP_ADVANCED, &output, mode); - - return EXIT_SUCCESS; -}