xref: /original-bsd/usr.bin/ctags/ctags.c (revision fac0c393)
1 /*
2  * Copyright (c) 1987, 1993, 1994, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)ctags.c	8.4 (Berkeley) 02/07/95";
16 #endif /* not lint */
17 
18 #include <err.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 
25 #include "ctags.h"
26 
27 /*
28  * ctags: create a tags file
29  */
30 
31 NODE	*head;			/* head of the sorted binary tree */
32 
33 				/* boolean "func" (see init()) */
34 bool	_wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
35 
36 FILE	*inf;			/* ioptr for current input file */
37 FILE	*outf;			/* ioptr for tags file */
38 
39 long	lineftell;		/* ftell after getc( inf ) == '\n' */
40 
41 int	lineno;			/* line number of current line */
42 int	dflag;			/* -d: non-macro defines */
43 int	tflag;			/* -t: create tags for typedefs */
44 int	vflag;			/* -v: vgrind style index output */
45 int	wflag;			/* -w: suppress warnings */
46 int	xflag;			/* -x: cxref style output */
47 
48 char	*curfile;		/* current input file name */
49 char	searchar = '/';		/* use /.../ searches by default */
50 char	lbuf[LINE_MAX];
51 
52 void	init __P((void));
53 void	find_entries __P((char *));
54 
55 int
56 main(argc, argv)
57 	int	argc;
58 	char	**argv;
59 {
60 	static char	*outfile = "tags";	/* output file */
61 	int	aflag;				/* -a: append to tags */
62 	int	uflag;				/* -u: update tags */
63 	int	exit_val;			/* exit value */
64 	int	step;				/* step through args */
65 	int	ch;				/* getopts char */
66 	char	cmd[100];			/* too ugly to explain */
67 
68 	aflag = uflag = NO;
69 	while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != EOF)
70 		switch(ch) {
71 		case 'B':
72 			searchar = '?';
73 			break;
74 		case 'F':
75 			searchar = '/';
76 			break;
77 		case 'a':
78 			aflag++;
79 			break;
80 		case 'd':
81 			dflag++;
82 			break;
83 		case 'f':
84 			outfile = optarg;
85 			break;
86 		case 't':
87 			tflag++;
88 			break;
89 		case 'u':
90 			uflag++;
91 			break;
92 		case 'w':
93 			wflag++;
94 			break;
95 		case 'v':
96 			vflag++;
97 		case 'x':
98 			xflag++;
99 			break;
100 		case '?':
101 		default:
102 			goto usage;
103 		}
104 	argv += optind;
105 	argc -= optind;
106 	if (!argc) {
107 usage:		(void)fprintf(stderr,
108 			"usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
109 		exit(1);
110 	}
111 
112 	init();
113 
114 	for (exit_val = step = 0; step < argc; ++step)
115 		if (!(inf = fopen(argv[step], "r"))) {
116 			warn("%s", argv[step]);
117 			exit_val = 1;
118 		}
119 		else {
120 			curfile = argv[step];
121 			find_entries(argv[step]);
122 			(void)fclose(inf);
123 		}
124 
125 	if (head)
126 		if (xflag)
127 			put_entries(head);
128 		else {
129 			if (uflag) {
130 				for (step = 0; step < argc; step++) {
131 					(void)sprintf(cmd,
132 						"mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
133 							outfile, argv[step],
134 							outfile);
135 					system(cmd);
136 				}
137 				++aflag;
138 			}
139 			if (!(outf = fopen(outfile, aflag ? "a" : "w")))
140 				err(exit_val, "%s", outfile);
141 			put_entries(head);
142 			(void)fclose(outf);
143 			if (uflag) {
144 				(void)sprintf(cmd, "sort -o %s %s",
145 						outfile, outfile);
146 				system(cmd);
147 			}
148 		}
149 	exit(exit_val);
150 }
151 
152 /*
153  * init --
154  *	this routine sets up the boolean psuedo-functions which work by
155  *	setting boolean flags dependent upon the corresponding character.
156  *	Every char which is NOT in that string is false with respect to
157  *	the pseudo-function.  Therefore, all of the array "_wht" is NO
158  *	by default and then the elements subscripted by the chars in
159  *	CWHITE are set to YES.  Thus, "_wht" of a char is YES if it is in
160  *	the string CWHITE, else NO.
161  */
162 void
163 init()
164 {
165 	int		i;
166 	unsigned char	*sp;
167 
168 	for (i = 0; i < 256; i++) {
169 		_wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
170 		_gd[i] = YES;
171 	}
172 #define	CWHITE	" \f\t\n"
173 	for (sp = CWHITE; *sp; sp++)	/* white space chars */
174 		_wht[*sp] = YES;
175 #define	CTOKEN	" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
176 	for (sp = CTOKEN; *sp; sp++)	/* token ending chars */
177 		_etk[*sp] = YES;
178 #define	CINTOK	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
179 	for (sp = CINTOK; *sp; sp++)	/* valid in-token chars */
180 		_itk[*sp] = YES;
181 #define	CBEGIN	"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
182 	for (sp = CBEGIN; *sp; sp++)	/* token starting chars */
183 		_btk[*sp] = YES;
184 #define	CNOTGD	",;"
185 	for (sp = CNOTGD; *sp; sp++)	/* invalid after-function chars */
186 		_gd[*sp] = NO;
187 }
188 
189 /*
190  * find_entries --
191  *	this routine opens the specified file and calls the function
192  *	which searches the file.
193  */
194 void
195 find_entries(file)
196 	char	*file;
197 {
198 	char	*cp;
199 
200 	lineno = 0;				/* should be 1 ?? KB */
201 	if (cp = strrchr(file, '.')) {
202 		if (cp[1] == 'l' && !cp[2]) {
203 			int	c;
204 
205 			for (;;) {
206 				if (GETC(==, EOF))
207 					return;
208 				if (!iswhite(c)) {
209 					rewind(inf);
210 					break;
211 				}
212 			}
213 #define	LISPCHR	";(["
214 /* lisp */		if (strchr(LISPCHR, c)) {
215 				l_entries();
216 				return;
217 			}
218 /* lex */		else {
219 				/*
220 				 * we search all 3 parts of a lex file
221 				 * for C references.  This may be wrong.
222 				 */
223 				toss_yysec();
224 				(void)strcpy(lbuf, "%%$");
225 				pfnote("yylex", lineno);
226 				rewind(inf);
227 			}
228 		}
229 /* yacc */	else if (cp[1] == 'y' && !cp[2]) {
230 			/*
231 			 * we search only the 3rd part of a yacc file
232 			 * for C references.  This may be wrong.
233 			 */
234 			toss_yysec();
235 			(void)strcpy(lbuf, "%%$");
236 			pfnote("yyparse", lineno);
237 			y_entries();
238 		}
239 /* fortran */	else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
240 			if (PF_funcs())
241 				return;
242 			rewind(inf);
243 		}
244 	}
245 /* C */	c_entries();
246 }
247