ctags.c revision 1590
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1987, 1993, 1994 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 * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1987, 1993, 1994\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 411590Srgrimesstatic char sccsid[] = "@(#)ctags.c 8.3 (Berkeley) 4/2/94"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 441590Srgrimes#include <err.h> 451590Srgrimes#include <limits.h> 461590Srgrimes#include <stdio.h> 471590Srgrimes#include <string.h> 481590Srgrimes#include <stdlib.h> 491590Srgrimes#include <unistd.h> 501590Srgrimes 511590Srgrimes#include "ctags.h" 521590Srgrimes 531590Srgrimes/* 541590Srgrimes * ctags: create a tags file 551590Srgrimes */ 561590Srgrimes 571590SrgrimesNODE *head; /* head of the sorted binary tree */ 581590Srgrimes 591590Srgrimes /* boolean "func" (see init()) */ 601590Srgrimesbool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256]; 611590Srgrimes 621590SrgrimesFILE *inf; /* ioptr for current input file */ 631590SrgrimesFILE *outf; /* ioptr for tags file */ 641590Srgrimes 651590Srgrimeslong lineftell; /* ftell after getc( inf ) == '\n' */ 661590Srgrimes 671590Srgrimesint lineno; /* line number of current line */ 681590Srgrimesint dflag; /* -d: non-macro defines */ 691590Srgrimesint tflag; /* -t: create tags for typedefs */ 701590Srgrimesint vflag; /* -v: vgrind style index output */ 711590Srgrimesint wflag; /* -w: suppress warnings */ 721590Srgrimesint xflag; /* -x: cxref style output */ 731590Srgrimes 741590Srgrimeschar *curfile; /* current input file name */ 751590Srgrimeschar searchar = '/'; /* use /.../ searches by default */ 761590Srgrimeschar lbuf[LINE_MAX]; 771590Srgrimes 781590Srgrimesvoid init __P((void)); 791590Srgrimesvoid find_entries __P((char *)); 801590Srgrimes 811590Srgrimesint 821590Srgrimesmain(argc, argv) 831590Srgrimes int argc; 841590Srgrimes char **argv; 851590Srgrimes{ 861590Srgrimes static char *outfile = "tags"; /* output file */ 871590Srgrimes int aflag; /* -a: append to tags */ 881590Srgrimes int uflag; /* -u: update tags */ 891590Srgrimes int exit_val; /* exit value */ 901590Srgrimes int step; /* step through args */ 911590Srgrimes int ch; /* getopts char */ 921590Srgrimes char cmd[100]; /* too ugly to explain */ 931590Srgrimes 941590Srgrimes aflag = uflag = NO; 951590Srgrimes while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != EOF) 961590Srgrimes switch(ch) { 971590Srgrimes case 'B': 981590Srgrimes searchar = '?'; 991590Srgrimes break; 1001590Srgrimes case 'F': 1011590Srgrimes searchar = '/'; 1021590Srgrimes break; 1031590Srgrimes case 'a': 1041590Srgrimes aflag++; 1051590Srgrimes break; 1061590Srgrimes case 'd': 1071590Srgrimes dflag++; 1081590Srgrimes break; 1091590Srgrimes case 'f': 1101590Srgrimes outfile = optarg; 1111590Srgrimes break; 1121590Srgrimes case 't': 1131590Srgrimes tflag++; 1141590Srgrimes break; 1151590Srgrimes case 'u': 1161590Srgrimes uflag++; 1171590Srgrimes break; 1181590Srgrimes case 'w': 1191590Srgrimes wflag++; 1201590Srgrimes break; 1211590Srgrimes case 'v': 1221590Srgrimes vflag++; 1231590Srgrimes case 'x': 1241590Srgrimes xflag++; 1251590Srgrimes break; 1261590Srgrimes case '?': 1271590Srgrimes default: 1281590Srgrimes goto usage; 1291590Srgrimes } 1301590Srgrimes argv += optind; 1311590Srgrimes argc -= optind; 1321590Srgrimes if (!argc) { 1331590Srgrimesusage: (void)fprintf(stderr, 1341590Srgrimes "usage: ctags [-BFadtuwvx] [-f tagsfile] file ..."); 1351590Srgrimes exit(1); 1361590Srgrimes } 1371590Srgrimes 1381590Srgrimes init(); 1391590Srgrimes 1401590Srgrimes for (exit_val = step = 0; step < argc; ++step) 1411590Srgrimes if (!(inf = fopen(argv[step], "r"))) { 1421590Srgrimes warn("%s", argv[step]); 1431590Srgrimes exit_val = 1; 1441590Srgrimes } 1451590Srgrimes else { 1461590Srgrimes curfile = argv[step]; 1471590Srgrimes find_entries(argv[step]); 1481590Srgrimes (void)fclose(inf); 1491590Srgrimes } 1501590Srgrimes 1511590Srgrimes if (head) 1521590Srgrimes if (xflag) 1531590Srgrimes put_entries(head); 1541590Srgrimes else { 1551590Srgrimes if (uflag) { 1561590Srgrimes for (step = 0; step < argc; step++) { 1571590Srgrimes (void)sprintf(cmd, 1581590Srgrimes "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS", 1591590Srgrimes outfile, argv[step], 1601590Srgrimes outfile); 1611590Srgrimes system(cmd); 1621590Srgrimes } 1631590Srgrimes ++aflag; 1641590Srgrimes } 1651590Srgrimes if (!(outf = fopen(outfile, aflag ? "a" : "w"))) 1661590Srgrimes err(exit_val, "%s", outfile); 1671590Srgrimes put_entries(head); 1681590Srgrimes (void)fclose(outf); 1691590Srgrimes if (uflag) { 1701590Srgrimes (void)sprintf(cmd, "sort -o %s %s", 1711590Srgrimes outfile, outfile); 1721590Srgrimes system(cmd); 1731590Srgrimes } 1741590Srgrimes } 1751590Srgrimes exit(exit_val); 1761590Srgrimes} 1771590Srgrimes 1781590Srgrimes/* 1791590Srgrimes * init -- 1801590Srgrimes * this routine sets up the boolean psuedo-functions which work by 1811590Srgrimes * setting boolean flags dependent upon the corresponding character. 1821590Srgrimes * Every char which is NOT in that string is false with respect to 1831590Srgrimes * the pseudo-function. Therefore, all of the array "_wht" is NO 1841590Srgrimes * by default and then the elements subscripted by the chars in 1851590Srgrimes * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 1861590Srgrimes * the string CWHITE, else NO. 1871590Srgrimes */ 1881590Srgrimesvoid 1891590Srgrimesinit() 1901590Srgrimes{ 1911590Srgrimes int i; 1921590Srgrimes unsigned char *sp; 1931590Srgrimes 1941590Srgrimes for (i = 0; i < 256; i++) { 1951590Srgrimes _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 1961590Srgrimes _gd[i] = YES; 1971590Srgrimes } 1981590Srgrimes#define CWHITE " \f\t\n" 1991590Srgrimes for (sp = CWHITE; *sp; sp++) /* white space chars */ 2001590Srgrimes _wht[*sp] = YES; 2011590Srgrimes#define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 2021590Srgrimes for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 2031590Srgrimes _etk[*sp] = YES; 2041590Srgrimes#define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 2051590Srgrimes for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 2061590Srgrimes _itk[*sp] = YES; 2071590Srgrimes#define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 2081590Srgrimes for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 2091590Srgrimes _btk[*sp] = YES; 2101590Srgrimes#define CNOTGD ",;" 2111590Srgrimes for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 2121590Srgrimes _gd[*sp] = NO; 2131590Srgrimes} 2141590Srgrimes 2151590Srgrimes/* 2161590Srgrimes * find_entries -- 2171590Srgrimes * this routine opens the specified file and calls the function 2181590Srgrimes * which searches the file. 2191590Srgrimes */ 2201590Srgrimesvoid 2211590Srgrimesfind_entries(file) 2221590Srgrimes char *file; 2231590Srgrimes{ 2241590Srgrimes char *cp; 2251590Srgrimes 2261590Srgrimes lineno = 0; /* should be 1 ?? KB */ 2271590Srgrimes if (cp = strrchr(file, '.')) { 2281590Srgrimes if (cp[1] == 'l' && !cp[2]) { 2291590Srgrimes int c; 2301590Srgrimes 2311590Srgrimes for (;;) { 2321590Srgrimes if (GETC(==, EOF)) 2331590Srgrimes return; 2341590Srgrimes if (!iswhite(c)) { 2351590Srgrimes rewind(inf); 2361590Srgrimes break; 2371590Srgrimes } 2381590Srgrimes } 2391590Srgrimes#define LISPCHR ";([" 2401590Srgrimes/* lisp */ if (strchr(LISPCHR, c)) { 2411590Srgrimes l_entries(); 2421590Srgrimes return; 2431590Srgrimes } 2441590Srgrimes/* lex */ else { 2451590Srgrimes /* 2461590Srgrimes * we search all 3 parts of a lex file 2471590Srgrimes * for C references. This may be wrong. 2481590Srgrimes */ 2491590Srgrimes toss_yysec(); 2501590Srgrimes (void)strcpy(lbuf, "%%$"); 2511590Srgrimes pfnote("yylex", lineno); 2521590Srgrimes rewind(inf); 2531590Srgrimes } 2541590Srgrimes } 2551590Srgrimes/* yacc */ else if (cp[1] == 'y' && !cp[2]) { 2561590Srgrimes /* 2571590Srgrimes * we search only the 3rd part of a yacc file 2581590Srgrimes * for C references. This may be wrong. 2591590Srgrimes */ 2601590Srgrimes toss_yysec(); 2611590Srgrimes (void)strcpy(lbuf, "%%$"); 2621590Srgrimes pfnote("yyparse", lineno); 2631590Srgrimes y_entries(); 2641590Srgrimes } 2651590Srgrimes/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 2661590Srgrimes if (PF_funcs()) 2671590Srgrimes return; 2681590Srgrimes rewind(inf); 2691590Srgrimes } 2701590Srgrimes } 2711590Srgrimes/* C */ c_entries(); 2721590Srgrimes} 273