ctags.c revision 201606
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
39
40#if 0
41#ifndef lint
42static char sccsid[] = "@(#)ctags.c	8.4 (Berkeley) 2/7/95";
43#endif
44#endif
45
46#include <sys/cdefs.h>
47#include <sys/types.h>
48#include <sys/wait.h>
49__FBSDID("$FreeBSD: head/usr.bin/ctags/ctags.c 201606 2010-01-05 20:32:08Z dwmalone $");
50
51#include <err.h>
52#include <limits.h>
53#include <locale.h>
54#include <regex.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59
60#include "ctags.h"
61
62/*
63 * ctags: create a tags file
64 */
65
66NODE	*head;			/* head of the sorted binary tree */
67
68				/* boolean "func" (see init()) */
69bool	_wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
70
71FILE	*inf;			/* ioptr for current input file */
72FILE	*outf;			/* ioptr for tags file */
73
74long	lineftell;		/* ftell after getc( inf ) == '\n' */
75
76int	lineno;			/* line number of current line */
77int	dflag;			/* -d: non-macro defines */
78int	tflag;			/* -t: create tags for typedefs */
79int	vflag;			/* -v: vgrind style index output */
80int	wflag;			/* -w: suppress warnings */
81int	xflag;			/* -x: cxref style output */
82
83char	*curfile;		/* current input file name */
84char	searchar = '/';		/* use /.../ searches by default */
85char	lbuf[LINE_MAX];
86
87void	init(void);
88void	find_entries(char *);
89static void usage(void);
90
91int
92main(int argc, char **argv)
93{
94	static const char	*outfile = "tags";	/* output file */
95	int	aflag;				/* -a: append to tags */
96	int	uflag;				/* -u: update tags */
97	int	exit_val;			/* exit value */
98	int	step;				/* step through args */
99	int	ch;				/* getopts char */
100
101	setlocale(LC_ALL, "");
102
103	aflag = uflag = NO;
104	tflag = YES;
105	while ((ch = getopt(argc, argv, "BFTadf:tuwvx")) != -1)
106		switch(ch) {
107		case 'B':
108			searchar = '?';
109			break;
110		case 'F':
111			searchar = '/';
112			break;
113		case 'T':
114			tflag = NO;
115			break;
116		case 'a':
117			aflag++;
118			break;
119		case 'd':
120			dflag++;
121			break;
122		case 'f':
123			outfile = optarg;
124			break;
125		case 't':
126			tflag = YES;
127			break;
128		case 'u':
129			uflag++;
130			break;
131		case 'w':
132			wflag++;
133			break;
134		case 'v':
135			vflag++;
136		case 'x':
137			xflag++;
138			break;
139		case '?':
140		default:
141			usage();
142		}
143	argv += optind;
144	argc -= optind;
145	if (!argc)
146		usage();
147
148	if (!xflag)
149		setlocale(LC_COLLATE, "C");
150
151	init();
152
153	for (exit_val = step = 0; step < argc; ++step)
154		if (!(inf = fopen(argv[step], "r"))) {
155			warn("%s", argv[step]);
156			exit_val = 1;
157		}
158		else {
159			curfile = argv[step];
160			find_entries(argv[step]);
161			(void)fclose(inf);
162		}
163
164	if (head) {
165		if (xflag)
166			put_entries(head);
167		else {
168			if (uflag) {
169				FILE *oldf;
170				regex_t *regx;
171
172				if ((oldf = fopen(outfile, "r")) == NULL)
173					err(1, "opening %s", outfile);
174				if (unlink(outfile))
175					err(1, "unlinking %s", outfile);
176				if ((outf = fopen(outfile, "w")) == NULL)
177					err(1, "recreating %s", outfile);
178				if ((regx = calloc(argc, sizeof(regex_t))) == NULL)
179					err(1, "RE alloc");
180				for (step = 0; step < argc; step++) {
181					(void)strcpy(lbuf, "\t");
182					(void)strlcat(lbuf, argv[step], LINE_MAX);
183					(void)strlcat(lbuf, "\t", LINE_MAX);
184					if (regcomp(regx + step, lbuf,
185					    REG_NOSPEC))
186						warn("RE compilation failed");
187				}
188nextline:
189				while (fgets(lbuf, LINE_MAX, oldf)) {
190					for (step = 0; step < argc; step++)
191						if (regexec(regx + step,
192						    lbuf, 0, NULL, 0) == 0)
193							goto nextline;
194					fputs(lbuf, outf);
195				}
196				for (step = 0; step < argc; step++)
197					regfree(regx + step);
198				free(regx);
199				fclose(oldf);
200				fclose(outf);
201				++aflag;
202			}
203			if (!(outf = fopen(outfile, aflag ? "a" : "w")))
204				err(1, "%s", outfile);
205			put_entries(head);
206			(void)fclose(outf);
207			if (uflag) {
208				pid_t pid;
209
210				if ((pid = fork()) == -1)
211					err(1, "fork failed");
212				else if (pid == 0) {
213					execlp("sort", "sort", "-o", outfile,
214					    outfile, NULL);
215					err(1, "exec of sort failed");
216				}
217				/* Just assume the sort went OK. The old code
218				   did not do any checks either. */
219				(void)wait(NULL);
220			}
221		}
222	}
223	exit(exit_val);
224}
225
226static void
227usage(void)
228{
229	(void)fprintf(stderr, "usage: ctags [-BFTaduwvx] [-f tagsfile] file ...\n");
230	exit(1);
231}
232
233/*
234 * init --
235 *	this routine sets up the boolean pseudo-functions which work by
236 *	setting boolean flags dependent upon the corresponding character.
237 *	Every char which is NOT in that string is false with respect to
238 *	the pseudo-function.  Therefore, all of the array "_wht" is NO
239 *	by default and then the elements subscripted by the chars in
240 *	CWHITE are set to YES.  Thus, "_wht" of a char is YES if it is in
241 *	the string CWHITE, else NO.
242 */
243void
244init(void)
245{
246	int		i;
247	const unsigned char	*sp;
248
249	for (i = 0; i < 256; i++) {
250		_wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
251		_gd[i] = YES;
252	}
253#define	CWHITE	" \f\t\n"
254	for (sp = CWHITE; *sp; sp++)	/* white space chars */
255		_wht[*sp] = YES;
256#define	CTOKEN	" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
257	for (sp = CTOKEN; *sp; sp++)	/* token ending chars */
258		_etk[*sp] = YES;
259#define	CINTOK	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
260	for (sp = CINTOK; *sp; sp++)	/* valid in-token chars */
261		_itk[*sp] = YES;
262#define	CBEGIN	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
263	for (sp = CBEGIN; *sp; sp++)	/* token starting chars */
264		_btk[*sp] = YES;
265#define	CNOTGD	",;"
266	for (sp = CNOTGD; *sp; sp++)	/* invalid after-function chars */
267		_gd[*sp] = NO;
268}
269
270/*
271 * find_entries --
272 *	this routine opens the specified file and calls the function
273 *	which searches the file.
274 */
275void
276find_entries(char *file)
277{
278	char	*cp;
279
280	lineno = 0;				/* should be 1 ?? KB */
281	if ((cp = strrchr(file, '.'))) {
282		if (cp[1] == 'l' && !cp[2]) {
283			int	c;
284
285			for (;;) {
286				if (GETC(==, EOF))
287					return;
288				if (!iswhite(c)) {
289					rewind(inf);
290					break;
291				}
292			}
293#define	LISPCHR	";(["
294/* lisp */		if (strchr(LISPCHR, c)) {
295				l_entries();
296				return;
297			}
298/* lex */		else {
299				/*
300				 * we search all 3 parts of a lex file
301				 * for C references.  This may be wrong.
302				 */
303				toss_yysec();
304				(void)strcpy(lbuf, "%%$");
305				pfnote("yylex", lineno);
306				rewind(inf);
307			}
308		}
309/* yacc */	else if (cp[1] == 'y' && !cp[2]) {
310			/*
311			 * we search only the 3rd part of a yacc file
312			 * for C references.  This may be wrong.
313			 */
314			toss_yysec();
315			(void)strcpy(lbuf, "%%$");
316			pfnote("yyparse", lineno);
317			y_entries();
318		}
319/* fortran */	else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
320			if (PF_funcs())
321				return;
322			rewind(inf);
323		}
324	}
325/* C */	c_entries();
326}
327