Initial version of asn1c
[com/asn1c.git] / libasn1compiler / asn1c_out.c
diff --git a/libasn1compiler/asn1c_out.c b/libasn1compiler/asn1c_out.c
new file mode 100644 (file)
index 0000000..b381e21
--- /dev/null
@@ -0,0 +1,116 @@
+#include "asn1c_internal.h"
+#include "asn1c_out.h"
+
+/*
+ * Add an elementary chunk of target language text
+ * into appropriate output stream.
+ */
+int
+asn1c_compiled_output(arg_t *arg, const char *source, int lineno, const char *func, const char *fmt,
+                      ...) {
+       struct compiler_stream_destination_s *dst;
+       const char *p;
+       int lf_found;
+       va_list ap;
+       out_chunk_t *m;
+       int ret;
+
+       switch(arg->target->target) {
+       case OT_IGNORE:
+               return 0;
+       default:
+               dst = &arg->target->destination[arg->target->target];
+               break;
+       }
+
+       /*
+        * Make sure the output has a single LF and only at the end.
+        */
+       for(lf_found = 0, p = fmt; *p; p++) {
+               if(*p == '\n') {
+                       lf_found++;
+                       assert(p[1] == '\0');
+               }
+       }
+       assert(lf_found <= 1);
+
+       /*
+        * Print out the indentation.
+        */
+       if(dst->indented == 0) {
+               int i = dst->indent_level;
+               if (i < 0) {
+                       /* fatal error */
+                       fprintf(stderr, "target %d : Indent level %d ?!\n", arg->target->target, i);
+                       exit(1);
+               }
+               dst->indented = 1;
+               while(i--) {
+                       ret = asn1c_compiled_output(arg, source, lineno, func, "\t");
+                       if(ret == -1) return -1;
+               }
+       }
+       if(lf_found)
+               dst->indented = 0;
+
+    size_t debug_reserve_size = 0;
+    if(lf_found && (arg->flags & A1C_DEBUG_OUTPUT_ORIGIN_LINES)) {
+        debug_reserve_size =
+            sizeof("\t// :100000 ()") + strlen(source) + strlen(func);
+    }
+
+       /*
+        * Allocate buffer.
+        */
+       m = calloc(1, sizeof(out_chunk_t));
+       if(m == NULL) return -1;
+
+       m->len = 16;
+       do {
+               void *tmp;
+               m->len <<= 2;
+               tmp = realloc(m->buf, m->len + debug_reserve_size);
+               if(tmp) {
+                       m->buf = (char *)tmp;
+               } else {
+                       free(m->buf);
+                       free(m);
+                       return -1;
+               }
+               va_start(ap, fmt);
+               ret = vsnprintf(m->buf, m->len, fmt, ap);
+               va_end(ap);
+       } while(ret >= (m->len - 1) || ret < 0);
+
+       m->len = ret;
+
+    /* Print out the origin of the lines */
+    if(lf_found && (arg->flags & A1C_DEBUG_OUTPUT_ORIGIN_LINES)) {
+        assert(m->buf[m->len - 1] == '\n');
+        ret = snprintf(m->buf + m->len - 1, debug_reserve_size,
+                       "\t// %s:%03d %s()\n", source, lineno, func);
+        assert(ret > 0 && (size_t)ret < debug_reserve_size);
+        m->len = m->len - 1 + ret;
+    }
+
+       if(arg->target->target == OT_INCLUDES
+       || arg->target->target == OT_FWD_DECLS
+       || arg->target->target == OT_POST_INCLUDE) {
+               out_chunk_t *v;
+               TQ_FOR(v, &dst->chunks, next) {
+                       if(m->len == v->len
+                       && !memcmp(m->buf, v->buf, m->len))
+                               break;
+               }
+               if(v) {
+                       /* Entry is already present. Skip it. */
+                       free(m->buf);
+                       free(m);
+                       return 0;
+               }
+       }
+
+       TQ_ADD(&dst->chunks, m, next);
+
+       return 0;
+}