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