Fix OpenBSD compile
[smatch.git] / ctags.c
blob7e129a6d1cf759b23296314c6e7ae99265d15771
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 const struct ident *a = ((const struct symbol *)m)->ident;
28 const struct ident *b = ((const struct symbol *)n)->ident;
29 int ret = strncmp(a->name, b->name, MAX(a->len, b->len));
30 if (!ret) {
31 const struct position a_pos = ((const struct symbol *)m)->pos;
32 const struct position b_pos = ((const 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;
114 if (sym->type == SYM_KEYWORD || sym->type == SYM_PREPROCESSOR)
115 return;
117 add_tag(sym);
118 base = sym->ctype.base_type;
120 switch (sym->type) {
121 case SYM_NODE:
122 if (base->type == SYM_FN)
123 sym->kind = 'f';
124 examine_symbol(base);
125 break;
126 case SYM_STRUCT:
127 sym->kind = 's';
128 examine_members(sym->symbol_list);
129 break;
130 case SYM_UNION:
131 sym->kind = 'u';
132 examine_members(sym->symbol_list);
133 break;
134 case SYM_ENUM:
135 sym->kind = 'e';
136 case SYM_PTR:
137 case SYM_TYPEOF:
138 case SYM_BITFIELD:
139 case SYM_FN:
140 case SYM_ARRAY:
141 examine_symbol(sym->ctype.base_type);
142 break;
143 case SYM_BASETYPE:
144 break;
146 default:
147 die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident),
148 sym->namespace, sym->type);
150 if (!sym->kind)
151 sym->kind = 'v';
152 return;
155 static void examine_namespace(struct symbol *sym)
157 if (sym->visited)
158 return;
159 if (sym->ident && sym->ident->reserved)
160 return;
162 switch(sym->namespace) {
163 case NS_KEYWORD:
164 case NS_PREPROCESSOR:
165 return;
166 case NS_LABEL:
167 sym->kind = 'l';
168 break;
169 case NS_MACRO:
170 case NS_UNDEF:
171 sym->kind = 'd';
172 break;
173 case NS_TYPEDEF:
174 sym->kind = 't';
175 case NS_SYMBOL:
176 case NS_STRUCT:
177 examine_symbol(sym);
178 break;
179 default:
180 die("unknown namespace %d symbol:%s type:%d\n", sym->namespace,
181 show_ident(sym->ident), sym->type);
183 add_tag(sym);
186 static inline void examine_symbol_list(struct symbol_list *list)
188 struct symbol *sym;
190 if (!list)
191 return;
192 FOR_EACH_PTR(list, sym) {
193 examine_namespace(sym);
194 } END_FOR_EACH_PTR(sym);
197 int main(int argc, char **argv)
199 struct string_list *filelist = NULL;
200 char *file;
202 examine_symbol_list(sparse_initialize(argc, argv, &filelist));
203 FOR_EACH_PTR_NOTAG(filelist, file) {
204 sparse(file);
205 examine_symbol_list(file_scope->symbols);
206 } END_FOR_EACH_PTR_NOTAG(file);
207 examine_symbol_list(global_scope->symbols);
208 sort_list((struct ptr_list **)&taglist, cmp_sym);
209 show_tags(taglist);
210 return 0;