xref: /minix3/usr.bin/ctags/ctags.c (revision 3e1db26a5a6252fcff0898d4cb0c3fa16ccf561d)
1 /*	$NetBSD: ctags.c,v 1.12 2008/07/21 14:19:22 lukem 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. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35 
36 #include <sys/cdefs.h>
37 #if defined(__COPYRIGHT) && !defined(lint)
38 __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\
39  The Regents of the University of California.  All rights reserved.");
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.12 2008/07/21 14:19:22 lukem 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(void);
84 void	find_entries(char *);
85 
86 int
main(int argc,char ** argv)87 main(int argc, char **argv)
88 {
89 	static const char	*outfile = "tags";	/* output file */
90 	int	aflag;				/* -a: append to tags */
91 	int	uflag;				/* -u: update tags */
92 	int	exit_val;			/* exit value */
93 	int	step;				/* step through args */
94 	int	ch;				/* getopts char */
95 	char	cmd[100];			/* too ugly to explain */
96 
97 	aflag = uflag = NO;
98 	while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
99 		switch(ch) {
100 		case 'B':
101 			searchar = '?';
102 			break;
103 		case 'F':
104 			searchar = '/';
105 			break;
106 		case 'a':
107 			aflag++;
108 			break;
109 		case 'd':
110 			dflag++;
111 			break;
112 		case 'f':
113 			outfile = optarg;
114 			break;
115 		case 't':
116 			tflag++;
117 			break;
118 		case 'u':
119 			uflag++;
120 			break;
121 		case 'w':
122 			wflag++;
123 			break;
124 		case 'v':
125 			vflag++;
126 		case 'x':
127 			xflag++;
128 			break;
129 		case '?':
130 		default:
131 			goto usage;
132 		}
133 	argv += optind;
134 	argc -= optind;
135 	if (!argc) {
136 usage:		(void)fprintf(stderr,
137 			"usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
138 		exit(1);
139 	}
140 
141 	init();
142 
143 	for (exit_val = step = 0; step < argc; ++step)
144 		if (!(inf = fopen(argv[step], "r"))) {
145 			warn("%s", argv[step]);
146 			exit_val = 1;
147 		}
148 		else {
149 			curfile = argv[step];
150 			find_entries(argv[step]);
151 			(void)fclose(inf);
152 		}
153 
154 	if (head) {
155 		if (xflag)
156 			put_entries(head);
157 		else {
158 			if (uflag) {
159 				for (step = 0; step < argc; step++) {
160 					(void)snprintf(cmd, sizeof(cmd),
161 						"mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
162 							outfile, argv[step],
163 							outfile);
164 					system(cmd);
165 				}
166 				++aflag;
167 			}
168 			if (!(outf = fopen(outfile, aflag ? "a" : "w")))
169 				err(exit_val, "%s", outfile);
170 			put_entries(head);
171 			(void)fclose(outf);
172 			if (uflag) {
173 				(void)snprintf(cmd, sizeof(cmd),
174 				    "sort -o %s %s", outfile, outfile);
175 				system(cmd);
176 			}
177 		}
178 	}
179 	exit(exit_val);
180 }
181 
182 /*
183  * init --
184  *	this routine sets up the boolean psuedo-functions which work by
185  *	setting boolean flags dependent upon the corresponding character.
186  *	Every char which is NOT in that string is false with respect to
187  *	the pseudo-function.  Therefore, all of the array "_wht" is NO
188  *	by default and then the elements subscripted by the chars in
189  *	CWHITE are set to YES.  Thus, "_wht" of a char is YES if it is in
190  *	the string CWHITE, else NO.
191  */
192 void
init(void)193 init(void)
194 {
195 	int		i;
196 	unsigned const char	*sp;
197 
198 	for (i = 0; i < 256; i++) {
199 		_wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
200 		_gd[i] = YES;
201 	}
202 #define	CWHITE	" \f\t\n"
203 	for (sp = CWHITE; *sp; sp++)	/* white space chars */
204 		_wht[*sp] = YES;
205 #define	CTOKEN	" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
206 	for (sp = CTOKEN; *sp; sp++)	/* token ending chars */
207 		_etk[*sp] = YES;
208 #define	CINTOK	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
209 	for (sp = CINTOK; *sp; sp++)	/* valid in-token chars */
210 		_itk[*sp] = YES;
211 #define	CBEGIN	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
212 	for (sp = CBEGIN; *sp; sp++)	/* token starting chars */
213 		_btk[*sp] = YES;
214 #define	CNOTGD	",;"
215 	for (sp = CNOTGD; *sp; sp++)	/* invalid after-function chars */
216 		_gd[*sp] = NO;
217 }
218 
219 /*
220  * find_entries --
221  *	this routine opens the specified file and calls the function
222  *	which searches the file.
223  */
224 void
find_entries(char * file)225 find_entries(char *file)
226 {
227 	char	*cp;
228 
229 	lineno = 0;				/* should be 1 ?? KB */
230 	if ((cp = strrchr(file, '.')) != NULL) {
231 		if (cp[1] == 'l' && !cp[2]) {
232 			int	c;
233 
234 			for (;;) {
235 				if (GETC(==, EOF))
236 					return;
237 				if (!iswhite(c)) {
238 					rewind(inf);
239 					break;
240 				}
241 			}
242 #define	LISPCHR	";(["
243 /* lisp */		if (strchr(LISPCHR, c)) {
244 				l_entries();
245 				return;
246 			}
247 /* lex */		else {
248 				/*
249 				 * we search all 3 parts of a lex file
250 				 * for C references.  This may be wrong.
251 				 */
252 				toss_yysec();
253 				(void)strlcpy(lbuf, "%%$", sizeof(lbuf));
254 				pfnote("yylex", lineno);
255 				rewind(inf);
256 			}
257 		}
258 /* yacc */	else if (cp[1] == 'y' && !cp[2]) {
259 			/*
260 			 * we search only the 3rd part of a yacc file
261 			 * for C references.  This may be wrong.
262 			 */
263 			toss_yysec();
264 			(void)strlcpy(lbuf, "%%$", sizeof(lbuf));
265 			pfnote("yyparse", lineno);
266 			y_entries();
267 		}
268 /* fortran */	else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
269 			if (PF_funcs())
270 				return;
271 			rewind(inf);
272 		}
273 	}
274 /* C */	c_entries();
275 }
276