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