aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1compiler/asn1c_out.c
blob: a6432418eab9dedf0f341e2bf49a121706ea179b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "asn1c_internal.h"

/*
 * Add an elementary chunk of target language text
 * into appropriate output stream.
 */
int
asn1c_compiled_output(arg_t *arg, const char *fmt, ...) {
	const char *p;
	int lf_found;
	va_list ap;
	out_chunk_t *m;
	char *buf;
	int ret;

	/*
	 * 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(arg->indented == 0) {
		int i = arg->indent_level;
		arg->indented = 1;
		while(i--) {
			ret = asn1c_compiled_output(arg, "\t");
			if(ret == -1) return -1;
		}
	}

	/*
	 * Estimate necessary size.
	 */
	buf = "";
	va_start(ap, fmt);
	ret = vsnprintf(buf, 0, fmt, ap);
	va_end(ap);
	assert(ret >= 0);

	/*
	 * Allocate buffer.
	 */
	m = calloc(1, sizeof(out_chunk_t));
	if(m == NULL) return -1;
	m->len = ret + 1;
	m->buf = malloc(ret + 1);
	if(m->buf == NULL) {
		free(m);
		return -1;
	}

	/*
	 * Fill the buffer.
	 */
	va_start(ap, fmt);
	ret = vsnprintf(m->buf, m->len, fmt, ap);
	assert(ret < m->len);
	m->len = ret;
	va_end(ap);

	TQ_ADD(&(arg->target->targets[arg->target->target]), m, next);

	if(lf_found)
		arg->indented = 0;

	return 0;
}