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