home *** CD-ROM | disk | FTP | other *** search
- From: decvax!ucbvax!ucsf-cgl.ARPA!arnold (Ken Arnold)
- Subject: ctags source
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 3, Issue 53
- Submitted by: ucbvax!ucsf-cgl.ARPA!arnold (Ken Arnold)
-
-
- #!/bin/sh
- #
- # I have received enough requests for the current source to ctags to
- # post it. Here is the latest version (what will go out with 4.3,
- # modulo any bugs fixed during the beta period). It is the 4.2 ctags
- # with recognition of yacc and lex tags added. Files ending in .y are
- # presumed to be yacc files, .l files are either lisp or lex files,
- # depending upon the first non-blank character (yeah, it's a hack, but
- # it works). Man page is included. Note that I wrote the original
- # ctags (recognized only C), and added the YACC and lex after others
- # wrote the recognizers for FORTRAN, PASCAL, and lisp, so this code is
- # rather a mix of styles, for which I take no responsibility. So, here
- # come those famous words:
- #
- # This is a shell archive, meaning:
- # 1. Remove everything above the #!/bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # ctags.1
- # ctags.c
- # This archive created: Mon Nov 25 12:53:49 1985
- export PATH; PATH=/bin:$PATH
- if test -f 'ctags.1'
- then
- echo shar: over-writing existing file "'ctags.1'"
- fi
- cat << \SHAR_EOF > 'ctags.1'
- .TH CTAGS 1 "25 August 1982"
- .UC 4
- .SH NAME
- ctags \- create a tags file
- .SH SYNOPSIS
- .B ctags
- [
- .B \-BFatuwvx
- ]
- name ...
- .SH DESCRIPTION
- .I Ctags
- makes a tags file for
- .IR ex (1)
- from the specified C, Pascal, Fortran, YACC, lex, and lisp sources.
- A tags file gives the locations of specified objects (in this case
- functions and typedefs) in a group of files. Each line of the tags
- file contains the object name, the file in which it is defined, and
- an address specification for the object definition. Functions are
- searched with a pattern, typedefs with a line number. Specifiers are
- given in separate fields on the line, separated by blanks or tabs.
- Using the
- .I tags
- file,
- .I ex
- can quickly find these objects definitions.
- .PP
- If the
- .B \-x
- flag is given,
- .I ctags
- produces a list of object names, the line number and file
- name on which each is defined, as well as the text of that line
- and prints this on the standard output. This is a simple index
- which can be printed out as an off-line readable function index.
- .PP
- If the
- .B \-v
- flag is given,
- an index of the form expected by
- .IR vgrind (1)
- is produced on the standard output.
- This listing contains the function name,
- file name, and page number
- (assuming 64 line pages).
- Since the output will be sorted into lexicographic order,
- it may be desired to run the output through
- .BR "sort \-f" .
- Sample use:
- .nf
- ctags \-v files | sort \-f > index
- vgrind \-x index
- .fi
- .PP
- Files whose names end in
- .B \.c
- or
- .B \.h
- are assumed to be C source files and are searched for C routine and
- macro definitions.
- Files whose names end in
- .B \.y
- are assumed to be YACC source files.
- Files whose names end in
- .B \.l
- are assumed to be either lisp files
- if their first non-blank character is `;', `(', or `[',
- or lex files otherwise.
- Other files are first examined to see if they contain any Pascal or
- Fortran routine definitions; if not, they are processed again
- looking for C definitions.
- .PP
- Other options are:
- .TP 5
- .B \-F
- use forward searching patterns (/.../) (default).
- .TP 5
- .B \-B
- use backward searching patterns (?...?).
- .TP 5
- .B \-a
- append to tags file.
- .TP 5
- .B \-t
- create tags for typedefs.
- .TP 5
- .B \-w
- suppressing warning diagnostics.
- .TP 5
- .B \-u
- causing the specified files to be
- .I updated
- in tags, that is, all references to them are deleted,
- and the new values are appended to the file.
- (Beware: this option is implemented in a way which is rather slow;
- it is usually faster to simply rebuild the
- .I tags
- file.)
- .PP
- The tag
- .I main
- is treated specially in C programs.
- The tag formed is created by prepending
- .I M
- to the name of the file, with a trailing .c removed, if
- any, and leading pathname components also removed.
- This makes use of
- .I ctags
- practical in directories with more than one program.
- .SH FILES
- .DT
- tags output tags file
- .SH SEE ALSO
- ex(1), vi(1)
- .SH AUTHOR
- Ken Arnold; FORTRAN added by Jim Kleckner; Bill Joy
- added Pascal and
- .B \-x,
- replacing
- .I cxref;
- C typedefs added by Ed Pelegri-Llopart.
- .SH BUGS
- Recognition of \fBfunctions\fR, \fBsubroutines\fR and \fBprocedures\fR
- for FORTRAN and Pascal is done is a very simpleminded way.
- No attempt is made to deal with block structure; if you have two
- Pascal procedures in different blocks with the same name you lose.
- .PP
- The method of deciding whether to look for C or Pascal and FORTRAN
- functions is a hack.
- .PP
- Does not know about #ifdefs.
- .PP
- Should know about Pascal types.
- Relies on the input being well formed to detect typedefs.
- Use of -tx shows only the last line of typedefs.
- SHAR_EOF
- if test -f 'ctags.c'
- then
- echo shar: over-writing existing file "'ctags.c'"
- fi
- cat << \SHAR_EOF > 'ctags.c'
- /* $Header */
-
- static char *sccsid = "@(#)ctags.c 4.7 (Berkeley) 8/18/83";
-
- #include <stdio.h>
- #include <ctype.h>
-
- /*
- * ctags: create a tags file
- */
-
- #define reg register
- #define bool char
-
- #define TRUE (1)
- #define FALSE (0)
-
- #define iswhite(arg) (_wht[arg]) /* T if char is white */
- #define begtoken(arg) (_btk[arg]) /* T if char can start token */
- #define intoken(arg) (_itk[arg]) /* T if char can be in token */
- #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
- #define isgood(arg) (_gd[arg]) /* T if char can be after ')' */
-
- #define max(I1,I2) (I1 > I2 ? I1 : I2)
-
- struct nd_st { /* sorting structure */
- char *entry; /* function or type name */
- char *file; /* file name */
- bool f; /* use pattern or line no */
- int lno; /* for -x option */
- char *pat; /* search pattern */
- bool been_warned; /* set if noticed dup */
- struct nd_st *left,*right; /* left and right sons */
- };
-
- long ftell();
- typedef struct nd_st NODE;
-
- bool number, /* T if on line starting with # */
- term = FALSE, /* T if print on terminal */
- makefile= TRUE, /* T if to creat "tags" file */
- gotone, /* found a func already on line */
- /* boolean "func" (see init) */
- _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
-
- /* typedefs are recognized using a simple finite automata,
- * tydef is its state variable.
- */
- typedef enum {none, begin, middle, end } TYST;
-
- TYST tydef = none;
-
- char searchar = '/'; /* use /.../ searches */
-
- int lineno; /* line number of current line */
- char line[4*BUFSIZ], /* current input line */
- *curfile, /* current input file name */
- *outfile= "tags", /* output file */
- *white = " \f\t\n", /* white chars */
- *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
- /* token ending chars */
- *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz",
- /* token starting chars */
- *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789",
- /* valid in-token chars */
- *notgd = ",;"; /* non-valid after-function chars */
-
- int file_num; /* current file number */
- int aflag; /* -a: append to tags */
- int tflag; /* -t: create tags for typedefs */
- int uflag; /* -u: update tags */
- int wflag; /* -w: suppress warnings */
- int vflag; /* -v: create vgrind style index output */
- int xflag; /* -x: create cxref style output */
-
- char lbuf[BUFSIZ];
-
- FILE *inf, /* ioptr for current input file */
- *outf; /* ioptr for tags file */
-
- long lineftell; /* ftell after getc( inf ) == '\n' */
-
- NODE *head; /* the head of the sorted binary tree */
-
- char *savestr();
- char *rindex(), *index();
- char *toss_comment();
-
- main(ac,av)
- int ac;
- char *av[];
- {
- char cmd[100];
- int i;
-
- while (ac > 1 && av[1][0] == '-') {
- for (i=1; av[1][i]; i++) {
- switch(av[1][i]) {
- case 'B':
- searchar='?';
- break;
- case 'F':
- searchar='/';
- break;
- case 'a':
- aflag++;
- break;
- case 't':
- tflag++;
- break;
- case 'u':
- uflag++;
- break;
- case 'w':
- wflag++;
- break;
- case 'v':
- vflag++;
- xflag++;
- break;
- case 'x':
- xflag++;
- break;
- default:
- goto usage;
- }
- }
- ac--; av++;
- }
-
- if (ac <= 1) {
- usage:
- printf("Usage: ctags [-BFatuwvx] file ...\n");
- exit(1);
- }
-
- init(); /* set up boolean "functions" */
- /*
- * loop through files finding functions
- */
- for (file_num = 1; file_num < ac; file_num++)
- find_entries(av[file_num]);
-
- if (xflag) {
- put_entries(head);
- exit(0);
- }
- if (uflag) {
- for (i=1; i<ac; i++) {
- sprintf(cmd,
- "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
- outfile, av[i], outfile);
- system(cmd);
- }
- aflag++;
- }
- outf = fopen(outfile, aflag ? "a" : "w");
- if (outf == NULL) {
- perror(outfile);
- exit(1);
- }
- put_entries(head);
- fclose(outf);
- if (uflag) {
- sprintf(cmd, "sort %s -o %s", outfile, outfile);
- system(cmd);
- }
- exit(0);
- }
-
- /*
- * This routine sets up the boolean psuedo-functions which work
- * by seting boolean flags dependent upon the corresponding character
- * Every char which is NOT in that string is not a white char. Therefore,
- * all of the array "_wht" is set to FALSE, and then the elements
- * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
- * of a char is TRUE if it is the string "white", else FALSE.
- */
- init()
- {
-
- reg char *sp;
- reg int i;
-
- for (i = 0; i < 0177; i++) {
- _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
- _gd[i] = TRUE;
- }
- for (sp = white; *sp; sp++)
- _wht[*sp] = TRUE;
- for (sp = endtk; *sp; sp++)
- _etk[*sp] = TRUE;
- for (sp = intk; *sp; sp++)
- _itk[*sp] = TRUE;
- for (sp = begtk; *sp; sp++)
- _btk[*sp] = TRUE;
- for (sp = notgd; *sp; sp++)
- _gd[*sp] = FALSE;
- }
-
- /*
- * This routine opens the specified file and calls the function
- * which finds the function and type definitions.
- */
- find_entries(file)
- char *file;
- {
- char *cp;
-
- if ((inf = fopen(file,"r")) == NULL) {
- perror(file);
- return;
- }
- curfile = savestr(file);
- lineno = 0;
- cp = rindex(file, '.');
- /* .l implies lisp or lex source code */
- if (cp && cp[1] == 'l' && cp[2] == '\0') {
- if (index(";([", first_char()) != NULL) { /* lisp */
- L_funcs(inf);
- fclose(inf);
- return;
- }
- else { /* lex */
- /*
- * throw away all the code before the second "%%"
- */
- toss_yysec();
- getline();
- pfnote("yylex", lineno, TRUE);
- toss_yysec();
- C_entries();
- fclose(inf);
- return;
- }
- }
- /* .y implies a yacc file */
- if (cp && cp[1] == 'y' && cp[2] == '\0') {
- toss_yysec();
- Y_entries();
- C_entries();
- fclose(inf);
- return;
- }
- /* if not a .c or .h file, try fortran */
- if (cp && (cp[1] != 'c' && cp[1] != 'h') && cp[2] == '\0') {
- if (PF_funcs(inf) != 0) {
- fclose(inf);
- return;
- }
- rewind(inf); /* no fortran tags found, try C */
- }
- C_entries();
- fclose(inf);
- }
-
- pfnote(name, ln, f)
- char *name;
- int ln;
- bool f; /* f == TRUE when function */
- {
- register char *fp;
- register NODE *np;
- char nbuf[BUFSIZ];
-
- if ((np = (NODE *) malloc(sizeof (NODE))) == NULL) {
- fprintf(stderr, "ctags: too many entries to sort\n");
- put_entries(head);
- free_tree(head);
- head = np = (NODE *) malloc(sizeof (NODE));
- }
- if (xflag == 0 && !strcmp(name, "main")) {
- fp = rindex(curfile, '/');
- if (fp == 0)
- fp = curfile;
- else
- fp++;
- sprintf(nbuf, "M%s", fp);
- fp = rindex(nbuf, '.');
- if (fp && fp[2] == 0)
- *fp = 0;
- name = nbuf;
- }
- np->entry = savestr(name);
- np->file = curfile;
- np->f = f;
- np->lno = ln;
- np->left = np->right = 0;
- if (xflag == 0) {
- lbuf[50] = 0;
- strcat(lbuf, "$");
- lbuf[50] = 0;
- }
- np->pat = savestr(lbuf);
- if (head == NULL)
- head = np;
- else
- add_node(np, head);
- }
-
- /*
- * This routine finds functions and typedefs in C syntax and adds them
- * to the list.
- */
- C_entries()
- {
- register int c;
- register char *token, *tp;
- bool incomm, inquote, inchar, midtoken;
- int level;
- char *sp;
- char tok[BUFSIZ];
-
- number = gotone = midtoken = inquote = inchar = incomm = FALSE;
- level = 0;
- sp = tp = token = line;
- lineno++;
- lineftell = ftell(inf);
- for (;;) {
- *sp = c = getc(inf);
- if (feof(inf))
- break;
- if (c == '\n')
- lineno++;
- else if (c == '\\') {
- c = *++sp = getc(inf);
- if (c == '\n')
- c = ' ';
- }
- else if (incomm) {
- if (c == '*') {
- while ((*++sp=c=getc(inf)) == '*')
- continue;
- if (c == '\n')
- lineno++;
- if (c == '/')
- incomm = FALSE;
- }
- }
- else if (inquote) {
- /*
- * Too dumb to know about \" not being magic, but
- * they usually occur in pairs anyway.
- */
- if (c == '"')
- inquote = FALSE;
- continue;
- }
- else if (inchar) {
- if (c == '\'')
- inchar = FALSE;
- continue;
- }
- else switch (c) {
- case '"':
- inquote = TRUE;
- continue;
- case '\'':
- inchar = TRUE;
- continue;
- case '/':
- if ((*++sp=c=getc(inf)) == '*')
- incomm = TRUE;
- else
- ungetc(*sp, inf);
- continue;
- case '#':
- if (sp == line)
- number = TRUE;
- continue;
- case '{':
- if (tydef == begin) {
- tydef=middle;
- }
- level++;
- continue;
- case '}':
- if (sp == line)
- level = 0; /* reset */
- else
- level--;
- if (!level && tydef==middle) {
- tydef=end;
- }
- continue;
- }
- if (!level && !inquote && !incomm && gotone == FALSE) {
- if (midtoken) {
- if (endtoken(c)) {
- int f;
- int pfline = lineno;
- if (start_entry(&sp,token,tp,&f)) {
- strncpy(tok,token,tp-token+1);
- tok[tp-token+1] = 0;
- getline();
- pfnote(tok, pfline, f);
- gotone = f; /* function */
- }
- midtoken = FALSE;
- token = sp;
- }
- else if (intoken(c))
- tp++;
- }
- else if (begtoken(c)) {
- token = tp = sp;
- midtoken = TRUE;
- }
- }
- if (c == ';' && tydef==end) /* clean with typedefs */
- tydef=none;
- sp++;
- if (c == '\n' || sp > &line[sizeof (line) - BUFSIZ]) {
- tp = token = sp = line;
- lineftell = ftell(inf);
- number = gotone = midtoken = inquote = inchar = FALSE;
- }
- }
- }
-
- /*
- * This routine checks to see if the current token is
- * at the start of a function, or corresponds to a typedef
- * It updates the input line * so that the '(' will be
- * in it when it returns.
- */
- start_entry(lp,token,tp,f)
- char **lp,*token,*tp;
- int *f;
- {
- reg char c,*sp,*tsp;
- static bool found;
- bool firsttok; /* T if have seen first token in ()'s */
- int bad;
-
- *f = 1; /* a function */
- sp = *lp;
- c = *sp;
- bad = FALSE;
- if (!number) { /* space is not allowed in macro defs */
- while (iswhite(c)) {
- *++sp = c = getc(inf);
- if (c == '\n') {
- lineno++;
- if (sp > &line[sizeof (line) - BUFSIZ])
- goto ret;
- }
- }
- /* the following tries to make it so that a #define a b(c) */
- /* doesn't count as a define of b. */
- }
- else {
- if (!strncmp(token, "define", 6))
- found = 0;
- else
- found++;
- if (found >= 2) {
- gotone = TRUE;
- badone: bad = TRUE;
- goto ret;
- }
- }
- /* check for the typedef cases */
- if (tflag && !strncmp(token, "typedef", 7)) {
- tydef=begin;
- goto badone;
- }
- if (tydef==begin && (!strncmp(token, "struct", 6) ||
- !strncmp(token, "union", 5) || !strncmp(token, "enum", 4))) {
- goto badone;
- }
- if (tydef==begin) {
- tydef=end;
- goto badone;
- }
- if (tydef==end) {
- *f = 0;
- goto ret;
- }
- if (c != '(')
- goto badone;
- firsttok = FALSE;
- while ((*++sp=c=getc(inf)) != ')') {
- if (c == '\n') {
- lineno++;
- if (sp > &line[sizeof (line) - BUFSIZ])
- goto ret;
- }
- /*
- * This line used to confuse ctags:
- * int (*oldhup)();
- * This fixes it. A nonwhite char before the first
- * token, other than a / (in case of a comment in there)
- * makes this not a declaration.
- */
- if (begtoken(c) || c=='/')
- firsttok++;
- else if (!iswhite(c) && !firsttok)
- goto badone;
- }
- while (iswhite(*++sp=c=getc(inf)))
- if (c == '\n') {
- lineno++;
- if (sp > &line[sizeof (line) - BUFSIZ])
- break;
- }
- ret:
- *lp = --sp;
- if (c == '\n')
- lineno--;
- ungetc(c,inf);
- return !bad && (!*f || isgood(c));
- /* hack for typedefs */
- }
-
- /*
- * Y_entries:
- * Find the yacc tags and put them in.
- */
- Y_entries()
- {
- register char *sp, *orig_sp;
- register int brace;
- register bool in_rule, toklen;
- char tok[BUFSIZ];
-
- brace = 0;
- getline();
- pfnote("yyparse", lineno, TRUE);
- while (fgets(line, sizeof line, inf) != NULL)
- for (sp = line; *sp; sp++)
- switch (*sp) {
- case '\n':
- lineno++;
- /* FALLTHROUGH */
- case ' ':
- case '\t':
- case '\f':
- case '\r':
- break;
- case '"':
- do {
- while (*++sp != '"')
- continue;
- } while (sp[-1] == '\\');
- break;
- case '\'':
- do {
- while (*++sp != '\'')
- continue;
- } while (sp[-1] == '\\');
- break;
- case '/':
- if (*++sp == '*')
- sp = toss_comment(sp);
- else
- --sp;
- break;
- case '{':
- brace++;
- break;
- case '}':
- brace--;
- break;
- case '%':
- if (sp[1] == '%' && sp == line)
- return;
- break;
- case '|':
- case ';':
- in_rule = FALSE;
- break;
- default:
- if (brace == 0 && !in_rule && (isalpha(*sp) ||
- *sp == '.' ||
- *sp == '_')) {
- orig_sp = sp;
- ++sp;
- while (isalnum(*sp) || *sp == '_' ||
- *sp == '.')
- sp++;
- toklen = sp - orig_sp;
- while (isspace(*sp))
- sp++;
- if (*sp == ':' || (*sp == '\0' &&
- first_char() == ':'))
- {
- strncpy(tok, orig_sp, toklen);
- tok[toklen] = '\0';
- strcpy(lbuf, line);
- lbuf[strlen(lbuf) - 1] = '\0';
- pfnote(tok, lineno, TRUE);
- in_rule = TRUE;
- }
- else
- sp--;
- }
- break;
- }
- }
-
- char *
- toss_comment(start)
- char *start;
- {
- register char *sp;
-
- /*
- * first, see if the end-of-comment is on the same line
- */
- do {
- while ((sp = index(start, '*')) != NULL)
- if (sp[1] == '/')
- return ++sp;
- else
- start = ++sp;
- start = line;
- lineno++;
- } while (fgets(line, sizeof line, inf) != NULL);
- }
-
- getline()
- {
- long saveftell = ftell( inf );
- register char *cp;
-
- fseek( inf , lineftell , 0 );
- fgets(lbuf, sizeof lbuf, inf);
- cp = rindex(lbuf, '\n');
- if (cp)
- *cp = 0;
- fseek(inf, saveftell, 0);
- }
-
- free_tree(node)
- NODE *node;
- {
-
- while (node) {
- free_tree(node->right);
- cfree(node);
- node = node->left;
- }
- }
-
- add_node(node, cur_node)
- NODE *node,*cur_node;
- {
- register int dif;
-
- dif = strcmp(node->entry, cur_node->entry);
- if (dif == 0) {
- if (node->file == cur_node->file) {
- if (!wflag) {
- fprintf(stderr,"Duplicate entry in file %s, line %d: %s\n",
- node->file,lineno,node->entry);
- fprintf(stderr,"Second entry ignored\n");
- }
- return;
- }
- if (!cur_node->been_warned)
- if (!wflag)
- fprintf(stderr,"Duplicate entry in files %s and %s: %s (Warning only)\n",
- node->file, cur_node->file, node->entry);
- cur_node->been_warned = TRUE;
- return;
- }
-
- if (dif < 0) {
- if (cur_node->left != NULL)
- add_node(node,cur_node->left);
- else
- cur_node->left = node;
- return;
- }
- if (cur_node->right != NULL)
- add_node(node,cur_node->right);
- else
- cur_node->right = node;
- }
-
- put_entries(node)
- reg NODE *node;
- {
- reg char *sp;
-
- if (node == NULL)
- return;
- put_entries(node->left);
- if (xflag == 0)
- if (node->f) { /* a function */
- fprintf(outf, "%s\t%s\t%c^",
- node->entry, node->file, searchar);
- for (sp = node->pat; *sp; sp++)
- if (*sp == '\\')
- fprintf(outf, "\\\\");
- else if (*sp == searchar)
- fprintf(outf, "\\%c", searchar);
- else
- putc(*sp, outf);
- fprintf(outf, "%c\n", searchar);
- }
- else { /* a typedef; text pattern inadequate */
- fprintf(outf, "%s\t%s\t%d\n",
- node->entry, node->file, node->lno);
- }
- else if (vflag)
- fprintf(stdout, "%s %s %d\n",
- node->entry, node->file, (node->lno+63)/64);
- else
- fprintf(stdout, "%-16s%4d %-16s %s\n",
- node->entry, node->lno, node->file, node->pat);
- put_entries(node->right);
- }
- char *dbp = lbuf;
- int pfcnt;
-
- PF_funcs(fi)
- FILE *fi;
- {
-
- pfcnt = 0;
- while (fgets(lbuf, sizeof(lbuf), fi)) {
- lineno++;
- dbp = lbuf;
- if ( *dbp == '%' ) dbp++ ; /* Ratfor escape to fortran */
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0)
- continue;
- switch (*dbp |' ') {
-
- case 'i':
- if (tail("integer"))
- takeprec();
- break;
- case 'r':
- if (tail("real"))
- takeprec();
- break;
- case 'l':
- if (tail("logical"))
- takeprec();
- break;
- case 'c':
- if (tail("complex") || tail("character"))
- takeprec();
- break;
- case 'd':
- if (tail("double")) {
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0)
- continue;
- if (tail("precision"))
- break;
- continue;
- }
- break;
- }
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0)
- continue;
- switch (*dbp|' ') {
-
- case 'f':
- if (tail("function"))
- getit();
- continue;
- case 's':
- if (tail("subroutine"))
- getit();
- continue;
- case 'p':
- if (tail("program")) {
- getit();
- continue;
- }
- if (tail("procedure"))
- getit();
- continue;
- }
- }
- return (pfcnt);
- }
-
- tail(cp)
- char *cp;
- {
- register int len = 0;
-
- while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
- cp++, len++;
- if (*cp == 0) {
- dbp += len;
- return (1);
- }
- return (0);
- }
-
- takeprec()
- {
-
- while (isspace(*dbp))
- dbp++;
- if (*dbp != '*')
- return;
- dbp++;
- while (isspace(*dbp))
- dbp++;
- if (!isdigit(*dbp)) {
- --dbp; /* force failure */
- return;
- }
- do
- dbp++;
- while (isdigit(*dbp));
- }
-
- getit()
- {
- register char *cp;
- char c;
- char nambuf[BUFSIZ];
-
- for (cp = lbuf; *cp; cp++)
- ;
- *--cp = 0; /* zap newline */
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0 || !isalpha(*dbp))
- return;
- for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
- continue;
- c = cp[0];
- cp[0] = 0;
- strcpy(nambuf, dbp);
- cp[0] = c;
- pfnote(nambuf, lineno);
- pfcnt++;
- }
-
- char *
- savestr(cp)
- char *cp;
- {
- register int len;
- register char *dp;
-
- len = strlen(cp);
- dp = (char *)malloc(len+1);
- strcpy(dp, cp);
- return (dp);
- }
-
- /*
- * Return the ptr in sp at which the character c last
- * appears; NULL if not found
- *
- * Identical to v7 rindex, included for portability.
- */
-
- char *
- rindex(sp, c)
- register char *sp, c;
- {
- register char *r;
-
- r = NULL;
- do {
- if (*sp == c)
- r = sp;
- } while (*sp++);
- return(r);
- }
-
- /*
- * lisp tag functions
- * just look for (def or (DEF
- */
-
- L_funcs (fi)
- FILE *fi;
- {
- register int special;
-
- pfcnt = 0;
- while (fgets(lbuf, sizeof(lbuf), fi)) {
- lineno++;
- dbp = lbuf;
- if (dbp[0] == '(' &&
- (dbp[1] == 'D' || dbp[1] == 'd') &&
- (dbp[2] == 'E' || dbp[2] == 'e') &&
- (dbp[3] == 'F' || dbp[3] == 'f')) {
- dbp += 4;
- if (striccmp(dbp, "method") == 0 ||
- striccmp(dbp, "wrapper") == 0 ||
- striccmp(dbp, "whopper") == 0)
- special = TRUE;
- else
- special = FALSE;
- while (!isspace(*dbp))
- dbp++;
- while (isspace(*dbp))
- dbp++;
- L_getit(special);
- }
- }
- }
-
- L_getit(special)
- int special;
- {
- register char *cp;
- register char c;
- char nambuf[BUFSIZ];
-
- for (cp = lbuf; *cp; cp++)
- continue;
- *--cp = 0; /* zap newline */
- if (*dbp == 0)
- return;
- if (special) {
- if ((cp = index(dbp, ')')) == NULL)
- return;
- while (cp >= dbp && *cp != ':')
- cp--;
- if (cp < dbp)
- return;
- dbp = cp;
- while (*cp && *cp != ')' && *cp != ' ')
- cp++;
- }
- else
- for (cp = dbp + 1; *cp && *cp != '(' && *cp != ' '; cp++)
- continue;
- c = cp[0];
- cp[0] = 0;
- strcpy(nambuf, dbp);
- cp[0] = c;
- pfnote(nambuf, lineno,TRUE);
- pfcnt++;
- }
-
- /*
- * striccmp:
- * Compare two strings over the length of the second, ignoring
- * case distinctions. If they are the same, return 0. If they
- * are different, return the difference of the first two different
- * characters. It is assumed that the pattern (second string) is
- * completely lower case.
- */
- striccmp(str, pat)
- register char *str, *pat;
- {
- register int c1;
-
- while (*pat) {
- if (isupper(*str))
- c1 = tolower(*str);
- else
- c1 = *str;
- if (c1 != *pat)
- return c1 - *pat;
- pat++;
- str++;
- }
- return 0;
- }
-
- /*
- * first_char:
- * Return the first non-blank character in the file. After
- * finding it, rewind the input file so we start at the beginning
- * again.
- */
- first_char()
- {
- register int c;
- register long off;
-
- off = ftell(inf);
- while ((c = getc(inf)) != EOF)
- if (!isspace(c) && c != '\r') {
- fseek(inf, off, 0);
- return c;
- }
- fseek(inf, off, 0);
- return EOF;
- }
-
- /*
- * toss_yysec:
- * Toss away code until the next "%%" line.
- */
- toss_yysec()
- {
- char buf[BUFSIZ];
-
- for (;;) {
- lineftell = ftell(inf);
- if (fgets(buf, BUFSIZ, inf) == NULL)
- return;
- lineno++;
- if (strncmp(buf, "%%", 2) == 0)
- return;
- }
- }
- SHAR_EOF
- # End of shell archive
- exit 0
-
-