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