xref: /illumos-gate/usr/src/tools/smatch/src/ctags.c (revision c85f09cc)
1 /*
2  * Sparse Ctags
3  *
4  * Ctags generates tags from preprocessing results.
5  *
6  * Copyright (C) 2006 Christopher Li
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 
32 #include "parse.h"
33 #include "scope.h"
34 
35 static struct symbol_list *taglist = NULL;
36 
37 static void examine_symbol(struct symbol *sym);
38 
39 #define MAX(_x,_y) ((_x) > (_y) ? (_x) : (_y))
40 
cmp_sym(const void * m,const void * n)41 static int cmp_sym(const void *m, const void *n)
42 {
43 	const struct ident *a = ((const struct symbol *)m)->ident;
44 	const struct ident *b = ((const struct symbol *)n)->ident;
45 	int ret = strncmp(a->name, b->name, MAX(a->len, b->len));
46 	if (!ret) {
47 		const struct position a_pos = ((const struct symbol *)m)->pos;
48 		const struct position b_pos = ((const struct symbol *)n)->pos;
49 
50 		ret = strcmp(stream_name(a_pos.stream),
51 		             stream_name(b_pos.stream));
52 		if (!ret)
53 			return a_pos.line < b_pos.line;
54 	}
55 	return ret;
56 }
57 
show_tag_header(FILE * fp)58 static void show_tag_header(FILE *fp)
59 {
60 	fprintf(fp, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n");
61 	fprintf(fp, "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n");
62 	fprintf(fp, "!_TAG_PROGRAM_AUTHOR\tChristopher Li\t/sparse@chrisli.org/\n");
63 	fprintf(fp, "!_TAG_PROGRAM_NAME\tSparse Ctags\t//\n");
64 	fprintf(fp, "!_TAG_PROGRAM_URL\thttp://www.kernel.org/pub/software/devel/sparse/\t/official site/\n");
65 	fprintf(fp, "!_TAG_PROGRAM_VERSION\t0.01\t//\n");
66 }
67 
show_symbol_tag(FILE * fp,struct symbol * sym)68 static inline void show_symbol_tag(FILE *fp, struct symbol *sym)
69 {
70 	fprintf(fp, "%s\t%s\t%d;\"\t%c\tfile:\n", show_ident(sym->ident),
71 	       stream_name(sym->pos.stream), sym->pos.line, (int)sym->kind);
72 }
73 
show_tags(struct symbol_list * list)74 static void show_tags(struct symbol_list *list)
75 {
76 	struct symbol *sym;
77 	struct ident *ident = NULL;
78 	struct position pos = {};
79 	static const char *filename;
80 	FILE *fp;
81 
82 	if (!list)
83 		return;
84 
85 	fp = fopen("tags", "w");
86 	if (!fp) {
87 		perror("open tags file");
88 		return;
89 	}
90 	show_tag_header(fp);
91 	FOR_EACH_PTR(list, sym) {
92 		if (ident == sym->ident && pos.line == sym->pos.line &&
93 		    !strcmp(filename, stream_name(sym->pos.stream)))
94 			continue;
95 
96 		show_symbol_tag(fp, sym);
97 		ident = sym->ident;
98 		pos = sym->pos;
99 		filename = stream_name(sym->pos.stream);
100 	} END_FOR_EACH_PTR(sym);
101 	fclose(fp);
102 }
103 
add_tag(struct symbol * sym)104 static inline void add_tag(struct symbol *sym)
105 {
106 	if (sym->ident && !sym->visited) {
107 		sym->visited = 1;
108 		add_symbol(&taglist, sym);
109 	}
110 }
111 
examine_members(struct symbol_list * list)112 static inline void examine_members(struct symbol_list *list)
113 {
114 	struct symbol *sym;
115 
116 	FOR_EACH_PTR(list, sym) {
117 		sym->kind = 'm';
118 		examine_symbol(sym);
119 	} END_FOR_EACH_PTR(sym);
120 }
121 
examine_symbol(struct symbol * sym)122 static void examine_symbol(struct symbol *sym)
123 {
124 	struct symbol *base = sym;
125 
126 	if (!sym || sym->visited)
127 		return;
128 	if (sym->ident && sym->ident->reserved)
129 		return;
130 	if (sym->type == SYM_KEYWORD || sym->type == SYM_PREPROCESSOR)
131 		return;
132 
133 	add_tag(sym);
134 	base = sym->ctype.base_type;
135 
136 	switch (sym->type) {
137 	case SYM_NODE:
138 		if (base && base->type == SYM_FN)
139 			sym->kind = 'f';
140 		examine_symbol(base);
141 		break;
142 	case SYM_STRUCT:
143 		sym->kind = 's';
144 		examine_members(sym->symbol_list);
145 		break;
146 	case SYM_UNION:
147 		sym->kind = 'u';
148 		examine_members(sym->symbol_list);
149 		break;
150 	case SYM_ENUM:
151 		sym->kind = 'e';
152 	case SYM_PTR:
153 	case SYM_TYPEOF:
154 	case SYM_BITFIELD:
155 	case SYM_FN:
156 	case SYM_ARRAY:
157 		examine_symbol(sym->ctype.base_type);
158 		break;
159 	case SYM_BASETYPE:
160 		break;
161 
162 	default:
163 		die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident),
164 		    sym->namespace, sym->type);
165 	}
166 	if (!sym->kind)
167 		sym->kind = 'v';
168 	return;
169 }
170 
examine_namespace(struct symbol * sym)171 static void examine_namespace(struct symbol *sym)
172 {
173 	if (sym->visited)
174 		return;
175 	if (sym->ident && sym->ident->reserved)
176 		return;
177 
178 	switch(sym->namespace) {
179 	case NS_KEYWORD:
180 	case NS_PREPROCESSOR:
181 		return;
182 	case NS_LABEL:
183 		sym->kind = 'l';
184 		break;
185 	case NS_MACRO:
186 	case NS_UNDEF:
187 		sym->kind = 'd';
188 		break;
189 	case NS_TYPEDEF:
190 		sym->kind = 't';
191 	case NS_SYMBOL:
192 	case NS_STRUCT:
193 		examine_symbol(sym);
194 		break;
195 	default:
196 		die("unknown namespace %d symbol:%s type:%d\n", sym->namespace,
197 		    show_ident(sym->ident), sym->type);
198 	}
199 	add_tag(sym);
200 }
201 
examine_symbol_list(struct symbol_list * list)202 static inline void examine_symbol_list(struct symbol_list *list)
203 {
204 	struct symbol *sym;
205 
206 	if (!list)
207 		return;
208 	FOR_EACH_PTR(list, sym) {
209 		examine_namespace(sym);
210 	} END_FOR_EACH_PTR(sym);
211 }
212 
main(int argc,char ** argv)213 int main(int argc, char **argv)
214 {
215 	struct string_list *filelist = NULL;
216 	char *file;
217 
218 	examine_symbol_list(sparse_initialize(argc, argv, &filelist));
219 	FOR_EACH_PTR(filelist, file) {
220 		sparse(file);
221 		examine_symbol_list(file_scope->symbols);
222 	} END_FOR_EACH_PTR(file);
223 	examine_symbol_list(global_scope->symbols);
224 	sort_list((struct ptr_list **)&taglist, cmp_sym);
225 	show_tags(taglist);
226 	return 0;
227 }
228