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