* This program examines each of its arguments for C function
* definitions, and puts them in a file "tags" for use by the editor
* (and anyone else who wants to).
* ken arnold wrote this program. ask him.
* brought over to the vax by peter b. kessler 7/79
* who disavows any knowledge of its actions,
* except for the stuff related to the construction
* of the search patterns.
* Some additional enhancements made by Mark Horton, involving
* the options and special treatment of "main", "}" at beginning
* of line, and a few bug fixes.
#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 */
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 */
#define MAXPATTERN 50 /* according to bill */
int lineno
; /* line number of current line */
char line
[256], /* 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 */
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
]);
sprintf(cmd
, "mv %s OTAGS ; fgrep -v '\t%s\t' OTAGS > %s ; rm OTAGS", outfile
, av
[i
], outfile
);
if ((outf
= fopen(outfile
, aflag
? "a" : "w")) == NULL
) {
put_funcs(head
); /* put the data in "tags" */
* 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.
* It also open up the "tags" output file.
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 program opens the specified file and calls the function
* which finds the function defenitions.
if ((inf
=fopen(file
,"r")) == NULL
) {
curfile
= (char *) calloc(strlen(file
)+1,1);
C_funcs(); /* find the C-style functions */
* This routine finds functions in C syntax and adds them
reg
char c
, /* current input char */
*token
, /* start of current token */
*tp
; /* end of current token */
logical incom
, /* T if inside a comment */
inquote
, /* T if inside a quoted string */
inchar
, /* T if inside a single char ' */
midtoken
; /* T if in middle of token */
char *sp
; /* current input char */
long insub
; /* level of "{}"s deep */
* init boolean flags, counters, and pointers
number
= gotone
= midtoken
= inquote
= inchar
= incom
= FALSE
;
printf(" t s c m q c g n\n");
printf(" s t k u o i u h o u\n");
printf(" c p p n b m d o r t m\n");
while ((*sp
=c
=getc(inf
)) != EOF
) {
printf("%2.2s: ",unctrl(c
));
printf("%2.2s ",unctrl(*sp
));
printf("%2.2s ",unctrl(*tp
));
printf("%2.2s ",unctrl(*token
));
printf("%2ld %d %d %d %d %d %d\n",insub
,incom
,midtoken
,inquote
,inchar
,gotone
,number
);
* action based on mixture of character type, *sp,
* Handling of backslash is very naive.
* We do, however, turn escaped newlines
while ((*++sp
=c
=getc(inf
)) == '*') {
printf("%2.2s- ",unctrl(c
));
printf("%2.2s ",unctrl(*sp
));
printf("%2.2s ",unctrl(*tp
));
printf("%2.2s ",unctrl(*token
));
printf("%2ld %d %d %d %d %d %d\n",insub
,incom
,midtoken
,inquote
,inchar
,gotone
,number
);
printf("%2.2s- ",unctrl(c
));
printf("%2.2s ",unctrl(*sp
));
printf("%2.2s ",unctrl(*tp
));
printf("%2.2s ",unctrl(*token
));
printf("%2ld %d %d %d %d %d %d\n",insub
,incom
,midtoken
,inquote
,inchar
,gotone
,number
);
* Too dumb to know about \" not being magic, but
* they usually occur in pairs anyway.
if ((*++sp
=c
=getc(inf
)) == '*')
else if (c
== '#' && sp
== line
)
* Kludge to get back in sync after getting confused.
* We really shouldn't be looking at indenting style,
* but tricking with the preprocessor can get us off,
* and most people indent this way anyway.
* This resets level of indenting to zero if '}' is
* found at beginning of line.
else if (!insub
&& !inquote
&& !inchar
&& !gotone
) {
if (start_func(&sp
,token
,tp
)) {
strncpy(tok
,token
,tp
-token
+1);
* move on to next char, and set flags accordingly
lineftell
= ftell( inf
);
printf("lineftell saved as %ld\n",lineftell
);
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 */
printf("%2.2s:\n",unctrl(c
));
/* 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
)) != ')') {
* 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
;
printf("%2.2s:\n",unctrl(c
));
printf("%2.2s:\n",unctrl(c
));
while (iswhite(*++sp
=c
=getc(inf
)))
printf("%2.2s:\n",unctrl(c
))
printf("%2.2s:\n",unctrl(c
));
return !bad
&& isgood(c
);
* This routine adds a function to the list
if ((np
= (NODE
*) calloc(1,sizeof (NODE
))) == NULL
) {
printf("too many functions to sort\n");
head
= np
= (NODE
*) calloc(1,sizeof (NODE
));
if (strcmp(token
,"main") == 0) {
* Since there are so many directories with lots of
* misc. complete programs in them, main tends to get
* redefined a lot. So we change all mains to instead
* refer to the name of the file, without leading
* pathname components and without a trailing .c.
for (pp
=curfile
; *pp
; pp
++)
pp
= &token
[strlen(token
)-2];
fp
= np
->func
= (char *) calloc(strlen(token
)+1,sizeof (char));
* this change to make the whole line the pattern
long saveftell
= ftell( inf
);
fseek( inf
, lineftell
, 0 );
printf("saveftell=%ld, lseek back to %ld\n",saveftell
,lineftell
);
while ( ch
!= '\n' && ch
!= searchar
&& patlen
< MAXPATTERN
) {
pp
= np
-> pat
= (char *) calloc( patlen
+ 2 , sizeof( char ) );
fseek( inf
, lineftell
, 0 );
fseek( inf
, saveftell
, 0 );
printf("seek back to %ld, ftell is now %ld\n",saveftell
,ftell(inf
));
printf("\"%s\"\t\"%s\"\t\"%s\"\n",np
->func
,np
->file
,np
->pat
);
* This routine cfrees the entire tree from the node down.
* This routine finds the node where the new function node
dif
= strcmp(node
->func
,cur_node
->func
);
printf("strcmp(\"%s\",\"%s\") == %d\n",node
->func
,cur_node
->func
,dif
);
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 name 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
);
printf("adding to left branch\n");
if (cur_node
->right
!= NULL
)
add_node(node
,cur_node
->right
);
printf("adding to right branch\n");
* This routine puts the functions in the file.
fprintf(outf
,"%s\t%s\t%c^%s%c\n",node
->func
,node
->file
,searchar
,node
->pat
,searchar
);