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