1: /* Tags file maker to go with GNUmacs
   2:    Copyright (C) 1984 Richard M. Stallman and Ken Arnold
   3: 
   4: This program is distributed in the hope that it will be useful,
   5: but without any warranty.  No author or distributor
   6: accepts responsibility to anyone for the consequences of using it
   7: or for whether it serves any particular purpose or works at all,
   8: unless he says so in writing.
   9: 
  10:    Permission is granted to anyone to distribute verbatim copies
  11:    of this program's source code as received, in any medium, provided that
  12:    the copyright notice, the nonwarraty notice above
  13:    and this permission notice are preserved,
  14:    and that the distributor grants the recipient all rights
  15:    for further redistribution as permitted by this notice,
  16:    and informs him of these rights.
  17: 
  18:    Permission is granted to distribute modified versions of this
  19:    program's source code, or of portions of it, under the above
  20:    conditions, plus the conditions that all changed files carry
  21:    prominent notices stating who last changed them and that the
  22:    derived material, including anything packaged together with it and
  23:    conceptually functioning as a modification of it rather than an
  24:    application of it, is in its entirety subject to a permission
  25:    notice identical to this one.
  26: 
  27:    Permission is granted to distribute this program (verbatim or
  28:    as modified) in compiled or executable form, provided verbatim
  29:    redistribution is permitted as stated above for source code, and
  30:     A.  it is accompanied by the corresponding machine-readable
  31:       source code, under the above conditions, or
  32:     B.  it is accompanied by a written offer, with no time limit,
  33:       to distribute the corresponding machine-readable source code,
  34:       under the above conditions, to any one, in return for reimbursement
  35:       of the cost of distribution.   Verbatim redistribution of the
  36:       written offer must be permitted.  Or,
  37:     C.  it is distributed by someone who received only the
  38:       compiled or executable form, and is accompanied by a copy of the
  39:       written offer of source code which he received along with it.
  40: 
  41:    Permission is granted to distribute this program (verbatim or as modified)
  42:    in executable form as part of a larger system provided that the source
  43:    code for this program, including any modifications used,
  44:    is also distributed or offered as stated in the preceding paragraph.
  45: 
  46: In other words, you are welcome to use, share and improve this program.
  47: You are forbidden to forbid anyone else to use, share and improve
  48: what you give them.   Help stamp out software-hoarding!  */
  49: 
  50: #include <stdio.h>
  51: #include <ctype.h>
  52: 
  53: /* Define the symbol ETAGS to make the program "etags",
  54:  which makes emacs-style tag tables by default.
  55:  Define CTAGS to make the program "ctags" compatible with the usual one.
  56:  Default is ETAGS.  */
  57: 
  58: #ifndef CTAGS
  59: #define ETAGS 1
  60: #endif
  61: 
  62: #define reg register
  63: #define logical char
  64: 
  65: #define TRUE    (1)
  66: #define FALSE   (0)
  67: 
  68: #define iswhite(arg)    (_wht[arg]) /* T if char is white		*/
  69: #define begtoken(arg)   (_btk[arg]) /* T if char can start token	*/
  70: #define intoken(arg)    (_itk[arg]) /* T if char can be in token	*/
  71: #define endtoken(arg)   (_etk[arg]) /* T if char ends tokens	*/
  72: #define isgood(arg) (_gd[arg])  /* T if char can be after ')'	*/
  73: 
  74: #define max(I1,I2)  (I1 > I2 ? I1 : I2)
  75: 
  76: struct  nd_st {         /* sorting structure			*/
  77:     char    *entry;         /* function or type name	*/
  78:     char    *file;          /* file name			*/
  79:     logical f;          /* use pattern or line no	*/
  80:     int lno;            /* line number tag is on	*/
  81:     long    cno;            /* character number line starts on */
  82:     char    *pat;           /* search pattern		*/
  83:     logical been_warned;        /* set if noticed dup		*/
  84:     struct  nd_st   *left,*right;   /* left and right sons		*/
  85: };
  86: 
  87: long    ftell();
  88: typedef struct  nd_st   NODE;
  89: 
  90: int number; /* tokens found so far on line starting with # (including #) */
  91: logical gotone,             /* found a func already on line	*/
  92:                     /* boolean "func" (see init)	*/
  93:     _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
  94: 
  95:     /* typedefs are recognized using a simple finite automata,
  96: 	 * tydef is its state variable.
  97: 	 */
  98: typedef enum {none, begin, middle, end } TYST;
  99: 
 100: TYST tydef = none;
 101: 
 102: char    searchar = '/';         /* use /.../ searches 		*/
 103: 
 104: int lineno;         /* line number of current line */
 105: long    charno;         /* current character number */
 106: long    linecharno;     /* character number of start of line */
 107: 
 108: char    *curfile,       /* current input file name		*/
 109:     *outfile= "tags",   /* output file				*/
 110:     *white  = " \f\t\n",    /* white chars				*/
 111:     *endtk  = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
 112:                 /* token ending chars			*/
 113:     *begtk  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz",
 114:                 /* token starting chars			*/
 115:     *intk   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789",
 116:                 /* valid in-token chars			*/
 117:     *notgd  = ",;";     /* non-valid after-function chars	*/
 118: 
 119: int file_num;       /* current file number			*/
 120: int aflag;          /* -a: append to tags */
 121: int tflag;          /* -t: create tags for typedefs */
 122: int uflag;          /* -u: update tags */
 123: int wflag;          /* -w: suppress warnings */
 124: int vflag;          /* -v: create vgrind style index output */
 125: int xflag;          /* -x: create cxref style output */
 126: int eflag;          /* -e: emacs style output */
 127: 
 128: FILE    *inf,           /* ioptr for current input file		*/
 129:     *outf;          /* ioptr for tags file			*/
 130: 
 131: NODE    *head;          /* the head of the sorted binary tree	*/
 132: 
 133: char    *savestr();
 134: char    *rindex();
 135: char *concat ();
 136: void initbuffer ();
 137: long readline ();
 138: 
 139: /* A `struct linebuffer' is a structure which holds a line of text.
 140:  `readline' reads a line from a stream into a linebuffer
 141:  and works regardless of the length of the line.  */
 142: 
 143: struct linebuffer
 144:   {
 145:     long size;
 146:     char *buffer;
 147:   };
 148: 
 149: struct linebuffer lb, lb1;
 150: 
 151: main(ac,av)
 152:      int    ac;
 153:      char   *av[];
 154: {
 155:   char cmd[100];
 156:   int i;
 157: 
 158: #ifdef ETAGS
 159:   eflag = 1;
 160: #endif
 161: 
 162:   while (ac > 1 && av[1][0] == '-')
 163:     {
 164:       eflag = 0;
 165:       for (i=1; av[1][i]; i++)
 166:     {
 167:       switch(av[1][i])
 168:         {
 169:         case 'B':
 170:           searchar='?';
 171:           break;
 172:         case 'F':
 173:           searchar='/';
 174:           break;
 175:         case 'a':
 176:           aflag++;
 177:           break;
 178:         case 'e':
 179:           eflag++;
 180:           break;
 181:         case 't':
 182:           tflag++;
 183:           break;
 184:         case 'u':
 185:           uflag++;
 186:           break;
 187:         case 'w':
 188:           wflag++;
 189:           break;
 190:         case 'v':
 191:           vflag++;
 192:           xflag++;
 193:           break;
 194:         case 'x':
 195:           xflag++;
 196:           break;
 197:         default:
 198:           goto usage;
 199:         }
 200:     }
 201:       ac--; av++;
 202:     }
 203: 
 204:   if (ac <= 1)
 205:     {
 206:     usage:
 207:       printf("Usage: ctags [-BFaetuwvx] file ...\n");
 208:       exit(1);
 209:     }
 210: 
 211:   if (eflag)
 212:     outfile = "TAGS";
 213: 
 214:   init();           /* set up boolean "functions"		*/
 215: 
 216:   initbuffer (&lb);
 217:   initbuffer (&lb1);
 218:   /*
 219:    * loop through files finding functions
 220:    */
 221:   if (eflag)
 222:     {
 223:       outf = fopen (outfile, aflag ? "a" : "w");
 224:       if (!outf)
 225:     {
 226:       perror (outfile);
 227:       exit (1);
 228:     }
 229:     }
 230: 
 231:   for (file_num = 1; file_num < ac; file_num++)
 232:     {
 233:       find_entries(av[file_num]);
 234:       if (eflag)
 235:     {
 236:       fprintf (outf, "\f\n%s,%d\n",
 237:            av[file_num], total_size_of_entries (head));
 238:       put_entries (head);
 239:       free_tree (head);
 240:       head = NULL;
 241:     }
 242:     }
 243: 
 244:   if (eflag)
 245:     {
 246:       fclose (outf);
 247:       exit (0);
 248:     }
 249: 
 250:   if (xflag)
 251:     {
 252:       put_entries(head);
 253:       exit(0);
 254:     }
 255:   if (uflag)
 256:     {
 257:       for (i=1; i<ac; i++)
 258:     {
 259:       sprintf(cmd,
 260:           "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
 261:           outfile, av[i], outfile);
 262:       system(cmd);
 263:     }
 264:       aflag++;
 265:     }
 266:   outf = fopen(outfile, aflag ? "a" : "w");
 267:   if (outf == NULL)
 268:     {
 269:       perror(outfile);
 270:       exit(1);
 271:     }
 272:   put_entries(head);
 273:   fclose(outf);
 274:   if (uflag)
 275:     {
 276:       sprintf(cmd, "sort %s -o %s", outfile, outfile);
 277:       system(cmd);
 278:     }
 279:   exit(0);
 280: }
 281: 
 282: /*
 283:  * This routine sets up the boolean psuedo-functions which work
 284:  * by seting boolean flags dependent upon the corresponding character
 285:  * Every char which is NOT in that string is not a white char.  Therefore,
 286:  * all of the array "_wht" is set to FALSE, and then the elements
 287:  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
 288:  * of a char is TRUE if it is the string "white", else FALSE.
 289:  */
 290: init()
 291: {
 292: 
 293:   reg char *sp;
 294:   reg int i;
 295: 
 296:   for (i = 0; i < 0177; i++)
 297:     {
 298:       _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
 299:       _gd[i] = TRUE;
 300:     }
 301:   for (sp = white; *sp; sp++)
 302:     _wht[*sp] = TRUE;
 303:   for (sp = endtk; *sp; sp++)
 304:     _etk[*sp] = TRUE;
 305:   for (sp = intk; *sp; sp++)
 306:     _itk[*sp] = TRUE;
 307:   for (sp = begtk; *sp; sp++)
 308:     _btk[*sp] = TRUE;
 309:   for (sp = notgd; *sp; sp++)
 310:     _gd[*sp] = FALSE;
 311:   _wht[0] = _wht['\n'];
 312:   _etk[0] = _etk['\n'];
 313:   _btk[0] = _btk['\n'];
 314:   _itk[0] = _itk['\n'];
 315:   _gd[0] = _gd['\n'];
 316: }
 317: 
 318: /*
 319:  * This routine opens the specified file and calls the function
 320:  * which finds the function and type definitions.
 321:  */
 322: find_entries (file)
 323:      char *file;
 324: {
 325:   char *cp;
 326: 
 327:   if ((inf=fopen(file,"r")) == NULL)
 328:     {
 329:       perror(file);
 330:       return;
 331:     }
 332:   curfile = savestr(file);
 333:   cp = rindex(file, '.');
 334:   /* .l or .el or .lisp implies lisp source code */
 335:   if (cp && (!strcmp (cp + 1, "l") || !strcmp (cp + 1, "el")
 336:          || !strcmp (cp + 1, "lisp")))
 337:     {
 338:       L_funcs(inf);
 339:       fclose(inf);
 340:       return;
 341:     }
 342:   /* if not a .c or .h or .y file, try fortran */
 343:   if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
 344:       && cp[2] == '\0')
 345:     {
 346:       if (PF_funcs(inf) != 0)
 347:     {
 348:       fclose(inf);
 349:       return;
 350:     }
 351:       rewind(inf);  /* no fortran tags found, try C */
 352:     }
 353:   C_entries();
 354:   fclose(inf);
 355: }
 356: 
 357: /* Record a tag on the current line.
 358:   name is the tag name,
 359:   f is nonzero to use a pattern, zero to use line number instead. */
 360: 
 361: pfnote (name, f, linestart, linelen, lno, cno)
 362:      char *name;
 363:      logical f;         /* f == TRUE when function */
 364:      char *linestart;
 365:      int linelen;
 366:      int lno;
 367:      long cno;
 368: {
 369:   register char *fp;
 370:   register NODE *np;
 371:   char *altname;
 372:   char tem[51];
 373: 
 374:   if ((np = (NODE *) malloc(sizeof (NODE))) == NULL)
 375:     {
 376:       fprintf(stderr, "ctags: too many entries to sort\n");
 377:       put_entries(head);
 378:       free_tree(head);
 379:       head = NULL;
 380:       np = (NODE *) xmalloc(sizeof (NODE));
 381:     }
 382:   /* Change name "main" to M<thisfilename>. */
 383:   if (!eflag && !xflag && !strcmp(name, "main"))
 384:     {
 385:       fp = rindex(curfile, '/');
 386:       if (fp == 0)
 387:     fp = curfile;
 388:       else
 389:     fp++;
 390:       altname = concat ("M", fp, "");
 391:       fp = rindex(altname, '.');
 392:       if (fp && fp[2] == 0)
 393:     *fp = 0;
 394:       name = altname;
 395:     }
 396:   np->entry = savestr(name);
 397:   np->file = curfile;
 398:   np->f = f;
 399:   np->lno = lno;
 400:   np->cno = cno;
 401:   np->left = np->right = 0;
 402:   if (eflag)
 403:     {
 404:       linestart[linelen] = 0;
 405:     }
 406:   else if (xflag == 0)
 407:     {
 408:       sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
 409:       linestart = tem;
 410:     }
 411:   np->pat = savestr (linestart);
 412:   if (head == NULL)
 413:     head = np;
 414:   else
 415:     add_node(np, head);
 416: }
 417: 
 418: free_tree(node)
 419:      NODE *node;
 420: {
 421:   while (node)
 422:     {
 423:       free_tree(node->right);
 424:       free(node);
 425:       node = node->left;
 426:     }
 427: }
 428: 
 429: add_node(node, cur_node)
 430:      NODE *node,*cur_node;
 431: {
 432:   register int dif;
 433: 
 434:   dif = strcmp(node->entry, cur_node->entry);
 435: 
 436:   /* If this tag name matches an existing one, then
 437:      unless -e was given, do not add the node, but maybe print a warning */
 438:   if (!eflag && !dif)
 439:     {
 440:       if (node->file == cur_node->file)
 441:     {
 442:       if (!wflag)
 443:         {
 444:           fprintf(stderr,"Duplicate entry in file %s, line %d: %s\n",
 445:               node->file,lineno,node->entry);
 446:           fprintf(stderr,"Second entry ignored\n");
 447:         }
 448:       return;
 449:     }
 450:       if (!cur_node->been_warned)
 451:     if (!wflag)
 452:       fprintf(stderr,"Duplicate entry in files %s and %s: %s (Warning only)\n",
 453:           node->file, cur_node->file, node->entry);
 454:       cur_node->been_warned = TRUE;
 455:       return;
 456:     }
 457: 
 458:   /* Actually add the node */
 459:   if (dif < 0)
 460:     {
 461:       if (cur_node->left != NULL)
 462:     add_node(node,cur_node->left);
 463:       else
 464:     cur_node->left = node;
 465:       return;
 466:     }
 467:   if (cur_node->right != NULL)
 468:     add_node(node,cur_node->right);
 469:   else
 470:     cur_node->right = node;
 471: }
 472: 
 473: put_entries(node)
 474:      reg NODE *node;
 475: {
 476:   reg char *sp;
 477: 
 478:   if (node == NULL)
 479:     return;
 480: 
 481:   /* Output subentries that precede this one */
 482:   put_entries (node->left);
 483: 
 484:   /* Output this entry */
 485: 
 486:   if (eflag)
 487:     {
 488:       fprintf (outf, "%s%c%d,%d\n",
 489:            node->pat, 0177, node->lno, node->cno);
 490:     }
 491:   else if (!xflag)
 492:     {
 493:       fprintf (outf, "%s\t%s\t",
 494:            node->entry, node->file);
 495: 
 496:       if (node->f)
 497:     {       /* a function */
 498:       putc (searchar, outf);
 499:       putc ('^', outf);
 500: 
 501:       for (sp = node->pat; *sp; sp++)
 502:         {
 503:           if (*sp == '\\' || *sp == searchar)
 504:         putc ('\\', outf);
 505:           putc (*sp, outf);
 506:         }
 507:       putc (searchar, outf);
 508:     }
 509:       else
 510:     {       /* a typedef; text pattern inadequate */
 511:       fprintf (outf, "%d", node->lno);
 512:     }
 513:       putc ('\n', outf);
 514:     }
 515:   else if (vflag)
 516:     fprintf (stdout, "%s %s %d\n",
 517:          node->entry, node->file, (node->lno+63)/64);
 518:   else
 519:     fprintf (stdout, "%-16s%4d %-16s %s\n",
 520:          node->entry, node->lno, node->file, node->pat);
 521: 
 522:   /* Output subentries that follow this one */
 523:   put_entries (node->right);
 524: }
 525: 
 526: /* Return total number of characters that put_entries will output for
 527:  the nodes in the subtree of the specified node.
 528:  Works only if eflag is set, but called only in that case.  */
 529: 
 530: total_size_of_entries(node)
 531:      reg NODE *node;
 532: {
 533:   reg int total = 0;
 534:   reg long num;
 535: 
 536:   if (node == NULL)
 537:     return 0;
 538: 
 539:   /* Count subentries that precede this one */
 540:   total = total_size_of_entries (node->left);
 541: 
 542:   /* Count subentries that follow this one */
 543:   total += total_size_of_entries (node->right);
 544: 
 545:   /* Count this entry */
 546: 
 547:   total += strlen (node->pat) + 3;
 548: 
 549:   num = node->lno;
 550:   while (num)
 551:     {
 552:       total++;
 553:       num /= 10;
 554:     }
 555: 
 556:   num = node->cno;
 557:   if (!num) total++;
 558:   while (num)
 559:     {
 560:       total++;
 561:       num /= 10;
 562:     }
 563:   return total;
 564: }
 565: 
 566: /*
 567:  * This routine finds functions and typedefs in C syntax and adds them
 568:  * to the list.
 569:  */
 570: #define CNL_SAVE_NUMBER \
 571: { \
 572:   linecharno = charno; lineno++; \
 573:   charno += 1 + readline (&lb, inf); \
 574:   lp = lb.buffer; \
 575: }
 576: 
 577: #define CNL \
 578: { \
 579:   CNL_SAVE_NUMBER; \
 580:   number = 0; \
 581: }
 582: 
 583: C_entries ()
 584: {
 585:   register int c;
 586:   register char *token, *tp, *lp;
 587:   logical incomm, inquote, inchar, midtoken;
 588:   int level;
 589:   char tok[BUFSIZ];
 590: 
 591:   lineno = 0;
 592:   charno = 0;
 593:   lp = lb.buffer;
 594:   *lp = 0;
 595: 
 596:   number = 0;
 597:   gotone = midtoken = inquote = inchar = incomm = FALSE;
 598:   level = 0;
 599: 
 600:   while (!feof (inf))
 601:     {
 602:       c = *lp++;
 603:       if (c == 0)
 604:     {
 605:       CNL;
 606:       gotone = FALSE;
 607:     }
 608:       if (c == '\\')
 609:     {
 610:       c = *lp++;
 611:       if (c == 0)
 612:         CNL_SAVE_NUMBER;
 613:       c = ' ';
 614:     }
 615:       else if (incomm)
 616:     {
 617:       if (c == '*')
 618:         {
 619:           while ((c = *lp++) == '*')
 620:         continue;
 621:           if (c == 0)
 622:         CNL;
 623:           if (c == '/')
 624:         incomm = FALSE;
 625:         }
 626:     }
 627:       else if (inquote)
 628:     {
 629:       /*
 630: 	  * Too dumb to know about \" not being magic, but
 631: 	  * they usually occur in pairs anyway.
 632: 	  */
 633:       if (c == '"')
 634:         inquote = FALSE;
 635:       continue;
 636:     }
 637:       else if (inchar)
 638:     {
 639:       if (c == '\'')
 640:         inchar = FALSE;
 641:       continue;
 642:     }
 643:       else switch (c)
 644:     {
 645:     case '"':
 646:       inquote = TRUE;
 647:       continue;
 648:     case '\'':
 649:       inchar = TRUE;
 650:       continue;
 651:     case '/':
 652:       if (*lp == '*')
 653:         {
 654:           lp++;
 655:           incomm = TRUE;
 656:         }
 657:       continue;
 658:     case '#':
 659:       if (lp == lb.buffer + 1)
 660:         number = 1;
 661:       continue;
 662:     case '{':
 663:       if (tydef == begin)
 664:         {
 665:           tydef=middle;
 666:         }
 667:       level++;
 668:       continue;
 669:     case '}':
 670:       if (lp == lb.buffer + 1)
 671:         level = 0;  /* reset */
 672:       else
 673:         level--;
 674:       if (!level && tydef==middle)
 675:         {
 676:           tydef=end;
 677:         }
 678:       continue;
 679:     }
 680:       if (!level && !inquote && !incomm && gotone == FALSE)
 681:     {
 682:       if (midtoken)
 683:         {
 684:           if (endtoken(c))
 685:         {
 686:           int f;
 687:           char *buf = lb.buffer;
 688:           int endpos = lp - lb.buffer;
 689:           char *lp1 = lp;
 690:           int line = lineno;
 691:           long linestart = linecharno;
 692:           int tem = consider_token (&lp1, token, &f);
 693:           lp = lp1;
 694:           if (tem)
 695:             {
 696:               if (linestart != linecharno)
 697:             {
 698:               getline (linestart);
 699:               strncpy (tok, token + (lb1.buffer - buf),
 700:                    tp-token+1);
 701:               tok[tp-token+1] = 0;
 702:               pfnote(tok, f, lb1.buffer, endpos, line, linestart);
 703:             }
 704:               else
 705:             {
 706:               strncpy (tok, token, tp-token+1);
 707:               tok[tp-token+1] = 0;
 708:               pfnote(tok, f, lb.buffer, endpos, line, linestart);
 709:             }
 710:               gotone = f;   /* function */
 711:             }
 712:           midtoken = FALSE;
 713:           token = lp - 1;
 714:         }
 715:           else if (intoken(c))
 716:         tp++;
 717:         }
 718:       else if (begtoken(c))
 719:         {
 720:           token = tp = lp - 1;
 721:           midtoken = TRUE;
 722:         }
 723:     }
 724:       if (c == ';'  &&  tydef==end) /* clean with typedefs */
 725:     tydef=none;
 726:     }
 727: }
 728: 
 729: /*
 730:  * This routine  checks to see if the current token is
 731:  * at the start of a function, or corresponds to a typedef
 732:  * It updates the input line * so that the '(' will be
 733:  * in it when it returns.
 734:  */
 735: consider_token (lpp, token, f)
 736:      char **lpp, *token;
 737:      int *f;
 738: {
 739:   reg char *lp = *lpp;
 740:   reg char c;
 741:   static logical next_token_is_func;
 742:   logical firsttok; /* T if have seen first token in ()'s */
 743:   int bad, win;
 744: 
 745:   *f = 1;           /* a function */
 746:   c = lp[-1];
 747:   bad = FALSE;
 748:   if (!number)
 749:     {       /* space is not allowed in macro defs	*/
 750:       while (iswhite(c))
 751:     {
 752:       c = *lp++;
 753:       if (c == 0)
 754:         {
 755:           if (feof (inf))
 756:         break;
 757:           CNL;
 758:         }
 759:     }
 760:       /* the following tries to make it so that a #define a b(c)	*/
 761:       /* doesn't count as a define of b.				*/
 762:     }
 763:   else
 764:     {
 765:       number++;
 766:       if (number >= 4  || (number==2 && strncmp (token, "define", 6)))
 767:     {
 768:       gotone = TRUE;
 769:     badone:
 770:       bad = TRUE;
 771:       goto ret;
 772:     }
 773:     }
 774:   /* check for the typedef cases		*/
 775:   if (tflag && !strncmp(token, "typedef", 7))
 776:     {
 777:       tydef=begin;
 778:       goto badone;
 779:     }
 780:   if (tydef==begin && (!strncmp(token, "struct", 6) ||
 781:                !strncmp(token, "union", 5) || !strncmp(token, "enum", 4)))
 782:   {
 783:     goto badone;
 784:   }
 785:   if (tydef==begin)
 786:     {
 787:       tydef=end;
 788:       goto badone;
 789:     }
 790:   if (tydef==end)
 791:     {
 792:       *f = 0;
 793:       win = 1;
 794:       goto ret;
 795:     }
 796:   /* Detect GNUmacs's function-defining macros. */
 797:   if (!number && !strncmp (token, "DEF", 3))
 798: 
 799:     {
 800:       next_token_is_func = 1;
 801:       goto badone;
 802:     }
 803:   if (next_token_is_func)
 804:     {
 805:       next_token_is_func = 0;
 806:       win = 1;
 807:       goto ret;
 808:     }
 809:   if (c != '(')
 810:     goto badone;
 811:   firsttok = FALSE;
 812:   while ((c = *lp++) != ')')
 813:     {
 814:       if (c == 0)
 815:     {
 816:       if (feof (inf))
 817:         break;
 818:       CNL;
 819:     }
 820:       /*
 821: 	* This line used to confuse ctags:
 822: 	*	int	(*oldhup)();
 823: 	* This fixes it. A nonwhite char before the first
 824: 	* token, other than a / (in case of a comment in there)
 825: 	* makes this not a declaration.
 826: 	*/
 827:       if (begtoken(c) || c=='/') firsttok++;
 828:       else if (!iswhite(c) && !firsttok) goto badone;
 829:     }
 830:   while (iswhite (c = *lp++))
 831:     {
 832:       if (!c)
 833:     CNL;
 834:     }
 835:   win = isgood (c);
 836: ret:
 837:   *lpp = lp - 1;
 838:   return !bad && win;
 839: }
 840: 
 841: getline (atchar)
 842:      long atchar;
 843: {
 844:   long saveftell = ftell (inf);
 845: 
 846:   fseek (inf, atchar, 0);
 847:   readline (&lb1, inf);
 848:   fseek (inf, saveftell, 0);
 849: }
 850: 
 851: /* Fortran parsing */
 852: 
 853: char    *dbp;
 854: int pfcnt;
 855: 
 856: PF_funcs(fi)
 857:      FILE *fi;
 858: {
 859:   lineno = 0;
 860:   charno = 0;
 861:   pfcnt = 0;
 862: 
 863:   while (!feof (fi))
 864:     {
 865:       lineno++;
 866:       linecharno = charno;
 867:       charno += readline (&lb, fi) + 1;
 868:       dbp = lb.buffer;
 869:       if (*dbp == '%') dbp++ ;  /* Ratfor escape to fortran */
 870:       while (isspace(*dbp))
 871:     dbp++;
 872:       if (*dbp == 0)
 873:     continue;
 874:       switch (*dbp |' ')
 875:     {
 876:     case 'i':
 877:       if (tail("integer"))
 878:         takeprec();
 879:       break;
 880:     case 'r':
 881:       if (tail("real"))
 882:         takeprec();
 883:       break;
 884:     case 'l':
 885:       if (tail("logical"))
 886:         takeprec();
 887:       break;
 888:     case 'c':
 889:       if (tail("complex") || tail("character"))
 890:         takeprec();
 891:       break;
 892:     case 'd':
 893:       if (tail("double"))
 894:         {
 895:           while (isspace(*dbp))
 896:         dbp++;
 897:           if (*dbp == 0)
 898:         continue;
 899:           if (tail("precision"))
 900:         break;
 901:           continue;
 902:         }
 903:       break;
 904:     }
 905:       while (isspace(*dbp))
 906:     dbp++;
 907:       if (*dbp == 0)
 908:     continue;
 909:       switch (*dbp|' ')
 910:     {
 911:     case 'f':
 912:       if (tail("function"))
 913:         getit();
 914:       continue;
 915:     case 's':
 916:       if (tail("subroutine"))
 917:         getit();
 918:       continue;
 919:     case 'p':
 920:       if (tail("program"))
 921:         {
 922:           getit();
 923:           continue;
 924:         }
 925:       if (tail("procedure"))
 926:         getit();
 927:       continue;
 928:     }
 929:     }
 930:   return (pfcnt);
 931: }
 932: 
 933: tail(cp)
 934:      char *cp;
 935: {
 936:   register int len = 0;
 937: 
 938:   while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
 939:     cp++, len++;
 940:   if (*cp == 0)
 941:     {
 942:       dbp += len;
 943:       return (1);
 944:     }
 945:   return (0);
 946: }
 947: 
 948: takeprec()
 949: {
 950:   while (isspace(*dbp))
 951:     dbp++;
 952:   if (*dbp != '*')
 953:     return;
 954:   dbp++;
 955:   while (isspace(*dbp))
 956:     dbp++;
 957:   if (!isdigit(*dbp))
 958:     {
 959:       --dbp;        /* force failure */
 960:       return;
 961:     }
 962:   do
 963:     dbp++;
 964:   while (isdigit(*dbp));
 965: }
 966: 
 967: getit()
 968: {
 969:   register char *cp;
 970:   char c;
 971:   char nambuf[BUFSIZ];
 972: 
 973:   while (isspace(*dbp))
 974:     dbp++;
 975:   if (*dbp == 0 || !isalpha(*dbp))
 976:     return;
 977:   for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
 978:     continue;
 979:   c = cp[0];
 980:   cp[0] = 0;
 981:   strcpy(nambuf, dbp);
 982:   cp[0] = c;
 983:   pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
 984:   pfcnt++;
 985: }
 986: 
 987: /*
 988:  * lisp tag functions
 989:  * just look for (def or (DEF
 990:  */
 991: 
 992: L_funcs (fi)
 993:      FILE *fi;
 994: {
 995:   lineno = 0;
 996:   charno = 0;
 997:   pfcnt = 0;
 998: 
 999:   while (!feof (fi))
1000:     {
1001:       lineno++;
1002:       linecharno = charno;
1003:       charno += readline (&lb, fi) + 1;
1004:       dbp = lb.buffer;
1005:       if (dbp[0] == '(' &&
1006:       (dbp[1] == 'D' || dbp[1] == 'd') &&
1007:         (dbp[2] == 'E' || dbp[2] == 'e') &&
1008:           (dbp[3] == 'F' || dbp[3] == 'f'))
1009:     {
1010:       while (!isspace(*dbp)) dbp++;
1011:       while (isspace(*dbp)) dbp++;
1012:       L_getit();
1013:     }
1014:     }
1015: }
1016: 
1017: L_getit()
1018: {
1019:   register char *cp;
1020:   char c;
1021:   char nambuf[BUFSIZ];
1022: 
1023:   if (*dbp == 0) return;
1024:   for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
1025:     continue;
1026:   c = cp[0];
1027:   cp[0] = 0;
1028:   strcpy(nambuf, dbp);
1029:   cp[0] = c;
1030:   pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
1031:   pfcnt++;
1032: }
1033: 
1034: /* Initialize a linebuffer for use */
1035: 
1036: void
1037: initbuffer (linebuffer)
1038:      struct linebuffer *linebuffer;
1039: {
1040:   linebuffer->size = 200;
1041:   linebuffer->buffer = (char *) xmalloc (200);
1042: }
1043: 
1044: /* Read a line of text from `stream' into `linebuffer'.
1045:  Return the length of the line.  */
1046: 
1047: long
1048: readline (linebuffer, stream)
1049:      struct linebuffer *linebuffer;
1050:      register FILE *stream;
1051: {
1052:   char *buffer = linebuffer->buffer;
1053:   register char *p = linebuffer->buffer;
1054:   register char *pend = p + linebuffer->size;
1055: 
1056:   while (1)
1057:     {
1058:       int c = getc (stream);
1059:       if (p == pend)
1060:     {
1061:       buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
1062:       p += buffer - linebuffer->buffer;
1063:       pend += buffer - linebuffer->buffer;
1064:       linebuffer->buffer = buffer;
1065:     }
1066:       if (c < 0 || c == '\n')
1067:     {
1068:       *p = 0;
1069:       break;
1070:     }
1071:       *p++ = c;
1072:     }
1073: 
1074:   return p - buffer;
1075: }
1076: 
1077: char *
1078: savestr(cp)
1079:      char *cp;
1080: {
1081:   register int len;
1082:   register char *dp;
1083: 
1084:   len = strlen(cp);
1085:   dp = (char *)xmalloc(len+1);
1086:   strcpy(dp, cp);
1087:   return (dp);
1088: }
1089: 
1090: /*
1091:  * Return the ptr in sp at which the character c last
1092:  * appears; NULL if not found
1093:  *
1094:  * Identical to v7 rindex, included for portability.
1095:  */
1096: 
1097: char *
1098: rindex(sp, c)
1099:      register char *sp, c;
1100: {
1101:   register char *r;
1102: 
1103:   r = NULL;
1104:   do
1105:     {
1106:       if (*sp == c)
1107:     r = sp;
1108:     } while (*sp++);
1109:   return(r);
1110: }
1111: 
1112: /* Print error message and exit.  */
1113: 
1114: fatal (s1, s2)
1115:      char *s1, *s2;
1116: {
1117:   error (s1, s2);
1118:   exit (1);
1119: }
1120: 
1121: /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
1122: 
1123: error (s1, s2)
1124:      char *s1, *s2;
1125: {
1126: #ifdef CTAGS
1127:   printf ("ctags: ");
1128: #else
1129:   printf ("etags: ");
1130: #endif
1131:   printf (s1, s2);
1132:   printf ("\n");
1133: }
1134: 
1135: /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
1136: 
1137: char *
1138: concat (s1, s2, s3)
1139:      char *s1, *s2, *s3;
1140: {
1141:   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
1142:   char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
1143: 
1144:   strcpy (result, s1);
1145:   strcpy (result + len1, s2);
1146:   strcpy (result + len1 + len2, s3);
1147:   *(result + len1 + len2 + len3) = 0;
1148: 
1149:   return result;
1150: }
1151: 
1152: /* Like malloc but get fatal error if memory is exhausted.  */
1153: 
1154: int
1155: xmalloc (size)
1156:      int size;
1157: {
1158:   int result = malloc (size);
1159:   if (!result)
1160:     fatal ("virtual memory exhausted", 0);
1161:   return result;
1162: }
1163: 
1164: int
1165: xrealloc (ptr, size)
1166:      char *ptr;
1167:      int size;
1168: {
1169:   int result = realloc (ptr, size);
1170:   if (!result)
1171:     fatal ("virtual memory exhausted");
1172:   return result;
1173: }

Defined functions

C_entries defined in line 583; used 1 times
L_funcs defined in line 992; used 1 times
L_getit defined in line 1017; used 1 times
PF_funcs defined in line 856; used 1 times
add_node defined in line 429; used 3 times
concat defined in line 1137; used 2 times
consider_token defined in line 735; used 1 times
error defined in line 1123; used 1 times
fatal defined in line 1114; used 2 times
find_entries defined in line 322; used 1 times
free_tree defined in line 418; used 3 times
getit defined in line 967; used 4 times
getline defined in line 841; used 1 times
init defined in line 290; used 1 times
initbuffer defined in line 1036; used 3 times
main defined in line 151; never used
pfnote defined in line 361; used 4 times
put_entries defined in line 473; used 6 times
readline defined in line 1047; used 5 times
rindex defined in line 1097; used 4 times
savestr defined in line 1077; used 4 times
tail defined in line 933; used 11 times
takeprec defined in line 948; used 4 times
total_size_of_entries defined in line 530; used 3 times
xmalloc defined in line 1154; used 4 times
xrealloc defined in line 1164; used 1 times

Defined variables

aflag defined in line 120; used 4 times
charno defined in line 105; used 9 times
curfile defined in line 108; used 4 times
dbp defined in line 853; used 47 times
eflag defined in line 126; used 11 times
file_num defined in line 119; used 5 times
head defined in line 131; used 12 times
lb defined in line 149; used 17 times
lb1 defined in line 149; used 4 times
linecharno defined in line 106; used 7 times
lineno defined in line 104; used 10 times
number defined in line 90; used 8 times
outfile defined in line 109; used 9 times
pfcnt defined in line 854; used 5 times
searchar defined in line 102; used 5 times
tflag defined in line 121; used 2 times
uflag defined in line 122; used 3 times
vflag defined in line 124; used 2 times
wflag defined in line 123; used 3 times
xflag defined in line 125; used 6 times

Defined struct's

linebuffer defined in line 143; used 6 times
nd_st defined in line 76; used 4 times

Defined typedef's

NODE defined in line 88; used 10 times

Defined macros

CNL defined in line 577; used 5 times
CNL_SAVE_NUMBER defined in line 570; used 2 times
ETAGS defined in line 59; used 1 times
FALSE defined in line 66; used 11 times
TRUE defined in line 65; used 14 times
begtoken defined in line 69; used 2 times
endtoken defined in line 71; used 1 times
intoken defined in line 70; used 1 times
isgood defined in line 72; used 1 times
iswhite defined in line 68; used 3 times
logical defined in line 63; used 7 times
max defined in line 74; never used
reg defined in line 62; used 9 times
Last modified: 1986-04-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3562
Valid CSS Valid XHTML 1.0 Strict