diff options
Diffstat (limited to 'libasn1compiler/asn1compiler.c')
-rw-r--r-- | libasn1compiler/asn1compiler.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/libasn1compiler/asn1compiler.c b/libasn1compiler/asn1compiler.c new file mode 100644 index 00000000..d647c05b --- /dev/null +++ b/libasn1compiler/asn1compiler.c @@ -0,0 +1,160 @@ +#include "asn1c_internal.h" + +static void default_logger_cb(int, const char *fmt, ...); +static int asn1c_compile_expr(arg_t *arg); +static int asn1c_attach_streams(asn1p_expr_t *expr); + +int +asn1_compile(asn1p_t *asn, const char *datadir, enum asn1c_flags flags) { + arg_t arg_s; + arg_t *arg = &arg_s; + int ret; + + /* + * Initialize target language. + */ + ret = asn1c_with_language(ASN1C_LANGUAGE_C); + assert(ret == 0); + + memset(arg, 0, sizeof(*arg)); + arg->default_cb = asn1c_compile_expr; + arg->logger_cb = default_logger_cb; + arg->flags = flags; + arg->asn = asn; + + /* + * Compile each individual top level structure. + */ + TQ_FOR(arg->mod, &(asn->modules), mod_next) { + TQ_FOR(arg->expr, &(arg->mod->members), next) { + compiler_streams_t *cs = NULL; + + if(asn1c_attach_streams(arg->expr)) + return -1; + + cs = arg->expr->data; + cs->target = OT_TYPE_DECLS; + arg->target = cs; + + ret = asn1c_compile_expr(arg); + if(ret) { + FATAL("Cannot compile %s (%x:%x) at line %d", + arg->expr->Identifier, + arg->expr->expr_type, + arg->expr->meta_type, + arg->expr->_lineno); + return ret; + } + } + } + + DEBUG("Saving compiled data"); + + /* + * Save or print out the compiled result. + */ + if(asn1c_save_compiled_output(arg, datadir)) + return -1; + + return 0; +} + +static int +asn1c_compile_expr(arg_t *arg) { + asn1p_expr_t *expr = arg->expr; + int (*type_cb)(arg_t *); + int ret; + + assert(expr->meta_type >= AMT_INVALID); + assert(expr->meta_type < AMT_EXPR_META_MAX); + assert(expr->expr_type >= A1TC_INVALID); + assert(expr->expr_type < ASN_EXPR_TYPE_MAX); + + type_cb = asn1_lang_map[expr->meta_type][expr->expr_type].type_cb; + if(type_cb) { + + if(arg->indent_level == 0) + OUT("\n"); + + DEBUG("Compiling %s at line %d", + expr->Identifier, + expr->_lineno); + + ret = type_cb(arg); + } else { + ret = -1; + /* + * Even if the target language compiler does not know + * how to compile the given expression, we know that + * certain expressions need not to be compiled at all. + */ + switch(expr->meta_type) { + case AMT_PARAMTYPE: + case AMT_OBJECT: + case AMT_OBJECTSET: + case AMT_VALUE: + case AMT_VALUESET: + ret = 0; + break; + default: + break; + } + + switch(expr->expr_type) { + case A1TC_TYPEID: + ret = 0; /* TYPE-IDENTIFIER is a CLASS */ + default: + break; + } + } + + if(ret == -1) { + OUT("#error Cannot compile \"%s\" (%x/%x) at line %d\n", + arg->expr->Identifier, + arg->expr->meta_type, + arg->expr->expr_type, + arg->expr->_lineno + ); + } + + return ret; +} + +static int +asn1c_attach_streams(asn1p_expr_t *expr) { + compiler_streams_t *cs; + int i; + + if(expr->data) + return 0; /* Already attached? */ + + expr->data = calloc(1, sizeof(compiler_streams_t)); + if(expr->data == NULL) + return -1; + + cs = expr->data; + for(i = 0; i < OT_MAX; i++) { + TQ_INIT(&(cs->targets[i])); + } + + return 0; +} + +static void +default_logger_cb(int _severity, const char *fmt, ...) { + va_list ap; + char *pfx = ""; + + switch(_severity) { + case -1: pfx = "DEBUG: "; break; + case 0: pfx = "WARNING: "; break; + case 1: pfx = "FATAL: "; break; + } + + fprintf(stderr, "%s", pfx); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + |