1 /* 2 * Copyright (c) 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1987, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ctags.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 #include <stdio.h> 19 #include <string.h> 20 #include <stdlib.h> 21 #include "ctags.h" 22 23 /* 24 * ctags: create a tags file 25 */ 26 27 NODE *head; /* head of the sorted binary tree */ 28 29 /* boolean "func" (see init()) */ 30 bool _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177]; 31 32 FILE *inf, /* ioptr for current input file */ 33 *outf; /* ioptr for tags file */ 34 35 long lineftell; /* ftell after getc( inf ) == '\n' */ 36 37 int lineno, /* line number of current line */ 38 dflag, /* -d: non-macro defines */ 39 tflag, /* -t: create tags for typedefs */ 40 wflag, /* -w: suppress warnings */ 41 vflag, /* -v: vgrind style index output */ 42 xflag; /* -x: cxref style output */ 43 44 char *curfile, /* current input file name */ 45 searchar = '/', /* use /.../ searches by default */ 46 lbuf[BUFSIZ]; 47 48 main(argc,argv) 49 int argc; 50 char **argv; 51 { 52 extern char *optarg; /* getopt arguments */ 53 extern int optind; 54 static char *outfile = "tags"; /* output file */ 55 int aflag, /* -a: append to tags */ 56 uflag, /* -u: update tags */ 57 exit_val, /* exit value */ 58 step, /* step through args */ 59 ch; /* getopts char */ 60 char cmd[100]; /* too ugly to explain */ 61 62 aflag = uflag = NO; 63 while ((ch = getopt(argc,argv,"BFadf:tuwvx")) != EOF) 64 switch((char)ch) { 65 case 'B': 66 searchar = '?'; 67 break; 68 case 'F': 69 searchar = '/'; 70 break; 71 case 'a': 72 aflag++; 73 break; 74 case 'd': 75 dflag++; 76 break; 77 case 'f': 78 outfile = optarg; 79 break; 80 case 't': 81 tflag++; 82 break; 83 case 'u': 84 uflag++; 85 break; 86 case 'w': 87 wflag++; 88 break; 89 case 'v': 90 vflag++; 91 case 'x': 92 xflag++; 93 break; 94 case '?': 95 default: 96 goto usage; 97 } 98 argv += optind; 99 argc -= optind; 100 if (!argc) { 101 usage: puts("Usage: ctags [-BFadtuwvx] [-f tagsfile] file ..."); 102 exit(1); 103 } 104 105 init(); 106 107 for (exit_val = step = 0;step < argc;++step) 108 if (!(inf = fopen(argv[step],"r"))) { 109 perror(argv[step]); 110 exit_val = 1; 111 } 112 else { 113 curfile = argv[step]; 114 find_entries(argv[step]); 115 (void)fclose(inf); 116 } 117 118 if (head) 119 if (xflag) 120 put_entries(head); 121 else { 122 if (uflag) { 123 for (step = 0;step < argc;step++) { 124 (void)sprintf(cmd,"mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",outfile,argv[step],outfile); 125 system(cmd); 126 } 127 ++aflag; 128 } 129 if (!(outf = fopen(outfile, aflag ? "a" : "w"))) { 130 perror(outfile); 131 exit(exit_val); 132 } 133 put_entries(head); 134 (void)fclose(outf); 135 if (uflag) { 136 (void)sprintf(cmd,"sort %s -o %s",outfile,outfile); 137 system(cmd); 138 } 139 } 140 exit(exit_val); 141 } 142 143 /* 144 * init -- 145 * this routine sets up the boolean psuedo-functions which work by 146 * setting boolean flags dependent upon the corresponding character. 147 * Every char which is NOT in that string is false with respect to 148 * the pseudo-function. Therefore, all of the array "_wht" is NO 149 * by default and then the elements subscripted by the chars in 150 * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in 151 * the string CWHITE, else NO. 152 */ 153 init() 154 { 155 register int i; 156 register char *sp; 157 158 for (i = 0; i < 0177; i++) { 159 _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; 160 _gd[i] = YES; 161 } 162 #define CWHITE " \f\t\n" 163 for (sp = CWHITE; *sp; sp++) /* white space chars */ 164 _wht[*sp] = YES; 165 #define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" 166 for (sp = CTOKEN; *sp; sp++) /* token ending chars */ 167 _etk[*sp] = YES; 168 #define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" 169 for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ 170 _itk[*sp] = YES; 171 #define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 172 for (sp = CBEGIN; *sp; sp++) /* token starting chars */ 173 _btk[*sp] = YES; 174 #define CNOTGD ",;" 175 for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ 176 _gd[*sp] = NO; 177 } 178 179 /* 180 * find_entries -- 181 * this routine opens the specified file and calls the function 182 * which searches the file. 183 */ 184 find_entries(file) 185 char *file; 186 { 187 register char *cp; 188 189 lineno = 0; /* should be 1 ?? KB */ 190 if (cp = rindex(file, '.')) { 191 if (cp[1] == 'l' && !cp[2]) { 192 register int c; 193 194 for (;;) { 195 if (GETC(==,EOF)) 196 return; 197 if (!iswhite(c)) { 198 rewind(inf); 199 break; 200 } 201 } 202 #define LISPCHR ";([" 203 /* lisp */ if (index(LISPCHR,(char)c)) { 204 l_entries(); 205 return; 206 } 207 /* lex */ else { 208 /* 209 * we search all 3 parts of a lex file 210 * for C references. This may be wrong. 211 */ 212 toss_yysec(); 213 (void)strcpy(lbuf,"%%$"); 214 pfnote("yylex",lineno); 215 rewind(inf); 216 } 217 } 218 /* yacc */ else if (cp[1] == 'y' && !cp[2]) { 219 /* 220 * we search only the 3rd part of a yacc file 221 * for C references. This may be wrong. 222 */ 223 toss_yysec(); 224 (void)strcpy(lbuf,"%%$"); 225 pfnote("yyparse",lineno); 226 y_entries(); 227 } 228 /* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { 229 if (PF_funcs()) 230 return; 231 rewind(inf); 232 } 233 } 234 /* C */ c_entries(); 235 } 236