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