Fix infinite loop in free_preprocessor_line()
[smatch.git] / ctags.c
blobcccee0a97577dff4699a43bec94afd5575c7d99c
1 /*
2 * Sparse Ctags
4 * Ctags generates tags from preprocessing results.
6 * Copyright (C) 2006 Christopher Li
8 * Licensed under the Open Software License version 1.1
9 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
16 #include "parse.h"
17 #include "scope.h"
19 static struct symbol_list *taglist = NULL;
21 static void examine_symbol(struct symbol *sym);
23 #define MAX(_x,_y) ((_x) > (_y) ? (_x) : (_y))
25 static int cmp_sym(const void *m, const void *n)
27 struct ident *a = ((struct symbol *)m)->ident;
28 struct ident *b = ((struct symbol *)n)->ident;
29 int ret = strncmp(a->name, b->name, MAX(a->len, b->len));
30 if (!ret) {
31 struct position a_pos = ((struct symbol *)m)->pos;
32 struct position b_pos = ((struct symbol *)n)->pos;
34 ret = strcmp(stream_name(a_pos.stream),
35 stream_name(b_pos.stream));
36 if (!ret)
37 return a_pos.line < b_pos.line;
39 return ret;
42 static void show_tag_header(FILE *fp)
44 fprintf(fp, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n");
45 fprintf(fp, "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n");
46 fprintf(fp, "!_TAG_PROGRAM_AUTHOR\tChristopher Li\t/sparse@chrisli.org/\n");
47 fprintf(fp, "!_TAG_PROGRAM_NAME\tSparse Ctags\t//\n");
48 fprintf(fp, "!_TAG_PROGRAM_URL\thttp://www.kernel.org/pub/software/devel/sparse/\t/official site/\n");
49 fprintf(fp, "!_TAG_PROGRAM_VERSION\t0.01\t//\n");
52 static inline void show_symbol_tag(FILE *fp, struct symbol *sym)
54 fprintf(fp, "%s\t%s\t%d;\"\t%c\tfile:\n", show_ident(sym->ident),
55 stream_name(sym->pos.stream), sym->pos.line, (int)sym->kind);
58 static void show_tags(struct symbol_list *list)
60 struct symbol *sym;
61 struct ident *ident = NULL;
62 struct position pos = {};
63 static const char *filename;
64 FILE *fp;
66 if (!list)
67 return;
69 fp = fopen("tags", "w");
70 if (!fp) {
71 perror("open tags file");
72 return;
74 show_tag_header(fp);
75 FOR_EACH_PTR(list, sym) {
76 if (ident == sym->ident && pos.line == sym->pos.line &&
77 !strcmp(filename, stream_name(sym->pos.stream)))
78 continue;
80 show_symbol_tag(fp, sym);
81 ident = sym->ident;
82 pos = sym->pos;
83 filename = stream_name(sym->pos.stream);
84 } END_FOR_EACH_PTR(sym);
85 fclose(fp);
88 static inline void add_tag(struct symbol *sym)
90 if (sym->ident && !sym->visited) {
91 sym->visited = 1;
92 add_symbol(&taglist, sym);
96 static inline void examine_members(struct symbol_list *list)
98 struct symbol *sym;
100 FOR_EACH_PTR(list, sym) {
101 sym->kind = 'm';
102 examine_symbol(sym);
103 } END_FOR_EACH_PTR(sym);
106 static void examine_symbol(struct symbol *sym)
108 struct symbol *base = sym;
110 if (!sym || sym->visited)
111 return;
112 if (sym->ident && sym->ident->reserved)
113 return;
115 add_tag(sym);
116 base = sym->ctype.base_type;
118 switch (sym->type) {
119 case SYM_NODE:
120 if (base->type == SYM_FN)
121 sym->kind = 'f';
122 examine_symbol(base);
123 break;
124 case SYM_STRUCT:
125 sym->kind = 's';
126 examine_members(sym->symbol_list);
127 break;
128 case SYM_UNION:
129 sym->kind = 'u';
130 examine_members(sym->symbol_list);
131 break;
132 case SYM_ENUM:
133 sym->kind = 'e';
134 case SYM_PTR:
135 case SYM_TYPEOF:
136 case SYM_BITFIELD:
137 case SYM_FN:
138 case SYM_ARRAY:
139 examine_symbol(sym->ctype.base_type);
140 break;
141 case SYM_BASETYPE:
142 break;
144 default:
145 die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident),
146 sym->namespace, sym->type);
148 if (!sym->kind)
149 sym->kind = 'v';
150 return;
153 static void examine_namespace(struct symbol *sym)
155 if (sym->visited)
156 return;
157 if (sym->ident && sym->ident->reserved)
158 return;
160 switch(sym->namespace) {
161 case NS_LABEL:
162 sym->kind = 'l';
163 break;
164 case NS_PREPROCESSOR:
165 break;
166 case NS_MACRO:
167 case NS_UNDEF:
168 sym->kind = 'd';
169 break;
170 case NS_TYPEDEF:
171 sym->kind = 't';
172 case NS_SYMBOL:
173 case NS_STRUCT:
174 examine_symbol(sym);
175 break;
176 default:
177 die("unknown namespace %d symbol:%s type:%d\n", sym->namespace,
178 show_ident(sym->ident), sym->type);
180 add_tag(sym);
183 static inline void examine_symbol_list(struct symbol_list *list)
185 struct symbol *sym;
187 if (!list)
188 return;
189 FOR_EACH_PTR(list, sym) {
190 examine_namespace(sym);
191 } END_FOR_EACH_PTR(sym);
194 int main(int argc, char **argv)
196 struct string_list *filelist = NULL;
197 char *file;
199 examine_symbol_list(sparse_initialize(argc, argv, &filelist));
200 FOR_EACH_PTR_NOTAG(filelist, file) {
201 sparse(file);
202 examine_symbol_list(file_scope->symbols);
203 } END_FOR_EACH_PTR_NOTAG(file);
204 examine_symbol_list(global_scope->symbols);
205 sort_list((struct ptr_list **)&taglist, cmp_sym);
206 show_tags(taglist);
207 return 0;