📄 etags.c
字号:
/* Tags file maker to go with GNU Emacs Copyright (C) 1984, 1987, 1988, 1989, 1992 Free Software Foundation, Inc. and Ken ArnoldThis file is part of GNU Emacs.GNU Emacs is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU Emacs is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Emacs; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* * Authors: * Ctags originally by Ken Arnold. * FORTRAN added by Jim Kleckner. * Ed Pelegri-Llopart added C typedefs. * Gnu Emacs TAGS format and modifications by RMS? * Sam Kendall added C++. */#include <stdio.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>#include "getopt.h"#ifdef __GNUC__#define alloca __builtin_alloca#else#ifdef sparc#include <alloca.h>#elseextern char *alloca ();#endif#endifextern char *malloc (), *realloc ();extern char *getenv ();extern char *index (), *rindex ();extern char *strcpy (), *strncpy ();extern int strcmp ();#ifdef hpux#define notdef#endif/* Define the symbol ETAGS to make the program "etags", which makes emacs-style tag tables by default. Define CTAGS to make the program "ctags" compatible with the usual one. Define neither one to get behavior that depends on the name with which the program is invoked (but we don't normally compile it that way). */#if !defined(ETAGS) && !defined(CTAGS)/* If neither is defined, program can be run as either. */#define ETAGS#define CTAGS#endif/* On VMS, CTAGS is not useful, so always do ETAGS. */#ifdef VMS#ifndef ETAGS#define ETAGS#endif#endif/* Exit codes for success and failure. */#ifdef VMS#define GOOD (1)#define BAD (0)#else#define GOOD (0)#define BAD (1)#endif/* * The FILEPOS abstract type, which represents a position in a file, * plus the following accessor functions: * * long GET_CHARNO (pos) * returns absolute char number. * long GET_COOKIE (pos) * returns ftell () cookie. * void SET_FILEPOS (pos, fp, charno) * FILE *fp; long charno; * sets `pos' from the current file * position of `fp' and from `charno', * which must be the absolute character * number corresponding to the current * position of `fp'. * * The `pos' parameter is an lvalue expression of type FILEPOS. * Parameters to the accessor functions are evaluated 0 or more times, * and so must have no side effects. * * FILEPOS objects can also be assigned and passed to and from * functions in the normal C manner. * * Implementation notes: the `+ 0' is to enforce rvalue-ness. */#ifdef VMStypedef struct{ long cookie; long charno;} FILEPOS;#define GET_CHARNO(pos) ((pos).charno + 0)#define GET_COOKIE(pos) ((pos).cookie + 0)#define SET_FILEPOS(pos, fp, cno) \ ((void) ((pos).cookie = ftell (fp), (pos).charno = (cno)))#else#ifndef DEBUG /* UNIX real implementation */typedef long FILEPOS;#define GET_CHARNO(pos) ((pos) + 0)#define GET_COOKIE(pos) GET_CHARNO (pos)#define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))#else /* UNIX debugging implementation */typedef struct{ long charno;} FILEPOS;#define GET_CHARNO(pos) ((pos).charno + 0)#define GET_COOKIE(pos) GET_CHARNO (pos)#define SET_FILEPOS(pos, fp, cno) \ ((void) ((pos).charno = (cno), \ (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \ : 0))#endif#endif#define streq(s, t) (strcmp (s, t) == 0)#define strneq(s, t, n) (strncmp (s, t, n) == 0)#define reg register#define logical char#define TRUE 1#define FALSE 0#define iswhite(arg) (_wht[arg]) /* T if char is white */#define begtoken(arg) (_btk[arg]) /* T if char can start token */#define intoken(arg) (_itk[arg]) /* T if char can be in token */#define endtoken(arg) (_etk[arg]) /* T if char ends tokens */#define isgood(arg) (_gd[arg]) /* T if char can be after ')' */#define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))struct nd_st{ /* sorting structure */ char *name; /* function or type name */ char *file; /* file name */ logical is_func; /* use pattern or line no */ logical rewritten; /* list name separately */ logical been_warned; /* set if noticed dup */ int lno; /* line number tag is on */ long cno; /* character number line starts on */ char *pat; /* search pattern */ struct nd_st *left, *right; /* left and right sons */};long ftell ();typedef struct nd_st NODE;logical gotone, /* found a func already on line */ /* boolean "func" (see init) */ header_file, /* TRUE if .h file, FALSE o.w. */ _wht[0177], _etk[0177], _itk[0177], _btk[0177], _gd[0177];char *concat ();char *savenstr ();char *savestr ();char *xmalloc ();char *xrealloc ();int L_isdef ();int PF_funcs ();int total_size_of_entries ();logical consider_token ();logical tail ();long readline ();void Asm_funcs ();void C_entries ();void L_funcs ();void L_getit ();void PAS_funcs ();void Scheme_funcs ();void TEX_funcs ();void add_node ();void error ();void fatal ();void find_entries ();void free_tree ();void getit ();void getline ();void init ();void initbuffer ();void initbuffer ();void pfnote ();void process_file ();void put_entries ();void takeprec ();/* * MACRO * xnew -- allocate storage * * SYNOPSIS * Type *xnew (int n, Type); */#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))/* * Symbol table stuff. * * Should probably be implemented with hash table; linked list for now. */enum sym_type{ st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec};struct stab_entry{ char *sym; int symlen; enum sym_type type; struct stab_entry *next;};typedef struct stab_entry Stab_entry;typedef Stab_entry *Stab;/* * NAME * Stab, Stab_entry, stab_create, stab_search, stab_find -- symbol table * * SYNOPSIS * Types: Stab, Stab_entry, enum sym_type * * Stab * stab_create () * * Stab_entry * stab_find (stab, sym) * Stab *stab; * char *sym; * * Stab_entry * stab_search (stab, sym) * Stab *stab; * char *sym; * * DESCRIPTION * stab_create creates a Stab, a symbol table object, and returns a * pointer to it. stab_find finds a symbol in a Stab; it returns a * pointer to the Stab_entry if found, otherwise NULL. stab_search * is like stab_find, except that it creates a new Stab_entry, * initialized with type = st_none, if one did not exist already * (it never returns NULL). * * A Stab_entry is a structure that contains at least the following * members: * * char *name; // must not be modified * enum sym_type type; // should be set * * The type field is initially set to st_none; it should be set to * something else by the caller of stab_search. Other possible values * of an enum sym_type can be added. */Stab *stab_create (){ Stab *sp; sp = xnew (1, Stab); *sp = NULL; /* a Stab starts out as a null Stab_entry* */ return sp;}Stab_entry *stab_find (stab, sym, symlen) Stab *stab; register char *sym; register int symlen;{ register Stab_entry *se; for (se = *stab; se != NULL; se = se->next) { if (se->symlen == symlen && strneq (se->sym, sym, symlen)) return se; } return NULL;}Stab_entry *stab_search (stab, sym, symlen) register Stab *stab; char *sym; int symlen;{ register Stab_entry *se; se = stab_find (stab, sym, symlen); if (se == NULL) { /* make a new one */ se = xnew (1, Stab_entry); se->sym = savenstr (sym, symlen); se->symlen = symlen; se->type = st_none; se->next = *stab; *stab = se; } return se;}/* * NAME * stab_type -- type of a symbol table entry * * SYNOPSIS * enum sym_type stab_type (Stab_entry *se); * * WARNING * May evaluate its argument more than once. */#define stab_type(se) ((se)==NULL ? st_none : (se)->type)typedef int LINENO;typedef struct{ char *p; int len; FILEPOS linestart; LINENO lineno; logical rewritten;} TOKEN; /* typedefs are recognized using a simple finite automaton. * tydef is its state variable. */typedef enum{ none, begin, middle, end} TYST;TYST tydef = none; /* struct tags for C++ are recognized using another simple * finite automaton. `structdef' is its state variable. * This machinery is only invoked for C++; otherwise structdef * should remain snone. However, this machinery can easily be * adapted to find structure tags in normal C code. */typedef enum{ snone, /* nothing seen yet */ skeyseen, /* struct-like keyword seen */ stagseen, /* struct-like tag seen */ scolonseen, /* colon seen after struct-like tag */ sinbody /* in a class body: recognize member func defs */} STRUCTST;STRUCTST structdef = snone;/* * When structdef is stagseen, scolonseen, or sinbody, structtag is the * struct tag, and structkey is the preceding struct-like keyword. */char structtag[512];Stab_entry *structkey;/* * Yet another little state machine to deal with preprocessor lines. */typedef enum{ dnone, /* nothing seen */ dsharpseen, /* '#' seen as first char on line */ ddefineseen, /* '#' and 'define' seen */ dignorerest /* ignore rest of line */} DEFINEST;DEFINEST definedef;/* * LEVEL_OK_FOR_FUNCDEF allows C++ function definition within class body. * Currently tydef and structdef stuff (typedefs and struct definitions) are * only noticed when level==0, but that may change. * * Note that this macro may only be evaluated inside C_entries(). It is * for self-documentation only. */#define LEVEL_OK_FOR_FUNCDEF() \ (level==0 || (c_ext && level==1 && structdef==sinbody))/* * next_token_is_func * set this to TRUE, and the next token considered is called a function. */logical next_token_is_func;/* C extensions. Currently all listed extensions are C++ dialects, so * `c_ext' is used as an abbreviation for `c_ext&C_PLPL'. If a non-C++ * dialect is added, this must change. */#define C_PLPL 0x1 /* C++ */#define C_STAR 0x3 /* C* */char searchar = '/'; /* use /.../ searches */LINENO lineno; /* line number of current line */long charno; /* current character number */FILEPOS linepos; /* start of line (C only) */FILEPOS prev_linepos; /* start of previous line (C only) */long linecharno; /* charno of start of line; not used by C, but * by every other language. */char *curfile, /* current input file name */ *outfile, /* output file */ *white = " \f\t\n", /* white chars */ *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */ *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$", /* token starting chars */ *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789", /* valid in-token chars */ *notgd = ",;"; /* non-valid after-function chars */int append_to_tagfile; /* -a: append to tags */int emacs_tags_format; /* emacs style output (no -e option any more) *//* The following three default to 1 for etags, but to 0 for ctags. */int typedefs; /* -t: create tags for typedefs */int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */ /* 0 struct/enum/union decls, and C++ */ /* member functions */int constantypedefs; /* -d: create tags for C #define and enum */ /* constants. Default under etags. Enum */ /* constants not implemented. */ /* -D: opposite of -d. Default under ctags. */int update; /* -u: update tags */int vgrind_style; /* -v: create vgrind style index output */int no_warnings; /* -w: suppress warnings */int cxref_style; /* -x: create cxref style output */int cplusplus; /* .[hc] means C++, not C */int noindentypedefs; /* -S: ignore indentation in C *//* Name this program was invoked with. */char *progname;struct option longopts[] = { { "append", no_argument, NULL, 'a' }, { "backward-search", no_argument, NULL, 'B' }, { "c++", no_argument, NULL, 'C' }, { "cxref", no_argument, NULL, 'x' }, { "defines", no_argument, NULL, 'd' }, { "forward-search", no_argument, NULL, 'F' }, { "help", no_argument, NULL, 'H' }, { "ignore-indentation", no_argument, NULL, 'S' }, { "include", required_argument, NULL, 'i' }, { "no-defines", no_argument, NULL, 'D' }, { "no-warn", no_argument, NULL, 'w' }, { "output", required_argument, NULL, 'o' }, { "typedefs", no_argument, NULL, 't' }, { "typedefs-and-c++", no_argument, NULL, 'T' }, { "update", no_argument, NULL, 'u' }, { "version", no_argument, NULL, 'V' }, { "vgrind", no_argument, NULL, 'v' }, { 0 }};FILE *inf, /* ioptr for current input file */ *outf; /* ioptr for tags file */NODE *head; /* the head of the binary tree of tags */int permit_duplicates = 1; /* Nonzero means allow duplicate tags. *//* A `struct linebuffer' is a structure which holds a line of text. `readline' reads a line from a stream into a linebuffer and works regardless of the length of the line. */struct linebuffer{ long size; char *buffer;};struct linebuffer lb; /* the current line */struct linebuffer lb1; /* sometimes, a previous line in which a token lies */struct linebuffer filename_lb; /* used to read in filenames */voidprint_version (){#ifdef CTAGS printf ("CTAGS ");#ifdef ETAGS printf ("and ");#endif#endif#ifdef ETAGS printf ("ETAGS ");#endif printf ("for Emacs version 19.0.\n"); exit (0);}voidprint_help (){ printf ("These are the options accepted by %s. You may use unambiguous\n\abbreviations for the long option names.\n\n", progname); fputs ("\-a, --append\n\ Append tag entries to existing tags file.\n\-C, --c++\n\ Treat files with `.c' and `.h' extensions as C++ code, not C\n\ code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\ extensions are always assumed to be C++ code.\n\-d, --defines\n\ Create tag entries for #defines, too.", stdout);#ifdef ETAGS fputs (" This is the default\n\ behavior.", stdout);#endif fputs ("\n\-D, --no-defines\n\ Don't create tag entries for #defines.", stdout);#ifdef CTAGS fputs (" This is the default\n\ behavior.", stdout);#endif puts ("\n\-o FILE, --output=FILE\n\ Write the tags to FILE.\n\-S, --ignore-indentation\n\ Don't rely on indentation quite as much as normal. Currently,\n\ this means not to assume that a closing brace in the first\n\ column is the final brace of a function or structure\n\ definition.\n\-t, --typedefs\n\ Generate tag entries for typedefs. This is the default\n\ behavior.\n\-T, --typedefs-and-c++\n\ Generate tag entries for typedefs, struct/enum/union tags, and\n\ C++ member functions.");#ifdef ETAGS puts ("-i FILE, --include=FILE\n\ Include a note in tag file indicating that, when searching for\n\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -