xref: /illumos-gate/usr/src/tools/smatch/src/ctags.c (revision c85f09cc)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Sparse Ctags
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * Ctags generates tags from preprocessing results.
51f5207b7SJohn Levon  *
61f5207b7SJohn Levon  * Copyright (C) 2006 Christopher Li
71f5207b7SJohn Levon  *
81f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
91f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
101f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
111f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
121f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
131f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
141f5207b7SJohn Levon  *
151f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
161f5207b7SJohn Levon  * all copies or substantial portions of the Software.
171f5207b7SJohn Levon  *
181f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
191f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
201f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
211f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
231f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
241f5207b7SJohn Levon  * THE SOFTWARE.
251f5207b7SJohn Levon  */
261f5207b7SJohn Levon #include <stdlib.h>
271f5207b7SJohn Levon #include <stdio.h>
281f5207b7SJohn Levon #include <string.h>
291f5207b7SJohn Levon #include <unistd.h>
301f5207b7SJohn Levon #include <fcntl.h>
311f5207b7SJohn Levon 
321f5207b7SJohn Levon #include "parse.h"
331f5207b7SJohn Levon #include "scope.h"
341f5207b7SJohn Levon 
351f5207b7SJohn Levon static struct symbol_list *taglist = NULL;
361f5207b7SJohn Levon 
371f5207b7SJohn Levon static void examine_symbol(struct symbol *sym);
381f5207b7SJohn Levon 
391f5207b7SJohn Levon #define MAX(_x,_y) ((_x) > (_y) ? (_x) : (_y))
401f5207b7SJohn Levon 
cmp_sym(const void * m,const void * n)411f5207b7SJohn Levon static int cmp_sym(const void *m, const void *n)
421f5207b7SJohn Levon {
431f5207b7SJohn Levon 	const struct ident *a = ((const struct symbol *)m)->ident;
441f5207b7SJohn Levon 	const struct ident *b = ((const struct symbol *)n)->ident;
451f5207b7SJohn Levon 	int ret = strncmp(a->name, b->name, MAX(a->len, b->len));
461f5207b7SJohn Levon 	if (!ret) {
471f5207b7SJohn Levon 		const struct position a_pos = ((const struct symbol *)m)->pos;
481f5207b7SJohn Levon 		const struct position b_pos = ((const struct symbol *)n)->pos;
491f5207b7SJohn Levon 
501f5207b7SJohn Levon 		ret = strcmp(stream_name(a_pos.stream),
511f5207b7SJohn Levon 		             stream_name(b_pos.stream));
521f5207b7SJohn Levon 		if (!ret)
531f5207b7SJohn Levon 			return a_pos.line < b_pos.line;
541f5207b7SJohn Levon 	}
551f5207b7SJohn Levon 	return ret;
561f5207b7SJohn Levon }
571f5207b7SJohn Levon 
show_tag_header(FILE * fp)581f5207b7SJohn Levon static void show_tag_header(FILE *fp)
591f5207b7SJohn Levon {
601f5207b7SJohn Levon 	fprintf(fp, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n");
611f5207b7SJohn Levon 	fprintf(fp, "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n");
621f5207b7SJohn Levon 	fprintf(fp, "!_TAG_PROGRAM_AUTHOR\tChristopher Li\t/sparse@chrisli.org/\n");
631f5207b7SJohn Levon 	fprintf(fp, "!_TAG_PROGRAM_NAME\tSparse Ctags\t//\n");
641f5207b7SJohn Levon 	fprintf(fp, "!_TAG_PROGRAM_URL\thttp://www.kernel.org/pub/software/devel/sparse/\t/official site/\n");
651f5207b7SJohn Levon 	fprintf(fp, "!_TAG_PROGRAM_VERSION\t0.01\t//\n");
661f5207b7SJohn Levon }
671f5207b7SJohn Levon 
show_symbol_tag(FILE * fp,struct symbol * sym)681f5207b7SJohn Levon static inline void show_symbol_tag(FILE *fp, struct symbol *sym)
691f5207b7SJohn Levon {
701f5207b7SJohn Levon 	fprintf(fp, "%s\t%s\t%d;\"\t%c\tfile:\n", show_ident(sym->ident),
711f5207b7SJohn Levon 	       stream_name(sym->pos.stream), sym->pos.line, (int)sym->kind);
721f5207b7SJohn Levon }
731f5207b7SJohn Levon 
show_tags(struct symbol_list * list)741f5207b7SJohn Levon static void show_tags(struct symbol_list *list)
751f5207b7SJohn Levon {
761f5207b7SJohn Levon 	struct symbol *sym;
771f5207b7SJohn Levon 	struct ident *ident = NULL;
781f5207b7SJohn Levon 	struct position pos = {};
791f5207b7SJohn Levon 	static const char *filename;
801f5207b7SJohn Levon 	FILE *fp;
811f5207b7SJohn Levon 
821f5207b7SJohn Levon 	if (!list)
831f5207b7SJohn Levon 		return;
841f5207b7SJohn Levon 
851f5207b7SJohn Levon 	fp = fopen("tags", "w");
861f5207b7SJohn Levon 	if (!fp) {
871f5207b7SJohn Levon 		perror("open tags file");
881f5207b7SJohn Levon 		return;
891f5207b7SJohn Levon 	}
901f5207b7SJohn Levon 	show_tag_header(fp);
911f5207b7SJohn Levon 	FOR_EACH_PTR(list, sym) {
921f5207b7SJohn Levon 		if (ident == sym->ident && pos.line == sym->pos.line &&
931f5207b7SJohn Levon 		    !strcmp(filename, stream_name(sym->pos.stream)))
941f5207b7SJohn Levon 			continue;
951f5207b7SJohn Levon 
961f5207b7SJohn Levon 		show_symbol_tag(fp, sym);
971f5207b7SJohn Levon 		ident = sym->ident;
981f5207b7SJohn Levon 		pos = sym->pos;
991f5207b7SJohn Levon 		filename = stream_name(sym->pos.stream);
1001f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
1011f5207b7SJohn Levon 	fclose(fp);
1021f5207b7SJohn Levon }
1031f5207b7SJohn Levon 
add_tag(struct symbol * sym)1041f5207b7SJohn Levon static inline void add_tag(struct symbol *sym)
1051f5207b7SJohn Levon {
1061f5207b7SJohn Levon 	if (sym->ident && !sym->visited) {
1071f5207b7SJohn Levon 		sym->visited = 1;
1081f5207b7SJohn Levon 		add_symbol(&taglist, sym);
1091f5207b7SJohn Levon 	}
1101f5207b7SJohn Levon }
1111f5207b7SJohn Levon 
examine_members(struct symbol_list * list)1121f5207b7SJohn Levon static inline void examine_members(struct symbol_list *list)
1131f5207b7SJohn Levon {
1141f5207b7SJohn Levon 	struct symbol *sym;
1151f5207b7SJohn Levon 
1161f5207b7SJohn Levon 	FOR_EACH_PTR(list, sym) {
1171f5207b7SJohn Levon 		sym->kind = 'm';
1181f5207b7SJohn Levon 		examine_symbol(sym);
1191f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
1201f5207b7SJohn Levon }
1211f5207b7SJohn Levon 
examine_symbol(struct symbol * sym)1221f5207b7SJohn Levon static void examine_symbol(struct symbol *sym)
1231f5207b7SJohn Levon {
1241f5207b7SJohn Levon 	struct symbol *base = sym;
1251f5207b7SJohn Levon 
1261f5207b7SJohn Levon 	if (!sym || sym->visited)
1271f5207b7SJohn Levon 		return;
1281f5207b7SJohn Levon 	if (sym->ident && sym->ident->reserved)
1291f5207b7SJohn Levon 		return;
1301f5207b7SJohn Levon 	if (sym->type == SYM_KEYWORD || sym->type == SYM_PREPROCESSOR)
1311f5207b7SJohn Levon 		return;
1321f5207b7SJohn Levon 
1331f5207b7SJohn Levon 	add_tag(sym);
1341f5207b7SJohn Levon 	base = sym->ctype.base_type;
1351f5207b7SJohn Levon 
1361f5207b7SJohn Levon 	switch (sym->type) {
1371f5207b7SJohn Levon 	case SYM_NODE:
138*c85f09ccSJohn Levon 		if (base && base->type == SYM_FN)
1391f5207b7SJohn Levon 			sym->kind = 'f';
1401f5207b7SJohn Levon 		examine_symbol(base);
1411f5207b7SJohn Levon 		break;
1421f5207b7SJohn Levon 	case SYM_STRUCT:
1431f5207b7SJohn Levon 		sym->kind = 's';
1441f5207b7SJohn Levon 		examine_members(sym->symbol_list);
1451f5207b7SJohn Levon 		break;
1461f5207b7SJohn Levon 	case SYM_UNION:
1471f5207b7SJohn Levon 		sym->kind = 'u';
1481f5207b7SJohn Levon 		examine_members(sym->symbol_list);
1491f5207b7SJohn Levon 		break;
1501f5207b7SJohn Levon 	case SYM_ENUM:
1511f5207b7SJohn Levon 		sym->kind = 'e';
1521f5207b7SJohn Levon 	case SYM_PTR:
1531f5207b7SJohn Levon 	case SYM_TYPEOF:
1541f5207b7SJohn Levon 	case SYM_BITFIELD:
1551f5207b7SJohn Levon 	case SYM_FN:
1561f5207b7SJohn Levon 	case SYM_ARRAY:
1571f5207b7SJohn Levon 		examine_symbol(sym->ctype.base_type);
1581f5207b7SJohn Levon 		break;
1591f5207b7SJohn Levon 	case SYM_BASETYPE:
1601f5207b7SJohn Levon 		break;
1611f5207b7SJohn Levon 
1621f5207b7SJohn Levon 	default:
1631f5207b7SJohn Levon 		die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident),
1641f5207b7SJohn Levon 		    sym->namespace, sym->type);
1651f5207b7SJohn Levon 	}
1661f5207b7SJohn Levon 	if (!sym->kind)
1671f5207b7SJohn Levon 		sym->kind = 'v';
1681f5207b7SJohn Levon 	return;
1691f5207b7SJohn Levon }
1701f5207b7SJohn Levon 
examine_namespace(struct symbol * sym)1711f5207b7SJohn Levon static void examine_namespace(struct symbol *sym)
1721f5207b7SJohn Levon {
1731f5207b7SJohn Levon 	if (sym->visited)
1741f5207b7SJohn Levon 		return;
1751f5207b7SJohn Levon 	if (sym->ident && sym->ident->reserved)
1761f5207b7SJohn Levon 		return;
1771f5207b7SJohn Levon 
1781f5207b7SJohn Levon 	switch(sym->namespace) {
1791f5207b7SJohn Levon 	case NS_KEYWORD:
1801f5207b7SJohn Levon 	case NS_PREPROCESSOR:
1811f5207b7SJohn Levon 		return;
1821f5207b7SJohn Levon 	case NS_LABEL:
1831f5207b7SJohn Levon 		sym->kind = 'l';
1841f5207b7SJohn Levon 		break;
1851f5207b7SJohn Levon 	case NS_MACRO:
1861f5207b7SJohn Levon 	case NS_UNDEF:
1871f5207b7SJohn Levon 		sym->kind = 'd';
1881f5207b7SJohn Levon 		break;
1891f5207b7SJohn Levon 	case NS_TYPEDEF:
1901f5207b7SJohn Levon 		sym->kind = 't';
1911f5207b7SJohn Levon 	case NS_SYMBOL:
1921f5207b7SJohn Levon 	case NS_STRUCT:
1931f5207b7SJohn Levon 		examine_symbol(sym);
1941f5207b7SJohn Levon 		break;
1951f5207b7SJohn Levon 	default:
1961f5207b7SJohn Levon 		die("unknown namespace %d symbol:%s type:%d\n", sym->namespace,
1971f5207b7SJohn Levon 		    show_ident(sym->ident), sym->type);
1981f5207b7SJohn Levon 	}
1991f5207b7SJohn Levon 	add_tag(sym);
2001f5207b7SJohn Levon }
2011f5207b7SJohn Levon 
examine_symbol_list(struct symbol_list * list)2021f5207b7SJohn Levon static inline void examine_symbol_list(struct symbol_list *list)
2031f5207b7SJohn Levon {
2041f5207b7SJohn Levon 	struct symbol *sym;
2051f5207b7SJohn Levon 
2061f5207b7SJohn Levon 	if (!list)
2071f5207b7SJohn Levon 		return;
2081f5207b7SJohn Levon 	FOR_EACH_PTR(list, sym) {
2091f5207b7SJohn Levon 		examine_namespace(sym);
2101f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
2111f5207b7SJohn Levon }
2121f5207b7SJohn Levon 
main(int argc,char ** argv)2131f5207b7SJohn Levon int main(int argc, char **argv)
2141f5207b7SJohn Levon {
2151f5207b7SJohn Levon 	struct string_list *filelist = NULL;
2161f5207b7SJohn Levon 	char *file;
2171f5207b7SJohn Levon 
2181f5207b7SJohn Levon 	examine_symbol_list(sparse_initialize(argc, argv, &filelist));
219*c85f09ccSJohn Levon 	FOR_EACH_PTR(filelist, file) {
2201f5207b7SJohn Levon 		sparse(file);
2211f5207b7SJohn Levon 		examine_symbol_list(file_scope->symbols);
222*c85f09ccSJohn Levon 	} END_FOR_EACH_PTR(file);
2231f5207b7SJohn Levon 	examine_symbol_list(global_scope->symbols);
2241f5207b7SJohn Levon 	sort_list((struct ptr_list **)&taglist, cmp_sym);
2251f5207b7SJohn Levon 	show_tags(taglist);
2261f5207b7SJohn Levon 	return 0;
2271f5207b7SJohn Levon }
228