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