1: /*
   2:  * Copyright (c) 1980 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: #if !defined(lint) && defined(DOSCCS)
   8: char copyright[] =
   9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: 
  12: static char sccsid[] = "@(#)ctags.c	5.1.1 (2.11BSD) 2/16/94";
  13: #endif
  14: 
  15: #include <stdio.h>
  16: #include <ctype.h>
  17: #include <strings.h>
  18: 
  19: /*
  20:  * ctags: create a tags file
  21:  */
  22: 
  23: #define bool    char
  24: 
  25: #define TRUE    (1)
  26: #define FALSE   (0)
  27: 
  28: #define iswhite(arg)    (_wht[arg]) /* T if char is white		*/
  29: #define begtoken(arg)   (_btk[arg]) /* T if char can start token	*/
  30: #define intoken(arg)    (_itk[arg]) /* T if char can be in token	*/
  31: #define endtoken(arg)   (_etk[arg]) /* T if char ends tokens	*/
  32: #define isgood(arg) (_gd[arg])  /* T if char can be after ')'	*/
  33: 
  34: #define max(I1,I2)  (I1 > I2 ? I1 : I2)
  35: 
  36: struct  nd_st {         /* sorting structure			*/
  37:     char    *entry;         /* function or type name	*/
  38:     char    *file;          /* file name			*/
  39:     bool    f;          /* use pattern or line no	*/
  40:     int lno;            /* for -x option		*/
  41:     char    *pat;           /* search pattern		*/
  42:     bool    been_warned;        /* set if noticed dup		*/
  43:     struct  nd_st   *left,*right;   /* left and right sons		*/
  44: };
  45: 
  46: long    ftell();
  47: typedef struct  nd_st   NODE;
  48: 
  49: bool    number,             /* T if on line starting with #	*/
  50:     term    = FALSE,        /* T if print on terminal	*/
  51:     makefile= TRUE,         /* T if to creat "tags" file	*/
  52:     gotone,             /* found a func already on line	*/
  53:                     /* boolean "func" (see init)	*/
  54:     _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
  55: 
  56:     /* typedefs are recognized using a simple finite automata,
  57: 	 * tydef is its state variable.
  58: 	 */
  59: typedef enum {none, begin, middle, end } TYST;
  60: 
  61: TYST tydef = none;
  62: 
  63: char    searchar = '/';         /* use /.../ searches 		*/
  64: 
  65: int lineno;             /* line number of current line */
  66: char    line[4*BUFSIZ],     /* current input line			*/
  67:     *curfile,       /* current input file name		*/
  68:     *outfile= "tags",   /* output file				*/
  69:     *white  = " \f\t\n",    /* white chars				*/
  70:     *endtk  = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
  71:                 /* token ending chars			*/
  72:     *begtk  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz",
  73:                 /* token starting chars			*/
  74:     *intk   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789",
  75:                 /* valid in-token chars			*/
  76:     *notgd  = ",;";     /* non-valid after-function chars	*/
  77: 
  78: int file_num;       /* current file number			*/
  79: int aflag;          /* -a: append to tags */
  80: int tflag;          /* -t: create tags for typedefs */
  81: int uflag;          /* -u: update tags */
  82: int wflag;          /* -w: suppress warnings */
  83: int vflag;          /* -v: create vgrind style index output */
  84: int xflag;          /* -x: create cxref style output */
  85: 
  86: char    lbuf[BUFSIZ];
  87: 
  88: FILE    *inf,           /* ioptr for current input file		*/
  89:     *outf;          /* ioptr for tags file			*/
  90: 
  91: long    lineftell;      /* ftell after getc( inf ) == '\n' 	*/
  92: 
  93: NODE    *head;          /* the head of the sorted binary tree	*/
  94: 
  95: char    *toss_comment();
  96: 
  97: main(ac,av)
  98: int ac;
  99: char    *av[];
 100: {
 101:     char cmd[100], outfbuf[BUFSIZ];
 102:     int i;
 103: 
 104:     while (ac > 1 && av[1][0] == '-') {
 105:         for (i=1; av[1][i]; i++) {
 106:             switch(av[1][i]) {
 107:               case 'B':
 108:                 searchar='?';
 109:                 break;
 110:               case 'F':
 111:                 searchar='/';
 112:                 break;
 113:               case 'a':
 114:                 aflag++;
 115:                 break;
 116:               case 't':
 117:                 tflag++;
 118:                 break;
 119:               case 'u':
 120:                 uflag++;
 121:                 break;
 122:               case 'w':
 123:                 wflag++;
 124:                 break;
 125:               case 'v':
 126:                 vflag++;
 127:                 xflag++;
 128:                 break;
 129:               case 'x':
 130:                 xflag++;
 131:                 break;
 132:               case 'f':
 133:                 if (ac < 2)
 134:                     goto usage;
 135:                 ac--, av++;
 136:                 outfile = av[1];
 137:                 goto next;
 138:               default:
 139:                 goto usage;
 140:         }
 141:         }
 142:     next:
 143:         ac--; av++;
 144:     }
 145: 
 146:     if (ac <= 1) {
 147: usage:
 148:         printf("Usage: ctags [-BFatuwvx] [-f tagsfile] file ...\n");
 149:         exit(1);
 150:     }
 151: 
 152:     init();         /* set up boolean "functions"		*/
 153:     /*
 154: 	 * loop through files finding functions
 155: 	 */
 156:     for (file_num = 1; file_num < ac; file_num++)
 157:         find_entries(av[file_num]);
 158: 
 159:     if (xflag) {
 160:         put_entries(head);
 161:         exit(0);
 162:     }
 163:     if (uflag) {
 164:         for (i=1; i<ac; i++) {
 165:             sprintf(cmd,
 166:                 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
 167:                 outfile, av[i], outfile);
 168:             system(cmd);
 169:         }
 170:         aflag++;
 171:     }
 172:     outf = fopen(outfile, aflag ? "a" : "w");
 173:     if (outf == NULL) {
 174:         perror(outfile);
 175:         exit(1);
 176:     }
 177:     setbuf(outf, outfbuf);
 178: 
 179:     put_entries(head);
 180:     fclose(outf);
 181:     if (uflag) {
 182:         sprintf(cmd, "sort %s -o %s", outfile, outfile);
 183:         system(cmd);
 184:     }
 185:     exit(0);
 186: }
 187: 
 188: /*
 189:  * This routine sets up the boolean psuedo-functions which work
 190:  * by seting boolean flags dependent upon the corresponding character
 191:  * Every char which is NOT in that string is not a white char.  Therefore,
 192:  * all of the array "_wht" is set to FALSE, and then the elements
 193:  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
 194:  * of a char is TRUE if it is the string "white", else FALSE.
 195:  */
 196: init()
 197: {
 198: 
 199:     register char   *sp;
 200:     register int    i;
 201: 
 202:     for (i = 0; i < 0177; i++) {
 203:         _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
 204:         _gd[i] = TRUE;
 205:     }
 206:     for (sp = white; *sp; sp++)
 207:         _wht[*sp] = TRUE;
 208:     for (sp = endtk; *sp; sp++)
 209:         _etk[*sp] = TRUE;
 210:     for (sp = intk; *sp; sp++)
 211:         _itk[*sp] = TRUE;
 212:     for (sp = begtk; *sp; sp++)
 213:         _btk[*sp] = TRUE;
 214:     for (sp = notgd; *sp; sp++)
 215:         _gd[*sp] = FALSE;
 216: }
 217: 
 218: /*
 219:  * This routine opens the specified file and calls the function
 220:  * which finds the function and type definitions.
 221:  */
 222: find_entries(file)
 223: char    *file;
 224: {
 225:     char *cp, infbuf[BUFSIZ];
 226: 
 227:     if ((inf = fopen(file,"r")) == NULL) {
 228:         perror(file);
 229:         return;
 230:     }
 231:     setbuf(inf, infbuf);
 232: 
 233:     curfile = strdup(file);
 234:     lineno = 0;
 235:     cp = rindex(file, '.');
 236:     /* .l implies lisp or lex source code */
 237:     if (cp && cp[1] == 'l' && cp[2] == '\0') {
 238:         if (index(";([", first_char()) != NULL) {   /* lisp */
 239:             L_funcs(inf);
 240:             fclose(inf);
 241:             return;
 242:         }
 243:         else {                      /* lex */
 244:             /*
 245: 			 * throw away all the code before the second "%%"
 246: 			 */
 247:             toss_yysec();
 248:             getline();
 249:             pfnote("yylex", lineno, TRUE);
 250:             toss_yysec();
 251:             C_entries();
 252:             fclose(inf);
 253:             return;
 254:         }
 255:     }
 256:     /* .y implies a yacc file */
 257:     if (cp && cp[1] == 'y' && cp[2] == '\0') {
 258:         toss_yysec();
 259:         Y_entries();
 260:         C_entries();
 261:         fclose(inf);
 262:         return;
 263:     }
 264:     /* if not a .c or .h file, try fortran */
 265:     if (cp && (cp[1] != 'c' && cp[1] != 'h') && cp[2] == '\0') {
 266:         if (PF_funcs(inf) != 0) {
 267:             fclose(inf);
 268:             return;
 269:         }
 270:         rewind(inf);    /* no fortran tags found, try C */
 271:     }
 272:     C_entries();
 273:     fclose(inf);
 274: }
 275: 
 276: pfnote(name, ln, f)
 277: char    *name;
 278: int ln;
 279: bool    f;      /* f == TRUE when function */
 280: {
 281:     register char *fp;
 282:     register NODE *np;
 283:     char nbuf[BUFSIZ];
 284: 
 285:     if ((np = (NODE *) malloc(sizeof (NODE))) == NULL) {
 286:         fprintf(stderr, "ctags: too many entries to sort\n");
 287:         put_entries(head);
 288:         free_tree(head);
 289:         head = np = (NODE *) malloc(sizeof (NODE));
 290:     }
 291:     if (xflag == 0 && !strcmp(name, "main")) {
 292:         fp = rindex(curfile, '/');
 293:         if (fp == 0)
 294:             fp = curfile;
 295:         else
 296:             fp++;
 297:         sprintf(nbuf, "M%s", fp);
 298:         fp = rindex(nbuf, '.');
 299:         if (fp && fp[2] == 0)
 300:             *fp = 0;
 301:         name = nbuf;
 302:     }
 303:     np->entry = strdup(name);
 304:     np->file = curfile;
 305:     np->f = f;
 306:     np->lno = ln;
 307:     np->left = np->right = 0;
 308:     if (xflag == 0) {
 309:         lbuf[50] = 0;
 310:         strcat(lbuf, "$");
 311:         lbuf[50] = 0;
 312:     }
 313:     np->pat = strdup(lbuf);
 314:     if (head == NULL)
 315:         head = np;
 316:     else
 317:         add_node(np, head);
 318: }
 319: 
 320: /*
 321:  * This routine finds functions and typedefs in C syntax and adds them
 322:  * to the list.
 323:  */
 324: C_entries()
 325: {
 326:     register int c;
 327:     register char *token, *tp;
 328:     bool incomm, inquote, inchar, midtoken;
 329:     int level;
 330:     char *sp;
 331:     char tok[BUFSIZ];
 332: 
 333:     number = gotone = midtoken = inquote = inchar = incomm = FALSE;
 334:     level = 0;
 335:     sp = tp = token = line;
 336:     lineno++;
 337:     lineftell = ftell(inf);
 338:     for (;;) {
 339:         *sp = c = getc(inf);
 340:         if (feof(inf))
 341:             break;
 342:         if (c == '\n')
 343:             lineno++;
 344:         else if (c == '\\') {
 345:             c = *++sp = getc(inf);
 346:             if (c == '\n')
 347:                 c = ' ';
 348:         }
 349:         else if (incomm) {
 350:             if (c == '*') {
 351:                 while ((*++sp=c=getc(inf)) == '*')
 352:                     continue;
 353:                 if (c == '\n')
 354:                     lineno++;
 355:                 if (c == '/')
 356:                     incomm = FALSE;
 357:             }
 358:         }
 359:         else if (inquote) {
 360:             /*
 361: 			 * Too dumb to know about \" not being magic, but
 362: 			 * they usually occur in pairs anyway.
 363: 			 */
 364:             if (c == '"')
 365:                 inquote = FALSE;
 366:             continue;
 367:         }
 368:         else if (inchar) {
 369:             if (c == '\'')
 370:                 inchar = FALSE;
 371:             continue;
 372:         }
 373:         else switch (c) {
 374:           case '"':
 375:             inquote = TRUE;
 376:             continue;
 377:           case '\'':
 378:             inchar = TRUE;
 379:             continue;
 380:           case '/':
 381:             if ((*++sp=c=getc(inf)) == '*')
 382:                 incomm = TRUE;
 383:             else
 384:                 ungetc(*sp, inf);
 385:             continue;
 386:           case '#':
 387:             if (sp == line)
 388:                 number = TRUE;
 389:             continue;
 390:           case '{':
 391:             if (tydef == begin) {
 392:                 tydef=middle;
 393:             }
 394:             level++;
 395:             continue;
 396:           case '}':
 397:             if (sp == line)
 398:                 level = 0;  /* reset */
 399:             else
 400:                 level--;
 401:             if (!level && tydef==middle) {
 402:                 tydef=end;
 403:             }
 404:             continue;
 405:         }
 406:         if (!level && !inquote && !incomm && gotone == FALSE) {
 407:             if (midtoken) {
 408:                 if (endtoken(c)) {
 409:                     int f;
 410:                     int pfline = lineno;
 411:                     if (start_entry(&sp,token,tp,&f)) {
 412:                         strncpy(tok,token,tp-token+1);
 413:                         tok[tp-token+1] = 0;
 414:                         getline();
 415:                         pfnote(tok, pfline, f);
 416:                         gotone = f; /* function */
 417:                     }
 418:                     midtoken = FALSE;
 419:                     token = sp;
 420:                 }
 421:                 else if (intoken(c))
 422:                     tp++;
 423:             }
 424:             else if (begtoken(c)) {
 425:                 token = tp = sp;
 426:                 midtoken = TRUE;
 427:             }
 428:         }
 429:         if (c == ';'  &&  tydef==end)   /* clean with typedefs */
 430:             tydef=none;
 431:         sp++;
 432:         if (c == '\n' || sp > &line[sizeof (line) - BUFSIZ]) {
 433:             tp = token = sp = line;
 434:             lineftell = ftell(inf);
 435:             number = gotone = midtoken = inquote = inchar = FALSE;
 436:         }
 437:     }
 438: }
 439: 
 440: /*
 441:  * This routine  checks to see if the current token is
 442:  * at the start of a function, or corresponds to a typedef
 443:  * It updates the input line * so that the '(' will be
 444:  * in it when it returns.
 445:  */
 446: start_entry(lp,token,tp,f)
 447: char    **lp,*token,*tp;
 448: int *f;
 449: {
 450:     register char   c,*sp,*tsp;
 451:     static  bool    found;
 452:     bool    firsttok;       /* T if have seen first token in ()'s */
 453:     int bad;
 454: 
 455:     *f = 1;         /* a function */
 456:     sp = *lp;
 457:     c = *sp;
 458:     bad = FALSE;
 459:     if (!number) {      /* space is not allowed in macro defs	*/
 460:         while (iswhite(c)) {
 461:             *++sp = c = getc(inf);
 462:             if (c == '\n') {
 463:                 lineno++;
 464:                 if (sp > &line[sizeof (line) - BUFSIZ])
 465:                     goto ret;
 466:             }
 467:         }
 468:     /* the following tries to make it so that a #define a b(c)	*/
 469:     /* doesn't count as a define of b.				*/
 470:     }
 471:     else {
 472:         if (!strncmp(token, "define", 6))
 473:             found = 0;
 474:         else
 475:             found++;
 476:         if (found >= 2) {
 477:             gotone = TRUE;
 478: badone:         bad = TRUE;
 479:             goto ret;
 480:         }
 481:     }
 482:     /* check for the typedef cases		*/
 483:     if (tflag && !strncmp(token, "typedef", 7)) {
 484:         tydef=begin;
 485:         goto badone;
 486:     }
 487:     if (tydef==begin && (!strncmp(token, "struct", 6) ||
 488:         !strncmp(token, "union", 5) || !strncmp(token, "enum", 4))) {
 489:         goto badone;
 490:     }
 491:     if (tydef==begin) {
 492:         tydef=end;
 493:         goto badone;
 494:     }
 495:     if (tydef==end) {
 496:         *f = 0;
 497:         goto ret;
 498:     }
 499:     if (c != '(')
 500:         goto badone;
 501:     firsttok = FALSE;
 502:     while ((*++sp=c=getc(inf)) != ')') {
 503:         if (c == '\n') {
 504:             lineno++;
 505:             if (sp > &line[sizeof (line) - BUFSIZ])
 506:                 goto ret;
 507:         }
 508:         /*
 509: 		 * This line used to confuse ctags:
 510: 		 *	int	(*oldhup)();
 511: 		 * This fixes it. A nonwhite char before the first
 512: 		 * token, other than a / (in case of a comment in there)
 513: 		 * makes this not a declaration.
 514: 		 */
 515:         if (begtoken(c) || c=='/')
 516:             firsttok++;
 517:         else if (!iswhite(c) && !firsttok)
 518:             goto badone;
 519:     }
 520:     while (iswhite(*++sp=c=getc(inf)))
 521:         if (c == '\n') {
 522:             lineno++;
 523:             if (sp > &line[sizeof (line) - BUFSIZ])
 524:                 break;
 525:         }
 526: ret:
 527:     *lp = --sp;
 528:     if (c == '\n')
 529:         lineno--;
 530:     ungetc(c,inf);
 531:     return !bad && (!*f || isgood(c));
 532:                     /* hack for typedefs */
 533: }
 534: 
 535: /*
 536:  * Y_entries:
 537:  *	Find the yacc tags and put them in.
 538:  */
 539: Y_entries()
 540: {
 541:     register char   *sp, *orig_sp;
 542:     register int    brace;
 543:     register bool   in_rule, toklen;
 544:     char        tok[BUFSIZ];
 545: 
 546:     brace = 0;
 547:     getline();
 548:     pfnote("yyparse", lineno, TRUE);
 549:     while (fgets(line, sizeof line, inf) != NULL)
 550:         for (sp = line; *sp; sp++)
 551:             switch (*sp) {
 552:               case '\n':
 553:                 lineno++;
 554:                 /* FALLTHROUGH */
 555:               case ' ':
 556:               case '\t':
 557:               case '\f':
 558:               case '\r':
 559:                 break;
 560:               case '"':
 561:                 do {
 562:                     while (*++sp != '"')
 563:                         continue;
 564:                 } while (sp[-1] == '\\');
 565:                 break;
 566:               case '\'':
 567:                 do {
 568:                     while (*++sp != '\'')
 569:                         continue;
 570:                 } while (sp[-1] == '\\');
 571:                 break;
 572:               case '/':
 573:                 if (*++sp == '*')
 574:                     sp = toss_comment(sp);
 575:                 else
 576:                     --sp;
 577:                 break;
 578:               case '{':
 579:                 brace++;
 580:                 break;
 581:               case '}':
 582:                 brace--;
 583:                 break;
 584:               case '%':
 585:                 if (sp[1] == '%' && sp == line)
 586:                     return;
 587:                 break;
 588:               case '|':
 589:               case ';':
 590:                 in_rule = FALSE;
 591:                 break;
 592:               default:
 593:                 if (brace == 0  && !in_rule && (isalpha(*sp) ||
 594:                                 *sp == '.' ||
 595:                                 *sp == '_')) {
 596:                     orig_sp = sp;
 597:                     ++sp;
 598:                     while (isalnum(*sp) || *sp == '_' ||
 599:                            *sp == '.')
 600:                         sp++;
 601:                     toklen = sp - orig_sp;
 602:                     while (isspace(*sp))
 603:                         sp++;
 604:                     if (*sp == ':' || (*sp == '\0' &&
 605:                                first_char() == ':'))
 606:                     {
 607:                         strncpy(tok, orig_sp, toklen);
 608:                         tok[toklen] = '\0';
 609:                         strcpy(lbuf, line);
 610:                         lbuf[strlen(lbuf) - 1] = '\0';
 611:                         pfnote(tok, lineno, TRUE);
 612:                         in_rule = TRUE;
 613:                     }
 614:                     else
 615:                         sp--;
 616:                 }
 617:                 break;
 618:             }
 619: }
 620: 
 621: char *
 622: toss_comment(start)
 623: char    *start;
 624: {
 625:     register char   *sp;
 626: 
 627:     /*
 628: 	 * first, see if the end-of-comment is on the same line
 629: 	 */
 630:     do {
 631:         while ((sp = index(start, '*')) != NULL)
 632:             if (sp[1] == '/')
 633:                 return ++sp;
 634:             else
 635:                 start = ++sp;
 636:         start = line;
 637:         lineno++;
 638:     } while (fgets(line, sizeof line, inf) != NULL);
 639: }
 640: 
 641: getline()
 642: {
 643:     long saveftell = ftell( inf );
 644:     register char *cp;
 645: 
 646:     fseek( inf , lineftell , 0 );
 647:     fgets(lbuf, sizeof lbuf, inf);
 648:     cp = rindex(lbuf, '\n');
 649:     if (cp)
 650:         *cp = 0;
 651:     fseek(inf, saveftell, 0);
 652: }
 653: 
 654: free_tree(node)
 655: NODE    *node;
 656: {
 657: 
 658:     while (node) {
 659:         free_tree(node->right);
 660:         cfree(node);
 661:         node = node->left;
 662:     }
 663: }
 664: 
 665: add_node(node, cur_node)
 666:     NODE *node,*cur_node;
 667: {
 668:     register int dif;
 669: 
 670:     dif = strcmp(node->entry, cur_node->entry);
 671:     if (dif == 0) {
 672:         if (node->file == cur_node->file) {
 673:             if (!wflag) {
 674: fprintf(stderr,"Duplicate entry in file %s, line %d: %s\n",
 675:     node->file,lineno,node->entry);
 676: fprintf(stderr,"Second entry ignored\n");
 677:             }
 678:             return;
 679:         }
 680:         if (!cur_node->been_warned)
 681:             if (!wflag)
 682: fprintf(stderr,"Duplicate entry in files %s and %s: %s (Warning only)\n",
 683:     node->file, cur_node->file, node->entry);
 684:         cur_node->been_warned = TRUE;
 685:         return;
 686:     }
 687: 
 688:     if (dif < 0) {
 689:         if (cur_node->left != NULL)
 690:             add_node(node,cur_node->left);
 691:         else
 692:             cur_node->left = node;
 693:         return;
 694:     }
 695:     if (cur_node->right != NULL)
 696:         add_node(node,cur_node->right);
 697:     else
 698:         cur_node->right = node;
 699: }
 700: 
 701: put_entries(node)
 702: register NODE   *node;
 703: {
 704:     register char   *sp;
 705: 
 706:     if (node == NULL)
 707:         return;
 708:     put_entries(node->left);
 709:     if (xflag == 0)
 710:         if (node->f) {      /* a function */
 711:             fprintf(outf, "%s\t%s\t%c^",
 712:                 node->entry, node->file, searchar);
 713:             for (sp = node->pat; *sp; sp++)
 714:                 if (*sp == '\\')
 715:                     fprintf(outf, "\\\\");
 716:                 else if (*sp == searchar)
 717:                     fprintf(outf, "\\%c", searchar);
 718:                 else
 719:                     putc(*sp, outf);
 720:             fprintf(outf, "%c\n", searchar);
 721:         }
 722:         else {      /* a typedef; text pattern inadequate */
 723:             fprintf(outf, "%s\t%s\t%d\n",
 724:                 node->entry, node->file, node->lno);
 725:         }
 726:     else if (vflag)
 727:         fprintf(stdout, "%s %s %d\n",
 728:                 node->entry, node->file, (node->lno+63)/64);
 729:     else
 730:         fprintf(stdout, "%-16s%4d %-16s %s\n",
 731:             node->entry, node->lno, node->file, node->pat);
 732:     put_entries(node->right);
 733: }
 734: char    *dbp = lbuf;
 735: int pfcnt;
 736: 
 737: PF_funcs(fi)
 738:     FILE *fi;
 739: {
 740: 
 741:     pfcnt = 0;
 742:     while (fgets(lbuf, sizeof(lbuf), fi)) {
 743:         lineno++;
 744:         dbp = lbuf;
 745:         if ( *dbp == '%' ) dbp++ ;  /* Ratfor escape to fortran */
 746:         while (isspace(*dbp))
 747:             dbp++;
 748:         if (*dbp == 0)
 749:             continue;
 750:         switch (*dbp |' ') {
 751: 
 752:           case 'i':
 753:             if (tail("integer"))
 754:                 takeprec();
 755:             break;
 756:           case 'r':
 757:             if (tail("real"))
 758:                 takeprec();
 759:             break;
 760:           case 'l':
 761:             if (tail("logical"))
 762:                 takeprec();
 763:             break;
 764:           case 'c':
 765:             if (tail("complex") || tail("character"))
 766:                 takeprec();
 767:             break;
 768:           case 'd':
 769:             if (tail("double")) {
 770:                 while (isspace(*dbp))
 771:                     dbp++;
 772:                 if (*dbp == 0)
 773:                     continue;
 774:                 if (tail("precision"))
 775:                     break;
 776:                 continue;
 777:             }
 778:             break;
 779:         }
 780:         while (isspace(*dbp))
 781:             dbp++;
 782:         if (*dbp == 0)
 783:             continue;
 784:         switch (*dbp|' ') {
 785: 
 786:           case 'f':
 787:             if (tail("function"))
 788:                 getit();
 789:             continue;
 790:           case 's':
 791:             if (tail("subroutine"))
 792:                 getit();
 793:             continue;
 794:           case 'p':
 795:             if (tail("program")) {
 796:                 getit();
 797:                 continue;
 798:             }
 799:             if (tail("procedure"))
 800:                 getit();
 801:             continue;
 802:         }
 803:     }
 804:     return (pfcnt);
 805: }
 806: 
 807: tail(cp)
 808:     char *cp;
 809: {
 810:     register int len = 0;
 811: 
 812:     while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
 813:         cp++, len++;
 814:     if (*cp == 0) {
 815:         dbp += len;
 816:         return (1);
 817:     }
 818:     return (0);
 819: }
 820: 
 821: takeprec()
 822: {
 823: 
 824:     while (isspace(*dbp))
 825:         dbp++;
 826:     if (*dbp != '*')
 827:         return;
 828:     dbp++;
 829:     while (isspace(*dbp))
 830:         dbp++;
 831:     if (!isdigit(*dbp)) {
 832:         --dbp;      /* force failure */
 833:         return;
 834:     }
 835:     do
 836:         dbp++;
 837:     while (isdigit(*dbp));
 838: }
 839: 
 840: getit()
 841: {
 842:     register char *cp;
 843:     char c;
 844:     char nambuf[BUFSIZ];
 845: 
 846:     for (cp = lbuf; *cp; cp++)
 847:         ;
 848:     *--cp = 0;  /* zap newline */
 849:     while (isspace(*dbp))
 850:         dbp++;
 851:     if (*dbp == 0 || !isalpha(*dbp))
 852:         return;
 853:     for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
 854:         continue;
 855:     c = cp[0];
 856:     cp[0] = 0;
 857:     strcpy(nambuf, dbp);
 858:     cp[0] = c;
 859:     pfnote(nambuf, lineno);
 860:     pfcnt++;
 861: }
 862: 
 863: /*
 864:  * lisp tag functions
 865:  * just look for (def or (DEF
 866:  */
 867: 
 868: L_funcs (fi)
 869: FILE *fi;
 870: {
 871:     register int    special;
 872: 
 873:     pfcnt = 0;
 874:     while (fgets(lbuf, sizeof(lbuf), fi)) {
 875:         lineno++;
 876:         dbp = lbuf;
 877:         if (dbp[0] == '(' &&
 878:             (dbp[1] == 'D' || dbp[1] == 'd') &&
 879:             (dbp[2] == 'E' || dbp[2] == 'e') &&
 880:             (dbp[3] == 'F' || dbp[3] == 'f')) {
 881:             dbp += 4;
 882:             if (strcasecmp(dbp, "method") == 0 ||
 883:                 strcasecmp(dbp, "wrapper") == 0 ||
 884:                 strcasecmp(dbp, "whopper") == 0)
 885:                 special = TRUE;
 886:             else
 887:                 special = FALSE;
 888:             while (!isspace(*dbp))
 889:                 dbp++;
 890:             while (isspace(*dbp))
 891:                 dbp++;
 892:             L_getit(special);
 893:         }
 894:     }
 895: }
 896: 
 897: L_getit(special)
 898: int special;
 899: {
 900:     register char   *cp;
 901:     register char   c;
 902:     char        nambuf[BUFSIZ];
 903: 
 904:     for (cp = lbuf; *cp; cp++)
 905:         continue;
 906:     *--cp = 0;      /* zap newline */
 907:     if (*dbp == 0)
 908:         return;
 909:     if (special) {
 910:         if ((cp = index(dbp, ')')) == NULL)
 911:             return;
 912:         while (cp >= dbp && *cp != ':')
 913:             cp--;
 914:         if (cp < dbp)
 915:             return;
 916:         dbp = cp;
 917:         while (*cp && *cp != ')' && *cp != ' ')
 918:             cp++;
 919:     }
 920:     else
 921:         for (cp = dbp + 1; *cp && *cp != '(' && *cp != ' '; cp++)
 922:             continue;
 923:     c = cp[0];
 924:     cp[0] = 0;
 925:     strcpy(nambuf, dbp);
 926:     cp[0] = c;
 927:     pfnote(nambuf, lineno,TRUE);
 928:     pfcnt++;
 929: }
 930: 
 931: /*
 932:  * first_char:
 933:  *	Return the first non-blank character in the file.  After
 934:  *	finding it, rewind the input file so we start at the beginning
 935:  *	again.
 936:  */
 937: first_char()
 938: {
 939:     register int    c;
 940:     register long   off;
 941: 
 942:     off = ftell(inf);
 943:     while ((c = getc(inf)) != EOF)
 944:         if (!isspace(c) && c != '\r') {
 945:             fseek(inf, off, 0);
 946:             return c;
 947:         }
 948:     fseek(inf, off, 0);
 949:     return EOF;
 950: }
 951: 
 952: /*
 953:  * toss_yysec:
 954:  *	Toss away code until the next "%%" line.
 955:  */
 956: toss_yysec()
 957: {
 958:     char        buf[BUFSIZ];
 959: 
 960:     for (;;) {
 961:         lineftell = ftell(inf);
 962:         if (fgets(buf, BUFSIZ, inf) == NULL)
 963:             return;
 964:         lineno++;
 965:         if (strncmp(buf, "%%", 2) == 0)
 966:             return;
 967:     }
 968: }

Defined functions

C_entries defined in line 324; used 3 times
L_funcs defined in line 868; used 1 times
L_getit defined in line 897; used 1 times
PF_funcs defined in line 737; used 1 times
Y_entries defined in line 539; used 1 times
add_node defined in line 665; used 3 times
find_entries defined in line 222; used 1 times
first_char defined in line 937; used 2 times
free_tree defined in line 654; used 2 times
getit defined in line 840; used 4 times
getline defined in line 641; used 3 times
init defined in line 196; used 1 times
main defined in line 97; never used
pfnote defined in line 276; used 6 times
put_entries defined in line 701; used 5 times
start_entry defined in line 446; used 1 times
tail defined in line 807; used 11 times
takeprec defined in line 821; used 4 times
toss_comment defined in line 621; used 2 times
toss_yysec defined in line 956; used 3 times

Defined variables

aflag defined in line 79; used 3 times
copyright defined in line 8; never used
curfile defined in line 67; used 4 times
dbp defined in line 734; used 55 times
file_num defined in line 78; used 4 times
head defined in line 93; used 8 times
lbuf defined in line 86; used 19 times
line defined in line 66; used 20 times
lineftell defined in line 91; used 4 times
lineno defined in line 65; used 20 times
outfile defined in line 68; used 7 times
pfcnt defined in line 735; used 5 times
sccsid defined in line 12; never used
searchar defined in line 63; used 6 times
tflag defined in line 80; used 2 times
uflag defined in line 81; used 3 times
vflag defined in line 83; used 2 times
wflag defined in line 82; used 3 times
xflag defined in line 84; used 6 times

Defined struct's

nd_st defined in line 36; used 4 times

Defined typedef's

NODE defined in line 47; used 9 times

Defined macros

FALSE defined in line 26; used 14 times
TRUE defined in line 25; used 20 times
begtoken defined in line 29; used 2 times
bool defined in line 23; used 8 times
endtoken defined in line 31; used 1 times
intoken defined in line 30; used 1 times
isgood defined in line 32; used 1 times
iswhite defined in line 28; used 3 times
max defined in line 34; never used
Last modified: 1994-02-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5605
Valid CSS Valid XHTML 1.0 Strict