#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; }