static char *sccsid
= "@(#)ctags.c 4.3 (Berkeley) 11/24/80";
* ctags: create a tags file
#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 *func
; /* function name */
char *file
; /* file name */
int lno
; /* for -x option */
char *pat
; /* search pattern */
logical been_warned
; /* set if noticed dup */
struct nd_st
*left
,*right
; /* left and right sons */
typedef struct nd_st NODE
;
logical number
, /* T if on line starting with # */
term
= FALSE
, /* T if print on terminal */
makefile
= TRUE
, /* T if to creat "tags" file */
gotone
, /* found a func already on line */
/* boolean "func" (see init) */
_wht
[0177],_etk
[0177],_itk
[0177],_btk
[0177],_gd
[0177];
char searchar
= '?'; /* use ?...? searches */
int lineno
; /* line number of current line */
char line
[4*BUFSIZ
], /* current input line */
*curfile
, /* current input file name */
*outfile
= "tags", /* output file */
*white
= " \f\t\n", /* white chars */
*endtk
= " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
*begtk
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz",
/* token starting chars */
*intk
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789", /* valid in-token chars */
*notgd
= ",;"; /* non-valid after-function chars */
int file_num
; /* current file number */
int aflag
; /* -a: append to tags */
int uflag
; /* -u: update tags */
int wflag
; /* -w: suppress warnings */
int vflag
; /* -v: create vgrind style index output */
int xflag
; /* -x: create cxref style output */
FILE *inf
, /* ioptr for current input file */
*outf
; /* ioptr for tags file */
long lineftell
; /* ftell after getc( inf ) == '\n' */
NODE
*head
; /* the head of the sorted binary tree */
while (ac
> 1 && av
[1][0] == '-') {
for (i
=1; av
[1][i
]; i
++) {
usage
: printf("Usage: ctags [-au] file ...\n");
init(); /* set up boolean "functions" */
* loop through files finding functions
for (file_num
= 1; file_num
< ac
; file_num
++)
find_funcs(av
[file_num
]);
"mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
outfile
, av
[i
], outfile
);
outf
= fopen(outfile
, aflag
? "a" : "w");
sprintf(cmd
, "sort %s -o %s", outfile
, outfile
);
* 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.
for (i
= 0; i
< 0177; i
++) {
_wht
[i
] = _etk
[i
] = _itk
[i
] = _btk
[i
] = FALSE
;
for (sp
= white
; *sp
; sp
++)
for (sp
= endtk
; *sp
; sp
++)
for (sp
= intk
; *sp
; sp
++)
for (sp
= begtk
; *sp
; sp
++)
for (sp
= notgd
; *sp
; sp
++)
* This routine opens the specified file and calls the function
* which finds the function definitions.
if ((inf
=fopen(file
,"r")) == NULL
) {
if (cp
&& (cp
[1] != 'c' || cp
[1] != 'h') && cp
[2] == 0) {
if (PF_funcs(inf
) == 0) {
if ((np
= (NODE
*) malloc(sizeof (NODE
))) == NULL
) {
fprintf(stderr
, "ctags: too many functions to sort\n");
head
= np
= (NODE
*) malloc(sizeof (NODE
));
if (xflag
== 0 && !strcmp(name
, "main")) {
fp
= rindex(curfile
, '/');
sprintf(nbuf
, "M%s", fp
);
np
->func
= savestr(name
);
np
->left
= np
->right
= 0;
* This routine finds functions in C syntax and adds them
register char *token
, *tp
;
int incomm
, inquote
, inchar
, midtoken
, level
;
number
= gotone
= midtoken
= inquote
= inchar
= incomm
= FALSE
;
while ((*++sp
=c
=getc(inf
)) == '*')
* Too dumb to know about \" not being magic, but
* they usually occur in pairs anyway.
if ((*++sp
=c
=getc(inf
)) == '*')
if (!level
&& !inquote
&& !incomm
&& gotone
== 0) {
if (start_func(&sp
,token
,tp
)) {
strncpy(tok
,token
,tp
-token
+1);
} else if (begtoken(c
)) {
if (c
== '\n' || sp
> &line
[sizeof (line
) - BUFSIZ
]) {
number
= gotone
= midtoken
= inquote
= inchar
= FALSE
;
* This routine checks to see if the current token is
* at the start of a function. It updates the input line
* so that the '(' will be in it when it returns.
logical firsttok
; /* T if have seen first token in ()'s */
if (!number
) { /* space is not allowed in macro defs */
if (sp
> &line
[sizeof (line
) - BUFSIZ
])
/* the following tries to make it so that a #define a b(c) */
/* doesn't count as a define of b. */
for (tsp
= "define"; *tsp
&& token
< tp
; tsp
++)
while ((*++sp
=c
=getc(inf
)) != ')') {
if (sp
> &line
[sizeof (line
) - BUFSIZ
])
* This line used to confuse ctags:
* This fixes it. A nonwhite char before the first
* token, other than a / (in case of a comment in there)
* makes this not a declaration.
if (begtoken(c
) || c
=='/') firsttok
++;
else if (!iswhite(c
) && !firsttok
) goto badone
;
while (iswhite(*++sp
=c
=getc(inf
)))
if (sp
> &line
[sizeof (line
) - BUFSIZ
])
return !bad
&& isgood(c
);
long saveftell
= ftell( inf
);
fseek( inf
, lineftell
, 0 );
fgets(lbuf
, sizeof lbuf
, inf
);
fseek(inf
, saveftell
, 0);
dif
= strcmp(node
->func
,cur_node
->func
);
if (node
->file
== cur_node
->file
) {
fprintf(stderr
,"Duplicate function in file %s, line %d: %s\n",
node
->file
,lineno
,node
->func
);
fprintf(stderr
,"Second entry ignored\n");
if (!cur_node
->been_warned
)
fprintf(stderr
,"Duplicate function in files %s and %s: %s (Warning only)\n",
node
->file
, cur_node
->file
, node
->func
);
cur_node
->been_warned
= TRUE
;
if (cur_node
->left
!= NULL
)
add_node(node
,cur_node
->left
);
if (cur_node
->right
!= NULL
)
add_node(node
,cur_node
->right
);
fprintf(outf
, "%s\t%s\t%c^", node
->func
, node
->file
,searchar
);
for (sp
= node
->pat
; *sp
; sp
++)
fprintf(outf
, "%c\n", searchar
);
fprintf(stdout
, "%s %s %d\n", node
->func
, node
->file
, (node
->lno
+63)/64);
fprintf(stdout
, "%-16s%4d %-16s %s\n",
node
->func
, node
->lno
, node
->file
, node
->pat
);
while (fgets(lbuf
, sizeof(lbuf
), fi
)) {
if ( *dbp
== '%' ) dbp
++ ; /* Ratfor escape to fortran */
if (tail("complex") || tail("character"))
while (*cp
&& (*cp
&~' ') == ((*(dbp
+len
))&~' '))
--dbp
; /* force failure */
for (cp
= lbuf
; *cp
; cp
++)
*--cp
= 0; /* zap newline */
if (*dbp
== 0 || !isalpha(*dbp
))
for (cp
= dbp
+1; *cp
&& (isalpha(*cp
) || isdigit(*cp
)); cp
++)
dp
= (char *)malloc(len
+1);
* Return the ptr in sp at which the character c last
* appears; NULL if not found
* Identical to v7 rindex, included for portability.