11590Srgrimes/* 227097Scharnier * Copyright (c) 1987, 1993, 1994, 1995 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3141568Sarchiestatic const char copyright[] = 3227097Scharnier"@(#) Copyright (c) 1987, 1993, 1994, 1995\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3487249Smarkm#endif 351590Srgrimes 3687628Sdwmalone#if 0 371590Srgrimes#ifndef lint 3887628Sdwmalonestatic char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95"; 3981782Smikeh#endif 4087628Sdwmalone#endif 411590Srgrimes 4287628Sdwmalone#include <sys/cdefs.h> 43129042Scjc#include <sys/types.h> 44129042Scjc#include <sys/wait.h> 4587628Sdwmalone__FBSDID("$FreeBSD$"); 4687628Sdwmalone 471590Srgrimes#include <err.h> 481590Srgrimes#include <limits.h> 4997581Stjr#include <locale.h> 50129042Scjc#include <regex.h> 511590Srgrimes#include <stdio.h> 5287750Scharnier#include <stdlib.h> 531590Srgrimes#include <string.h> 541590Srgrimes#include <unistd.h> 551590Srgrimes 561590Srgrimes#include "ctags.h" 571590Srgrimes 581590Srgrimes/* 591590Srgrimes * ctags: create a tags file 601590Srgrimes */ 611590Srgrimes 621590SrgrimesNODE *head; /* head of the sorted binary tree */ 631590Srgrimes 641590Srgrimes /* boolean "func" (see init()) */ 651590Srgrimesbool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256]; 661590Srgrimes 671590SrgrimesFILE *inf; /* ioptr for current input file */ 681590SrgrimesFILE *outf; /* ioptr for tags file */ 691590Srgrimes 701590Srgrimeslong lineftell; /* ftell after getc( inf ) == '\n' */ 711590Srgrimes 721590Srgrimesint lineno; /* line number of current line */ 731590Srgrimesint dflag; /* -d: non-macro defines */ 741590Srgrimesint tflag; /* -t: create tags for typedefs */ 751590Srgrimesint vflag; /* -v: vgrind style index output */ 761590Srgrimesint wflag; /* -w: suppress warnings */ 771590Srgrimesint xflag; /* -x: cxref style output */ 781590Srgrimes 791590Srgrimeschar *curfile; /* current input file name */ 801590Srgrimeschar searchar = '/'; /* use /.../ searches by default */ 811590Srgrimeschar lbuf[LINE_MAX]; 821590Srgrimes 8392920Simpvoid init(void); 8492920Simpvoid find_entries(char *); 8592920Simpstatic void usage(void); 861590Srgrimes 871590Srgrimesint 88100822Sdwmalonemain(int argc, char **argv) 891590Srgrimes{ 9087215Smarkm static const char *outfile = "tags"; /* output file */ 911590Srgrimes int aflag; /* -a: append to tags */ 921590Srgrimes int uflag; /* -u: update tags */ 931590Srgrimes int exit_val; /* exit value */ 941590Srgrimes int step; /* step through args */ 951590Srgrimes int ch; /* getopts char */ 961590Srgrimes 9797581Stjr setlocale(LC_ALL, ""); 9897581Stjr 991590Srgrimes aflag = uflag = NO; 10097577Stjr tflag = YES; 10197577Stjr while ((ch = getopt(argc, argv, "BFTadf:tuwvx")) != -1) 1021590Srgrimes switch(ch) { 1031590Srgrimes case 'B': 1041590Srgrimes searchar = '?'; 1051590Srgrimes break; 1061590Srgrimes case 'F': 1071590Srgrimes searchar = '/'; 1081590Srgrimes break; 10997577Stjr case 'T': 11097577Stjr tflag = NO; 11197577Stjr break; 1121590Srgrimes case 'a': 1131590Srgrimes aflag++; 1141590Srgrimes break; 1151590Srgrimes case 'd': 1161590Srgrimes dflag++; 1171590Srgrimes break; 1181590Srgrimes case 'f': 1191590Srgrimes outfile = optarg; 1201590Srgrimes break; 1211590Srgrimes case 't': 12297577Stjr tflag = YES; 1231590Srgrimes break; 1241590Srgrimes case 'u': 1251590Srgrimes uflag++; 1261590Srgrimes break; 1271590Srgrimes case 'w': 1281590Srgrimes wflag++; 1291590Srgrimes break; 1301590Srgrimes case 'v': 1311590Srgrimes vflag++; 1321590Srgrimes case 'x': 1331590Srgrimes xflag++; 1341590Srgrimes break; 1351590Srgrimes case '?': 1361590Srgrimes default: 13727097Scharnier usage(); 1381590Srgrimes } 1391590Srgrimes argv += optind; 1401590Srgrimes argc -= optind; 14127097Scharnier if (!argc) 14227097Scharnier usage(); 1431590Srgrimes 14497581Stjr if (!xflag) 14597581Stjr setlocale(LC_COLLATE, "C"); 14697581Stjr 1471590Srgrimes init(); 1481590Srgrimes 1491590Srgrimes for (exit_val = step = 0; step < argc; ++step) 1501590Srgrimes if (!(inf = fopen(argv[step], "r"))) { 1511590Srgrimes warn("%s", argv[step]); 1521590Srgrimes exit_val = 1; 1531590Srgrimes } 1541590Srgrimes else { 1551590Srgrimes curfile = argv[step]; 1561590Srgrimes find_entries(argv[step]); 1571590Srgrimes (void)fclose(inf); 1581590Srgrimes } 1591590Srgrimes 16048465Sbillf if (head) { 1611590Srgrimes if (xflag) 1621590Srgrimes put_entries(head); 1631590Srgrimes else { 1641590Srgrimes if (uflag) { 165129042Scjc FILE *oldf; 166129042Scjc regex_t *regx; 167129042Scjc 168129042Scjc if ((oldf = fopen(outfile, "r")) == NULL) 169129042Scjc err(1, "opening %s", outfile); 170129042Scjc if (unlink(outfile)) 171129042Scjc err(1, "unlinking %s", outfile); 172129042Scjc if ((outf = fopen(outfile, "w")) == NULL) 173129042Scjc err(1, "recreating %s", outfile); 174129042Scjc if ((regx = calloc(argc, sizeof(regex_t))) == NULL) 175129042Scjc err(1, "RE alloc"); 1761590Srgrimes for (step = 0; step < argc; step++) { 177129042Scjc (void)strcpy(lbuf, "\t"); 178129042Scjc (void)strlcat(lbuf, argv[step], LINE_MAX); 179129042Scjc (void)strlcat(lbuf, "\t", LINE_MAX); 180129042Scjc if (regcomp(regx + step, lbuf, 181129042Scjc REG_NOSPEC)) 182129042Scjc warn("RE compilation failed"); 1831590Srgrimes } 184129042Scjcnextline: 185129042Scjc while (fgets(lbuf, LINE_MAX, oldf)) { 186129042Scjc for (step = 0; step < argc; step++) 187129042Scjc if (regexec(regx + step, 188129042Scjc lbuf, 0, NULL, 0) == 0) 189129042Scjc goto nextline; 190129042Scjc fputs(lbuf, outf); 191129042Scjc } 192129042Scjc for (step = 0; step < argc; step++) 193129042Scjc regfree(regx + step); 194129042Scjc free(regx); 195129042Scjc fclose(oldf); 196129042Scjc fclose(outf); 1971590Srgrimes ++aflag; 1981590Srgrimes } 1991590Srgrimes if (!(outf = fopen(outfile, aflag ? "a" : "w"))) 20097331Stjr err(1, "%s", outfile); 2011590Srgrimes put_entries(head); 2021590Srgrimes (void)fclose(outf); 2031590Srgrimes if (uflag) { 204129042Scjc pid_t pid; 205129042Scjc 206129042Scjc if ((pid = fork()) == -1) 207129042Scjc err(1, "fork failed"); 208129042Scjc else if (pid == 0) { 209129042Scjc execlp("sort", "sort", "-o", outfile, 210129042Scjc outfile, NULL); 211129042Scjc err(1, "exec of sort failed"); 212129042Scjc } 213129042Scjc /* Just assume the sort went OK. The old code 214129042Scjc did not do any checks either. */ 215129042Scjc (void)wait(NULL); 2161590Srgrimes } 2171590Srgrimes } 21848465Sbillf } 2191590Srgrimes exit(exit_val); 2201590Srgrimes} 2211590Srgrimes 22227097Scharnierstatic void 223100822Sdwmaloneusage(void) 22427097Scharnier{ 22597577Stjr (void)fprintf(stderr, "usage: ctags [-BFTaduwvx] [-f tagsfile] file ...\n"); 22627097Scharnier exit(1); 22727097Scharnier} 22827097Scharnier 2291590Srgrimes/* 2301590Srgrimes * init -- 23187750Scharnier * this routine sets up the boolean pseudo-functions which work by 2321590Srgrimes * setting boolean flags dependent upon the corresponding character. 2331590Srgrimes * Every char which is NOT in that string is false with respect to 2341590Srgrimes * the pseudo-function. Therefore, all of the array "_wht" is NO 2351590Srgrimes * by default and then the elements subscripted by the chars in 2361590Srgrimes * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 2371590Srgrimes * the string CWHITE, else NO. 2381590Srgrimes */ 2391590Srgrimesvoid 240100822Sdwmaloneinit(void) 2411590Srgrimes{ 2421590Srgrimes int i; 243201606Sdwmalone const unsigned char *sp; 2441590Srgrimes 2451590Srgrimes for (i = 0; i < 256; i++) { 2461590Srgrimes _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 2471590Srgrimes _gd[i] = YES; 2481590Srgrimes } 2491590Srgrimes#define CWHITE " \f\t\n" 2501590Srgrimes for (sp = CWHITE; *sp; sp++) /* white space chars */ 2511590Srgrimes _wht[*sp] = YES; 2521590Srgrimes#define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 2531590Srgrimes for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 2541590Srgrimes _etk[*sp] = YES; 2551590Srgrimes#define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 2561590Srgrimes for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 2571590Srgrimes _itk[*sp] = YES; 2581590Srgrimes#define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 2591590Srgrimes for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 2601590Srgrimes _btk[*sp] = YES; 2611590Srgrimes#define CNOTGD ",;" 2621590Srgrimes for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 2631590Srgrimes _gd[*sp] = NO; 2641590Srgrimes} 2651590Srgrimes 2661590Srgrimes/* 2671590Srgrimes * find_entries -- 2681590Srgrimes * this routine opens the specified file and calls the function 2691590Srgrimes * which searches the file. 2701590Srgrimes */ 2711590Srgrimesvoid 272100822Sdwmalonefind_entries(char *file) 2731590Srgrimes{ 2741590Srgrimes char *cp; 2751590Srgrimes 2761590Srgrimes lineno = 0; /* should be 1 ?? KB */ 27732069Salex if ((cp = strrchr(file, '.'))) { 2781590Srgrimes if (cp[1] == 'l' && !cp[2]) { 2791590Srgrimes int c; 2801590Srgrimes 2811590Srgrimes for (;;) { 2821590Srgrimes if (GETC(==, EOF)) 2831590Srgrimes return; 2841590Srgrimes if (!iswhite(c)) { 2851590Srgrimes rewind(inf); 2861590Srgrimes break; 2871590Srgrimes } 2881590Srgrimes } 2891590Srgrimes#define LISPCHR ";([" 2901590Srgrimes/* lisp */ if (strchr(LISPCHR, c)) { 2911590Srgrimes l_entries(); 2921590Srgrimes return; 2931590Srgrimes } 2941590Srgrimes/* lex */ else { 2951590Srgrimes /* 2961590Srgrimes * we search all 3 parts of a lex file 2971590Srgrimes * for C references. This may be wrong. 2981590Srgrimes */ 2991590Srgrimes toss_yysec(); 3001590Srgrimes (void)strcpy(lbuf, "%%$"); 3011590Srgrimes pfnote("yylex", lineno); 3021590Srgrimes rewind(inf); 3031590Srgrimes } 3041590Srgrimes } 3051590Srgrimes/* yacc */ else if (cp[1] == 'y' && !cp[2]) { 3061590Srgrimes /* 3071590Srgrimes * we search only the 3rd part of a yacc file 3081590Srgrimes * for C references. This may be wrong. 3091590Srgrimes */ 3101590Srgrimes toss_yysec(); 3111590Srgrimes (void)strcpy(lbuf, "%%$"); 3121590Srgrimes pfnote("yyparse", lineno); 3131590Srgrimes y_entries(); 3141590Srgrimes } 3151590Srgrimes/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 3161590Srgrimes if (PF_funcs()) 3171590Srgrimes return; 3181590Srgrimes rewind(inf); 3191590Srgrimes } 3201590Srgrimes } 3211590Srgrimes/* C */ c_entries(); 3221590Srgrimes} 323