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 case 'x': 122 xflag++; 123 break; 124 case '?': 125 default: 126 usage(); 127 } 128 argv += optind; 129 argc -= optind; 130 if (!argc) 131 usage(); 132 133 if (!xflag) 134 setlocale(LC_COLLATE, "C"); 135 136 init(); 137 138 for (exit_val = step = 0; step < argc; ++step) 139 if (!(inf = fopen(argv[step], "r"))) { 140 warn("%s", argv[step]); 141 exit_val = 1; 142 } 143 else { 144 curfile = argv[step]; 145 find_entries(argv[step]); 146 fclose(inf); 147 } 148 149 if (head) { 150 if (xflag) 151 put_entries(head); 152 else { 153 if (uflag) { 154 FILE *oldf; 155 regex_t *regx; 156 157 if ((oldf = fopen(outfile, "r")) == NULL) 158 err(1, "opening %s", outfile); 159 if (unlink(outfile)) 160 err(1, "unlinking %s", outfile); 161 if ((outf = fopen(outfile, "w")) == NULL) 162 err(1, "recreating %s", outfile); 163 if ((regx = calloc(argc, sizeof(regex_t))) == NULL) 164 err(1, "RE alloc"); 165 for (step = 0; step < argc; step++) { 166 strcpy(lbuf, "\t"); 167 strlcat(lbuf, argv[step], LINE_MAX); 168 strlcat(lbuf, "\t", LINE_MAX); 169 if (regcomp(regx + step, lbuf, 170 REG_NOSPEC)) 171 warn("RE compilation failed"); 172 } 173 nextline: 174 while (fgets(lbuf, LINE_MAX, oldf)) { 175 for (step = 0; step < argc; step++) 176 if (regexec(regx + step, 177 lbuf, 0, NULL, 0) == 0) 178 goto nextline; 179 fputs(lbuf, outf); 180 } 181 for (step = 0; step < argc; step++) 182 regfree(regx + step); 183 free(regx); 184 fclose(oldf); 185 fclose(outf); 186 ++aflag; 187 } 188 if (!(outf = fopen(outfile, aflag ? "a" : "w"))) 189 err(1, "%s", outfile); 190 put_entries(head); 191 fclose(outf); 192 if (uflag) { 193 pid_t pid; 194 195 if ((pid = fork()) == -1) 196 err(1, "fork failed"); 197 else if (pid == 0) { 198 execlp("sort", "sort", "-o", outfile, 199 outfile, NULL); 200 err(1, "exec of sort failed"); 201 } 202 /* Just assume the sort went OK. The old code 203 did not do any checks either. */ 204 wait(NULL); 205 } 206 } 207 } 208 exit(exit_val); 209 } 210 211 static void 212 usage(void) 213 { 214 fprintf(stderr, "usage: ctags [-BFTadtuwvx] [-f tagsfile] file ...\n"); 215 exit(1); 216 } 217 218 /* 219 * init -- 220 * this routine sets up the boolean pseudo-functions which work by 221 * setting boolean flags dependent upon the corresponding character. 222 * Every char which is NOT in that string is false with respect to 223 * the pseudo-function. Therefore, all of the array "_wht" is NO 224 * by default and then the elements subscripted by the chars in 225 * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 226 * the string CWHITE, else NO. 227 */ 228 void 229 init(void) 230 { 231 int i; 232 const unsigned char *sp; 233 234 for (i = 0; i < 256; i++) { 235 _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 236 _gd[i] = YES; 237 } 238 #define CWHITE " \f\t\n" 239 for (sp = CWHITE; *sp; sp++) /* white space chars */ 240 _wht[*sp] = YES; 241 #define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 242 for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 243 _etk[*sp] = YES; 244 #define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 245 for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 246 _itk[*sp] = YES; 247 #define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 248 for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 249 _btk[*sp] = YES; 250 #define CNOTGD ",;" 251 for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 252 _gd[*sp] = NO; 253 } 254 255 /* 256 * find_entries -- 257 * this routine opens the specified file and calls the function 258 * which searches the file. 259 */ 260 void 261 find_entries(char *file) 262 { 263 char *cp; 264 265 lineno = 0; /* should be 1 ?? KB */ 266 if ((cp = strrchr(file, '.'))) { 267 if (cp[1] == 'l' && !cp[2]) { 268 int c; 269 270 for (;;) { 271 if (GETC(==, EOF)) 272 return; 273 if (!iswhite(c)) { 274 rewind(inf); 275 break; 276 } 277 } 278 #define LISPCHR ";([" 279 /* lisp */ if (strchr(LISPCHR, c)) { 280 l_entries(); 281 return; 282 } 283 /* lex */ else { 284 /* 285 * we search all 3 parts of a lex file 286 * for C references. This may be wrong. 287 */ 288 toss_yysec(); 289 strcpy(lbuf, "%%$"); 290 pfnote("yylex", lineno); 291 rewind(inf); 292 } 293 } 294 /* yacc */ else if (cp[1] == 'y' && !cp[2]) { 295 /* 296 * we search only the 3rd part of a yacc file 297 * for C references. This may be wrong. 298 */ 299 toss_yysec(); 300 strcpy(lbuf, "%%$"); 301 pfnote("yyparse", lineno); 302 y_entries(); 303 } 304 /* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 305 if (PF_funcs()) 306 return; 307 rewind(inf); 308 } 309 } 310 /* C */ c_entries(); 311 } 312