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