1 /* 2 * Sparse Ctags 3 * 4 * Ctags generates tags from preprocessing results. 5 * 6 * Copyright (C) 2006 Christopher Li 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 * THE SOFTWARE. 25 */ 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <fcntl.h> 31 32 #include "parse.h" 33 #include "scope.h" 34 35 static struct symbol_list *taglist = NULL; 36 37 static void examine_symbol(struct symbol *sym); 38 39 #define MAX(_x,_y) ((_x) > (_y) ? (_x) : (_y)) 40 41 static int cmp_sym(const void *m, const void *n) 42 { 43 const struct ident *a = ((const struct symbol *)m)->ident; 44 const struct ident *b = ((const struct symbol *)n)->ident; 45 int ret = strncmp(a->name, b->name, MAX(a->len, b->len)); 46 if (!ret) { 47 const struct position a_pos = ((const struct symbol *)m)->pos; 48 const struct position b_pos = ((const struct symbol *)n)->pos; 49 50 ret = strcmp(stream_name(a_pos.stream), 51 stream_name(b_pos.stream)); 52 if (!ret) 53 return a_pos.line < b_pos.line; 54 } 55 return ret; 56 } 57 58 static void show_tag_header(FILE *fp) 59 { 60 fprintf(fp, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n"); 61 fprintf(fp, "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n"); 62 fprintf(fp, "!_TAG_PROGRAM_AUTHOR\tChristopher Li\t/sparse@chrisli.org/\n"); 63 fprintf(fp, "!_TAG_PROGRAM_NAME\tSparse Ctags\t//\n"); 64 fprintf(fp, "!_TAG_PROGRAM_URL\thttp://www.kernel.org/pub/software/devel/sparse/\t/official site/\n"); 65 fprintf(fp, "!_TAG_PROGRAM_VERSION\t0.01\t//\n"); 66 } 67 68 static inline void show_symbol_tag(FILE *fp, struct symbol *sym) 69 { 70 fprintf(fp, "%s\t%s\t%d;\"\t%c\tfile:\n", show_ident(sym->ident), 71 stream_name(sym->pos.stream), sym->pos.line, (int)sym->kind); 72 } 73 74 static void show_tags(struct symbol_list *list) 75 { 76 struct symbol *sym; 77 struct ident *ident = NULL; 78 struct position pos = {}; 79 static const char *filename; 80 FILE *fp; 81 82 if (!list) 83 return; 84 85 fp = fopen("tags", "w"); 86 if (!fp) { 87 perror("open tags file"); 88 return; 89 } 90 show_tag_header(fp); 91 FOR_EACH_PTR(list, sym) { 92 if (ident == sym->ident && pos.line == sym->pos.line && 93 !strcmp(filename, stream_name(sym->pos.stream))) 94 continue; 95 96 show_symbol_tag(fp, sym); 97 ident = sym->ident; 98 pos = sym->pos; 99 filename = stream_name(sym->pos.stream); 100 } END_FOR_EACH_PTR(sym); 101 fclose(fp); 102 } 103 104 static inline void add_tag(struct symbol *sym) 105 { 106 if (sym->ident && !sym->visited) { 107 sym->visited = 1; 108 add_symbol(&taglist, sym); 109 } 110 } 111 112 static inline void examine_members(struct symbol_list *list) 113 { 114 struct symbol *sym; 115 116 FOR_EACH_PTR(list, sym) { 117 sym->kind = 'm'; 118 examine_symbol(sym); 119 } END_FOR_EACH_PTR(sym); 120 } 121 122 static void examine_symbol(struct symbol *sym) 123 { 124 struct symbol *base = sym; 125 126 if (!sym || sym->visited) 127 return; 128 if (sym->ident && sym->ident->reserved) 129 return; 130 if (sym->type == SYM_KEYWORD || sym->type == SYM_PREPROCESSOR) 131 return; 132 133 add_tag(sym); 134 base = sym->ctype.base_type; 135 136 switch (sym->type) { 137 case SYM_NODE: 138 if (base && base->type == SYM_FN) 139 sym->kind = 'f'; 140 examine_symbol(base); 141 break; 142 case SYM_STRUCT: 143 sym->kind = 's'; 144 examine_members(sym->symbol_list); 145 break; 146 case SYM_UNION: 147 sym->kind = 'u'; 148 examine_members(sym->symbol_list); 149 break; 150 case SYM_ENUM: 151 sym->kind = 'e'; 152 case SYM_PTR: 153 case SYM_TYPEOF: 154 case SYM_BITFIELD: 155 case SYM_FN: 156 case SYM_ARRAY: 157 examine_symbol(sym->ctype.base_type); 158 break; 159 case SYM_BASETYPE: 160 break; 161 162 default: 163 die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident), 164 sym->namespace, sym->type); 165 } 166 if (!sym->kind) 167 sym->kind = 'v'; 168 return; 169 } 170 171 static void examine_namespace(struct symbol *sym) 172 { 173 if (sym->visited) 174 return; 175 if (sym->ident && sym->ident->reserved) 176 return; 177 178 switch(sym->namespace) { 179 case NS_KEYWORD: 180 case NS_PREPROCESSOR: 181 return; 182 case NS_LABEL: 183 sym->kind = 'l'; 184 break; 185 case NS_MACRO: 186 case NS_UNDEF: 187 sym->kind = 'd'; 188 break; 189 case NS_TYPEDEF: 190 sym->kind = 't'; 191 case NS_SYMBOL: 192 case NS_STRUCT: 193 examine_symbol(sym); 194 break; 195 default: 196 die("unknown namespace %d symbol:%s type:%d\n", sym->namespace, 197 show_ident(sym->ident), sym->type); 198 } 199 add_tag(sym); 200 } 201 202 static inline void examine_symbol_list(struct symbol_list *list) 203 { 204 struct symbol *sym; 205 206 if (!list) 207 return; 208 FOR_EACH_PTR(list, sym) { 209 examine_namespace(sym); 210 } END_FOR_EACH_PTR(sym); 211 } 212 213 int main(int argc, char **argv) 214 { 215 struct string_list *filelist = NULL; 216 char *file; 217 218 examine_symbol_list(sparse_initialize(argc, argv, &filelist)); 219 FOR_EACH_PTR(filelist, file) { 220 sparse(file); 221 examine_symbol_list(file_scope->symbols); 222 } END_FOR_EACH_PTR(file); 223 examine_symbol_list(global_scope->symbols); 224 sort_list((struct ptr_list **)&taglist, cmp_sym); 225 show_tags(taglist); 226 return 0; 227 } 228