📄 etags.c
字号:
/* Tags file maker to go with GNUmacs Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.In other words, you are welcome to use, share and improve this program.You are forbidden to forbid anyone else to use, share and improvewhat you give them. Help stamp out software-hoarding! */#include <stdio.h>#include <ctype.h>/* 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). *//* 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#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)/* cause token checking for typedef, struct, union, enum to distinguish keywords from identifier-prefixes (e.g. struct vs struct_tag). */#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))struct nd_st { /* sorting structure */ char *name; /* function or type name */ char *file; /* file name */ logical f; /* use pattern or line no */ int lno; /* line number tag is on */ long cno; /* character number line starts on */ char *pat; /* search pattern */ logical been_warned; /* set if noticed dup */ struct nd_st *left,*right; /* left and right sons */};long ftell();typedef struct nd_st NODE;int number; /* tokens found so far on line starting with # (including #) */logical gotone, /* found a func already on line */ /* boolean "func" (see init) */ _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177]; /* typedefs are recognized using a simple finite automata, * tydef is its state variable. */typedef enum {none, begin, tag_ok, middle, end } TYST;TYST tydef = none;char searchar = '/'; /* use /.../ searches */int lineno; /* line number of current line */long charno; /* current character number */long linecharno; /* character number of start of line */char *curfile, /* current input file name */ *outfile= 0, /* 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 file_num = 0; /* current file number */int aflag = 0; /* -a: append to tags */int tflag = 0; /* -t: create tags for typedefs */int uflag = 0; /* -u: update tags */int wflag = 0; /* -w: suppress warnings */int vflag = 0; /* -v: create vgrind style index output */int xflag = 0; /* -x: create cxref style output */int eflag = 0; /* -e: emacs style output *//* Name this program was invoked with. */char *progname;FILE *inf, /* ioptr for current input file */ *outf; /* ioptr for tags file */NODE *head; /* the head of the sorted binary tree */char *savestr();char *savenstr ();char *rindex();char *index();char *concat ();void initbuffer ();long readline ();/* 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, lb1;#if 0 /* VMS now provides the `system' function. */#ifdef VMS#include <descrip.h>voidsystem (buf) char *buf;{ struct dsc$descriptor_s command = { strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf }; LIB$SPAWN(&command);}#endif /* VMS */#endif /* 0 */main(ac,av) int ac; char *av[];{ char cmd[100]; int i; int fflag = 0; char *this_file;#ifdef VMS char got_err; extern char *gfnames(); extern char *massage_name();#endif progname = av[0];#ifdef ETAGS eflag = 1;#else#ifdef CTAGS eflag = 0;#else { char *subname = rindex (progname, '/'); if (subname++ == NULL) subname = progname; eflag = ! strcmp(subname, "ctags"); }#endif#endif while (ac > 1 && av[1][0] == '-') { for (i=1; av[1][i]; i++) { switch(av[1][i]) {#ifndef VMS /* These options are useful only with ctags, and VMS can't input them, so just omit them. */ case 'B': searchar='?'; eflag = 0; break; case 'F': searchar='/'; eflag = 0; break;#endif case 'a': aflag++; break; case 'e': eflag++; break; case 'f': if (fflag > 0) { fprintf(stderr, "%s: -f flag may only be given once\n", progname); goto usage; } fflag++, ac--; av++; if (ac <= 1 || av[1][0] == '\0') { fprintf(stderr, "%s: -f flag must be followed by a filename\n", progname); goto usage; } outfile = av[1]; goto end_loop; case 't': tflag++; break;#ifndef VMS case 'u': uflag++; eflag = 0; break;#endif case 'w': wflag++; break; case 'v': vflag++; xflag++; eflag = 0; break; case 'x': xflag++; eflag = 0; break; default: goto usage; } } end_loop: ; ac--; av++; } if (ac <= 1) { usage:#ifdef VMS fprintf (stderr, "Usage: %s [-aetwvx] [-f outfile] file ...\n", progname);#else fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname);#endif exit(BAD); } if (outfile == 0) { outfile = eflag ? "TAGS" : "tags"; } init(); /* set up boolean "functions" */ initbuffer (&lb); initbuffer (&lb1); /* * loop through files finding functions */ if (eflag) { outf = fopen (outfile, aflag ? "a" : "w"); if (!outf) { fprintf (stderr, "%s: ", progname); perror (outfile); exit (BAD); } } file_num = 1;#ifdef VMS for (ac--, av++; (this_file = gfnames (&ac, &av, &got_err)) != NULL; file_num++) { if (got_err) { error("Can't find file %s\n", this_file); ac--, av++; } else { this_file = massage_name (this_file);#else for (; file_num < ac; file_num++) { this_file = av[file_num]; if (1) {#endif find_entries (this_file); if (eflag) { fprintf (outf, "\f\n%s,%d\n", this_file, total_size_of_entries (head)); put_entries (head); free_tree (head); head = NULL; } } } if (eflag) { fclose (outf); exit (GOOD); } if (xflag) { put_entries(head); exit(GOOD); } if (uflag) { for (i=1; i<ac; i++) { sprintf(cmd, "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS", outfile, av[i], outfile); system(cmd); } aflag++; } outf = fopen(outfile, aflag ? "a" : "w"); if (outf == NULL) { fprintf (stderr, "%s: ", outfile); perror(outfile); exit(BAD); } put_entries(head); fclose(outf);#ifndef VMS if (uflag) { sprintf(cmd, "sort %s -o %s", outfile, outfile); system(cmd); }#endif exit(GOOD);}/* * This routine sets up the boolean psuedo-functions which work * by seting boolean flags dependent upon the corresponding character * Every char which is NOT in that string is not a white char. Therefore, * all of the array "_wht" is set to FALSE, and then the elements * subscripted by the chars in "white" are set to TRUE. Thus "_wht" * of a char is TRUE if it is the string "white", else FALSE. */init(){ reg char *sp; reg int i; for (i = 0; i < 0177; i++) { _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE; _gd[i] = TRUE; } for (sp = white; *sp; sp++) _wht[*sp] = TRUE; for (sp = endtk; *sp; sp++) _etk[*sp] = TRUE; for (sp = intk; *sp; sp++) _itk[*sp] = TRUE; for (sp = begtk; *sp; sp++) _btk[*sp] = TRUE; for (sp = notgd; *sp; sp++) _gd[*sp] = FALSE; _wht[0] = _wht['\n']; _etk[0] = _etk['\n']; _btk[0] = _btk['\n']; _itk[0] = _itk['\n']; _gd[0] = _gd['\n'];}/* * This routine opens the specified file and calls the function * which finds the function and type definitions. */find_entries (file) char *file;{ char *cp; if ((inf=fopen(file,"r")) == NULL) { fprintf (stderr, "%s: ", progname); perror(file); return; } curfile = savestr(file); cp = rindex(file, '.'); /* .tex, .aux or .bbl implies LaTeX source code */ if (cp && (!strcmp (cp + 1, "tex") || !strcmp (cp + 1, "aux") || !strcmp (cp + 1, "bbl"))) { TEX_funcs(inf); fclose(inf); return; } /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */ if (cp && (!strcmp (cp + 1, "l") || !strcmp (cp + 1, "el") || !strcmp (cp + 1, "lsp") || !strcmp (cp + 1, "lisp") || !strcmp (cp + 1, "cl") || !strcmp (cp + 1, "clisp"))) { L_funcs(inf); fclose(inf); return; } /* .scm or .sm or .scheme implies scheme source code */ if (cp && (!strcmp (cp + 1, "sm") || !strcmp (cp + 1, "scm") || !strcmp (cp + 1, "scheme") || !strcmp (cp + 1, "t") || !strcmp (cp + 1, "sch") || !strcmp (cp + 1, "SM") || !strcmp (cp + 1, "SCM") /* The `SCM' or `scm' prefix with a version number */ || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's' && string_numeric_p (cp + 1)) || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S' && string_numeric_p (cp + 1)))) { Scheme_funcs(inf); fclose(inf); return; } /* if not a .c or .h or .y file, try fortran */ if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y') && cp[2] == '\0') { if (PF_funcs(inf) != 0) { fclose(inf); return; } rewind(inf); /* no fortran tags found, try C */ } C_entries(); fclose(inf);}/* Nonzero if string STR is composed of digits. */intstring_numeric_p (str) char *str;{ while (*str) { if (*str < '0' || *str > '9') return 0; } return 1;}/* Record a tag on the current line. name is the tag name, f is nonzero to use a pattern, zero to use line number instead. */pfnote (name, f, linestart, linelen, lno, cno) char *name; logical f; /* f == TRUE when function */ char *linestart; int linelen; int lno; long cno;{ register char *fp; register NODE *np; char *altname; char tem[51]; if ((np = (NODE *) malloc (sizeof (NODE))) == NULL) { fprintf(stderr, "%s: too many entries to sort\n", progname); put_entries(head); free_tree(head); head = NULL; np = (NODE *) xmalloc(sizeof (NODE)); } /* Change name "main" to M<thisfilename>. */ if (!eflag && !xflag && !strcmp(name, "main")) { fp = rindex(curfile, '/'); if (fp == 0) fp = curfile; else fp++; altname = concat ("M", fp, ""); fp = rindex(altname, '.'); if (fp && fp[2] == 0) *fp = 0; name = altname; } np->name = savestr(name); np->file = curfile; np->f = f; np->lno = lno; np->cno = cno; np->left = np->right = 0; if (eflag) { linestart[linelen] = 0; } else if (xflag == 0) { sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart); linestart = tem;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -