1/*	$NetBSD: treesource.c,v 1.1.1.3 2019/12/22 12:34:03 skrll Exp $	*/
2
3// SPDX-License-Identifier: GPL-2.0-or-later
4/*
5 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
6 */
7
8#include "dtc.h"
9#include "srcpos.h"
10
11extern FILE *yyin;
12extern int yyparse(void);
13extern YYLTYPE yylloc;
14
15struct dt_info *parser_output;
16bool treesource_error;
17
18struct dt_info *dt_from_source(const char *fname)
19{
20	parser_output = NULL;
21	treesource_error = false;
22
23	srcfile_push(fname);
24	yyin = current_srcfile->f;
25	yylloc.file = current_srcfile;
26
27	if (yyparse() != 0)
28		die("Unable to parse input tree\n");
29
30	if (treesource_error)
31		die("Syntax error parsing input tree\n");
32
33	return parser_output;
34}
35
36static void write_prefix(FILE *f, int level)
37{
38	int i;
39
40	for (i = 0; i < level; i++)
41		fputc('\t', f);
42}
43
44static bool isstring(char c)
45{
46	return (isprint((unsigned char)c)
47		|| (c == '\0')
48		|| strchr("\a\b\t\n\v\f\r", c));
49}
50
51static void write_propval_string(FILE *f, const char *s, size_t len)
52{
53	const char *end = s + len - 1;
54
55	if (!len)
56		return;
57
58	assert(*end == '\0');
59
60	fprintf(f, "\"");
61	while (s < end) {
62		char c = *s++;
63		switch (c) {
64		case '\a':
65			fprintf(f, "\\a");
66			break;
67		case '\b':
68			fprintf(f, "\\b");
69			break;
70		case '\t':
71			fprintf(f, "\\t");
72			break;
73		case '\n':
74			fprintf(f, "\\n");
75			break;
76		case '\v':
77			fprintf(f, "\\v");
78			break;
79		case '\f':
80			fprintf(f, "\\f");
81			break;
82		case '\r':
83			fprintf(f, "\\r");
84			break;
85		case '\\':
86			fprintf(f, "\\\\");
87			break;
88		case '\"':
89			fprintf(f, "\\\"");
90			break;
91		case '\0':
92			fprintf(f, "\\0");
93			break;
94		default:
95			if (isprint((unsigned char)c))
96				fprintf(f, "%c", c);
97			else
98				fprintf(f, "\\x%02"PRIx8, c);
99		}
100	}
101	fprintf(f, "\"");
102}
103
104static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
105{
106	const char *end = p + len;
107	assert(len % width == 0);
108
109	for (; p < end; p += width) {
110		switch (width) {
111		case 1:
112			fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
113			break;
114		case 2:
115			fprintf(f, "0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p));
116			break;
117		case 4:
118			fprintf(f, "0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p));
119			break;
120		case 8:
121			fprintf(f, "0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p));
122			break;
123		}
124		if (p + width < end)
125			fputc(' ', f);
126	}
127}
128
129static bool has_data_type_information(struct marker *m)
130{
131	return m->type >= TYPE_UINT8;
132}
133
134static struct marker *next_type_marker(struct marker *m)
135{
136	while (m && !has_data_type_information(m))
137		m = m->next;
138	return m;
139}
140
141size_t type_marker_length(struct marker *m)
142{
143	struct marker *next = next_type_marker(m->next);
144
145	if (next)
146		return next->offset - m->offset;
147	return 0;
148}
149
150static const char *delim_start[] = {
151	[TYPE_UINT8] = "[",
152	[TYPE_UINT16] = "/bits/ 16 <",
153	[TYPE_UINT32] = "<",
154	[TYPE_UINT64] = "/bits/ 64 <",
155	[TYPE_STRING] = "",
156};
157static const char *delim_end[] = {
158	[TYPE_UINT8] = "]",
159	[TYPE_UINT16] = ">",
160	[TYPE_UINT32] = ">",
161	[TYPE_UINT64] = ">",
162	[TYPE_STRING] = "",
163};
164
165static enum markertype guess_value_type(struct property *prop)
166{
167	int len = prop->val.len;
168	const char *p = prop->val.val;
169	struct marker *m = prop->val.markers;
170	int nnotstring = 0, nnul = 0;
171	int nnotstringlbl = 0, nnotcelllbl = 0;
172	int i;
173
174	for (i = 0; i < len; i++) {
175		if (! isstring(p[i]))
176			nnotstring++;
177		if (p[i] == '\0')
178			nnul++;
179	}
180
181	for_each_marker_of_type(m, LABEL) {
182		if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
183			nnotstringlbl++;
184		if ((m->offset % sizeof(cell_t)) != 0)
185			nnotcelllbl++;
186	}
187
188	if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
189	    && (nnotstringlbl == 0)) {
190		return TYPE_STRING;
191	} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
192		return TYPE_UINT32;
193	}
194
195	return TYPE_UINT8;
196}
197
198static void write_propval(FILE *f, struct property *prop)
199{
200	size_t len = prop->val.len;
201	struct marker *m = prop->val.markers;
202	struct marker dummy_marker;
203	enum markertype emit_type = TYPE_NONE;
204	char *srcstr;
205
206	if (len == 0) {
207		fprintf(f, ";");
208		if (annotate) {
209			srcstr = srcpos_string_first(prop->srcpos, annotate);
210			if (srcstr) {
211				fprintf(f, " /* %s */", srcstr);
212				free(srcstr);
213			}
214		}
215		fprintf(f, "\n");
216		return;
217	}
218
219	fprintf(f, " =");
220
221	if (!next_type_marker(m)) {
222		/* data type information missing, need to guess */
223		dummy_marker.type = guess_value_type(prop);
224		dummy_marker.next = prop->val.markers;
225		dummy_marker.offset = 0;
226		dummy_marker.ref = NULL;
227		m = &dummy_marker;
228	}
229
230	for_each_marker(m) {
231		size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
232		size_t data_len = type_marker_length(m) ? : len - m->offset;
233		const char *p = &prop->val.val[m->offset];
234
235		if (has_data_type_information(m)) {
236			emit_type = m->type;
237			fprintf(f, " %s", delim_start[emit_type]);
238		} else if (m->type == LABEL)
239			fprintf(f, " %s:", m->ref);
240		else if (m->offset)
241			fputc(' ', f);
242
243		if (emit_type == TYPE_NONE) {
244			assert(chunk_len == 0);
245			continue;
246		}
247
248		switch(emit_type) {
249		case TYPE_UINT16:
250			write_propval_int(f, p, chunk_len, 2);
251			break;
252		case TYPE_UINT32:
253			write_propval_int(f, p, chunk_len, 4);
254			break;
255		case TYPE_UINT64:
256			write_propval_int(f, p, chunk_len, 8);
257			break;
258		case TYPE_STRING:
259			write_propval_string(f, p, chunk_len);
260			break;
261		default:
262			write_propval_int(f, p, chunk_len, 1);
263		}
264
265		if (chunk_len == data_len) {
266			size_t pos = m->offset + chunk_len;
267			fprintf(f, pos == len ? "%s" : "%s,",
268			        delim_end[emit_type] ? : "");
269			emit_type = TYPE_NONE;
270		}
271	}
272	fprintf(f, ";");
273	if (annotate) {
274		srcstr = srcpos_string_first(prop->srcpos, annotate);
275		if (srcstr) {
276			fprintf(f, " /* %s */", srcstr);
277			free(srcstr);
278		}
279	}
280	fprintf(f, "\n");
281}
282
283static void write_tree_source_node(FILE *f, struct node *tree, int level)
284{
285	struct property *prop;
286	struct node *child;
287	struct label *l;
288	char *srcstr;
289
290	write_prefix(f, level);
291	for_each_label(tree->labels, l)
292		fprintf(f, "%s: ", l->label);
293	if (tree->name && (*tree->name))
294		fprintf(f, "%s {", tree->name);
295	else
296		fprintf(f, "/ {");
297
298	if (annotate) {
299		srcstr = srcpos_string_first(tree->srcpos, annotate);
300		if (srcstr) {
301			fprintf(f, " /* %s */", srcstr);
302			free(srcstr);
303		}
304	}
305	fprintf(f, "\n");
306
307	for_each_property(tree, prop) {
308		write_prefix(f, level+1);
309		for_each_label(prop->labels, l)
310			fprintf(f, "%s: ", l->label);
311		fprintf(f, "%s", prop->name);
312		write_propval(f, prop);
313	}
314	for_each_child(tree, child) {
315		fprintf(f, "\n");
316		write_tree_source_node(f, child, level+1);
317	}
318	write_prefix(f, level);
319	fprintf(f, "};");
320	if (annotate) {
321		srcstr = srcpos_string_last(tree->srcpos, annotate);
322		if (srcstr) {
323			fprintf(f, " /* %s */", srcstr);
324			free(srcstr);
325		}
326	}
327	fprintf(f, "\n");
328}
329
330void dt_to_source(FILE *f, struct dt_info *dti)
331{
332	struct reserve_info *re;
333
334	fprintf(f, "/dts-v1/;\n\n");
335
336	for (re = dti->reservelist; re; re = re->next) {
337		struct label *l;
338
339		for_each_label(re->labels, l)
340			fprintf(f, "%s: ", l->label);
341		fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
342			(unsigned long long)re->address,
343			(unsigned long long)re->size);
344	}
345
346	write_tree_source_node(f, dti->dt, 0);
347}
348