aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1compiler/asn1compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'libasn1compiler/asn1compiler.c')
-rw-r--r--libasn1compiler/asn1compiler.c160
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");
+}
+