ctags.c revision 41568
1/*
2 * Copyright (c) 1987, 1993, 1994, 1995
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static const char sccsid[] = "@(#)ctags.c	8.4 (Berkeley) 2/7/95";
42#endif /* not lint */
43
44#include <err.h>
45#include <limits.h>
46#include <stdio.h>
47#include <string.h>
48#include <stdlib.h>
49#include <unistd.h>
50
51#include "ctags.h"
52
53/*
54 * ctags: create a tags file
55 */
56
57NODE	*head;			/* head of the sorted binary tree */
58
59				/* boolean "func" (see init()) */
60bool	_wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
61
62FILE	*inf;			/* ioptr for current input file */
63FILE	*outf;			/* ioptr for tags file */
64
65long	lineftell;		/* ftell after getc( inf ) == '\n' */
66
67int	lineno;			/* line number of current line */
68int	dflag;			/* -d: non-macro defines */
69int	tflag;			/* -t: create tags for typedefs */
70int	vflag;			/* -v: vgrind style index output */
71int	wflag;			/* -w: suppress warnings */
72int	xflag;			/* -x: cxref style output */
73
74char	*curfile;		/* current input file name */
75char	searchar = '/';		/* use /.../ searches by default */
76char	lbuf[LINE_MAX];
77
78void	init __P((void));
79void	find_entries __P((char *));
80static void usage __P((void));
81
82int
83main(argc, argv)
84	int	argc;
85	char	**argv;
86{
87	static char	*outfile = "tags";	/* output file */
88	int	aflag;				/* -a: append to tags */
89	int	uflag;				/* -u: update tags */
90	int	exit_val;			/* exit value */
91	int	step;				/* step through args */
92	int	ch;				/* getopts char */
93	char	cmd[100];			/* too ugly to explain */
94
95	aflag = uflag = NO;
96	while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
97		switch(ch) {
98		case 'B':
99			searchar = '?';
100			break;
101		case 'F':
102			searchar = '/';
103			break;
104		case 'a':
105			aflag++;
106			break;
107		case 'd':
108			dflag++;
109			break;
110		case 'f':
111			outfile = optarg;
112			break;
113		case 't':
114			tflag++;
115			break;
116		case 'u':
117			uflag++;
118			break;
119		case 'w':
120			wflag++;
121			break;
122		case 'v':
123			vflag++;
124		case 'x':
125			xflag++;
126			break;
127		case '?':
128		default:
129			usage();
130		}
131	argv += optind;
132	argc -= optind;
133	if (!argc)
134		usage();
135
136	init();
137
138	for (exit_val = step = 0; step < argc; ++step)
139		if (!(inf = fopen(argv[step], "r"))) {
140			warn("%s", argv[step]);
141			exit_val = 1;
142		}
143		else {
144			curfile = argv[step];
145			find_entries(argv[step]);
146			(void)fclose(inf);
147		}
148
149	if (head)
150		if (xflag)
151			put_entries(head);
152		else {
153			if (uflag) {
154				for (step = 0; step < argc; step++) {
155					(void)sprintf(cmd,
156						"mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
157							outfile, argv[step],
158							outfile);
159					system(cmd);
160				}
161				++aflag;
162			}
163			if (!(outf = fopen(outfile, aflag ? "a" : "w")))
164				err(exit_val, "%s", outfile);
165			put_entries(head);
166			(void)fclose(outf);
167			if (uflag) {
168				(void)sprintf(cmd, "sort -o %s %s",
169						outfile, outfile);
170				system(cmd);
171			}
172		}
173	exit(exit_val);
174}
175
176static void
177usage()
178{
179	(void)fprintf(stderr, "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
180	exit(1);
181}
182
183/*
184 * init --
185 *	this routine sets up the boolean psuedo-functions which work by
186 *	setting boolean flags dependent upon the corresponding character.
187 *	Every char which is NOT in that string is false with respect to
188 *	the pseudo-function.  Therefore, all of the array "_wht" is NO
189 *	by default and then the elements subscripted by the chars in
190 *	CWHITE are set to YES.  Thus, "_wht" of a char is YES if it is in
191 *	the string CWHITE, else NO.
192 */
193void
194init()
195{
196	int		i;
197	unsigned char	*sp;
198
199	for (i = 0; i < 256; i++) {
200		_wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
201		_gd[i] = YES;
202	}
203#define	CWHITE	" \f\t\n"
204	for (sp = CWHITE; *sp; sp++)	/* white space chars */
205		_wht[*sp] = YES;
206#define	CTOKEN	" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
207	for (sp = CTOKEN; *sp; sp++)	/* token ending chars */
208		_etk[*sp] = YES;
209#define	CINTOK	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
210	for (sp = CINTOK; *sp; sp++)	/* valid in-token chars */
211		_itk[*sp] = YES;
212#define	CBEGIN	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
213	for (sp = CBEGIN; *sp; sp++)	/* token starting chars */
214		_btk[*sp] = YES;
215#define	CNOTGD	",;"
216	for (sp = CNOTGD; *sp; sp++)	/* invalid after-function chars */
217		_gd[*sp] = NO;
218}
219
220/*
221 * find_entries --
222 *	this routine opens the specified file and calls the function
223 *	which searches the file.
224 */
225void
226find_entries(file)
227	char	*file;
228{
229	char	*cp;
230
231	lineno = 0;				/* should be 1 ?? KB */
232	if ((cp = strrchr(file, '.'))) {
233		if (cp[1] == 'l' && !cp[2]) {
234			int	c;
235
236			for (;;) {
237				if (GETC(==, EOF))
238					return;
239				if (!iswhite(c)) {
240					rewind(inf);
241					break;
242				}
243			}
244#define	LISPCHR	";(["
245/* lisp */		if (strchr(LISPCHR, c)) {
246				l_entries();
247				return;
248			}
249/* lex */		else {
250				/*
251				 * we search all 3 parts of a lex file
252				 * for C references.  This may be wrong.
253				 */
254				toss_yysec();
255				(void)strcpy(lbuf, "%%$");
256				pfnote("yylex", lineno);
257				rewind(inf);
258			}
259		}
260/* yacc */	else if (cp[1] == 'y' && !cp[2]) {
261			/*
262			 * we search only the 3rd part of a yacc file
263			 * for C references.  This may be wrong.
264			 */
265			toss_yysec();
266			(void)strcpy(lbuf, "%%$");
267			pfnote("yyparse", lineno);
268			y_entries();
269		}
270/* fortran */	else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
271			if (PF_funcs())
272				return;
273			rewind(inf);
274		}
275	}
276/* C */	c_entries();
277}
278