home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bbs
/
gnu
/
emacs-18.59-bin.lha
/
lib
/
emacs
/
18.59
/
etc
/
etags.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-09
|
34KB
|
1,643 lines
/* 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 improve
what 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;
logical next_token_is_func;
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>
void
system (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
eflag = 0;
#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++)
{
#ifdef AMIGA
rename(outfile, "OTAGS");
sprintf(cmd, "egrep >%s -v '\t%s\t' OTAGS", outfile, av[i]);
system(cmd);
unlink("OTAGS");
#else
sprintf(cmd,
"mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",