📄 ctags.c
字号:
next = cpp_getc(); } break; case '/': /* start of a C++ comment */ do { ch = cpp_getc(); } while (ch != '\n' && ch != EOF); break; default: /* some other slash */ cpp_ungetc(ch); } token = DELETED; break; case '(': ch = cpp_getc(); if (ch == '*') { token = DELETED; } else { next = cpp_getc(); while (ch != '{' && ch != EOF && (ch != ')' || next != ';'))/*}*/ { ch = next; next = cpp_getc(); } if (ch == '{')/*}*/ { cpp_ungetc(ch); } else if (next == ';') { cpp_ungetc(next); } token = ARGS; } break; case '{':/*}*/ /* don't send the next characters to "refs" */ cpp_refsok = FALSE; /* skip ahead to closing '}', or to embedded '{' */ do { ch = cpp_getc(); } while (ch != '{' && ch != '}' && ch != EOF); /* if has embedded '{', then skip to '}' in column 1 */ if (ch == '{') /*}*/ { ch = cpp_getc(); next = cpp_getc(); while (ch != EOF && (ch != '\n' || next != '}'))/*{*/ { ch = next; next = cpp_getc(); } } /* resume "refs" processing */ cpp_refsok = TRUE; cpp_echo('}'); token = BODY; break; case '[': /* skip to matching ']' */ do { ch = cpp_getc(); } while (ch != ']' && ch != EOF); token = DELETED; break; case '=': /* skip to next ';' */ do { ch = cpp_getc(); /* leave array initializers out of "refs" */ if (ch == '{') { cpp_refsok = FALSE; } } while (ch != ';' && ch != EOF); /* resume echoing to "refs" */ if (!cpp_refsok) { cpp_refsok = TRUE; cpp_echo('}'); cpp_echo(';'); } token = SEMICOLON; break; case EOF: token = EOF; break; default: /* is this the start of a name/keyword? */ if (isalpha(ch) || ch == '_') { /* collect the whole word */ lex_name[0] = ch; for (i = 1, ch = cpp_getc(); i < BLKSIZE - 1 && (isalnum(ch) || ch == '_'); i++, ch = cpp_getc()) { lex_name[i] = ch; } lex_name[i] = '\0'; cpp_ungetc(ch); /* is it a reserved word? */ if (!strcmp(lex_name, "typedef")) { token = TYPEDEF; lex_seek = -1L; } else if (!strcmp(lex_name, "static") || !strcmp(lex_name, "private") || !strcmp(lex_name, "PRIVATE")) { token = STATIC; lex_seek = -1L; } else if (!strcmp(lex_name, "extern") || !strcmp(lex_name, "EXTERN") || !strcmp(lex_name, "FORWARD")) { token = EXTERN; lex_seek = -1L; } else { token = NAME; lex_seek = file_seek; } } else /* not part of a name/keyword */ { token = DELETED; } } /* end switch(ch) */ } while (token == DELETED); return token;}/* -------------------------------------------------------------------------- *//* This is the parser. It locates tag candidates, and then decides whether to * generate a tag for them. *//* This function generates a tag for the object in lex_name, whose tag line is * located at a given seek offset. */void maketag(scope, seek) int scope; /* 0 if global, or STATIC if static */ long seek; /* the seek offset of the line */{ /* output the tagname and filename fields */ if (scope == EXTERN) { /* whoa! we should *never* output a tag for "extern" decl */ return; } else if (scope == STATIC) { fprintf(tags, "%s:%s\t%s\t", file_name, lex_name, file_name); } else { fprintf(tags, "%s\t%s\t", lex_name, file_name); } /* output the target line */ putc('/', tags); putc('^', tags); file_copyline(seek, tags); putc('$', tags); putc('/', tags); putc('\n', tags);}/* This function parses a source file, adding any tags that it finds */void ctags(name) char *name; /* the name of a source file to be checked */{ int prev; /* the previous token from the source file */ int token; /* the current token from the source file */ int scope; /* normally 0, but could be a TYPEDEF or STATIC token */ int gotname;/* boolean: does lex_name contain a tag candidate? */ long tagseek;/* start of line that contains lex_name */ /* open the file */ cpp_open(name); /* reset */ scope = 0; gotname = FALSE; token = SEMICOLON; /* parse until the end of the file */ while (prev = token, (token = lex_gettoken()) != EOF) { /* scope keyword? */ if (token == TYPEDEF || token == STATIC || token == EXTERN) { scope = token; gotname = FALSE; continue; } /* name of a possible tag candidate? */ if (token == NAME) { tagseek = file_seek; gotname = TRUE; continue; } /* if NAME BODY, without ARGS, then NAME is a struct tag */ if (gotname && token == BODY && prev != ARGS) { gotname = FALSE; /* ignore if in typedef -- better name is coming soon */ if (scope == TYPEDEF) { continue; } /* generate a tag, if -t and maybe -s */ if (incl_types && (file_header || incl_static)) { maketag(file_header ? 0 : STATIC, tagseek); } } /* If NAME ARGS BODY, then NAME is a function */ if (gotname && prev == ARGS && token == BODY) { gotname = FALSE; /* generate a tag, maybe checking -s */ if (scope != STATIC || incl_static) { maketag(scope, tagseek); } } /* If NAME SEMICOLON or NAME COMMA, then NAME is var/typedef */ if (gotname && (token == SEMICOLON || token == COMMA)) { gotname = FALSE; /* generate a tag, if -v/-t and maybe -s */ if (scope == TYPEDEF && incl_types && (file_header || incl_static) || scope == STATIC && incl_vars && incl_static || incl_vars) { /* a TYPEDEF outside of a header is STATIC */ if (scope == TYPEDEF && !file_header) { maketag(STATIC, tagseek); } else /* use whatever scope was declared */ { maketag(scope, tagseek); } } } /* reset after a semicolon or ARGS BODY pair */ if (token == SEMICOLON || (prev == ARGS && token == BODY)) { scope = 0; gotname = FALSE; } } /* The source file will be automatically closed */}/* -------------------------------------------------------------------------- */void usage(){ fprintf(stderr, "usage: ctags [flags] filenames...\n"); fprintf(stderr, "\t-s include static functions\n"); fprintf(stderr, "\t-t include typedefs\n"); fprintf(stderr, "\t-v include variable declarations\n"); fprintf(stderr, "\t-r generate a \"refs\" file, too\n"); fprintf(stderr, "\t-a append to \"tags\", instead of overwriting\n"); exit(2);}#if AMIGA# include "amiwild.c"#endif#if VMS# include "vmswild.c"#endifmain(argc, argv) int argc; char **argv;{ int i, j;#if MSDOS || TOS char **wildexpand(); argv = wildexpand(&argc, argv);#endif /* build the tables used by the ctype macros */ _ct_init(""); /* parse the option flags */ for (i = 1; i < argc && argv[i][0] == '-'; i++) { for (j = 1; argv[i][j]; j++) { switch (argv[i][j]) { case 's': incl_static = TRUE; break; case 't': incl_types = TRUE; break; case 'v': incl_vars = TRUE; break; case 'r': make_refs = TRUE; break; case 'a': append_files = TRUE; break; default: usage(); } } } /* There should always be at least one source file named in args */ if (i == argc) { usage(); } /* open the "tags" and maybe "refs" files */ tags = fopen(TAGS, append_files ? "a" : "w"); if (!tags) { perror(TAGS); exit(3); } if (make_refs) { refs = fopen(REFS, append_files ? "a" : "w"); if (!refs) { perror(REFS); exit(4); } } /* parse each source file */ for (; i < argc; i++) { ctags(argv[i]); } /* close "tags" and maybe "refs" */ fclose(tags); if (make_refs) { fclose(refs); }#ifdef SORT /* This is a hack which will sort the tags list. It should * on UNIX and OS-9. You may have trouble with csh. Note * that the tags list only has to be sorted if you intend to * use it with the real vi; elvis permits unsorted tags. */# if OSK system("qsort tags >-_tags; -nx; del tags; rename _tags tags");# else system("sort tags >_tags$$; mv _tags$$ tags");# endif#endif exit(0); /*NOTREACHED*/}#if MSDOS || TOS# define WILDCARD_NO_MAIN# include "wildcard.c"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -