00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include "config.h"
00009 #ifndef FALSE
00010 # define FALSE 0
00011 # define TRUE 1
00012 #endif
00013 #ifndef TAGS
00014 # define TAGS "tags"
00015 #endif
00016 #ifndef REFS
00017 # define REFS "refs"
00018 #endif
00019 #ifndef BLKSIZE
00020 # define BLKSIZE 1024
00021 #endif
00022
00023 #include "ctype.c"
00024
00025
00026
00027
00028
00029 int incl_static;
00030 int incl_types;
00031 int incl_vars;
00032 int make_refs;
00033 int append_files;
00034
00035
00036 FILE *tags;
00037 FILE *refs;
00038
00039
00040
00041 char *file_name;
00042 FILE *file_fp;
00043 long file_lnum;
00044 long file_seek;
00045 int file_afternl;
00046 int file_prevch;
00047 int file_header;
00048
00049
00050
00051
00052 void file_open(name)
00053 char *name;
00054 {
00055
00056 if (file_fp)
00057 {
00058 fclose(file_fp);
00059 }
00060
00061
00062
00063
00064 #if MSDOS || TOS
00065 file_fp = fopen(name, "rb");
00066 #else
00067 file_fp = fopen(name, "r");
00068 #endif
00069 if (!file_fp)
00070 {
00071 perror(name);
00072 }
00073
00074
00075 file_name = name;
00076 file_lnum = 0L;
00077 file_seek = 0L;
00078 file_afternl = TRUE;
00079
00080
00081 file_header = FALSE;
00082 name += strlen(name) - 2;
00083 if (name >= file_name && name[0] == '.' && (name[1] == 'h' || name[1] == 'H'))
00084 {
00085 file_header = TRUE;
00086 }
00087 }
00088
00089
00090
00091
00092
00093 int file_getc()
00094 {
00095 int ch;
00096
00097
00098
00099
00100
00101 if (file_prevch)
00102 {
00103 ch = file_prevch;
00104 file_prevch = 0;
00105 return ch;
00106 }
00107
00108
00109 if (file_afternl)
00110 {
00111 file_afternl = FALSE;
00112 file_seek = ftell(file_fp);
00113 file_lnum++;
00114 }
00115
00116
00117 ch = (file_fp ? getc(file_fp) : EOF);
00118
00119
00120 if (ch == '\n')
00121 {
00122 file_afternl = TRUE;
00123 }
00124
00125
00126 return ch;
00127 }
00128
00129
00130 void file_ungetc(ch)
00131 int ch;
00132 {
00133 file_prevch = ch;
00134 }
00135
00136
00137
00138
00139
00140
00141
00142
00143 void file_copyline(seek, fp)
00144 long seek;
00145 FILE *fp;
00146 {
00147 long oldseek;
00148 char ch;
00149 char next;
00150
00151
00152 oldseek = ftell(file_fp);
00153 fseek(file_fp, seek, 0);
00154
00155
00156 ch = getc(file_fp);
00157 if (ch == '^')
00158 {
00159 putc('\\', fp);
00160 putc('^', fp);
00161 ch = getc(file_fp);
00162 }
00163
00164
00165 while (ch != '\n')
00166 {
00167
00168 next = getc(file_fp);
00169
00170
00171 if (ch == '\\' || (ch == '$' && next == '\n'))
00172 {
00173 putc('\\', fp);
00174 }
00175 putc(ch, fp);
00176
00177
00178 ch = next;
00179 }
00180
00181
00182 fseek(file_fp, oldseek, 0);
00183 }
00184
00185
00186
00187
00188
00189
00190 int cpp_afternl;
00191 int cpp_prevch;
00192 int cpp_refsok;
00193
00194
00195 void cpp_open(name)
00196 char *name;
00197 {
00198
00199 file_open(name);
00200
00201
00202 cpp_afternl = TRUE;
00203 cpp_refsok = TRUE;
00204 }
00205
00206
00207 void cpp_echo(ch)
00208 int ch;
00209 {
00210 static wasnl;
00211
00212
00213 if (ch != EOF && make_refs && cpp_refsok && !file_header)
00214 {
00215
00216 if (ch == '\n')
00217 {
00218 if (wasnl)
00219 {
00220 return;
00221 }
00222 wasnl = TRUE;
00223 }
00224 else
00225 {
00226 wasnl = FALSE;
00227 }
00228
00229
00230 putc(ch, refs);
00231 }
00232 }
00233
00234
00235 int cpp_getc()
00236 {
00237 static
00238 int ch;
00239 char *scan;
00240
00241
00242 if (cpp_prevch)
00243 {
00244 ch = cpp_prevch;
00245 cpp_prevch = 0;
00246 return ch;
00247 }
00248
00249
00250 ch = file_getc();
00251 if (ch == '\n')
00252 {
00253 cpp_afternl = TRUE;
00254 cpp_echo(ch);
00255 return ch;
00256 }
00257 else if (ch != '#' || !cpp_afternl)
00258 {
00259
00260 if (ch != ' ' && ch != '\t')
00261 {
00262 cpp_afternl = FALSE;
00263 }
00264 cpp_echo(ch);
00265 return ch;
00266 }
00267
00268
00269
00270
00271 scan = " define ";
00272 while (*scan)
00273 {
00274 if (*scan == ' ')
00275 {
00276
00277 do
00278 {
00279 ch = file_getc();
00280 } while (ch == ' ' || ch == '\t');
00281 file_ungetc(ch);
00282 }
00283 else
00284 {
00285
00286 ch = file_getc();
00287 if (ch != *scan)
00288 {
00289 file_ungetc(ch);
00290 break;
00291 }
00292 }
00293 scan++;
00294 }
00295
00296
00297 if (!*scan && (file_header || incl_static))
00298 {
00299
00300 if (!file_header)
00301 {
00302 fputs(file_name, tags);
00303 putc(':', tags);
00304 }
00305
00306
00307 for (ch = file_getc(); isalnum(ch) || ch == '_'; ch = file_getc())
00308 {
00309 putc(ch, tags);
00310 }
00311
00312
00313 fprintf(tags, "\t%s\t%ld\n", file_name, file_lnum);
00314 }
00315
00316
00317
00318
00319 while (ch != EOF && ch != '\n')
00320 {
00321 if (ch == '\\')
00322 {
00323 ch = file_getc();
00324 }
00325 ch = file_getc();
00326 }
00327
00328
00329 cpp_echo(ch);
00330 return ch;
00331 }
00332
00333
00334 cpp_ungetc(ch)
00335 int ch;
00336 {
00337 cpp_prevch = ch;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 #define DELETED 0
00364 #define BODY 1
00365 #define ARGS 2
00366 #define COMMA 3
00367 #define SEMICOLON 4
00368 #define TYPEDEF 5
00369 #define STATIC 6
00370 #define EXTERN 7
00371 #define NAME 8
00372
00373 char lex_name[BLKSIZE];
00374 long lex_seek;
00375
00376 lex_gettoken()
00377 {
00378 int ch;
00379 int next;
00380 int token;
00381 int i;
00382
00383
00384 do
00385 {
00386
00387 ch = cpp_getc();
00388
00389
00390 switch (ch)
00391 {
00392 case ',':
00393 token = COMMA;
00394 break;
00395
00396 case ';':
00397 token = SEMICOLON;
00398 break;
00399
00400 case '/':
00401
00402 ch = cpp_getc();
00403 switch (ch)
00404 {
00405 case '*':
00406 ch = cpp_getc();
00407 next = cpp_getc();
00408 while (next != EOF && (ch != '*' || next != '/'))
00409 {
00410 ch = next;
00411 next = cpp_getc();
00412 }
00413 break;
00414
00415 case '/':
00416 do
00417 {
00418 ch = cpp_getc();
00419 } while (ch != '\n' && ch != EOF);
00420 break;
00421
00422 default:
00423 cpp_ungetc(ch);
00424 }
00425 token = DELETED;
00426 break;
00427
00428 case '(':
00429 ch = cpp_getc();
00430 if (ch == '*')
00431 {
00432 token = DELETED;
00433 }
00434 else
00435 {
00436 next = cpp_getc();
00437 while (ch != '{' && ch != EOF && (ch != ')' || next != ';'))
00438 {
00439 ch = next;
00440 next = cpp_getc();
00441 }
00442 if (ch == '{')
00443 {
00444 cpp_ungetc(ch);
00445 }
00446 else if (next == ';')
00447 {
00448 cpp_ungetc(next);
00449 }
00450 token = ARGS;
00451 }
00452 break;
00453
00454 case '{':
00455
00456 cpp_refsok = FALSE;
00457
00458
00459 do
00460 {
00461 ch = cpp_getc();
00462 } while (ch != '{' && ch != '}' && ch != EOF);
00463
00464
00465 if (ch == '{')
00466 {
00467 ch = cpp_getc();
00468 next = cpp_getc();
00469 while (ch != EOF && (ch != '\n' || next != '}'))
00470 {
00471 ch = next;
00472 next = cpp_getc();
00473 }
00474 }
00475
00476
00477 cpp_refsok = TRUE;
00478 cpp_echo('}');
00479
00480 token = BODY;
00481 break;
00482
00483 case '[':
00484
00485 do
00486 {
00487 ch = cpp_getc();
00488 } while (ch != ']' && ch != EOF);
00489 token = DELETED;
00490 break;
00491
00492 case '=':
00493
00494 do
00495 {
00496 ch = cpp_getc();
00497
00498
00499 if (ch == '{')
00500 {
00501 cpp_refsok = FALSE;
00502 }
00503 } while (ch != ';' && ch != EOF);
00504
00505
00506 if (!cpp_refsok)
00507 {
00508 cpp_refsok = TRUE;
00509 cpp_echo('}');
00510 cpp_echo(';');
00511 }
00512 token = SEMICOLON;
00513 break;
00514
00515 case EOF:
00516 token = EOF;
00517 break;
00518
00519 default:
00520
00521 if (isalpha(ch) || ch == '_')
00522 {
00523
00524 lex_name[0] = ch;
00525 for (i = 1, ch = cpp_getc();
00526 i < BLKSIZE - 1 && (isalnum(ch) || ch == '_');
00527 i++, ch = cpp_getc())
00528 {
00529 lex_name[i] = ch;
00530 }
00531 lex_name[i] = '\0';
00532 cpp_ungetc(ch);
00533
00534
00535 if (!strcmp(lex_name, "typedef"))
00536 {
00537 token = TYPEDEF;
00538 lex_seek = -1L;
00539 }
00540 else if (!strcmp(lex_name, "static")
00541 || !strcmp(lex_name, "private")
00542 || !strcmp(lex_name, "PRIVATE"))
00543 {
00544 token = STATIC;
00545 lex_seek = -1L;
00546 }
00547 else if (!strcmp(lex_name, "extern")
00548 || !strcmp(lex_name, "EXTERN")
00549 || !strcmp(lex_name, "FORWARD"))
00550 {
00551 token = EXTERN;
00552 lex_seek = -1L;
00553 }
00554 else
00555 {
00556 token = NAME;
00557 lex_seek = file_seek;
00558 }
00559 }
00560 else
00561 {
00562 token = DELETED;
00563 }
00564
00565 }
00566
00567 } while (token == DELETED);
00568
00569 return token;
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 void maketag(scope, seek)
00581 int scope;
00582 long seek;
00583 {
00584
00585 if (scope == EXTERN)
00586 {
00587
00588 return;
00589 }
00590 else if (scope == STATIC)
00591 {
00592 fprintf(tags, "%s:%s\t%s\t", file_name, lex_name, file_name);
00593 }
00594 else
00595 {
00596 fprintf(tags, "%s\t%s\t", lex_name, file_name);
00597 }
00598
00599
00600 putc('/', tags);
00601 putc('^', tags);
00602 file_copyline(seek, tags);
00603 putc('$', tags);
00604 putc('/', tags);
00605 putc('\n', tags);
00606 }
00607
00608
00609
00610 void ctags(name)
00611 char *name;
00612 {
00613 int prev;
00614 int token;
00615 int scope;
00616 int gotname;
00617 long tagseek;
00618
00619
00620 cpp_open(name);
00621
00622
00623 scope = 0;
00624 gotname = FALSE;
00625 token = SEMICOLON;
00626
00627
00628 while (prev = token, (token = lex_gettoken()) != EOF)
00629 {
00630
00631 if (token == TYPEDEF || token == STATIC || token == EXTERN)
00632 {
00633 scope = token;
00634 gotname = FALSE;
00635 continue;
00636 }
00637
00638
00639 if (token == NAME)
00640 {
00641 tagseek = file_seek;
00642 gotname = TRUE;
00643 continue;
00644 }
00645
00646
00647 if (gotname && token == BODY && prev != ARGS)
00648 {
00649 gotname = FALSE;
00650
00651
00652 if (scope == TYPEDEF)
00653 {
00654 continue;
00655 }
00656
00657
00658 if (incl_types && (file_header || incl_static))
00659 {
00660 maketag(file_header ? 0 : STATIC, tagseek);
00661 }
00662 }
00663
00664
00665 if (gotname && prev == ARGS && token == BODY)
00666 {
00667 gotname = FALSE;
00668
00669
00670 if (scope != STATIC || incl_static)
00671 {
00672 maketag(scope, tagseek);
00673 }
00674 }
00675
00676
00677 if (gotname && (token == SEMICOLON || token == COMMA))
00678 {
00679 gotname = FALSE;
00680
00681
00682 if (scope == TYPEDEF && incl_types && (file_header || incl_static)
00683 || scope == STATIC && incl_vars && incl_static
00684 || incl_vars)
00685 {
00686
00687 if (scope == TYPEDEF && !file_header)
00688 {
00689 maketag(STATIC, tagseek);
00690 }
00691 else
00692 {
00693 maketag(scope, tagseek);
00694 }
00695 }
00696 }
00697
00698
00699 if (token == SEMICOLON || (prev == ARGS && token == BODY))
00700 {
00701 scope = 0;
00702 gotname = FALSE;
00703 }
00704 }
00705
00706
00707 }
00708
00709
00710
00711 void usage()
00712 {
00713 fprintf(stderr, "usage: ctags [flags] filenames...\n");
00714 fprintf(stderr, "\t-s include static functions\n");
00715 fprintf(stderr, "\t-t include typedefs\n");
00716 fprintf(stderr, "\t-v include variable declarations\n");
00717 fprintf(stderr, "\t-r generate a \"refs\" file, too\n");
00718 fprintf(stderr, "\t-a append to \"tags\", instead of overwriting\n");
00719 exit(2);
00720 }
00721
00722
00723
00724 #if AMIGA
00725 # include "amiwild.c"
00726 #endif
00727
00728 #if VMS
00729 # include "vmswild.c"
00730 #endif
00731
00732 main(argc, argv)
00733 int argc;
00734 char **argv;
00735 {
00736 int i, j;
00737
00738 #if MSDOS || TOS
00739 char **wildexpand();
00740 argv = wildexpand(&argc, argv);
00741 #endif
00742
00743
00744 _ct_init("");
00745
00746
00747 for (i = 1; i < argc && argv[i][0] == '-'; i++)
00748 {
00749 for (j = 1; argv[i][j]; j++)
00750 {
00751 switch (argv[i][j])
00752 {
00753 case 's': incl_static = TRUE; break;
00754 case 't': incl_types = TRUE; break;
00755 case 'v': incl_vars = TRUE; break;
00756 case 'r': make_refs = TRUE; break;
00757 case 'a': append_files = TRUE; break;
00758 default: usage();
00759 }
00760 }
00761 }
00762
00763
00764 if (i == argc)
00765 {
00766 usage();
00767 }
00768
00769
00770 tags = fopen(TAGS, append_files ? "a" : "w");
00771 if (!tags)
00772 {
00773 perror(TAGS);
00774 exit(3);
00775 }
00776 if (make_refs)
00777 {
00778 refs = fopen(REFS, append_files ? "a" : "w");
00779 if (!refs)
00780 {
00781 perror(REFS);
00782 exit(4);
00783 }
00784 }
00785
00786
00787 for (; i < argc; i++)
00788 {
00789 ctags(argv[i]);
00790 }
00791
00792
00793 fclose(tags);
00794 if (make_refs)
00795 {
00796 fclose(refs);
00797 }
00798
00799 #ifdef SORT
00800
00801
00802
00803
00804
00805 # if OSK
00806 system("qsort tags >-_tags; -nx; del tags; rename _tags tags");
00807 # else
00808 system("sort tags >_tags$$; mv _tags$$ tags");
00809 # endif
00810 #endif
00811
00812 exit(0);
00813
00814 }
00815
00816 #if MSDOS || TOS
00817 # define WILDCARD_NO_MAIN
00818 # include "wildcard.c"
00819 #endif