ctags.c revision 100822
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 * 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 3541568Sarchiestatic const char copyright[] = 3627097Scharnier"@(#) Copyright (c) 1987, 1993, 1994, 1995\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3887249Smarkm#endif 391590Srgrimes 4087628Sdwmalone#if 0 411590Srgrimes#ifndef lint 4287628Sdwmalonestatic char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95"; 4381782Smikeh#endif 4487628Sdwmalone#endif 451590Srgrimes 4687628Sdwmalone#include <sys/cdefs.h> 4787628Sdwmalone__FBSDID("$FreeBSD: head/usr.bin/ctags/ctags.c 100822 2002-07-28 15:50:38Z dwmalone $"); 4887628Sdwmalone 491590Srgrimes#include <err.h> 501590Srgrimes#include <limits.h> 5197581Stjr#include <locale.h> 521590Srgrimes#include <stdio.h> 5387750Scharnier#include <stdlib.h> 541590Srgrimes#include <string.h> 551590Srgrimes#include <unistd.h> 561590Srgrimes 571590Srgrimes#include "ctags.h" 581590Srgrimes 591590Srgrimes/* 601590Srgrimes * ctags: create a tags file 611590Srgrimes */ 621590Srgrimes 631590SrgrimesNODE *head; /* head of the sorted binary tree */ 641590Srgrimes 651590Srgrimes /* boolean "func" (see init()) */ 661590Srgrimesbool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256]; 671590Srgrimes 681590SrgrimesFILE *inf; /* ioptr for current input file */ 691590SrgrimesFILE *outf; /* ioptr for tags file */ 701590Srgrimes 711590Srgrimeslong lineftell; /* ftell after getc( inf ) == '\n' */ 721590Srgrimes 731590Srgrimesint lineno; /* line number of current line */ 741590Srgrimesint dflag; /* -d: non-macro defines */ 751590Srgrimesint tflag; /* -t: create tags for typedefs */ 761590Srgrimesint vflag; /* -v: vgrind style index output */ 771590Srgrimesint wflag; /* -w: suppress warnings */ 781590Srgrimesint xflag; /* -x: cxref style output */ 791590Srgrimes 801590Srgrimeschar *curfile; /* current input file name */ 811590Srgrimeschar searchar = '/'; /* use /.../ searches by default */ 821590Srgrimeschar lbuf[LINE_MAX]; 831590Srgrimes 8492920Simpvoid init(void); 8592920Simpvoid find_entries(char *); 8692920Simpstatic void usage(void); 871590Srgrimes 881590Srgrimesint 89100822Sdwmalonemain(int argc, char **argv) 901590Srgrimes{ 9187215Smarkm static const char *outfile = "tags"; /* output file */ 921590Srgrimes int aflag; /* -a: append to tags */ 931590Srgrimes int uflag; /* -u: update tags */ 941590Srgrimes int exit_val; /* exit value */ 951590Srgrimes int step; /* step through args */ 961590Srgrimes int ch; /* getopts char */ 9797574Stjr char *cmd; 981590Srgrimes 9997581Stjr setlocale(LC_ALL, ""); 10097581Stjr 1011590Srgrimes aflag = uflag = NO; 10297577Stjr tflag = YES; 10397577Stjr while ((ch = getopt(argc, argv, "BFTadf:tuwvx")) != -1) 1041590Srgrimes switch(ch) { 1051590Srgrimes case 'B': 1061590Srgrimes searchar = '?'; 1071590Srgrimes break; 1081590Srgrimes case 'F': 1091590Srgrimes searchar = '/'; 1101590Srgrimes break; 11197577Stjr case 'T': 11297577Stjr tflag = NO; 11397577Stjr break; 1141590Srgrimes case 'a': 1151590Srgrimes aflag++; 1161590Srgrimes break; 1171590Srgrimes case 'd': 1181590Srgrimes dflag++; 1191590Srgrimes break; 1201590Srgrimes case 'f': 1211590Srgrimes outfile = optarg; 1221590Srgrimes break; 1231590Srgrimes case 't': 12497577Stjr tflag = YES; 1251590Srgrimes break; 1261590Srgrimes case 'u': 1271590Srgrimes uflag++; 1281590Srgrimes break; 1291590Srgrimes case 'w': 1301590Srgrimes wflag++; 1311590Srgrimes break; 1321590Srgrimes case 'v': 1331590Srgrimes vflag++; 1341590Srgrimes case 'x': 1351590Srgrimes xflag++; 1361590Srgrimes break; 1371590Srgrimes case '?': 1381590Srgrimes default: 13927097Scharnier usage(); 1401590Srgrimes } 1411590Srgrimes argv += optind; 1421590Srgrimes argc -= optind; 14327097Scharnier if (!argc) 14427097Scharnier usage(); 1451590Srgrimes 14697581Stjr if (!xflag) 14797581Stjr setlocale(LC_COLLATE, "C"); 14897581Stjr 1491590Srgrimes init(); 1501590Srgrimes 1511590Srgrimes for (exit_val = step = 0; step < argc; ++step) 1521590Srgrimes if (!(inf = fopen(argv[step], "r"))) { 1531590Srgrimes warn("%s", argv[step]); 1541590Srgrimes exit_val = 1; 1551590Srgrimes } 1561590Srgrimes else { 1571590Srgrimes curfile = argv[step]; 1581590Srgrimes find_entries(argv[step]); 1591590Srgrimes (void)fclose(inf); 1601590Srgrimes } 1611590Srgrimes 16248465Sbillf if (head) { 1631590Srgrimes if (xflag) 1641590Srgrimes put_entries(head); 1651590Srgrimes else { 1661590Srgrimes if (uflag) { 1671590Srgrimes for (step = 0; step < argc; step++) { 16897574Stjr (void)asprintf(&cmd, 16997574Stjr "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS", 17097574Stjr outfile, argv[step], outfile); 17197574Stjr if (cmd == NULL) 17297574Stjr err(1, "out of space"); 1731590Srgrimes system(cmd); 17497574Stjr free(cmd); 17597574Stjr cmd = NULL; 1761590Srgrimes } 1771590Srgrimes ++aflag; 1781590Srgrimes } 1791590Srgrimes if (!(outf = fopen(outfile, aflag ? "a" : "w"))) 18097331Stjr err(1, "%s", outfile); 1811590Srgrimes put_entries(head); 1821590Srgrimes (void)fclose(outf); 1831590Srgrimes if (uflag) { 18497574Stjr (void)asprintf(&cmd, "sort -o %s %s", 18597574Stjr outfile, outfile); 18697574Stjr if (cmd == NULL) 18797574Stjr err(1, "out of space"); 1881590Srgrimes system(cmd); 18997574Stjr free(cmd); 19097574Stjr cmd = NULL; 1911590Srgrimes } 1921590Srgrimes } 19348465Sbillf } 1941590Srgrimes exit(exit_val); 1951590Srgrimes} 1961590Srgrimes 19727097Scharnierstatic void 198100822Sdwmaloneusage(void) 19927097Scharnier{ 20097577Stjr (void)fprintf(stderr, "usage: ctags [-BFTaduwvx] [-f tagsfile] file ...\n"); 20127097Scharnier exit(1); 20227097Scharnier} 20327097Scharnier 2041590Srgrimes/* 2051590Srgrimes * init -- 20687750Scharnier * this routine sets up the boolean pseudo-functions which work by 2071590Srgrimes * setting boolean flags dependent upon the corresponding character. 2081590Srgrimes * Every char which is NOT in that string is false with respect to 2091590Srgrimes * the pseudo-function. Therefore, all of the array "_wht" is NO 2101590Srgrimes * by default and then the elements subscripted by the chars in 2111590Srgrimes * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 2121590Srgrimes * the string CWHITE, else NO. 2131590Srgrimes */ 2141590Srgrimesvoid 215100822Sdwmaloneinit(void) 2161590Srgrimes{ 2171590Srgrimes int i; 21887215Smarkm const unsigned char *sp; 2191590Srgrimes 2201590Srgrimes for (i = 0; i < 256; i++) { 2211590Srgrimes _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 2221590Srgrimes _gd[i] = YES; 2231590Srgrimes } 2241590Srgrimes#define CWHITE " \f\t\n" 2251590Srgrimes for (sp = CWHITE; *sp; sp++) /* white space chars */ 2261590Srgrimes _wht[*sp] = YES; 2271590Srgrimes#define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 2281590Srgrimes for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 2291590Srgrimes _etk[*sp] = YES; 2301590Srgrimes#define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 2311590Srgrimes for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 2321590Srgrimes _itk[*sp] = YES; 2331590Srgrimes#define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 2341590Srgrimes for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 2351590Srgrimes _btk[*sp] = YES; 2361590Srgrimes#define CNOTGD ",;" 2371590Srgrimes for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 2381590Srgrimes _gd[*sp] = NO; 2391590Srgrimes} 2401590Srgrimes 2411590Srgrimes/* 2421590Srgrimes * find_entries -- 2431590Srgrimes * this routine opens the specified file and calls the function 2441590Srgrimes * which searches the file. 2451590Srgrimes */ 2461590Srgrimesvoid 247100822Sdwmalonefind_entries(char *file) 2481590Srgrimes{ 2491590Srgrimes char *cp; 2501590Srgrimes 2511590Srgrimes lineno = 0; /* should be 1 ?? KB */ 25232069Salex if ((cp = strrchr(file, '.'))) { 2531590Srgrimes if (cp[1] == 'l' && !cp[2]) { 2541590Srgrimes int c; 2551590Srgrimes 2561590Srgrimes for (;;) { 2571590Srgrimes if (GETC(==, EOF)) 2581590Srgrimes return; 2591590Srgrimes if (!iswhite(c)) { 2601590Srgrimes rewind(inf); 2611590Srgrimes break; 2621590Srgrimes } 2631590Srgrimes } 2641590Srgrimes#define LISPCHR ";([" 2651590Srgrimes/* lisp */ if (strchr(LISPCHR, c)) { 2661590Srgrimes l_entries(); 2671590Srgrimes return; 2681590Srgrimes } 2691590Srgrimes/* lex */ else { 2701590Srgrimes /* 2711590Srgrimes * we search all 3 parts of a lex file 2721590Srgrimes * for C references. This may be wrong. 2731590Srgrimes */ 2741590Srgrimes toss_yysec(); 2751590Srgrimes (void)strcpy(lbuf, "%%$"); 2761590Srgrimes pfnote("yylex", lineno); 2771590Srgrimes rewind(inf); 2781590Srgrimes } 2791590Srgrimes } 2801590Srgrimes/* yacc */ else if (cp[1] == 'y' && !cp[2]) { 2811590Srgrimes /* 2821590Srgrimes * we search only the 3rd part of a yacc file 2831590Srgrimes * for C references. This may be wrong. 2841590Srgrimes */ 2851590Srgrimes toss_yysec(); 2861590Srgrimes (void)strcpy(lbuf, "%%$"); 2871590Srgrimes pfnote("yyparse", lineno); 2881590Srgrimes y_entries(); 2891590Srgrimes } 2901590Srgrimes/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 2911590Srgrimes if (PF_funcs()) 2921590Srgrimes return; 2931590Srgrimes rewind(inf); 2941590Srgrimes } 2951590Srgrimes } 2961590Srgrimes/* C */ c_entries(); 2971590Srgrimes} 298