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: head/usr.bin/ctags/ctags.c 216370 2010-12-11 08:32:16Z joel $ 32 */ 33 34 #include <sys/wait.h> 35 36 #include <err.h> 37 #include <limits.h> 38 #include <locale.h> 39 #include <regex.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "ctags.h" 46 47 /* 48 * ctags: create a tags file 49 */ 50 51 NODE *head; /* head of the sorted binary tree */ 52 53 /* boolean "func" (see init()) */ 54 bool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256]; 55 56 FILE *inf; /* ioptr for current input file */ 57 FILE *outf; /* ioptr for tags file */ 58 59 long lineftell; /* ftell after getc( inf ) == '\n' */ 60 61 int lineno; /* line number of current line */ 62 int dflag; /* -d: non-macro defines */ 63 int tflag; /* -t: create tags for typedefs */ 64 int vflag; /* -v: vgrind style index output */ 65 int wflag; /* -w: suppress warnings */ 66 int xflag; /* -x: cxref style output */ 67 68 char *curfile; /* current input file name */ 69 char searchar = '/'; /* use /.../ searches by default */ 70 char lbuf[LINE_MAX]; 71 72 void init(void); 73 void find_entries(char *); 74 static void usage(void); 75 76 int 77 main(int argc, char **argv) 78 { 79 static const char *outfile = "tags"; /* output file */ 80 int aflag; /* -a: append to tags */ 81 int uflag; /* -u: update tags */ 82 int exit_val; /* exit value */ 83 int step; /* step through args */ 84 int ch; /* getopts char */ 85 86 setlocale(LC_ALL, ""); 87 88 aflag = uflag = NO; 89 tflag = YES; 90 while ((ch = getopt(argc, argv, "BFTadf:tuwvx")) != -1) 91 switch(ch) { 92 case 'B': 93 searchar = '?'; 94 break; 95 case 'F': 96 searchar = '/'; 97 break; 98 case 'T': 99 tflag = NO; 100 break; 101 case 'a': 102 aflag++; 103 break; 104 case 'd': 105 dflag++; 106 break; 107 case 'f': 108 outfile = optarg; 109 break; 110 case 't': 111 tflag = YES; 112 break; 113 case 'u': 114 uflag++; 115 break; 116 case 'w': 117 wflag++; 118 break; 119 case 'v': 120 vflag++; 121 /* FALLTHROUGH */ 122 case 'x': 123 xflag++; 124 break; 125 case '?': 126 default: 127 usage(); 128 } 129 argv += optind; 130 argc -= optind; 131 if (!argc) 132 usage(); 133 134 if (!xflag) 135 setlocale(LC_COLLATE, "C"); 136 137 init(); 138 139 for (exit_val = step = 0; step < argc; ++step) 140 if (!(inf = fopen(argv[step], "r"))) { 141 warn("%s", argv[step]); 142 exit_val = 1; 143 } 144 else { 145 curfile = argv[step]; 146 find_entries(argv[step]); 147 fclose(inf); 148 } 149 150 if (head) { 151 if (xflag) 152 put_entries(head); 153 else { 154 if (uflag) { 155 FILE *oldf; 156 regex_t *regx; 157 158 if ((oldf = fopen(outfile, "r")) == NULL) 159 err(1, "opening %s", outfile); 160 if (unlink(outfile)) 161 err(1, "unlinking %s", outfile); 162 if ((outf = fopen(outfile, "w")) == NULL) 163 err(1, "recreating %s", outfile); 164 if ((regx = calloc(argc, sizeof(regex_t))) == NULL) 165 err(1, "RE alloc"); 166 for (step = 0; step < argc; step++) { 167 strcpy(lbuf, "\t"); 168 strlcat(lbuf, argv[step], LINE_MAX); 169 strlcat(lbuf, "\t", LINE_MAX); 170 if (regcomp(regx + step, lbuf, 171 REG_NOSPEC)) 172 warn("RE compilation failed"); 173 } 174 nextline: 175 while (fgets(lbuf, LINE_MAX, oldf)) { 176 for (step = 0; step < argc; step++) 177 if (regexec(regx + step, 178 lbuf, 0, NULL, 0) == 0) 179 goto nextline; 180 fputs(lbuf, outf); 181 } 182 for (step = 0; step < argc; step++) 183 regfree(regx + step); 184 free(regx); 185 fclose(oldf); 186 fclose(outf); 187 ++aflag; 188 } 189 if (!(outf = fopen(outfile, aflag ? "a" : "w"))) 190 err(1, "%s", outfile); 191 put_entries(head); 192 fclose(outf); 193 if (uflag) { 194 pid_t pid; 195 196 if ((pid = fork()) == -1) 197 err(1, "fork failed"); 198 else if (pid == 0) { 199 execlp("sort", "sort", "-o", outfile, 200 outfile, NULL); 201 err(1, "exec of sort failed"); 202 } 203 /* Just assume the sort went OK. The old code 204 did not do any checks either. */ 205 wait(NULL); 206 } 207 } 208 } 209 exit(exit_val); 210 } 211 212 static void 213 usage(void) 214 { 215 fprintf(stderr, "usage: ctags [-BFTadtuwvx] [-f tagsfile] file ...\n"); 216 exit(1); 217 } 218 219 /* 220 * init -- 221 * this routine sets up the boolean pseudo-functions which work by 222 * setting boolean flags dependent upon the corresponding character. 223 * Every char which is NOT in that string is false with respect to 224 * the pseudo-function. Therefore, all of the array "_wht" is NO 225 * by default and then the elements subscripted by the chars in 226 * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 227 * the string CWHITE, else NO. 228 */ 229 void 230 init(void) 231 { 232 int i; 233 const unsigned char *sp; 234 235 for (i = 0; i < 256; i++) { 236 _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 237 _gd[i] = YES; 238 } 239 #define CWHITE " \f\t\n" 240 for (sp = CWHITE; *sp; sp++) /* white space chars */ 241 _wht[*sp] = YES; 242 #define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 243 for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 244 _etk[*sp] = YES; 245 #define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 246 for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 247 _itk[*sp] = YES; 248 #define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 249 for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 250 _btk[*sp] = YES; 251 #define CNOTGD ",;" 252 for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 253 _gd[*sp] = NO; 254 } 255 256 /* 257 * find_entries -- 258 * this routine opens the specified file and calls the function 259 * which searches the file. 260 */ 261 void 262 find_entries(char *file) 263 { 264 char *cp; 265 266 lineno = 0; /* should be 1 ?? KB */ 267 if ((cp = strrchr(file, '.'))) { 268 if (cp[1] == 'l' && !cp[2]) { 269 int c; 270 271 for (;;) { 272 if (GETC(==, EOF)) 273 return; 274 if (!iswhite(c)) { 275 rewind(inf); 276 break; 277 } 278 } 279 #define LISPCHR ";([" 280 /* lisp */ if (strchr(LISPCHR, c)) { 281 l_entries(); 282 return; 283 } 284 /* lex */ else { 285 /* 286 * we search all 3 parts of a lex file 287 * for C references. This may be wrong. 288 */ 289 toss_yysec(); 290 strcpy(lbuf, "%%$"); 291 pfnote("yylex", lineno); 292 rewind(inf); 293 } 294 } 295 /* yacc */ else if (cp[1] == 'y' && !cp[2]) { 296 /* 297 * we search only the 3rd part of a yacc file 298 * for C references. This may be wrong. 299 */ 300 toss_yysec(); 301 strcpy(lbuf, "%%$"); 302 pfnote("yyparse", lineno); 303 y_entries(); 304 } 305 /* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 306 if (PF_funcs()) 307 return; 308 rewind(inf); 309 } 310 } 311 /* C */ c_entries(); 312 } 313