| /* |
| * Sparse Ctags |
| * |
| * Ctags generates tags from preprocessing results. |
| * |
| * Copyright (C) 2006 Christopher Li |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| * THE SOFTWARE. |
| */ |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| |
| #include "parse.h" |
| #include "scope.h" |
| |
| static struct symbol_list *taglist = NULL; |
| |
| static void examine_symbol(struct symbol *sym); |
| |
| #define MAX(_x,_y) ((_x) > (_y) ? (_x) : (_y)) |
| |
| static int cmp_sym(const void *m, const void *n) |
| { |
| const struct ident *a = ((const struct symbol *)m)->ident; |
| const struct ident *b = ((const struct symbol *)n)->ident; |
| int ret = strncmp(a->name, b->name, MAX(a->len, b->len)); |
| if (!ret) { |
| const struct position a_pos = ((const struct symbol *)m)->pos; |
| const struct position b_pos = ((const struct symbol *)n)->pos; |
| |
| ret = strcmp(stream_name(a_pos.stream), |
| stream_name(b_pos.stream)); |
| if (!ret) |
| return a_pos.line < b_pos.line; |
| } |
| return ret; |
| } |
| |
| static void show_tag_header(FILE *fp) |
| { |
| fprintf(fp, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n"); |
| fprintf(fp, "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n"); |
| fprintf(fp, "!_TAG_PROGRAM_AUTHOR\tChristopher Li\t/sparse@chrisli.org/\n"); |
| fprintf(fp, "!_TAG_PROGRAM_NAME\tSparse Ctags\t//\n"); |
| fprintf(fp, "!_TAG_PROGRAM_URL\thttp://www.kernel.org/pub/software/devel/sparse/\t/official site/\n"); |
| fprintf(fp, "!_TAG_PROGRAM_VERSION\t0.01\t//\n"); |
| } |
| |
| static inline void show_symbol_tag(FILE *fp, struct symbol *sym) |
| { |
| fprintf(fp, "%s\t%s\t%d;\"\t%c\tfile:\n", show_ident(sym->ident), |
| stream_name(sym->pos.stream), sym->pos.line, (int)sym->kind); |
| } |
| |
| static void show_tags(struct symbol_list *list) |
| { |
| struct symbol *sym; |
| struct ident *ident = NULL; |
| struct position pos = {}; |
| static const char *filename; |
| FILE *fp; |
| |
| if (!list) |
| return; |
| |
| fp = fopen("tags", "w"); |
| if (!fp) { |
| perror("open tags file"); |
| return; |
| } |
| show_tag_header(fp); |
| FOR_EACH_PTR(list, sym) { |
| if (ident == sym->ident && pos.line == sym->pos.line && |
| !strcmp(filename, stream_name(sym->pos.stream))) |
| continue; |
| |
| show_symbol_tag(fp, sym); |
| ident = sym->ident; |
| pos = sym->pos; |
| filename = stream_name(sym->pos.stream); |
| } END_FOR_EACH_PTR(sym); |
| fclose(fp); |
| } |
| |
| static inline void add_tag(struct symbol *sym) |
| { |
| if (sym->ident && !sym->visited) { |
| sym->visited = 1; |
| add_symbol(&taglist, sym); |
| } |
| } |
| |
| static inline void examine_members(struct symbol_list *list) |
| { |
| struct symbol *sym; |
| |
| FOR_EACH_PTR(list, sym) { |
| sym->kind = 'm'; |
| examine_symbol(sym); |
| } END_FOR_EACH_PTR(sym); |
| } |
| |
| static void examine_symbol(struct symbol *sym) |
| { |
| struct symbol *base = sym; |
| |
| if (!sym || sym->visited) |
| return; |
| if (sym->ident && sym->ident->reserved) |
| return; |
| if (sym->type == SYM_KEYWORD || sym->type == SYM_PREPROCESSOR) |
| return; |
| |
| add_tag(sym); |
| base = sym->ctype.base_type; |
| |
| switch (sym->type) { |
| case SYM_NODE: |
| if (base && base->type == SYM_FN) |
| sym->kind = 'f'; |
| examine_symbol(base); |
| break; |
| case SYM_STRUCT: |
| sym->kind = 's'; |
| examine_members(sym->symbol_list); |
| break; |
| case SYM_UNION: |
| sym->kind = 'u'; |
| examine_members(sym->symbol_list); |
| break; |
| case SYM_ENUM: |
| sym->kind = 'e'; |
| case SYM_PTR: |
| case SYM_TYPEOF: |
| case SYM_BITFIELD: |
| case SYM_FN: |
| case SYM_ARRAY: |
| examine_symbol(sym->ctype.base_type); |
| break; |
| case SYM_BASETYPE: |
| break; |
| |
| default: |
| die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident), |
| sym->namespace, sym->type); |
| } |
| if (!sym->kind) |
| sym->kind = 'v'; |
| return; |
| } |
| |
| static void examine_namespace(struct symbol *sym) |
| { |
| if (sym->visited) |
| return; |
| if (sym->ident && sym->ident->reserved) |
| return; |
| |
| switch(sym->namespace) { |
| case NS_KEYWORD: |
| case NS_PREPROCESSOR: |
| return; |
| case NS_LABEL: |
| sym->kind = 'l'; |
| break; |
| case NS_MACRO: |
| case NS_UNDEF: |
| sym->kind = 'd'; |
| break; |
| case NS_TYPEDEF: |
| sym->kind = 't'; |
| case NS_SYMBOL: |
| case NS_STRUCT: |
| examine_symbol(sym); |
| break; |
| default: |
| die("unknown namespace %d symbol:%s type:%d\n", sym->namespace, |
| show_ident(sym->ident), sym->type); |
| } |
| add_tag(sym); |
| } |
| |
| static inline void examine_symbol_list(struct symbol_list *list) |
| { |
| struct symbol *sym; |
| |
| if (!list) |
| return; |
| FOR_EACH_PTR(list, sym) { |
| examine_namespace(sym); |
| } END_FOR_EACH_PTR(sym); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| struct string_list *filelist = NULL; |
| char *file; |
| |
| examine_symbol_list(sparse_initialize(argc, argv, &filelist)); |
| FOR_EACH_PTR(filelist, file) { |
| sparse(file); |
| examine_symbol_list(file_scope->symbols); |
| } END_FOR_EACH_PTR(file); |
| examine_symbol_list(global_scope->symbols); |
| sort_list((struct ptr_list **)&taglist, cmp_sym); |
| show_tags(taglist); |
| return 0; |
| } |