ctags.c revision 32069
1252867Sdelphij/* 2252867Sdelphij * Copyright (c) 1987, 1993, 1994, 1995 3252867Sdelphij * The Regents of the University of California. All rights reserved. 4252867Sdelphij * 5252867Sdelphij * Redistribution and use in source and binary forms, with or without 6252867Sdelphij * modification, are permitted provided that the following conditions 7252867Sdelphij * are met: 8252867Sdelphij * 1. Redistributions of source code must retain the above copyright 9252867Sdelphij * notice, this list of conditions and the following disclaimer. 10252867Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11252867Sdelphij * notice, this list of conditions and the following disclaimer in the 12252867Sdelphij * documentation and/or other materials provided with the distribution. 13252867Sdelphij * 3. All advertising materials mentioning features or use of this software 14252867Sdelphij * must display the following acknowledgement: 15252867Sdelphij * This product includes software developed by the University of 16252867Sdelphij * California, Berkeley and its contributors. 17252867Sdelphij * 4. Neither the name of the University nor the names of its contributors 18252867Sdelphij * may be used to endorse or promote products derived from this software 19252867Sdelphij * without specific prior written permission. 20252867Sdelphij * 21252867Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22252867Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23252867Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24252867Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25252867Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26252867Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27252867Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28252867Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29252867Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30252867Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31252867Sdelphij * SUCH DAMAGE. 32252867Sdelphij */ 33252867Sdelphij 34252867Sdelphij#ifndef lint 35252867Sdelphijstatic char copyright[] = 36252867Sdelphij"@(#) Copyright (c) 1987, 1993, 1994, 1995\n\ 37252867Sdelphij The Regents of the University of California. All rights reserved.\n"; 38252867Sdelphij#endif /* not lint */ 39252867Sdelphij 40252867Sdelphij#ifndef lint 41252867Sdelphijstatic char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95"; 42252867Sdelphij#endif /* not lint */ 43252867Sdelphij 44252867Sdelphij#include <err.h> 45252867Sdelphij#include <limits.h> 46252867Sdelphij#include <stdio.h> 47252867Sdelphij#include <string.h> 48252867Sdelphij#include <stdlib.h> 49252867Sdelphij#include <unistd.h> 50252867Sdelphij 51252867Sdelphij#include "ctags.h" 52252867Sdelphij 53252867Sdelphij/* 54252867Sdelphij * ctags: create a tags file 55252867Sdelphij */ 56252867Sdelphij 57252867SdelphijNODE *head; /* head of the sorted binary tree */ 58252867Sdelphij 59252867Sdelphij /* boolean "func" (see init()) */ 60252867Sdelphijbool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256]; 61252867Sdelphij 62252867SdelphijFILE *inf; /* ioptr for current input file */ 63252867SdelphijFILE *outf; /* ioptr for tags file */ 64252867Sdelphij 65252867Sdelphijlong lineftell; /* ftell after getc( inf ) == '\n' */ 66252867Sdelphij 67252867Sdelphijint lineno; /* line number of current line */ 68252867Sdelphijint dflag; /* -d: non-macro defines */ 69252867Sdelphijint tflag; /* -t: create tags for typedefs */ 70252867Sdelphijint vflag; /* -v: vgrind style index output */ 71252867Sdelphijint wflag; /* -w: suppress warnings */ 72252867Sdelphijint xflag; /* -x: cxref style output */ 73252867Sdelphij 74252867Sdelphijchar *curfile; /* current input file name */ 75252867Sdelphijchar searchar = '/'; /* use /.../ searches by default */ 76252867Sdelphijchar lbuf[LINE_MAX]; 77252867Sdelphij 78252867Sdelphijvoid init __P((void)); 79252867Sdelphijvoid find_entries __P((char *)); 80252867Sdelphijstatic void usage __P((void)); 81252867Sdelphij 82252867Sdelphijint 83252867Sdelphijmain(argc, argv) 84252867Sdelphij int argc; 85252867Sdelphij char **argv; 86252867Sdelphij{ 87252867Sdelphij static char *outfile = "tags"; /* output file */ 88252867Sdelphij int aflag; /* -a: append to tags */ 89252867Sdelphij int uflag; /* -u: update tags */ 90252867Sdelphij int exit_val; /* exit value */ 91252867Sdelphij int step; /* step through args */ 92252867Sdelphij int ch; /* getopts char */ 93252867Sdelphij char cmd[100]; /* too ugly to explain */ 94252867Sdelphij 95252867Sdelphij aflag = uflag = NO; 96252867Sdelphij while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1) 97252867Sdelphij switch(ch) { 98252867Sdelphij case 'B': 99252867Sdelphij searchar = '?'; 100252867Sdelphij break; 101252867Sdelphij case 'F': 102252867Sdelphij searchar = '/'; 103252867Sdelphij break; 104252867Sdelphij case 'a': 105252867Sdelphij aflag++; 106252867Sdelphij break; 107252867Sdelphij case 'd': 108252867Sdelphij dflag++; 109252867Sdelphij break; 110252867Sdelphij case 'f': 111252867Sdelphij outfile = optarg; 112252867Sdelphij break; 113252867Sdelphij case 't': 114252867Sdelphij tflag++; 115252867Sdelphij break; 116252867Sdelphij case 'u': 117252867Sdelphij uflag++; 118252867Sdelphij break; 119252867Sdelphij case 'w': 120252867Sdelphij wflag++; 121252867Sdelphij break; 122252867Sdelphij case 'v': 123252867Sdelphij vflag++; 124252867Sdelphij case 'x': 125252867Sdelphij xflag++; 126252867Sdelphij break; 127252867Sdelphij case '?': 128252867Sdelphij default: 129252867Sdelphij usage(); 130252867Sdelphij } 131252867Sdelphij argv += optind; 132252867Sdelphij argc -= optind; 133252867Sdelphij if (!argc) 134252867Sdelphij usage(); 135252867Sdelphij 136252867Sdelphij init(); 137252867Sdelphij 138252867Sdelphij for (exit_val = step = 0; step < argc; ++step) 139252867Sdelphij if (!(inf = fopen(argv[step], "r"))) { 140252867Sdelphij warn("%s", argv[step]); 141252867Sdelphij exit_val = 1; 142252867Sdelphij } 143252867Sdelphij else { 144252867Sdelphij curfile = argv[step]; 145252867Sdelphij find_entries(argv[step]); 146252867Sdelphij (void)fclose(inf); 147252867Sdelphij } 148252867Sdelphij 149252867Sdelphij if (head) 150252867Sdelphij if (xflag) 151252867Sdelphij put_entries(head); 152252867Sdelphij else { 153252867Sdelphij if (uflag) { 154252867Sdelphij for (step = 0; step < argc; step++) { 155252867Sdelphij (void)sprintf(cmd, 156252867Sdelphij "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS", 157252867Sdelphij outfile, argv[step], 158252867Sdelphij outfile); 159252867Sdelphij system(cmd); 160252867Sdelphij } 161252867Sdelphij ++aflag; 162252867Sdelphij } 163252867Sdelphij if (!(outf = fopen(outfile, aflag ? "a" : "w"))) 164252867Sdelphij err(exit_val, "%s", outfile); 165252867Sdelphij put_entries(head); 166252867Sdelphij (void)fclose(outf); 167252867Sdelphij if (uflag) { 168252867Sdelphij (void)sprintf(cmd, "sort -o %s %s", 169252867Sdelphij outfile, outfile); 170252867Sdelphij system(cmd); 171252867Sdelphij } 172252867Sdelphij } 173252867Sdelphij exit(exit_val); 174252867Sdelphij} 175252867Sdelphij 176252867Sdelphijstatic void 177252867Sdelphijusage() 178252867Sdelphij{ 179252867Sdelphij (void)fprintf(stderr, "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n"); 180252867Sdelphij exit(1); 181252867Sdelphij} 182252867Sdelphij 183252867Sdelphij/* 184252867Sdelphij * init -- 185252867Sdelphij * this routine sets up the boolean psuedo-functions which work by 186252867Sdelphij * setting boolean flags dependent upon the corresponding character. 187252867Sdelphij * Every char which is NOT in that string is false with respect to 188252867Sdelphij * the pseudo-function. Therefore, all of the array "_wht" is NO 189252867Sdelphij * by default and then the elements subscripted by the chars in 190252867Sdelphij * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 191252867Sdelphij * the string CWHITE, else NO. 192252867Sdelphij */ 193252867Sdelphijvoid 194252867Sdelphijinit() 195252867Sdelphij{ 196252867Sdelphij int i; 197252867Sdelphij unsigned char *sp; 198252867Sdelphij 199252867Sdelphij for (i = 0; i < 256; i++) { 200252867Sdelphij _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 201252867Sdelphij _gd[i] = YES; 202252867Sdelphij } 203252867Sdelphij#define CWHITE " \f\t\n" 204252867Sdelphij for (sp = CWHITE; *sp; sp++) /* white space chars */ 205252867Sdelphij _wht[*sp] = YES; 206252867Sdelphij#define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 207252867Sdelphij for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 208252867Sdelphij _etk[*sp] = YES; 209252867Sdelphij#define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 210252867Sdelphij for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 211252867Sdelphij _itk[*sp] = YES; 212252867Sdelphij#define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 213252867Sdelphij for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 214252867Sdelphij _btk[*sp] = YES; 215252867Sdelphij#define CNOTGD ",;" 216252867Sdelphij for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 217252867Sdelphij _gd[*sp] = NO; 218252867Sdelphij} 219252867Sdelphij 220252867Sdelphij/* 221252867Sdelphij * find_entries -- 222252867Sdelphij * this routine opens the specified file and calls the function 223252867Sdelphij * which searches the file. 224252867Sdelphij */ 225252867Sdelphijvoid 226252867Sdelphijfind_entries(file) 227252867Sdelphij char *file; 228252867Sdelphij{ 229252867Sdelphij char *cp; 230252867Sdelphij 231252867Sdelphij lineno = 0; /* should be 1 ?? KB */ 232252867Sdelphij if ((cp = strrchr(file, '.'))) { 233252867Sdelphij if (cp[1] == 'l' && !cp[2]) { 234252867Sdelphij int c; 235252867Sdelphij 236252867Sdelphij for (;;) { 237252867Sdelphij if (GETC(==, EOF)) 238252867Sdelphij return; 239252867Sdelphij if (!iswhite(c)) { 240252867Sdelphij rewind(inf); 241252867Sdelphij break; 242252867Sdelphij } 243252867Sdelphij } 244252867Sdelphij#define LISPCHR ";([" 245252867Sdelphij/* lisp */ if (strchr(LISPCHR, c)) { 246252867Sdelphij l_entries(); 247252867Sdelphij return; 248252867Sdelphij } 249252867Sdelphij/* lex */ else { 250252867Sdelphij /* 251252867Sdelphij * we search all 3 parts of a lex file 252252867Sdelphij * for C references. This may be wrong. 253252867Sdelphij */ 254252867Sdelphij toss_yysec(); 255252867Sdelphij (void)strcpy(lbuf, "%%$"); 256252867Sdelphij pfnote("yylex", lineno); 257252867Sdelphij rewind(inf); 258252867Sdelphij } 259252867Sdelphij } 260252867Sdelphij/* yacc */ else if (cp[1] == 'y' && !cp[2]) { 261252867Sdelphij /* 262252867Sdelphij * we search only the 3rd part of a yacc file 263252867Sdelphij * for C references. This may be wrong. 264252867Sdelphij */ 265252867Sdelphij toss_yysec(); 266252867Sdelphij (void)strcpy(lbuf, "%%$"); 267252867Sdelphij pfnote("yyparse", lineno); 268252867Sdelphij y_entries(); 269252867Sdelphij } 270252867Sdelphij/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 271252867Sdelphij if (PF_funcs()) 272252867Sdelphij return; 273252867Sdelphij rewind(inf); 274252867Sdelphij } 275252867Sdelphij } 276252867Sdelphij/* C */ c_entries(); 277252867Sdelphij} 278252867Sdelphij