ctags.c revision 48465
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	}
174	exit(exit_val);
175}
176
177static void
178usage()
179{
180	(void)fprintf(stderr, "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
181	exit(1);
182}
183
184/*
185 * init --
186 *	this routine sets up the boolean psuedo-functions which work by
187 *	setting boolean flags dependent upon the corresponding character.
188 *	Every char which is NOT in that string is false with respect to
189 *	the pseudo-function.  Therefore, all of the array "_wht" is NO
190 *	by default and then the elements subscripted by the chars in
191 *	CWHITE are set to YES.  Thus, "_wht" of a char is YES if it is in
192 *	the string CWHITE, else NO.
193 */
194void
195init()
196{
197	int		i;
198	unsigned char	*sp;
199
200	for (i = 0; i < 256; i++) {
201		_wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
202		_gd[i] = YES;
203	}
204#define	CWHITE	" \f\t\n"
205	for (sp = CWHITE; *sp; sp++)	/* white space chars */
206		_wht[*sp] = YES;
207#define	CTOKEN	" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
208	for (sp = CTOKEN; *sp; sp++)	/* token ending chars */
209		_etk[*sp] = YES;
210#define	CINTOK	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
211	for (sp = CINTOK; *sp; sp++)	/* valid in-token chars */
212		_itk[*sp] = YES;
213#define	CBEGIN	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
214	for (sp = CBEGIN; *sp; sp++)	/* token starting chars */
215		_btk[*sp] = YES;
216#define	CNOTGD	",;"
217	for (sp = CNOTGD; *sp; sp++)	/* invalid after-function chars */
218		_gd[*sp] = NO;
219}
220
221/*
222 * find_entries --
223 *	this routine opens the specified file and calls the function
224 *	which searches the file.
225 */
226void
227find_entries(file)
228	char	*file;
229{
230	char	*cp;
231
232	lineno = 0;				/* should be 1 ?? KB */
233	if ((cp = strrchr(file, '.'))) {
234		if (cp[1] == 'l' && !cp[2]) {
235			int	c;
236
237			for (;;) {
238				if (GETC(==, EOF))
239					return;
240				if (!iswhite(c)) {
241					rewind(inf);
242					break;
243				}
244			}
245#define	LISPCHR	";(["
246/* lisp */		if (strchr(LISPCHR, c)) {
247				l_entries();
248				return;
249			}
250/* lex */		else {
251				/*
252				 * we search all 3 parts of a lex file
253				 * for C references.  This may be wrong.
254				 */
255				toss_yysec();
256				(void)strcpy(lbuf, "%%$");
257				pfnote("yylex", lineno);
258				rewind(inf);
259			}
260		}
261/* yacc */	else if (cp[1] == 'y' && !cp[2]) {
262			/*
263			 * we search only the 3rd part of a yacc file
264			 * for C references.  This may be wrong.
265			 */
266			toss_yysec();
267			(void)strcpy(lbuf, "%%$");
268			pfnote("yyparse", lineno);
269			y_entries();
270		}
271/* fortran */	else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
272			if (PF_funcs())
273				return;
274			rewind(inf);
275		}
276	}
277/* C */	c_entries();
278}
279