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: *
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: }