1/*
2 * Sparse c2xml
3 *
4 * Dumps the parse tree as an xml document
5 *
6 * Copyright (C) 2007 Rob Taylor
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <assert.h>
32#include <libxml/parser.h>
33#include <libxml/tree.h>
34
35#include "expression.h"
36#include "parse.h"
37#include "scope.h"
38#include "symbol.h"
39
40static xmlDocPtr doc = NULL;       /* document pointer */
41static xmlNodePtr root_node = NULL;/* root node pointer */
42static int idcount = 0;
43
44static void examine_symbol(struct symbol *sym, xmlNodePtr node);
45
46static xmlAttrPtr newProp(xmlNodePtr node, const char *name, const char *value)
47{
48	return xmlNewProp(node, BAD_CAST name, BAD_CAST value);
49}
50
51static xmlAttrPtr newNumProp(xmlNodePtr node, const char *name, int value)
52{
53	char buf[256];
54	snprintf(buf, 256, "%d", value);
55	return newProp(node, name, buf);
56}
57
58static xmlAttrPtr newIdProp(xmlNodePtr node, const char *name, unsigned int id)
59{
60	char buf[256];
61	snprintf(buf, 256, "_%d", id);
62	return newProp(node, name, buf);
63}
64
65static xmlNodePtr new_sym_node(struct symbol *sym, const char *name, xmlNodePtr parent)
66{
67	xmlNodePtr node;
68	const char *ident = show_ident(sym->ident);
69
70	assert(name != NULL);
71	assert(sym != NULL);
72	assert(parent != NULL);
73
74	node = xmlNewChild(parent, NULL, BAD_CAST "symbol", NULL);
75
76	newProp(node, "type", name);
77
78	newIdProp(node, "id", idcount);
79
80	if (sym->ident && ident)
81		newProp(node, "ident", ident);
82	newProp(node, "file", stream_name(sym->pos.stream));
83
84	newNumProp(node, "start-line", sym->pos.line);
85	newNumProp(node, "start-col", sym->pos.pos);
86
87	if (sym->endpos.type) {
88		newNumProp(node, "end-line", sym->endpos.line);
89		newNumProp(node, "end-col", sym->endpos.pos);
90		if (sym->pos.stream != sym->endpos.stream)
91			newProp(node, "end-file", stream_name(sym->endpos.stream));
92        }
93	sym->aux = node;
94
95	idcount++;
96
97	return node;
98}
99
100static inline void examine_members(struct symbol_list *list, xmlNodePtr node)
101{
102	struct symbol *sym;
103
104	FOR_EACH_PTR(list, sym) {
105		examine_symbol(sym, node);
106	} END_FOR_EACH_PTR(sym);
107}
108
109static void examine_modifiers(struct symbol *sym, xmlNodePtr node)
110{
111	const char *modifiers[] = {
112			"auto",
113			"register",
114			"static",
115			"extern",
116			"const",
117			"volatile",
118			"signed",
119			"unsigned",
120			"char",
121			"short",
122			"long",
123			"long-long",
124			"typedef",
125			NULL,
126			NULL,
127			NULL,
128			NULL,
129			NULL,
130			"inline",
131			"addressable",
132			"nocast",
133			"noderef",
134			"accessed",
135			"toplevel",
136			"label",
137			"assigned",
138			"type-type",
139			"safe",
140			"user-type",
141			"force",
142			"explicitly-signed",
143			"bitwise"};
144
145	int i;
146
147	if (sym->namespace != NS_SYMBOL)
148		return;
149
150	/*iterate over the 32 bit bitfield*/
151	for (i=0; i < 32; i++) {
152		if ((sym->ctype.modifiers & 1<<i) && modifiers[i])
153			newProp(node, modifiers[i], "1");
154	}
155}
156
157static void
158examine_layout(struct symbol *sym, xmlNodePtr node)
159{
160	examine_symbol_type(sym);
161
162	newNumProp(node, "bit-size", sym->bit_size);
163	newNumProp(node, "alignment", sym->ctype.alignment);
164	newNumProp(node, "offset", sym->offset);
165	if (is_bitfield_type(sym)) {
166		newNumProp(node, "bit-offset", sym->bit_offset);
167	}
168}
169
170static void examine_symbol(struct symbol *sym, xmlNodePtr node)
171{
172	xmlNodePtr child = NULL;
173	const char *base;
174	int array_size;
175
176	if (!sym)
177		return;
178	if (sym->aux)		/*already visited */
179		return;
180
181	if (sym->ident && sym->ident->reserved)
182		return;
183
184	child = new_sym_node(sym, get_type_name(sym->type), node);
185	examine_modifiers(sym, child);
186	examine_layout(sym, child);
187
188	if (sym->ctype.base_type) {
189		if ((base = builtin_typename(sym->ctype.base_type)) == NULL) {
190			if (!sym->ctype.base_type->aux) {
191				examine_symbol(sym->ctype.base_type, root_node);
192			}
193			xmlNewProp(child, BAD_CAST "base-type",
194			           xmlGetProp((xmlNodePtr)sym->ctype.base_type->aux, BAD_CAST "id"));
195		} else {
196			newProp(child, "base-type-builtin", base);
197		}
198	}
199	if (sym->array_size) {
200		/* TODO: modify get_expression_value to give error return */
201		array_size = get_expression_value(sym->array_size);
202		newNumProp(child, "array-size", array_size);
203	}
204
205
206	switch (sym->type) {
207	case SYM_STRUCT:
208	case SYM_UNION:
209		examine_members(sym->symbol_list, child);
210		break;
211	case SYM_FN:
212		examine_members(sym->arguments, child);
213		break;
214	case SYM_UNINITIALIZED:
215		newProp(child, "base-type-builtin", builtin_typename(sym));
216		break;
217	default:
218		break;
219	}
220	return;
221}
222
223static struct position *get_expansion_end (struct token *token)
224{
225	struct token *p1, *p2;
226
227	for (p1=NULL, p2=NULL;
228	     !eof_token(token);
229	     p2 = p1, p1 = token, token = token->next);
230
231	if (p2)
232		return &(p2->pos);
233	else
234		return NULL;
235}
236
237static void examine_macro(struct symbol *sym, xmlNodePtr node)
238{
239	struct position *pos;
240
241	/* this should probably go in the main codebase*/
242	pos = get_expansion_end(sym->expansion);
243	if (pos)
244		sym->endpos = *pos;
245	else
246		sym->endpos = sym->pos;
247
248	new_sym_node(sym, "macro", node);
249}
250
251static void examine_namespace(struct symbol *sym)
252{
253	if (sym->ident && sym->ident->reserved)
254		return;
255
256	switch(sym->namespace) {
257	case NS_MACRO:
258		examine_macro(sym, root_node);
259		break;
260	case NS_TYPEDEF:
261	case NS_STRUCT:
262	case NS_SYMBOL:
263		examine_symbol(sym, root_node);
264		break;
265	case NS_NONE:
266	case NS_LABEL:
267	case NS_ITERATOR:
268	case NS_UNDEF:
269	case NS_PREPROCESSOR:
270	case NS_KEYWORD:
271		break;
272	default:
273		die("Unrecognised namespace type %d",sym->namespace);
274	}
275
276}
277
278static int get_stream_id (const char *name)
279{
280	int i;
281	for (i=0; i<input_stream_nr; i++) {
282		if (strcmp(name, stream_name(i))==0)
283			return i;
284	}
285	return -1;
286}
287
288static inline void examine_symbol_list(const char *file, struct symbol_list *list)
289{
290	struct symbol *sym;
291	int stream_id = get_stream_id (file);
292
293	if (!list)
294		return;
295	FOR_EACH_PTR(list, sym) {
296		if (sym->pos.stream == stream_id)
297			examine_namespace(sym);
298	} END_FOR_EACH_PTR(sym);
299}
300
301int main(int argc, char **argv)
302{
303	struct string_list *filelist = NULL;
304	struct symbol_list *symlist = NULL;
305	char *file;
306
307	doc = xmlNewDoc(BAD_CAST "1.0");
308	root_node = xmlNewNode(NULL, BAD_CAST "parse");
309	xmlDocSetRootElement(doc, root_node);
310
311/* - A DTD is probably unnecessary for something like this
312
313	dtd = xmlCreateIntSubset(doc, "parse", "http://www.kernel.org/pub/software/devel/sparse/parse.dtd" NULL, "parse.dtd");
314
315	ns = xmlNewNs (root_node, "http://www.kernel.org/pub/software/devel/sparse/parse.dtd", NULL);
316
317	xmlSetNs(root_node, ns);
318*/
319	symlist = sparse_initialize(argc, argv, &filelist);
320
321	FOR_EACH_PTR(filelist, file) {
322		examine_symbol_list(file, symlist);
323		sparse_keep_tokens(file);
324		examine_symbol_list(file, file_scope->symbols);
325		examine_symbol_list(file, global_scope->symbols);
326	} END_FOR_EACH_PTR(file);
327
328
329	xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
330	xmlFreeDoc(doc);
331	xmlCleanupParser();
332
333	return 0;
334}
335