Annotation of src/usr.bin/ctags/ctags.c, Revision 1.13
1.13 ! millert 1: /* $OpenBSD: ctags.c,v 1.12 2009/10/27 23:59:37 deraadt 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 vflag; /* -v: vgrind style index output */
59: int wflag; /* -w: suppress warnings */
60: int xflag; /* -x: cxref style output */
61:
62: char *curfile; /* current input file name */
63: char searchar = '/'; /* use /.../ searches by default */
64: char lbuf[LINE_MAX];
65:
1.6 millert 66: void init(void);
67: void find_entries(char *);
1.1 deraadt 68:
69: int
1.10 deraadt 70: main(int argc, char *argv[])
1.1 deraadt 71: {
72: static char *outfile = "tags"; /* output file */
73: int aflag; /* -a: append to tags */
74: int uflag; /* -u: update tags */
75: int exit_val; /* exit value */
76: int step; /* step through args */
77: int ch; /* getopts char */
1.5 deraadt 78: char *cmd;
1.1 deraadt 79:
80: aflag = uflag = NO;
1.3 millert 81: while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
1.1 deraadt 82: switch(ch) {
83: case 'B':
84: searchar = '?';
85: break;
86: case 'F':
87: searchar = '/';
88: break;
89: case 'a':
90: aflag++;
91: break;
92: case 'd':
93: dflag++;
94: break;
95: case 'f':
96: outfile = optarg;
97: break;
98: case 't':
1.13 ! millert 99: /* backwards compatibility */
1.1 deraadt 100: break;
101: case 'u':
102: uflag++;
103: break;
104: case 'w':
105: wflag++;
106: break;
107: case 'v':
108: vflag++;
109: case 'x':
110: xflag++;
111: break;
112: case '?':
113: default:
114: goto usage;
115: }
116: argv += optind;
117: argc -= optind;
118: if (!argc) {
119: usage: (void)fprintf(stderr,
1.13 ! millert 120: "usage: ctags [-aBdFuvwx] [-f tagsfile] file ...\n");
1.1 deraadt 121: exit(1);
122: }
123:
124: init();
125:
126: for (exit_val = step = 0; step < argc; ++step)
127: if (!(inf = fopen(argv[step], "r"))) {
128: warn("%s", argv[step]);
129: exit_val = 1;
130: }
131: else {
132: curfile = argv[step];
133: find_entries(argv[step]);
134: (void)fclose(inf);
135: }
136:
1.4 deraadt 137: if (head) {
1.1 deraadt 138: if (xflag)
139: put_entries(head);
140: else {
141: if (uflag) {
142: for (step = 0; step < argc; step++) {
1.8 pvalchev 143: if (asprintf(&cmd,
1.5 deraadt 144: "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
1.8 pvalchev 145: outfile, argv[step], outfile) == -1)
1.5 deraadt 146: err(1, "out of space");
1.1 deraadt 147: system(cmd);
1.5 deraadt 148: free(cmd);
149: cmd = NULL;
1.1 deraadt 150: }
151: ++aflag;
152: }
153: if (!(outf = fopen(outfile, aflag ? "a" : "w")))
154: err(exit_val, "%s", outfile);
155: put_entries(head);
156: (void)fclose(outf);
157: if (uflag) {
1.8 pvalchev 158: if (asprintf(&cmd, "sort -o %s %s",
159: outfile, outfile) == -1)
1.5 deraadt 160: err(1, "out of space");
1.1 deraadt 161: system(cmd);
1.5 deraadt 162: free(cmd);
163: cmd = NULL;
1.1 deraadt 164: }
165: }
1.4 deraadt 166: }
1.1 deraadt 167: exit(exit_val);
168: }
169:
170: /*
171: * init --
172: * this routine sets up the boolean psuedo-functions which work by
173: * setting boolean flags dependent upon the corresponding character.
174: * Every char which is NOT in that string is false with respect to
175: * the pseudo-function. Therefore, all of the array "_wht" is NO
176: * by default and then the elements subscripted by the chars in
177: * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in
178: * the string CWHITE, else NO.
179: */
180: void
1.10 deraadt 181: init(void)
1.1 deraadt 182: {
183: int i;
184: unsigned char *sp;
185:
186: for (i = 0; i < 256; i++) {
187: _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
188: _gd[i] = YES;
189: }
190: #define CWHITE " \f\t\n"
191: for (sp = CWHITE; *sp; sp++) /* white space chars */
192: _wht[*sp] = YES;
193: #define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
194: for (sp = CTOKEN; *sp; sp++) /* token ending chars */
195: _etk[*sp] = YES;
196: #define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
197: for (sp = CINTOK; *sp; sp++) /* valid in-token chars */
198: _itk[*sp] = YES;
199: #define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
200: for (sp = CBEGIN; *sp; sp++) /* token starting chars */
201: _btk[*sp] = YES;
202: #define CNOTGD ",;"
203: for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */
204: _gd[*sp] = NO;
205: }
206:
207: /*
208: * find_entries --
209: * this routine opens the specified file and calls the function
210: * which searches the file.
211: */
212: void
1.10 deraadt 213: find_entries(char *file)
1.1 deraadt 214: {
215: char *cp;
216:
217: lineno = 0; /* should be 1 ?? KB */
1.5 deraadt 218: if ((cp = strrchr(file, '.'))) {
1.1 deraadt 219: if (cp[1] == 'l' && !cp[2]) {
220: int c;
221:
222: for (;;) {
223: if (GETC(==, EOF))
224: return;
225: if (!iswhite(c)) {
226: rewind(inf);
227: break;
228: }
229: }
230: #define LISPCHR ";(["
231: /* lisp */ if (strchr(LISPCHR, c)) {
232: l_entries();
233: return;
234: }
235: /* lex */ else {
236: /*
237: * we search all 3 parts of a lex file
238: * for C references. This may be wrong.
239: */
240: toss_yysec();
1.7 deraadt 241: (void)strlcpy(lbuf, "%%$", sizeof lbuf);
1.1 deraadt 242: pfnote("yylex", lineno);
243: rewind(inf);
244: }
245: }
246: /* yacc */ else if (cp[1] == 'y' && !cp[2]) {
247: /*
248: * we search only the 3rd part of a yacc file
249: * for C references. This may be wrong.
250: */
251: toss_yysec();
1.7 deraadt 252: (void)strlcpy(lbuf, "%%$", sizeof lbuf);
1.1 deraadt 253: pfnote("yyparse", lineno);
254: y_entries();
255: }
256: /* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
257: if (PF_funcs())
258: return;
259: rewind(inf);
260: }
261: }
262: /* C */ c_entries();
263: }