ctags.c revision 32069
1252867Sdelphij/*
2252867Sdelphij * Copyright (c) 1987, 1993, 1994, 1995
3252867Sdelphij *	The Regents of the University of California.  All rights reserved.
4252867Sdelphij *
5252867Sdelphij * Redistribution and use in source and binary forms, with or without
6252867Sdelphij * modification, are permitted provided that the following conditions
7252867Sdelphij * are met:
8252867Sdelphij * 1. Redistributions of source code must retain the above copyright
9252867Sdelphij *    notice, this list of conditions and the following disclaimer.
10252867Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
11252867Sdelphij *    notice, this list of conditions and the following disclaimer in the
12252867Sdelphij *    documentation and/or other materials provided with the distribution.
13252867Sdelphij * 3. All advertising materials mentioning features or use of this software
14252867Sdelphij *    must display the following acknowledgement:
15252867Sdelphij *	This product includes software developed by the University of
16252867Sdelphij *	California, Berkeley and its contributors.
17252867Sdelphij * 4. Neither the name of the University nor the names of its contributors
18252867Sdelphij *    may be used to endorse or promote products derived from this software
19252867Sdelphij *    without specific prior written permission.
20252867Sdelphij *
21252867Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22252867Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23252867Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24252867Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25252867Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26252867Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27252867Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28252867Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29252867Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30252867Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31252867Sdelphij * SUCH DAMAGE.
32252867Sdelphij */
33252867Sdelphij
34252867Sdelphij#ifndef lint
35252867Sdelphijstatic char copyright[] =
36252867Sdelphij"@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
37252867Sdelphij	The Regents of the University of California.  All rights reserved.\n";
38252867Sdelphij#endif /* not lint */
39252867Sdelphij
40252867Sdelphij#ifndef lint
41252867Sdelphijstatic char sccsid[] = "@(#)ctags.c	8.4 (Berkeley) 2/7/95";
42252867Sdelphij#endif /* not lint */
43252867Sdelphij
44252867Sdelphij#include <err.h>
45252867Sdelphij#include <limits.h>
46252867Sdelphij#include <stdio.h>
47252867Sdelphij#include <string.h>
48252867Sdelphij#include <stdlib.h>
49252867Sdelphij#include <unistd.h>
50252867Sdelphij
51252867Sdelphij#include "ctags.h"
52252867Sdelphij
53252867Sdelphij/*
54252867Sdelphij * ctags: create a tags file
55252867Sdelphij */
56252867Sdelphij
57252867SdelphijNODE	*head;			/* head of the sorted binary tree */
58252867Sdelphij
59252867Sdelphij				/* boolean "func" (see init()) */
60252867Sdelphijbool	_wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
61252867Sdelphij
62252867SdelphijFILE	*inf;			/* ioptr for current input file */
63252867SdelphijFILE	*outf;			/* ioptr for tags file */
64252867Sdelphij
65252867Sdelphijlong	lineftell;		/* ftell after getc( inf ) == '\n' */
66252867Sdelphij
67252867Sdelphijint	lineno;			/* line number of current line */
68252867Sdelphijint	dflag;			/* -d: non-macro defines */
69252867Sdelphijint	tflag;			/* -t: create tags for typedefs */
70252867Sdelphijint	vflag;			/* -v: vgrind style index output */
71252867Sdelphijint	wflag;			/* -w: suppress warnings */
72252867Sdelphijint	xflag;			/* -x: cxref style output */
73252867Sdelphij
74252867Sdelphijchar	*curfile;		/* current input file name */
75252867Sdelphijchar	searchar = '/';		/* use /.../ searches by default */
76252867Sdelphijchar	lbuf[LINE_MAX];
77252867Sdelphij
78252867Sdelphijvoid	init __P((void));
79252867Sdelphijvoid	find_entries __P((char *));
80252867Sdelphijstatic void usage __P((void));
81252867Sdelphij
82252867Sdelphijint
83252867Sdelphijmain(argc, argv)
84252867Sdelphij	int	argc;
85252867Sdelphij	char	**argv;
86252867Sdelphij{
87252867Sdelphij	static char	*outfile = "tags";	/* output file */
88252867Sdelphij	int	aflag;				/* -a: append to tags */
89252867Sdelphij	int	uflag;				/* -u: update tags */
90252867Sdelphij	int	exit_val;			/* exit value */
91252867Sdelphij	int	step;				/* step through args */
92252867Sdelphij	int	ch;				/* getopts char */
93252867Sdelphij	char	cmd[100];			/* too ugly to explain */
94252867Sdelphij
95252867Sdelphij	aflag = uflag = NO;
96252867Sdelphij	while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
97252867Sdelphij		switch(ch) {
98252867Sdelphij		case 'B':
99252867Sdelphij			searchar = '?';
100252867Sdelphij			break;
101252867Sdelphij		case 'F':
102252867Sdelphij			searchar = '/';
103252867Sdelphij			break;
104252867Sdelphij		case 'a':
105252867Sdelphij			aflag++;
106252867Sdelphij			break;
107252867Sdelphij		case 'd':
108252867Sdelphij			dflag++;
109252867Sdelphij			break;
110252867Sdelphij		case 'f':
111252867Sdelphij			outfile = optarg;
112252867Sdelphij			break;
113252867Sdelphij		case 't':
114252867Sdelphij			tflag++;
115252867Sdelphij			break;
116252867Sdelphij		case 'u':
117252867Sdelphij			uflag++;
118252867Sdelphij			break;
119252867Sdelphij		case 'w':
120252867Sdelphij			wflag++;
121252867Sdelphij			break;
122252867Sdelphij		case 'v':
123252867Sdelphij			vflag++;
124252867Sdelphij		case 'x':
125252867Sdelphij			xflag++;
126252867Sdelphij			break;
127252867Sdelphij		case '?':
128252867Sdelphij		default:
129252867Sdelphij			usage();
130252867Sdelphij		}
131252867Sdelphij	argv += optind;
132252867Sdelphij	argc -= optind;
133252867Sdelphij	if (!argc)
134252867Sdelphij		usage();
135252867Sdelphij
136252867Sdelphij	init();
137252867Sdelphij
138252867Sdelphij	for (exit_val = step = 0; step < argc; ++step)
139252867Sdelphij		if (!(inf = fopen(argv[step], "r"))) {
140252867Sdelphij			warn("%s", argv[step]);
141252867Sdelphij			exit_val = 1;
142252867Sdelphij		}
143252867Sdelphij		else {
144252867Sdelphij			curfile = argv[step];
145252867Sdelphij			find_entries(argv[step]);
146252867Sdelphij			(void)fclose(inf);
147252867Sdelphij		}
148252867Sdelphij
149252867Sdelphij	if (head)
150252867Sdelphij		if (xflag)
151252867Sdelphij			put_entries(head);
152252867Sdelphij		else {
153252867Sdelphij			if (uflag) {
154252867Sdelphij				for (step = 0; step < argc; step++) {
155252867Sdelphij					(void)sprintf(cmd,
156252867Sdelphij						"mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
157252867Sdelphij							outfile, argv[step],
158252867Sdelphij							outfile);
159252867Sdelphij					system(cmd);
160252867Sdelphij				}
161252867Sdelphij				++aflag;
162252867Sdelphij			}
163252867Sdelphij			if (!(outf = fopen(outfile, aflag ? "a" : "w")))
164252867Sdelphij				err(exit_val, "%s", outfile);
165252867Sdelphij			put_entries(head);
166252867Sdelphij			(void)fclose(outf);
167252867Sdelphij			if (uflag) {
168252867Sdelphij				(void)sprintf(cmd, "sort -o %s %s",
169252867Sdelphij						outfile, outfile);
170252867Sdelphij				system(cmd);
171252867Sdelphij			}
172252867Sdelphij		}
173252867Sdelphij	exit(exit_val);
174252867Sdelphij}
175252867Sdelphij
176252867Sdelphijstatic void
177252867Sdelphijusage()
178252867Sdelphij{
179252867Sdelphij	(void)fprintf(stderr, "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
180252867Sdelphij	exit(1);
181252867Sdelphij}
182252867Sdelphij
183252867Sdelphij/*
184252867Sdelphij * init --
185252867Sdelphij *	this routine sets up the boolean psuedo-functions which work by
186252867Sdelphij *	setting boolean flags dependent upon the corresponding character.
187252867Sdelphij *	Every char which is NOT in that string is false with respect to
188252867Sdelphij *	the pseudo-function.  Therefore, all of the array "_wht" is NO
189252867Sdelphij *	by default and then the elements subscripted by the chars in
190252867Sdelphij *	CWHITE are set to YES.  Thus, "_wht" of a char is YES if it is in
191252867Sdelphij *	the string CWHITE, else NO.
192252867Sdelphij */
193252867Sdelphijvoid
194252867Sdelphijinit()
195252867Sdelphij{
196252867Sdelphij	int		i;
197252867Sdelphij	unsigned char	*sp;
198252867Sdelphij
199252867Sdelphij	for (i = 0; i < 256; i++) {
200252867Sdelphij		_wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
201252867Sdelphij		_gd[i] = YES;
202252867Sdelphij	}
203252867Sdelphij#define	CWHITE	" \f\t\n"
204252867Sdelphij	for (sp = CWHITE; *sp; sp++)	/* white space chars */
205252867Sdelphij		_wht[*sp] = YES;
206252867Sdelphij#define	CTOKEN	" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
207252867Sdelphij	for (sp = CTOKEN; *sp; sp++)	/* token ending chars */
208252867Sdelphij		_etk[*sp] = YES;
209252867Sdelphij#define	CINTOK	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
210252867Sdelphij	for (sp = CINTOK; *sp; sp++)	/* valid in-token chars */
211252867Sdelphij		_itk[*sp] = YES;
212252867Sdelphij#define	CBEGIN	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
213252867Sdelphij	for (sp = CBEGIN; *sp; sp++)	/* token starting chars */
214252867Sdelphij		_btk[*sp] = YES;
215252867Sdelphij#define	CNOTGD	",;"
216252867Sdelphij	for (sp = CNOTGD; *sp; sp++)	/* invalid after-function chars */
217252867Sdelphij		_gd[*sp] = NO;
218252867Sdelphij}
219252867Sdelphij
220252867Sdelphij/*
221252867Sdelphij * find_entries --
222252867Sdelphij *	this routine opens the specified file and calls the function
223252867Sdelphij *	which searches the file.
224252867Sdelphij */
225252867Sdelphijvoid
226252867Sdelphijfind_entries(file)
227252867Sdelphij	char	*file;
228252867Sdelphij{
229252867Sdelphij	char	*cp;
230252867Sdelphij
231252867Sdelphij	lineno = 0;				/* should be 1 ?? KB */
232252867Sdelphij	if ((cp = strrchr(file, '.'))) {
233252867Sdelphij		if (cp[1] == 'l' && !cp[2]) {
234252867Sdelphij			int	c;
235252867Sdelphij
236252867Sdelphij			for (;;) {
237252867Sdelphij				if (GETC(==, EOF))
238252867Sdelphij					return;
239252867Sdelphij				if (!iswhite(c)) {
240252867Sdelphij					rewind(inf);
241252867Sdelphij					break;
242252867Sdelphij				}
243252867Sdelphij			}
244252867Sdelphij#define	LISPCHR	";(["
245252867Sdelphij/* lisp */		if (strchr(LISPCHR, c)) {
246252867Sdelphij				l_entries();
247252867Sdelphij				return;
248252867Sdelphij			}
249252867Sdelphij/* lex */		else {
250252867Sdelphij				/*
251252867Sdelphij				 * we search all 3 parts of a lex file
252252867Sdelphij				 * for C references.  This may be wrong.
253252867Sdelphij				 */
254252867Sdelphij				toss_yysec();
255252867Sdelphij				(void)strcpy(lbuf, "%%$");
256252867Sdelphij				pfnote("yylex", lineno);
257252867Sdelphij				rewind(inf);
258252867Sdelphij			}
259252867Sdelphij		}
260252867Sdelphij/* yacc */	else if (cp[1] == 'y' && !cp[2]) {
261252867Sdelphij			/*
262252867Sdelphij			 * we search only the 3rd part of a yacc file
263252867Sdelphij			 * for C references.  This may be wrong.
264252867Sdelphij			 */
265252867Sdelphij			toss_yysec();
266252867Sdelphij			(void)strcpy(lbuf, "%%$");
267252867Sdelphij			pfnote("yyparse", lineno);
268252867Sdelphij			y_entries();
269252867Sdelphij		}
270252867Sdelphij/* fortran */	else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
271252867Sdelphij			if (PF_funcs())
272252867Sdelphij				return;
273252867Sdelphij			rewind(inf);
274252867Sdelphij		}
275252867Sdelphij	}
276252867Sdelphij/* C */	c_entries();
277252867Sdelphij}
278252867Sdelphij