xref: /third_party/ltp/metadata/metaparse.c (revision f08c3bdf)
1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2019-2021 Cyril Hrubis <chrubis@suse.cz>
4f08c3bdfSopenharmony_ci * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci#define _GNU_SOURCE
8f08c3bdfSopenharmony_ci
9f08c3bdfSopenharmony_ci#include <search.h>
10f08c3bdfSopenharmony_ci#include <stdio.h>
11f08c3bdfSopenharmony_ci#include <string.h>
12f08c3bdfSopenharmony_ci#include <libgen.h>
13f08c3bdfSopenharmony_ci#include <ctype.h>
14f08c3bdfSopenharmony_ci#include <unistd.h>
15f08c3bdfSopenharmony_ci#include <errno.h>
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci#include "data_storage.h"
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci#define INCLUDE_PATH_MAX 5
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_cistatic int verbose;
22f08c3bdfSopenharmony_cistatic char *cmdline_includepath[INCLUDE_PATH_MAX];
23f08c3bdfSopenharmony_cistatic unsigned int cmdline_includepaths;
24f08c3bdfSopenharmony_cistatic char *includepath;
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#define WARN(str) fprintf(stderr, "WARNING: " str "\n")
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic void oneline_comment(FILE *f)
29f08c3bdfSopenharmony_ci{
30f08c3bdfSopenharmony_ci	int c;
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_ci	do {
33f08c3bdfSopenharmony_ci		c = getc(f);
34f08c3bdfSopenharmony_ci	} while (c != '\n');
35f08c3bdfSopenharmony_ci}
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_cistatic const char *eat_asterisk_space(const char *c)
38f08c3bdfSopenharmony_ci{
39f08c3bdfSopenharmony_ci	unsigned int i = 0;
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci	while (isspace(c[i]))
42f08c3bdfSopenharmony_ci		i++;
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci	if (c[i] == '*') {
45f08c3bdfSopenharmony_ci		if (isspace(c[i+1]))
46f08c3bdfSopenharmony_ci			i++;
47f08c3bdfSopenharmony_ci		return &c[i+1];
48f08c3bdfSopenharmony_ci	}
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_ci	return c;
51f08c3bdfSopenharmony_ci}
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_cistatic void multiline_comment(FILE *f, struct data_node *doc)
54f08c3bdfSopenharmony_ci{
55f08c3bdfSopenharmony_ci	int c;
56f08c3bdfSopenharmony_ci	int state = 0;
57f08c3bdfSopenharmony_ci	char buf[4096];
58f08c3bdfSopenharmony_ci	unsigned int bufp = 0;
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	for (;;) {
61f08c3bdfSopenharmony_ci		c = getc(f);
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci		if (doc) {
64f08c3bdfSopenharmony_ci			if (c == '\n') {
65f08c3bdfSopenharmony_ci				struct data_node *line;
66f08c3bdfSopenharmony_ci				buf[bufp] = 0;
67f08c3bdfSopenharmony_ci				line = data_node_string(eat_asterisk_space(buf));
68f08c3bdfSopenharmony_ci				if (data_node_array_add(doc, line))
69f08c3bdfSopenharmony_ci					WARN("doc string comment truncated");
70f08c3bdfSopenharmony_ci				bufp = 0;
71f08c3bdfSopenharmony_ci				continue;
72f08c3bdfSopenharmony_ci			}
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci			if (bufp + 1 >= sizeof(buf))
75f08c3bdfSopenharmony_ci				continue;
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci			buf[bufp++] = c;
78f08c3bdfSopenharmony_ci		}
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci		switch (state) {
81f08c3bdfSopenharmony_ci		case 0:
82f08c3bdfSopenharmony_ci			if (c == '*')
83f08c3bdfSopenharmony_ci				state = 1;
84f08c3bdfSopenharmony_ci		break;
85f08c3bdfSopenharmony_ci		case 1:
86f08c3bdfSopenharmony_ci			switch (c) {
87f08c3bdfSopenharmony_ci			case '/':
88f08c3bdfSopenharmony_ci				return;
89f08c3bdfSopenharmony_ci			case '*':
90f08c3bdfSopenharmony_ci				continue;
91f08c3bdfSopenharmony_ci			default:
92f08c3bdfSopenharmony_ci				state = 0;
93f08c3bdfSopenharmony_ci			break;
94f08c3bdfSopenharmony_ci			}
95f08c3bdfSopenharmony_ci		break;
96f08c3bdfSopenharmony_ci		}
97f08c3bdfSopenharmony_ci	}
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_cistatic const char doc_prefix[] = "\\\n";
102f08c3bdfSopenharmony_ci
103f08c3bdfSopenharmony_cistatic void maybe_doc_comment(FILE *f, struct data_node *doc)
104f08c3bdfSopenharmony_ci{
105f08c3bdfSopenharmony_ci	int c, i;
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci	for (i = 0; doc_prefix[i]; i++) {
108f08c3bdfSopenharmony_ci		c = getc(f);
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci		if (c == doc_prefix[i])
111f08c3bdfSopenharmony_ci			continue;
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ci		if (c == '*')
114f08c3bdfSopenharmony_ci			ungetc(c, f);
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci		multiline_comment(f, NULL);
117f08c3bdfSopenharmony_ci		return;
118f08c3bdfSopenharmony_ci	}
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci	multiline_comment(f, doc);
121f08c3bdfSopenharmony_ci}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_cistatic void maybe_comment(FILE *f, struct data_node *doc)
124f08c3bdfSopenharmony_ci{
125f08c3bdfSopenharmony_ci	int c = getc(f);
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	switch (c) {
128f08c3bdfSopenharmony_ci	case '/':
129f08c3bdfSopenharmony_ci		oneline_comment(f);
130f08c3bdfSopenharmony_ci	break;
131f08c3bdfSopenharmony_ci	case '*':
132f08c3bdfSopenharmony_ci		maybe_doc_comment(f, doc);
133f08c3bdfSopenharmony_ci	break;
134f08c3bdfSopenharmony_ci	default:
135f08c3bdfSopenharmony_ci		ungetc(c, f);
136f08c3bdfSopenharmony_ci	break;
137f08c3bdfSopenharmony_ci	}
138f08c3bdfSopenharmony_ci}
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_cistatic char *next_token2(FILE *f, char *buf, size_t buf_len, struct data_node *doc)
141f08c3bdfSopenharmony_ci{
142f08c3bdfSopenharmony_ci	size_t i = 0;
143f08c3bdfSopenharmony_ci	int c;
144f08c3bdfSopenharmony_ci	int in_str = 0;
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_ci	buf_len--;
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_ci	for (;;) {
149f08c3bdfSopenharmony_ci		c = fgetc(f);
150f08c3bdfSopenharmony_ci
151f08c3bdfSopenharmony_ci		if (c == EOF)
152f08c3bdfSopenharmony_ci			goto exit;
153f08c3bdfSopenharmony_ci
154f08c3bdfSopenharmony_ci		if (in_str) {
155f08c3bdfSopenharmony_ci			if (c == '"') {
156f08c3bdfSopenharmony_ci				if (i == 0 || buf[i-1] != '\\')
157f08c3bdfSopenharmony_ci					goto exit;
158f08c3bdfSopenharmony_ci			}
159f08c3bdfSopenharmony_ci
160f08c3bdfSopenharmony_ci			if (i < buf_len)
161f08c3bdfSopenharmony_ci				buf[i++] = c;
162f08c3bdfSopenharmony_ci			continue;
163f08c3bdfSopenharmony_ci		}
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci		switch (c) {
166f08c3bdfSopenharmony_ci		case '{':
167f08c3bdfSopenharmony_ci		case '}':
168f08c3bdfSopenharmony_ci		case ';':
169f08c3bdfSopenharmony_ci		case '(':
170f08c3bdfSopenharmony_ci		case ')':
171f08c3bdfSopenharmony_ci		case '=':
172f08c3bdfSopenharmony_ci		case ',':
173f08c3bdfSopenharmony_ci		case '[':
174f08c3bdfSopenharmony_ci		case ']':
175f08c3bdfSopenharmony_ci		case '#':
176f08c3bdfSopenharmony_ci			if (i) {
177f08c3bdfSopenharmony_ci				ungetc(c, f);
178f08c3bdfSopenharmony_ci				goto exit;
179f08c3bdfSopenharmony_ci			}
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_ci			if (i < buf_len)
182f08c3bdfSopenharmony_ci				buf[i++] = c;
183f08c3bdfSopenharmony_ci			goto exit;
184f08c3bdfSopenharmony_ci		case '0' ... '9':
185f08c3bdfSopenharmony_ci		case 'a' ... 'z':
186f08c3bdfSopenharmony_ci		case 'A' ... 'Z':
187f08c3bdfSopenharmony_ci		case '.':
188f08c3bdfSopenharmony_ci		case '_':
189f08c3bdfSopenharmony_ci		case '-':
190f08c3bdfSopenharmony_ci			buf[i++] = c;
191f08c3bdfSopenharmony_ci		break;
192f08c3bdfSopenharmony_ci		case '/':
193f08c3bdfSopenharmony_ci			maybe_comment(f, doc);
194f08c3bdfSopenharmony_ci		break;
195f08c3bdfSopenharmony_ci		case '"':
196f08c3bdfSopenharmony_ci			in_str = 1;
197f08c3bdfSopenharmony_ci		break;
198f08c3bdfSopenharmony_ci		case ' ':
199f08c3bdfSopenharmony_ci		case '\n':
200f08c3bdfSopenharmony_ci		case '\t':
201f08c3bdfSopenharmony_ci			if (i)
202f08c3bdfSopenharmony_ci				goto exit;
203f08c3bdfSopenharmony_ci		break;
204f08c3bdfSopenharmony_ci		}
205f08c3bdfSopenharmony_ci	}
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ciexit:
208f08c3bdfSopenharmony_ci	if (i == 0 && !in_str)
209f08c3bdfSopenharmony_ci		return NULL;
210f08c3bdfSopenharmony_ci
211f08c3bdfSopenharmony_ci	buf[i] = 0;
212f08c3bdfSopenharmony_ci	return buf;
213f08c3bdfSopenharmony_ci}
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_cistatic char *next_token(FILE *f, struct data_node *doc)
216f08c3bdfSopenharmony_ci{
217f08c3bdfSopenharmony_ci	static char buf[4096];
218f08c3bdfSopenharmony_ci
219f08c3bdfSopenharmony_ci	return next_token2(f, buf, sizeof(buf), doc);
220f08c3bdfSopenharmony_ci}
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_cistatic FILE *open_file(const char *dir, const char *fname)
223f08c3bdfSopenharmony_ci{
224f08c3bdfSopenharmony_ci	FILE *f;
225f08c3bdfSopenharmony_ci	char *path;
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_ci	if (asprintf(&path, "%s/%s", dir, fname) < 0)
228f08c3bdfSopenharmony_ci		return NULL;
229f08c3bdfSopenharmony_ci
230f08c3bdfSopenharmony_ci	f = fopen(path, "r");
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci	free(path);
233f08c3bdfSopenharmony_ci
234f08c3bdfSopenharmony_ci	return f;
235f08c3bdfSopenharmony_ci}
236f08c3bdfSopenharmony_ci
237f08c3bdfSopenharmony_cistatic FILE *open_include(FILE *f)
238f08c3bdfSopenharmony_ci{
239f08c3bdfSopenharmony_ci	char buf[256], *fname;
240f08c3bdfSopenharmony_ci	FILE *inc;
241f08c3bdfSopenharmony_ci	unsigned int i;
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci	if (!fscanf(f, "%s\n", buf))
244f08c3bdfSopenharmony_ci		return NULL;
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_ci	if (buf[0] != '"')
247f08c3bdfSopenharmony_ci		return NULL;
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_ci	fname = buf + 1;
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci	if (!buf[0])
252f08c3bdfSopenharmony_ci		return NULL;
253f08c3bdfSopenharmony_ci
254f08c3bdfSopenharmony_ci	fname[strlen(fname)-1] = 0;
255f08c3bdfSopenharmony_ci
256f08c3bdfSopenharmony_ci	inc = open_file(includepath, fname);
257f08c3bdfSopenharmony_ci	if (inc) {
258f08c3bdfSopenharmony_ci		if (verbose)
259f08c3bdfSopenharmony_ci			fprintf(stderr, "INCLUDE %s/%s\n", includepath, fname);
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci		return inc;
262f08c3bdfSopenharmony_ci	}
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	for (i = 0; i < cmdline_includepaths; i++) {
265f08c3bdfSopenharmony_ci		inc = open_file(cmdline_includepath[i], fname);
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_ci		if (!inc)
268f08c3bdfSopenharmony_ci			continue;
269f08c3bdfSopenharmony_ci
270f08c3bdfSopenharmony_ci		if (verbose) {
271f08c3bdfSopenharmony_ci			fprintf(stderr, "INCLUDE %s/%s\n",
272f08c3bdfSopenharmony_ci				cmdline_includepath[i], fname);
273f08c3bdfSopenharmony_ci		}
274f08c3bdfSopenharmony_ci
275f08c3bdfSopenharmony_ci		return inc;
276f08c3bdfSopenharmony_ci	}
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_ci	return NULL;
279f08c3bdfSopenharmony_ci}
280f08c3bdfSopenharmony_ci
281f08c3bdfSopenharmony_cistatic void close_include(FILE *inc)
282f08c3bdfSopenharmony_ci{
283f08c3bdfSopenharmony_ci	if (verbose)
284f08c3bdfSopenharmony_ci		fprintf(stderr, "INCLUDE END\n");
285f08c3bdfSopenharmony_ci
286f08c3bdfSopenharmony_ci	fclose(inc);
287f08c3bdfSopenharmony_ci}
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_cistatic int parse_array(FILE *f, struct data_node *node)
290f08c3bdfSopenharmony_ci{
291f08c3bdfSopenharmony_ci	const char *token;
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_ci	for (;;) {
294f08c3bdfSopenharmony_ci		if (!(token = next_token(f, NULL)))
295f08c3bdfSopenharmony_ci			return 1;
296f08c3bdfSopenharmony_ci
297f08c3bdfSopenharmony_ci		if (!strcmp(token, "{")) {
298f08c3bdfSopenharmony_ci			struct data_node *ret = data_node_array();
299f08c3bdfSopenharmony_ci			parse_array(f, ret);
300f08c3bdfSopenharmony_ci
301f08c3bdfSopenharmony_ci			if (data_node_array_len(ret))
302f08c3bdfSopenharmony_ci				data_node_array_add(node, ret);
303f08c3bdfSopenharmony_ci			else
304f08c3bdfSopenharmony_ci				data_node_free(ret);
305f08c3bdfSopenharmony_ci
306f08c3bdfSopenharmony_ci			continue;
307f08c3bdfSopenharmony_ci		}
308f08c3bdfSopenharmony_ci
309f08c3bdfSopenharmony_ci		if (!strcmp(token, "}"))
310f08c3bdfSopenharmony_ci			return 0;
311f08c3bdfSopenharmony_ci
312f08c3bdfSopenharmony_ci		if (!strcmp(token, ","))
313f08c3bdfSopenharmony_ci			continue;
314f08c3bdfSopenharmony_ci
315f08c3bdfSopenharmony_ci		if (!strcmp(token, "NULL"))
316f08c3bdfSopenharmony_ci			continue;
317f08c3bdfSopenharmony_ci
318f08c3bdfSopenharmony_ci		struct data_node *str = data_node_string(token);
319f08c3bdfSopenharmony_ci
320f08c3bdfSopenharmony_ci		data_node_array_add(node, str);
321f08c3bdfSopenharmony_ci	}
322f08c3bdfSopenharmony_ci
323f08c3bdfSopenharmony_ci	return 0;
324f08c3bdfSopenharmony_ci}
325f08c3bdfSopenharmony_ci
326f08c3bdfSopenharmony_cistatic void try_apply_macro(char **res)
327f08c3bdfSopenharmony_ci{
328f08c3bdfSopenharmony_ci	ENTRY macro = {
329f08c3bdfSopenharmony_ci		.key = *res,
330f08c3bdfSopenharmony_ci	};
331f08c3bdfSopenharmony_ci
332f08c3bdfSopenharmony_ci	ENTRY *ret;
333f08c3bdfSopenharmony_ci
334f08c3bdfSopenharmony_ci	ret = hsearch(macro, FIND);
335f08c3bdfSopenharmony_ci
336f08c3bdfSopenharmony_ci	if (!ret)
337f08c3bdfSopenharmony_ci		return;
338f08c3bdfSopenharmony_ci
339f08c3bdfSopenharmony_ci	if (verbose)
340f08c3bdfSopenharmony_ci		fprintf(stderr, "APPLYING MACRO %s=%s\n", ret->key, (char*)ret->data);
341f08c3bdfSopenharmony_ci
342f08c3bdfSopenharmony_ci	*res = ret->data;
343f08c3bdfSopenharmony_ci}
344f08c3bdfSopenharmony_ci
345f08c3bdfSopenharmony_cistatic int parse_get_array_len(FILE *f)
346f08c3bdfSopenharmony_ci{
347f08c3bdfSopenharmony_ci	const char *token;
348f08c3bdfSopenharmony_ci	int cnt = 0, depth = 0, prev_comma = 0;
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_ci	if (!(token = next_token(f, NULL)))
351f08c3bdfSopenharmony_ci		return 0;
352f08c3bdfSopenharmony_ci
353f08c3bdfSopenharmony_ci	if (strcmp(token, "{"))
354f08c3bdfSopenharmony_ci		return 0;
355f08c3bdfSopenharmony_ci
356f08c3bdfSopenharmony_ci	for (;;) {
357f08c3bdfSopenharmony_ci		if (!(token = next_token(f, NULL)))
358f08c3bdfSopenharmony_ci			return 0;
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_ci		if (!strcmp(token, "{"))
361f08c3bdfSopenharmony_ci			depth++;
362f08c3bdfSopenharmony_ci
363f08c3bdfSopenharmony_ci		if (!strcmp(token, "}"))
364f08c3bdfSopenharmony_ci			depth--;
365f08c3bdfSopenharmony_ci		else
366f08c3bdfSopenharmony_ci			prev_comma = 0;
367f08c3bdfSopenharmony_ci
368f08c3bdfSopenharmony_ci		if (!strcmp(token, ",") && !depth) {
369f08c3bdfSopenharmony_ci			prev_comma = 1;
370f08c3bdfSopenharmony_ci			cnt++;
371f08c3bdfSopenharmony_ci		}
372f08c3bdfSopenharmony_ci
373f08c3bdfSopenharmony_ci		if (depth < 0)
374f08c3bdfSopenharmony_ci			return cnt + !prev_comma;
375f08c3bdfSopenharmony_ci	}
376f08c3bdfSopenharmony_ci}
377f08c3bdfSopenharmony_ci
378f08c3bdfSopenharmony_cistatic void look_for_array_size(FILE *f, const char *arr_id, struct data_node **res)
379f08c3bdfSopenharmony_ci{
380f08c3bdfSopenharmony_ci	const char *token;
381f08c3bdfSopenharmony_ci	char buf[2][2048] = {};
382f08c3bdfSopenharmony_ci	int cur_buf = 0;
383f08c3bdfSopenharmony_ci	int prev_buf = 1;
384f08c3bdfSopenharmony_ci
385f08c3bdfSopenharmony_ci	for (;;) {
386f08c3bdfSopenharmony_ci		if (!(token = next_token2(f, buf[cur_buf], sizeof(buf[cur_buf]), NULL)))
387f08c3bdfSopenharmony_ci			break;
388f08c3bdfSopenharmony_ci
389f08c3bdfSopenharmony_ci		if (!strcmp(token, "=") && !strcmp(buf[prev_buf], arr_id)) {
390f08c3bdfSopenharmony_ci			int arr_len = parse_get_array_len(f);
391f08c3bdfSopenharmony_ci
392f08c3bdfSopenharmony_ci			if (verbose)
393f08c3bdfSopenharmony_ci				fprintf(stderr, "ARRAY %s LENGTH = %i\n", arr_id, arr_len);
394f08c3bdfSopenharmony_ci
395f08c3bdfSopenharmony_ci			*res = data_node_int(arr_len);
396f08c3bdfSopenharmony_ci
397f08c3bdfSopenharmony_ci			break;
398f08c3bdfSopenharmony_ci		}
399f08c3bdfSopenharmony_ci
400f08c3bdfSopenharmony_ci		if (strcmp(buf[cur_buf], "]") && strcmp(buf[cur_buf], "[")) {
401f08c3bdfSopenharmony_ci			cur_buf = !cur_buf;
402f08c3bdfSopenharmony_ci			prev_buf = !prev_buf;
403f08c3bdfSopenharmony_ci		}
404f08c3bdfSopenharmony_ci	}
405f08c3bdfSopenharmony_ci}
406f08c3bdfSopenharmony_ci
407f08c3bdfSopenharmony_cistatic int parse_array_size(FILE *f, struct data_node **res)
408f08c3bdfSopenharmony_ci{
409f08c3bdfSopenharmony_ci	const char *token;
410f08c3bdfSopenharmony_ci	char *arr_id;
411f08c3bdfSopenharmony_ci	long pos;
412f08c3bdfSopenharmony_ci	int hash = 0;
413f08c3bdfSopenharmony_ci
414f08c3bdfSopenharmony_ci	*res = NULL;
415f08c3bdfSopenharmony_ci
416f08c3bdfSopenharmony_ci	if (!(token = next_token(f, NULL)))
417f08c3bdfSopenharmony_ci		return 1;
418f08c3bdfSopenharmony_ci
419f08c3bdfSopenharmony_ci	if (strcmp(token, "("))
420f08c3bdfSopenharmony_ci		return 1;
421f08c3bdfSopenharmony_ci
422f08c3bdfSopenharmony_ci	if (!(token = next_token(f, NULL)))
423f08c3bdfSopenharmony_ci		return 1;
424f08c3bdfSopenharmony_ci
425f08c3bdfSopenharmony_ci	arr_id = strdup(token);
426f08c3bdfSopenharmony_ci
427f08c3bdfSopenharmony_ci	if (verbose)
428f08c3bdfSopenharmony_ci		fprintf(stderr, "COMPUTING ARRAY '%s' LENGHT\n", arr_id);
429f08c3bdfSopenharmony_ci
430f08c3bdfSopenharmony_ci	pos = ftell(f);
431f08c3bdfSopenharmony_ci
432f08c3bdfSopenharmony_ci	rewind(f);
433f08c3bdfSopenharmony_ci
434f08c3bdfSopenharmony_ci	look_for_array_size(f, arr_id, res);
435f08c3bdfSopenharmony_ci
436f08c3bdfSopenharmony_ci	if (!*res) {
437f08c3bdfSopenharmony_ci		FILE *inc;
438f08c3bdfSopenharmony_ci
439f08c3bdfSopenharmony_ci		rewind(f);
440f08c3bdfSopenharmony_ci
441f08c3bdfSopenharmony_ci		for (;;) {
442f08c3bdfSopenharmony_ci			if (!(token = next_token(f, NULL)))
443f08c3bdfSopenharmony_ci				break;
444f08c3bdfSopenharmony_ci
445f08c3bdfSopenharmony_ci			if (token[0] == '#') {
446f08c3bdfSopenharmony_ci				hash = 1;
447f08c3bdfSopenharmony_ci				continue;
448f08c3bdfSopenharmony_ci			}
449f08c3bdfSopenharmony_ci
450f08c3bdfSopenharmony_ci			if (!hash)
451f08c3bdfSopenharmony_ci				continue;
452f08c3bdfSopenharmony_ci
453f08c3bdfSopenharmony_ci			if (!strcmp(token, "include")) {
454f08c3bdfSopenharmony_ci				inc = open_include(f);
455f08c3bdfSopenharmony_ci
456f08c3bdfSopenharmony_ci				if (inc) {
457f08c3bdfSopenharmony_ci					look_for_array_size(inc, arr_id, res);
458f08c3bdfSopenharmony_ci					close_include(inc);
459f08c3bdfSopenharmony_ci				}
460f08c3bdfSopenharmony_ci			}
461f08c3bdfSopenharmony_ci
462f08c3bdfSopenharmony_ci			if (*res)
463f08c3bdfSopenharmony_ci				break;
464f08c3bdfSopenharmony_ci		}
465f08c3bdfSopenharmony_ci	}
466f08c3bdfSopenharmony_ci
467f08c3bdfSopenharmony_ci	free(arr_id);
468f08c3bdfSopenharmony_ci
469f08c3bdfSopenharmony_ci	if (fseek(f, pos, SEEK_SET))
470f08c3bdfSopenharmony_ci		return 1;
471f08c3bdfSopenharmony_ci
472f08c3bdfSopenharmony_ci	return 0;
473f08c3bdfSopenharmony_ci}
474f08c3bdfSopenharmony_ci
475f08c3bdfSopenharmony_cistatic int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *node)
476f08c3bdfSopenharmony_ci{
477f08c3bdfSopenharmony_ci	char *token;
478f08c3bdfSopenharmony_ci	char *id = NULL;
479f08c3bdfSopenharmony_ci	int state = 0;
480f08c3bdfSopenharmony_ci	struct data_node *ret;
481f08c3bdfSopenharmony_ci
482f08c3bdfSopenharmony_ci	for (;;) {
483f08c3bdfSopenharmony_ci		if (!(token = next_token(f, doc)))
484f08c3bdfSopenharmony_ci			return 1;
485f08c3bdfSopenharmony_ci
486f08c3bdfSopenharmony_ci		if (!strcmp(token, "}"))
487f08c3bdfSopenharmony_ci			return 0;
488f08c3bdfSopenharmony_ci
489f08c3bdfSopenharmony_ci		switch (state) {
490f08c3bdfSopenharmony_ci		case 0:
491f08c3bdfSopenharmony_ci			id = strdup(token);
492f08c3bdfSopenharmony_ci			state = 1;
493f08c3bdfSopenharmony_ci			continue;
494f08c3bdfSopenharmony_ci		case 1:
495f08c3bdfSopenharmony_ci			if (!strcmp(token, "="))
496f08c3bdfSopenharmony_ci				state = 2;
497f08c3bdfSopenharmony_ci			else
498f08c3bdfSopenharmony_ci				WARN("Expected '='");
499f08c3bdfSopenharmony_ci			continue;
500f08c3bdfSopenharmony_ci		case 2:
501f08c3bdfSopenharmony_ci			if (!strcmp(token, "(")) {
502f08c3bdfSopenharmony_ci				state = 3;
503f08c3bdfSopenharmony_ci				continue;
504f08c3bdfSopenharmony_ci			}
505f08c3bdfSopenharmony_ci		break;
506f08c3bdfSopenharmony_ci		case 3:
507f08c3bdfSopenharmony_ci			if (!strcmp(token, ")"))
508f08c3bdfSopenharmony_ci				state = 2;
509f08c3bdfSopenharmony_ci			continue;
510f08c3bdfSopenharmony_ci
511f08c3bdfSopenharmony_ci		case 4:
512f08c3bdfSopenharmony_ci			if (!strcmp(token, ","))
513f08c3bdfSopenharmony_ci				state = 0;
514f08c3bdfSopenharmony_ci			continue;
515f08c3bdfSopenharmony_ci		}
516f08c3bdfSopenharmony_ci
517f08c3bdfSopenharmony_ci		if (!strcmp(token, "{")) {
518f08c3bdfSopenharmony_ci			ret = data_node_array();
519f08c3bdfSopenharmony_ci			parse_array(f, ret);
520f08c3bdfSopenharmony_ci		} else if (!strcmp(token, "ARRAY_SIZE")) {
521f08c3bdfSopenharmony_ci			if (parse_array_size(f, &ret))
522f08c3bdfSopenharmony_ci				return 1;
523f08c3bdfSopenharmony_ci		} else {
524f08c3bdfSopenharmony_ci			try_apply_macro(&token);
525f08c3bdfSopenharmony_ci			ret = data_node_string(token);
526f08c3bdfSopenharmony_ci		}
527f08c3bdfSopenharmony_ci
528f08c3bdfSopenharmony_ci		if (!ret)
529f08c3bdfSopenharmony_ci			continue;
530f08c3bdfSopenharmony_ci
531f08c3bdfSopenharmony_ci		const char *key = id;
532f08c3bdfSopenharmony_ci		if (key[0] == '.')
533f08c3bdfSopenharmony_ci			key++;
534f08c3bdfSopenharmony_ci
535f08c3bdfSopenharmony_ci		data_node_hash_add(node, key, ret);
536f08c3bdfSopenharmony_ci		free(id);
537f08c3bdfSopenharmony_ci		state = 4;
538f08c3bdfSopenharmony_ci	}
539f08c3bdfSopenharmony_ci}
540f08c3bdfSopenharmony_ci
541f08c3bdfSopenharmony_cistatic const char *tokens[] = {
542f08c3bdfSopenharmony_ci	"static",
543f08c3bdfSopenharmony_ci	"struct",
544f08c3bdfSopenharmony_ci	"tst_test",
545f08c3bdfSopenharmony_ci	"test",
546f08c3bdfSopenharmony_ci	"=",
547f08c3bdfSopenharmony_ci	"{",
548f08c3bdfSopenharmony_ci};
549f08c3bdfSopenharmony_ci
550f08c3bdfSopenharmony_cistatic void macro_get_string(FILE *f, char *buf, char *buf_end)
551f08c3bdfSopenharmony_ci{
552f08c3bdfSopenharmony_ci	int c;
553f08c3bdfSopenharmony_ci	char *buf_start = buf;
554f08c3bdfSopenharmony_ci
555f08c3bdfSopenharmony_ci	for (;;) {
556f08c3bdfSopenharmony_ci		c = fgetc(f);
557f08c3bdfSopenharmony_ci
558f08c3bdfSopenharmony_ci		switch (c) {
559f08c3bdfSopenharmony_ci		case EOF:
560f08c3bdfSopenharmony_ci			*buf = 0;
561f08c3bdfSopenharmony_ci			return;
562f08c3bdfSopenharmony_ci		case '"':
563f08c3bdfSopenharmony_ci			if (buf == buf_start || buf[-1] != '\\') {
564f08c3bdfSopenharmony_ci				*buf = 0;
565f08c3bdfSopenharmony_ci				return;
566f08c3bdfSopenharmony_ci			}
567f08c3bdfSopenharmony_ci			buf[-1] = '"';
568f08c3bdfSopenharmony_ci		break;
569f08c3bdfSopenharmony_ci		default:
570f08c3bdfSopenharmony_ci			if (buf < buf_end)
571f08c3bdfSopenharmony_ci				*(buf++) = c;
572f08c3bdfSopenharmony_ci		}
573f08c3bdfSopenharmony_ci	}
574f08c3bdfSopenharmony_ci}
575f08c3bdfSopenharmony_ci
576f08c3bdfSopenharmony_cistatic void macro_get_val(FILE *f, char *buf, size_t buf_len)
577f08c3bdfSopenharmony_ci{
578f08c3bdfSopenharmony_ci	int c, prev = 0;
579f08c3bdfSopenharmony_ci	char *buf_end = buf + buf_len - 1;
580f08c3bdfSopenharmony_ci
581f08c3bdfSopenharmony_ci	while (isspace(c = fgetc(f)));
582f08c3bdfSopenharmony_ci
583f08c3bdfSopenharmony_ci	if (c == '"') {
584f08c3bdfSopenharmony_ci		macro_get_string(f, buf, buf_end);
585f08c3bdfSopenharmony_ci		return;
586f08c3bdfSopenharmony_ci	}
587f08c3bdfSopenharmony_ci
588f08c3bdfSopenharmony_ci	for (;;) {
589f08c3bdfSopenharmony_ci		switch (c) {
590f08c3bdfSopenharmony_ci		case '\n':
591f08c3bdfSopenharmony_ci			if (prev == '\\') {
592f08c3bdfSopenharmony_ci				buf--;
593f08c3bdfSopenharmony_ci			} else {
594f08c3bdfSopenharmony_ci				*buf = 0;
595f08c3bdfSopenharmony_ci				return;
596f08c3bdfSopenharmony_ci			}
597f08c3bdfSopenharmony_ci		break;
598f08c3bdfSopenharmony_ci		case EOF:
599f08c3bdfSopenharmony_ci			*buf = 0;
600f08c3bdfSopenharmony_ci			return;
601f08c3bdfSopenharmony_ci		case ' ':
602f08c3bdfSopenharmony_ci		case '\t':
603f08c3bdfSopenharmony_ci		break;
604f08c3bdfSopenharmony_ci		default:
605f08c3bdfSopenharmony_ci			if (buf < buf_end)
606f08c3bdfSopenharmony_ci				*(buf++) = c;
607f08c3bdfSopenharmony_ci		}
608f08c3bdfSopenharmony_ci
609f08c3bdfSopenharmony_ci		prev = c;
610f08c3bdfSopenharmony_ci		c = fgetc(f);
611f08c3bdfSopenharmony_ci	}
612f08c3bdfSopenharmony_ci}
613f08c3bdfSopenharmony_ci
614f08c3bdfSopenharmony_cistatic void parse_macro(FILE *f)
615f08c3bdfSopenharmony_ci{
616f08c3bdfSopenharmony_ci	char name[128];
617f08c3bdfSopenharmony_ci	char val[256];
618f08c3bdfSopenharmony_ci
619f08c3bdfSopenharmony_ci	if (!fscanf(f, "%s[^\n]", name))
620f08c3bdfSopenharmony_ci		return;
621f08c3bdfSopenharmony_ci
622f08c3bdfSopenharmony_ci	if (fgetc(f) == '\n')
623f08c3bdfSopenharmony_ci		return;
624f08c3bdfSopenharmony_ci
625f08c3bdfSopenharmony_ci	macro_get_val(f, val, sizeof(val));
626f08c3bdfSopenharmony_ci
627f08c3bdfSopenharmony_ci	if (name[0] == '_')
628f08c3bdfSopenharmony_ci		return;
629f08c3bdfSopenharmony_ci
630f08c3bdfSopenharmony_ci	ENTRY e = {
631f08c3bdfSopenharmony_ci		.key = strdup(name),
632f08c3bdfSopenharmony_ci		.data = strdup(val),
633f08c3bdfSopenharmony_ci	};
634f08c3bdfSopenharmony_ci
635f08c3bdfSopenharmony_ci	if (verbose)
636f08c3bdfSopenharmony_ci		fprintf(stderr, " MACRO %s=%s\n", e.key, (char*)e.data);
637f08c3bdfSopenharmony_ci
638f08c3bdfSopenharmony_ci	hsearch(e, ENTER);
639f08c3bdfSopenharmony_ci}
640f08c3bdfSopenharmony_ci
641f08c3bdfSopenharmony_cistatic void parse_include_macros(FILE *f)
642f08c3bdfSopenharmony_ci{
643f08c3bdfSopenharmony_ci	FILE *inc;
644f08c3bdfSopenharmony_ci	const char *token;
645f08c3bdfSopenharmony_ci	int hash = 0;
646f08c3bdfSopenharmony_ci
647f08c3bdfSopenharmony_ci	inc = open_include(f);
648f08c3bdfSopenharmony_ci	if (!inc)
649f08c3bdfSopenharmony_ci		return;
650f08c3bdfSopenharmony_ci
651f08c3bdfSopenharmony_ci	while ((token = next_token(inc, NULL))) {
652f08c3bdfSopenharmony_ci		if (token[0] == '#') {
653f08c3bdfSopenharmony_ci			hash = 1;
654f08c3bdfSopenharmony_ci			continue;
655f08c3bdfSopenharmony_ci		}
656f08c3bdfSopenharmony_ci
657f08c3bdfSopenharmony_ci		if (!hash)
658f08c3bdfSopenharmony_ci			continue;
659f08c3bdfSopenharmony_ci
660f08c3bdfSopenharmony_ci		if (!strcmp(token, "define"))
661f08c3bdfSopenharmony_ci			parse_macro(inc);
662f08c3bdfSopenharmony_ci
663f08c3bdfSopenharmony_ci		hash = 0;
664f08c3bdfSopenharmony_ci	}
665f08c3bdfSopenharmony_ci
666f08c3bdfSopenharmony_ci	close_include(inc);
667f08c3bdfSopenharmony_ci}
668f08c3bdfSopenharmony_ci
669f08c3bdfSopenharmony_cistatic struct data_node *parse_file(const char *fname)
670f08c3bdfSopenharmony_ci{
671f08c3bdfSopenharmony_ci	int state = 0, found = 0;
672f08c3bdfSopenharmony_ci	const char *token;
673f08c3bdfSopenharmony_ci
674f08c3bdfSopenharmony_ci	if (access(fname, F_OK)) {
675f08c3bdfSopenharmony_ci		fprintf(stderr, "file %s does not exist\n", fname);
676f08c3bdfSopenharmony_ci		return NULL;
677f08c3bdfSopenharmony_ci	}
678f08c3bdfSopenharmony_ci
679f08c3bdfSopenharmony_ci	FILE *f = fopen(fname, "r");
680f08c3bdfSopenharmony_ci
681f08c3bdfSopenharmony_ci	includepath = dirname(strdup(fname));
682f08c3bdfSopenharmony_ci
683f08c3bdfSopenharmony_ci	struct data_node *res = data_node_hash();
684f08c3bdfSopenharmony_ci	struct data_node *doc = data_node_array();
685f08c3bdfSopenharmony_ci
686f08c3bdfSopenharmony_ci	while ((token = next_token(f, doc))) {
687f08c3bdfSopenharmony_ci		if (state < 6 && !strcmp(tokens[state], token)) {
688f08c3bdfSopenharmony_ci			state++;
689f08c3bdfSopenharmony_ci		} else {
690f08c3bdfSopenharmony_ci			if (token[0] == '#') {
691f08c3bdfSopenharmony_ci				token = next_token(f, doc);
692f08c3bdfSopenharmony_ci				if (token) {
693f08c3bdfSopenharmony_ci					if (!strcmp(token, "define"))
694f08c3bdfSopenharmony_ci						parse_macro(f);
695f08c3bdfSopenharmony_ci
696f08c3bdfSopenharmony_ci					if (!strcmp(token, "include"))
697f08c3bdfSopenharmony_ci						parse_include_macros(f);
698f08c3bdfSopenharmony_ci				}
699f08c3bdfSopenharmony_ci			}
700f08c3bdfSopenharmony_ci
701f08c3bdfSopenharmony_ci			state = 0;
702f08c3bdfSopenharmony_ci		}
703f08c3bdfSopenharmony_ci
704f08c3bdfSopenharmony_ci		if (state < 6)
705f08c3bdfSopenharmony_ci			continue;
706f08c3bdfSopenharmony_ci
707f08c3bdfSopenharmony_ci		found = 1;
708f08c3bdfSopenharmony_ci		parse_test_struct(f, doc, res);
709f08c3bdfSopenharmony_ci	}
710f08c3bdfSopenharmony_ci
711f08c3bdfSopenharmony_ci	if (data_node_array_len(doc)) {
712f08c3bdfSopenharmony_ci		data_node_hash_add(res, "doc", doc);
713f08c3bdfSopenharmony_ci		found = 1;
714f08c3bdfSopenharmony_ci	} else {
715f08c3bdfSopenharmony_ci		data_node_free(doc);
716f08c3bdfSopenharmony_ci	}
717f08c3bdfSopenharmony_ci
718f08c3bdfSopenharmony_ci	fclose(f);
719f08c3bdfSopenharmony_ci
720f08c3bdfSopenharmony_ci	if (!found) {
721f08c3bdfSopenharmony_ci		data_node_free(res);
722f08c3bdfSopenharmony_ci		return NULL;
723f08c3bdfSopenharmony_ci	}
724f08c3bdfSopenharmony_ci
725f08c3bdfSopenharmony_ci	return res;
726f08c3bdfSopenharmony_ci}
727f08c3bdfSopenharmony_ci
728f08c3bdfSopenharmony_cistatic struct typemap {
729f08c3bdfSopenharmony_ci	const char *id;
730f08c3bdfSopenharmony_ci	enum data_type type;
731f08c3bdfSopenharmony_ci} tst_test_typemap[] = {
732f08c3bdfSopenharmony_ci	{.id = "test_variants", .type = DATA_INT},
733f08c3bdfSopenharmony_ci	{}
734f08c3bdfSopenharmony_ci};
735f08c3bdfSopenharmony_ci
736f08c3bdfSopenharmony_cistatic void convert_str2int(struct data_node *res, const char *id, const char *str_val)
737f08c3bdfSopenharmony_ci{
738f08c3bdfSopenharmony_ci	long val;
739f08c3bdfSopenharmony_ci	char *endptr;
740f08c3bdfSopenharmony_ci
741f08c3bdfSopenharmony_ci	errno = 0;
742f08c3bdfSopenharmony_ci	val = strtol(str_val, &endptr, 10);
743f08c3bdfSopenharmony_ci
744f08c3bdfSopenharmony_ci	if (errno || *endptr) {
745f08c3bdfSopenharmony_ci		fprintf(stderr,	"Cannot convert %s value %s to int!\n", id, str_val);
746f08c3bdfSopenharmony_ci		exit(1);
747f08c3bdfSopenharmony_ci	}
748f08c3bdfSopenharmony_ci
749f08c3bdfSopenharmony_ci	if (verbose)
750f08c3bdfSopenharmony_ci		fprintf(stderr, "NORMALIZING %s TO INT %li\n", id, val);
751f08c3bdfSopenharmony_ci
752f08c3bdfSopenharmony_ci	data_node_hash_del(res, id);
753f08c3bdfSopenharmony_ci	data_node_hash_add(res, id, data_node_int(val));
754f08c3bdfSopenharmony_ci}
755f08c3bdfSopenharmony_ci
756f08c3bdfSopenharmony_cistatic void check_normalize_types(struct data_node *res)
757f08c3bdfSopenharmony_ci{
758f08c3bdfSopenharmony_ci	unsigned int i;
759f08c3bdfSopenharmony_ci
760f08c3bdfSopenharmony_ci	for (i = 0; tst_test_typemap[i].id; i++) {
761f08c3bdfSopenharmony_ci		struct data_node *n;
762f08c3bdfSopenharmony_ci		struct typemap *typemap = &tst_test_typemap[i];
763f08c3bdfSopenharmony_ci
764f08c3bdfSopenharmony_ci		n = data_node_hash_get(res, typemap->id);
765f08c3bdfSopenharmony_ci		if (!n)
766f08c3bdfSopenharmony_ci			continue;
767f08c3bdfSopenharmony_ci
768f08c3bdfSopenharmony_ci		if (n->type == typemap->type)
769f08c3bdfSopenharmony_ci			continue;
770f08c3bdfSopenharmony_ci
771f08c3bdfSopenharmony_ci		if (n->type == DATA_STRING && typemap->type == DATA_INT) {
772f08c3bdfSopenharmony_ci			convert_str2int(res, typemap->id, n->string.val);
773f08c3bdfSopenharmony_ci			continue;
774f08c3bdfSopenharmony_ci		}
775f08c3bdfSopenharmony_ci
776f08c3bdfSopenharmony_ci		fprintf(stderr, "Cannot convert %s from %s to %s!\n",
777f08c3bdfSopenharmony_ci			typemap->id, data_type_name(n->type),
778f08c3bdfSopenharmony_ci			data_type_name(typemap->type));
779f08c3bdfSopenharmony_ci		exit(1);
780f08c3bdfSopenharmony_ci	}
781f08c3bdfSopenharmony_ci}
782f08c3bdfSopenharmony_ci
783f08c3bdfSopenharmony_cistatic const char *filter_out[] = {
784f08c3bdfSopenharmony_ci	"bufs",
785f08c3bdfSopenharmony_ci	"cleanup",
786f08c3bdfSopenharmony_ci	"mntpoint",
787f08c3bdfSopenharmony_ci	"setup",
788f08c3bdfSopenharmony_ci	"tcnt",
789f08c3bdfSopenharmony_ci	"test",
790f08c3bdfSopenharmony_ci	"test_all",
791f08c3bdfSopenharmony_ci	NULL
792f08c3bdfSopenharmony_ci};
793f08c3bdfSopenharmony_ci
794f08c3bdfSopenharmony_cistatic struct implies {
795f08c3bdfSopenharmony_ci	const char *flag;
796f08c3bdfSopenharmony_ci	const char **implies;
797f08c3bdfSopenharmony_ci} implies[] = {
798f08c3bdfSopenharmony_ci	{"mount_device", (const char *[]) {"format_device", "needs_device",
799f08c3bdfSopenharmony_ci		"needs_tmpdir", NULL}},
800f08c3bdfSopenharmony_ci	{"format_device", (const char *[]) {"needs_device", "needs_tmpdir",
801f08c3bdfSopenharmony_ci		NULL}},
802f08c3bdfSopenharmony_ci	{"all_filesystems", (const char *[]) {"needs_device", "needs_tmpdir",
803f08c3bdfSopenharmony_ci		NULL}},
804f08c3bdfSopenharmony_ci	{"needs_device", (const char *[]) {"needs_tmpdir", NULL}},
805f08c3bdfSopenharmony_ci	{"needs_checkpoints", (const char *[]) {"needs_tmpdir", NULL}},
806f08c3bdfSopenharmony_ci	{"resource_files", (const char *[]) {"needs_tmpdir", NULL}},
807f08c3bdfSopenharmony_ci	{NULL, (const char *[]) {NULL}}
808f08c3bdfSopenharmony_ci};
809f08c3bdfSopenharmony_ci
810f08c3bdfSopenharmony_ciconst char *strip_name(char *path)
811f08c3bdfSopenharmony_ci{
812f08c3bdfSopenharmony_ci	char *name = basename(path);
813f08c3bdfSopenharmony_ci	size_t len = strlen(name);
814f08c3bdfSopenharmony_ci
815f08c3bdfSopenharmony_ci	if (len > 2 && name[len-1] == 'c' && name[len-2] == '.')
816f08c3bdfSopenharmony_ci		name[len-2] = '\0';
817f08c3bdfSopenharmony_ci
818f08c3bdfSopenharmony_ci	return name;
819f08c3bdfSopenharmony_ci}
820f08c3bdfSopenharmony_ci
821f08c3bdfSopenharmony_cistatic void print_help(const char *prgname)
822f08c3bdfSopenharmony_ci{
823f08c3bdfSopenharmony_ci	printf("usage: %s [-vh] input.c\n\n", prgname);
824f08c3bdfSopenharmony_ci	printf("-v sets verbose mode\n");
825f08c3bdfSopenharmony_ci	printf("-I add include path\n");
826f08c3bdfSopenharmony_ci	printf("-h prints this help\n\n");
827f08c3bdfSopenharmony_ci	exit(0);
828f08c3bdfSopenharmony_ci}
829f08c3bdfSopenharmony_ci
830f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
831f08c3bdfSopenharmony_ci{
832f08c3bdfSopenharmony_ci	unsigned int i, j;
833f08c3bdfSopenharmony_ci	struct data_node *res;
834f08c3bdfSopenharmony_ci	int opt;
835f08c3bdfSopenharmony_ci
836f08c3bdfSopenharmony_ci	while ((opt = getopt(argc, argv, "hI:v")) != -1) {
837f08c3bdfSopenharmony_ci		switch (opt) {
838f08c3bdfSopenharmony_ci		case 'h':
839f08c3bdfSopenharmony_ci			print_help(argv[0]);
840f08c3bdfSopenharmony_ci		break;
841f08c3bdfSopenharmony_ci		case 'I':
842f08c3bdfSopenharmony_ci			if (cmdline_includepaths >= INCLUDE_PATH_MAX) {
843f08c3bdfSopenharmony_ci				fprintf(stderr, "Too much include paths!");
844f08c3bdfSopenharmony_ci				exit(1);
845f08c3bdfSopenharmony_ci			}
846f08c3bdfSopenharmony_ci
847f08c3bdfSopenharmony_ci			cmdline_includepath[cmdline_includepaths++] = optarg;
848f08c3bdfSopenharmony_ci		break;
849f08c3bdfSopenharmony_ci		case 'v':
850f08c3bdfSopenharmony_ci			verbose = 1;
851f08c3bdfSopenharmony_ci		break;
852f08c3bdfSopenharmony_ci		}
853f08c3bdfSopenharmony_ci	}
854f08c3bdfSopenharmony_ci
855f08c3bdfSopenharmony_ci	if (optind >= argc) {
856f08c3bdfSopenharmony_ci		fprintf(stderr, "No input filename.c\n");
857f08c3bdfSopenharmony_ci		return 1;
858f08c3bdfSopenharmony_ci	}
859f08c3bdfSopenharmony_ci
860f08c3bdfSopenharmony_ci	if (!hcreate(128)) {
861f08c3bdfSopenharmony_ci		fprintf(stderr, "Failed to initialize hash table\n");
862f08c3bdfSopenharmony_ci		return 1;
863f08c3bdfSopenharmony_ci	}
864f08c3bdfSopenharmony_ci
865f08c3bdfSopenharmony_ci	res = parse_file(argv[optind]);
866f08c3bdfSopenharmony_ci	if (!res)
867f08c3bdfSopenharmony_ci		return 0;
868f08c3bdfSopenharmony_ci
869f08c3bdfSopenharmony_ci	/* Filter out useless data */
870f08c3bdfSopenharmony_ci	for (i = 0; filter_out[i]; i++)
871f08c3bdfSopenharmony_ci		data_node_hash_del(res, filter_out[i]);
872f08c3bdfSopenharmony_ci
873f08c3bdfSopenharmony_ci	/* Normalize the result */
874f08c3bdfSopenharmony_ci	for (i = 0; implies[i].flag; i++) {
875f08c3bdfSopenharmony_ci		if (data_node_hash_get(res, implies[i].flag)) {
876f08c3bdfSopenharmony_ci			for (j = 0; implies[i].implies[j]; j++) {
877f08c3bdfSopenharmony_ci				if (data_node_hash_get(res, implies[i].implies[j]))
878f08c3bdfSopenharmony_ci					fprintf(stderr, "%s: useless tag: %s\n",
879f08c3bdfSopenharmony_ci						argv[optind], implies[i].implies[j]);
880f08c3bdfSopenharmony_ci			}
881f08c3bdfSopenharmony_ci		}
882f08c3bdfSopenharmony_ci	}
883f08c3bdfSopenharmony_ci
884f08c3bdfSopenharmony_ci	/* Normalize types */
885f08c3bdfSopenharmony_ci	check_normalize_types(res);
886f08c3bdfSopenharmony_ci
887f08c3bdfSopenharmony_ci	for (i = 0; implies[i].flag; i++) {
888f08c3bdfSopenharmony_ci		if (data_node_hash_get(res, implies[i].flag)) {
889f08c3bdfSopenharmony_ci			for (j = 0; implies[i].implies[j]; j++) {
890f08c3bdfSopenharmony_ci				if (!data_node_hash_get(res, implies[i].implies[j]))
891f08c3bdfSopenharmony_ci					data_node_hash_add(res, implies[i].implies[j],
892f08c3bdfSopenharmony_ci							   data_node_string("1"));
893f08c3bdfSopenharmony_ci			}
894f08c3bdfSopenharmony_ci		}
895f08c3bdfSopenharmony_ci	}
896f08c3bdfSopenharmony_ci
897f08c3bdfSopenharmony_ci	data_node_hash_add(res, "fname", data_node_string(argv[optind]));
898f08c3bdfSopenharmony_ci	printf("  \"%s\": ", strip_name(argv[optind]));
899f08c3bdfSopenharmony_ci	data_to_json(res, stdout, 2);
900f08c3bdfSopenharmony_ci	data_node_free(res);
901f08c3bdfSopenharmony_ci
902f08c3bdfSopenharmony_ci	return 0;
903f08c3bdfSopenharmony_ci}
904