+++ /dev/null
-/* Tags file maker to go with GNUmacs
- Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
-NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
-WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
-RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
-WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
-AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
-DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
-CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
-STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
-WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
-OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
-DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
-A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
-PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
-as you receive it, in any medium, provided that you conspicuously
-and appropriately publish on each copy a valid copyright notice
-"Copyright (C) 1986 Free Software Foundation"; and include
-following the copyright notice a verbatim copy of the above disclaimer
-of warranty and of this License.
-
- 2. You may modify your copy or copies of this source file or
-any portion of it, and copy and distribute such modifications under
-the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
-Mere aggregation of another unrelated program with this program (or its
-derivative) on a volume of a storage or distribution medium does not bring
-the other program under the scope of these terms.
-
- 3. You may copy and distribute this program (or a portion or derivative
-of it, under Paragraph 2) in object code or executable form under the terms
-of Paragraphs 1 and 2 above provided that you also do one of the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
-For an executable file, complete source code means all the source code for
-all modules it contains; but, as a special exception, it need not include
-source code for modules which are standard libraries that accompany the
-operating system on which the executable file runs.
-
- 4. You may not copy, sublicense, distribute or transfer this program
-except as expressly provided under this License Agreement. Any attempt
-otherwise to copy, sublicense, distribute or transfer this program is void and
-your rights to use the program under this License agreement shall be
-automatically terminated. However, parties who have received computer
-software programs from you with this License Agreement will not have
-their licenses terminated so long as such parties remain in full compliance.
-
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what you give them. Help stamp out software-hoarding! */
-
-#include <stdio.h>
-#include <ctype.h>
-
-/* Define the symbol ETAGS to make the program "etags",
- which makes emacs-style tag tables by default.
- Define CTAGS to make the program "ctags" compatible with the usual one.
- Define neither one to get behavior that depends
- on the name with which the program is invoked
- (but we don't normally compile it that way). */
-
-/* On VMS, CTAGS is not useful, so always do ETAGS. */
-#ifdef VMS
-#ifndef ETAGS
-#define ETAGS
-#endif
-#endif
-
-/* Exit codes for success and failure. */
-
-#ifdef VMS
-#define GOOD (1)
-#define BAD (0)
-#else
-#define GOOD (0)
-#define BAD (1)
-#endif
-
-#define reg register
-#define logical char
-
-#ifndef TRUE
-#define TRUE (1)
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
-#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)
-
-/* cause token checking for typedef, struct, union, enum to distinguish
- keywords from identifier-prefixes (e.g. struct vs struct_tag). */
-#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))
-
-struct nd_st { /* sorting structure */
- char *name; /* function or type name */
- char *file; /* file name */
- logical f; /* use pattern or line no */
- int lno; /* line number tag is on */
- long cno; /* character number line starts on */
- char *pat; /* search pattern */
- logical been_warned; /* set if noticed dup */
- struct nd_st *left,*right; /* left and right sons */
-};
-
-long ftell();
-typedef struct nd_st NODE;
-
-int number; /* tokens found so far on line starting with # (including #) */
-logical 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, tag_ok, middle, end } TYST;
-
-TYST tydef = none;
-
-char searchar = '/'; /* use /.../ searches */
-
-int lineno; /* line number of current line */
-long charno; /* current character number */
-long linecharno; /* character number of start of line */
-
-char *curfile, /* current input file name */
- *outfile= 0, /* output file */
- *white = " \f\t\n", /* white chars */
- *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
- /* token ending chars */
- *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
- /* token starting chars */
- *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",
- /* valid in-token chars */
- *notgd = ",;"; /* non-valid after-function chars */
-
-int file_num = 0; /* current file number */
-int aflag = 0; /* -a: append to tags */
-int tflag = 0; /* -t: create tags for typedefs */
-int uflag = 0; /* -u: update tags */
-int wflag = 0; /* -w: suppress warnings */
-int vflag = 0; /* -v: create vgrind style index output */
-int xflag = 0; /* -x: create cxref style output */
-int eflag = 0; /* -e: emacs style output */
-
-/* Name this program was invoked with. */
-char *progname;
-
-FILE *inf, /* ioptr for current input file */
- *outf; /* ioptr for tags file */
-
-NODE *head; /* the head of the sorted binary tree */
-
-char *savestr();
-char *savenstr ();
-char *rindex();
-char *index();
-char *concat ();
-void initbuffer ();
-long readline ();
-
-/* A `struct linebuffer' is a structure which holds a line of text.
- `readline' reads a line from a stream into a linebuffer
- and works regardless of the length of the line. */
-
-struct linebuffer
- {
- long size;
- char *buffer;
- };
-
-struct linebuffer lb, lb1;
-\f
-#if 0 /* VMS now provides the `system' function. */
-#ifdef VMS
-
-#include <descrip.h>
-
-void
-system (buf)
- char *buf;
-{
- struct dsc$descriptor_s command =
- {
- strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf
- };
-
- LIB$SPAWN(&command);
-}
-#endif /* VMS */
-#endif /* 0 */
-\f
-main(ac,av)
- int ac;
- char *av[];
-{
- char cmd[100];
- int i;
- int fflag = 0;
- char *this_file;
-#ifdef VMS
- char got_err;
-
- extern char *gfnames();
- extern char *massage_name();
-#endif
-
- progname = av[0];
-
-#ifdef ETAGS
- eflag = 1;
-#else
-#ifdef CTAGS
- eflag = 0;
-#else
- {
- char *subname = rindex (progname, '/');
- if (subname++ == NULL)
- subname = progname;
- eflag = ! strcmp(subname, "ctags");
- }
-#endif
-#endif
-
- while (ac > 1 && av[1][0] == '-')
- {
- for (i=1; av[1][i]; i++)
- {
- switch(av[1][i])
- {
-#ifndef VMS /* These options are useful only with ctags,
- and VMS can't input them, so just omit them. */
- case 'B':
- searchar='?';
- eflag = 0;
- break;
- case 'F':
- searchar='/';
- eflag = 0;
- break;
-#endif
- case 'a':
- aflag++;
- break;
- case 'e':
- eflag++;
- break;
- case 'f':
- if (fflag > 0)
- {
- fprintf(stderr,
- "%s: -f flag may only be given once\n", progname);
- goto usage;
- }
- fflag++, ac--; av++;
- if (ac <= 1 || av[1][0] == '\0')
- {
- fprintf(stderr,
- "%s: -f flag must be followed by a filename\n",
- progname);
- goto usage;
- }
- outfile = av[1];
- goto end_loop;
- case 't':
- tflag++;
- break;
-#ifndef VMS
- case 'u':
- uflag++;
- eflag = 0;
- break;
-#endif
- case 'w':
- wflag++;
- break;
- case 'v':
- vflag++;
- xflag++;
- eflag = 0;
- break;
- case 'x':
- xflag++;
- eflag = 0;
- break;
- default:
- goto usage;
- }
- }
- end_loop: ;
- ac--; av++;
- }
-
- if (ac <= 1)
- {
- usage:
-#ifdef VMS
- fprintf (stderr, "Usage: %s [-aetwvx] [-f outfile] file ...\n", progname);
-#else
- fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname);
-#endif
- exit(BAD);
- }
-
- if (outfile == 0)
- {
- outfile = eflag ? "TAGS" : "tags";
- }
-
- init(); /* set up boolean "functions" */
-
- initbuffer (&lb);
- initbuffer (&lb1);
- /*
- * loop through files finding functions
- */
- if (eflag)
- {
- outf = fopen (outfile, aflag ? "a" : "w");
- if (!outf)
- {
- fprintf (stderr, "%s: ", progname);
- perror (outfile);
- exit (BAD);
- }
- }
-
- file_num = 1;
-#ifdef VMS
- for (ac--, av++;
- (this_file = gfnames (&ac, &av, &got_err)) != NULL; file_num++)
- {
- if (got_err)
- {
- error("Can't find file %s\n", this_file);
- ac--, av++;
- }
- else
- {
- this_file = massage_name (this_file);
-#else
- for (; file_num < ac; file_num++)
- {
- this_file = av[file_num];
- if (1)
- {
-#endif
- find_entries (this_file);
- if (eflag)
- {
- fprintf (outf, "\f\n%s,%d\n",
- this_file, total_size_of_entries (head));
- put_entries (head);
- free_tree (head);
- head = NULL;
- }
- }
- }
-
- if (eflag)
- {
- fclose (outf);
- exit (GOOD);
- }
-
- if (xflag)
- {
- put_entries(head);
- exit(GOOD);
- }
- 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)
- {
- fprintf (stderr, "%s: ", outfile);
- perror(outfile);
- exit(BAD);
- }
- put_entries(head);
- fclose(outf);
-#ifndef VMS
- if (uflag)
- {
- sprintf(cmd, "sort %s -o %s", outfile, outfile);
- system(cmd);
- }
-#endif
- exit(GOOD);
-}
-
-/*
- * 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;
- _wht[0] = _wht['\n'];
- _etk[0] = _etk['\n'];
- _btk[0] = _btk['\n'];
- _itk[0] = _itk['\n'];
- _gd[0] = _gd['\n'];
-}
-
-/*
- * 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)
- {
- fprintf (stderr, "%s: ", progname);
- perror(file);
- return;
- }
- curfile = savestr(file);
- cp = rindex(file, '.');
- /* .tex, .aux or .bbl implies LaTeX source code */
- if (cp && (!strcmp (cp + 1, "tex") || !strcmp (cp + 1, "aux")
- || !strcmp (cp + 1, "bbl")))
- {
- TEX_funcs(inf);
- fclose(inf);
- return;
- }
- /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
- if (cp && (!strcmp (cp + 1, "l") ||
- !strcmp (cp + 1, "el") ||
- !strcmp (cp + 1, "lsp") ||
- !strcmp (cp + 1, "lisp") ||
- !strcmp (cp + 1, "cl") ||
- !strcmp (cp + 1, "clisp")))
- {
- L_funcs(inf);
- fclose(inf);
- return;
- }
- /* .scm or .sm or .scheme implies scheme source code */
- if (cp && (!strcmp (cp + 1, "sm")
- || !strcmp (cp + 1, "scm")
- || !strcmp (cp + 1, "scheme")
- || !strcmp (cp + 1, "t")
- || !strcmp (cp + 1, "sch")
- || !strcmp (cp + 1, "SM")
- || !strcmp (cp + 1, "SCM")
- /* The `SCM' or `scm' prefix with a version number */
- || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's')
- || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S')))
- {
- Scheme_funcs(inf);
- fclose(inf);
- return;
- }
- /* .M implies Mcode source code */
- if (cp && !strcmp (cp + 1, "M"))
- {
- Mcode_funcs(inf);
- fclose(inf);
- return;
- }
-
- /* if not a .c or .h or .y file, try fortran */
- if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
- && cp[2] == '\0')
- {
- if (PF_funcs(inf) != 0)
- {
- fclose(inf);
- return;
- }
- rewind(inf); /* no fortran tags found, try C */
- }
- C_entries();
- fclose(inf);
-}
-\f
-/* Record a tag on the current line.
- name is the tag name,
- f is nonzero to use a pattern, zero to use line number instead. */
-
-pfnote (name, f, linestart, linelen, lno, cno)
- char *name;
- logical f; /* f == TRUE when function */
- char *linestart;
- int linelen;
- int lno;
- long cno;
-{
- register char *fp;
- register NODE *np;
- char *altname;
- char tem[51];
-
- if ((np = (NODE *) malloc (sizeof (NODE))) == NULL)
- {
- fprintf(stderr, "%s: too many entries to sort\n", progname);
- put_entries(head);
- free_tree(head);
- head = NULL;
- np = (NODE *) xmalloc(sizeof (NODE));
- }
- /* Change name "main" to M<thisfilename>. */
- if (!eflag && !xflag && !strcmp(name, "main"))
- {
- fp = rindex(curfile, '/');
- if (fp == 0)
- fp = curfile;
- else
- fp++;
- altname = concat ("M", fp, "");
- fp = rindex(altname, '.');
- if (fp && fp[2] == 0)
- *fp = 0;
- name = altname;
- }
- np->name = savestr(name);
- np->file = curfile;
- np->f = f;
- np->lno = lno;
- np->cno = cno;
- np->left = np->right = 0;
- if (eflag)
- {
- linestart[linelen] = 0;
- }
- else if (xflag == 0)
- {
- sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
- linestart = tem;
- }
- np->pat = savestr (linestart);
- if (head == NULL)
- head = np;
- else
- add_node(np, head);
-}
-
-free_tree(node)
- NODE *node;
-{
- while (node)
- {
- free_tree(node->right);
- free(node);
- node = node->left;
- }
-}
-
-add_node(node, cur_node)
- NODE *node,*cur_node;
-{
- register int dif;
-
- dif = strcmp(node->name, cur_node->name);
-
- /* If this tag name matches an existing one, then
- unless -e was given, do not add the node, but maybe print a warning */
- if (!eflag && !dif)
- {
- if (node->file == cur_node->file)
- {
- if (!wflag)
- {
- fprintf(stderr,"%s: Duplicate entry in file %s, line %d: %s\n",
- progname, node->file,lineno,node->name);
- fprintf(stderr,"Second entry ignored\n");
- }
- return;
- }
- if (!cur_node->been_warned)
- if (!wflag)
- fprintf(stderr,"%s: Duplicate entry in files %s and %s: %s (Warning only)\n",
- progname, node->file, cur_node->file, node->name);
- cur_node->been_warned = TRUE;
- return;
- }
-
- /* Actually add the node */
- 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;
-}
-\f
-put_entries(node)
- reg NODE *node;
-{
- reg char *sp;
-
- if (node == NULL)
- return;
-
- /* Output subentries that precede this one */
- put_entries (node->left);
-
- /* Output this entry */
-
- if (eflag)
- {
- fprintf (outf, "%s%c%d,%d\n",
- node->pat, 0177, node->lno, node->cno);
- }
- else if (!xflag)
- {
- fprintf (outf, "%s\t%s\t",
- node->name, node->file);
-
- if (node->f)
- { /* a function */
- putc (searchar, outf);
- putc ('^', outf);
-
- for (sp = node->pat; *sp; sp++)
- {
- if (*sp == '\\' || *sp == searchar)
- putc ('\\', outf);
- putc (*sp, outf);
- }
- putc (searchar, outf);
- }
- else
- { /* a typedef; text pattern inadequate */
- fprintf (outf, "%d", node->lno);
- }
- putc ('\n', outf);
- }
- else if (vflag)
- fprintf (stdout, "%s %s %d\n",
- node->name, node->file, (node->lno+63)/64);
- else
- fprintf (stdout, "%-16s%4d %-16s %s\n",
- node->name, node->lno, node->file, node->pat);
-
- /* Output subentries that follow this one */
- put_entries (node->right);
-}
-
-/* Return total number of characters that put_entries will output for
- the nodes in the subtree of the specified node.
- Works only if eflag is set, but called only in that case. */
-
-total_size_of_entries(node)
- reg NODE *node;
-{
- reg int total = 0;
- reg long num;
-
- if (node == NULL)
- return 0;
-
- /* Count subentries that precede this one */
- total = total_size_of_entries (node->left);
-
- /* Count subentries that follow this one */
- total += total_size_of_entries (node->right);
-
- /* Count this entry */
-
- total += strlen (node->pat) + 3;
-
- num = node->lno;
- while (num)
- {
- total++;
- num /= 10;
- }
-
- num = node->cno;
- if (!num) total++;
- while (num)
- {
- total++;
- num /= 10;
- }
- return total;
-}
-\f
-/*
- * This routine finds functions and typedefs in C syntax and adds them
- * to the list.
- */
-#ifdef VMS
-long vmslinecharno;
-#define VMS_SET_LINECHARNO (vmslinecharno = ftell(inf))
-#else
-#define VMS_SET_LINECHARNO
-#endif
-
-#define CNL_SAVE_NUMBER \
-{ \
- VMS_SET_LINECHARNO; \
- linecharno = charno; lineno++; \
- charno += 1 + readline (&lb, inf); \
- lp = lb.buffer; \
-}
-
-#define CNL \
-{ \
- CNL_SAVE_NUMBER; \
- number = 0; \
-}
-
-C_entries ()
-{
- register int c;
- register char *token, *tp, *lp;
- logical incomm, inquote, inchar, midtoken;
- int level;
- char tok[BUFSIZ];
-
- lineno = 0;
- charno = 0;
- lp = lb.buffer;
- *lp = 0;
-
- number = 0;
- gotone = midtoken = inquote = inchar = incomm = FALSE;
- level = 0;
-
- while (!feof (inf))
- {
- c = *lp++;
- if (c == 0)
- {
- CNL;
- gotone = FALSE;
- }
- if (c == '\\')
- {
- c = *lp++;
- if (c == 0)
- CNL_SAVE_NUMBER;
- c = ' ';
- }
- else if (incomm)
- {
- if (c == '*')
- {
- while ((c = *lp++) == '*')
- continue;
- if (c == 0)
- CNL;
- 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 (*lp == '*')
- {
- lp++;
- incomm = TRUE;
- }
- continue;
- case '#':
- if (lp == lb.buffer + 1)
- number = 1;
- continue;
- case '{':
- if (tydef == tag_ok)
- {
- tydef=middle;
- }
- level++;
- continue;
- case '}':
- if (lp == lb.buffer + 1)
- 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;
- char *buf = lb.buffer;
- int endpos = lp - lb.buffer;
- char *lp1 = lp;
- int line = lineno;
- long linestart = linecharno;
-#ifdef VMS
- long vmslinestart = vmslinecharno;
-#endif
- int tem = consider_token (&lp1, token, &f, level);
- lp = lp1;
- if (tem)
- {
- if (linestart != linecharno)
- {
-#ifdef VMS
- getline (vmslinestart);
-#else
- getline (linestart);
-#endif
- strncpy (tok, token + (lb1.buffer - buf),
- tp-token+1);
- tok[tp-token+1] = 0;
- pfnote(tok, f, lb1.buffer, endpos, line, linestart);
- }
- else
- {
- strncpy (tok, token, tp-token+1);
- tok[tp-token+1] = 0;
- pfnote(tok, f, lb.buffer, endpos, line, linestart);
- }
- gotone = f; /* function */
- }
- midtoken = FALSE;
- token = lp - 1;
- }
- else if (intoken(c))
- tp++;
- }
- else if (begtoken(c))
- {
- token = tp = lp - 1;
- midtoken = TRUE;
- }
- }
- if (c == ';' && tydef==end) /* clean with typedefs */
- tydef=none;
- }
-}
-
-/*
- * 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.
- */
-consider_token (lpp, token, f, level)
- char **lpp, *token;
- int *f, level;
-{
- reg char *lp = *lpp;
- reg char c;
- static logical next_token_is_func;
- logical firsttok; /* T if have seen first token in ()'s */
- int bad, win;
-
- *f = 1; /* a function */
- c = lp[-1];
- bad = FALSE;
- if (!number)
- { /* space is not allowed in macro defs */
- while (iswhite(c))
- {
- c = *lp++;
- if (c == 0)
- {
- if (feof (inf))
- break;
- CNL;
- }
- }
- }
- else
- {
- /* the following tries to make it so that a #define a b(c) */
- /* doesn't count as a define of b. */
-
- number++;
- if (number >= 4 || (number==2 && strncmp (token, "define", 6)==0))
- {
- /* Force the next symbol to be recognised, even if it is #define a b(c)! */
- if(number == 2) next_token_is_func = 1;
- else
- gotone = TRUE;
- badone:
- bad = TRUE;
- goto ret;
- }
- }
- /* check for the typedef cases */
- if (tflag && istoken(token, "typedef", 7))
- {
- tydef=begin;
- goto badone;
- }
- if (tydef==begin && (istoken(token, "struct", 6) ||
- istoken(token, "union", 5) || istoken(token, "enum", 4)))
- {
- tydef=tag_ok;
- goto badone;
- }
- if (tydef==tag_ok)
- {
- tydef=middle;
- goto badone;
- }
- if (tydef==begin) /* e.g. typedef ->int<- */
- {
- tydef=end;
- goto badone;
- }
- if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */
- {
- tydef=end;
- }
- if (tydef==end)
- {
- *f = 0;
- win = 1;
- goto ret;
- }
- /* Detect GNUmacs's function-defining macros. */
- if (!number && !strncmp (token, "DEF", 3))
-
- {
- next_token_is_func = 1;
- goto badone;
- }
- if (next_token_is_func)
- {
- next_token_is_func = 0;
- win = 1;
- goto ret;
- }
- if (c != '(')
- goto badone;
- firsttok = FALSE;
- while ((c = *lp++) != ')')
- {
- if (c == 0)
- {
- if (feof (inf))
- break;
- CNL;
- }
- /*
- * 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 (c = *lp++))
- {
- if (c == 0)
- {
- if (feof (inf))
- break;
- CNL;
- }
- }
- win = isgood (c);
-ret:
- *lpp = lp - 1;
- return !bad && win;
-}
-
-getline (atchar)
- long atchar;
-{
- long saveftell = ftell (inf);
-
- fseek (inf, atchar, 0);
- readline (&lb1, inf);
- fseek (inf, saveftell, 0);
-}
-\f
-/* Fortran parsing */
-
-char *dbp;
-int pfcnt;
-
-PF_funcs(fi)
- FILE *fi;
-{
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno += readline (&lb, fi) + 1;
- dbp = lb.buffer;
- 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];
-
- 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, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
- pfcnt++;
-}
-\f
-/*
- * lisp tag functions
- * just look for (def or (DEF
- */
-
-L_funcs (fi)
- FILE *fi;
-{
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno += readline (&lb, fi) + 1;
- dbp = lb.buffer;
- if (dbp[0] == '(' &&
- (dbp[1] == 'D' || dbp[1] == 'd') &&
- (dbp[2] == 'E' || dbp[2] == 'e') &&
- (dbp[3] == 'F' || dbp[3] == 'f'))
- {
- while (!isspace(*dbp)) dbp++;
- while (isspace(*dbp)) dbp++;
- L_getit();
- }
- }
-}
-
-L_getit()
-{
- register char *cp;
- char c;
- char nambuf[BUFSIZ];
-
- if (*dbp == 0) return;
- for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
- continue;
- c = cp[0];
- cp[0] = 0;
- strcpy(nambuf, dbp);
- cp[0] = c;
- pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
- pfcnt++;
-}
-\f
-/*
- * Scheme tag functions
- * look for (def... xyzzy
- * look for (def... (xyzzy
- * look for (def ... ((...(xyzzy ....
- * look for (set! xyzzy
- */
-
-static get_scheme ();
-Scheme_funcs (fi)
- FILE *fi;
-{
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno += readline (&lb, fi) + 1;
- dbp = lb.buffer;
- if (dbp[0] == '(' &&
- (dbp[1] == 'D' || dbp[1] == 'd') &&
- (dbp[2] == 'E' || dbp[2] == 'e') &&
- (dbp[3] == 'F' || dbp[3] == 'f'))
- {
- while (!isspace(*dbp)) dbp++;
- /* Skip over open parens and white space */
- while (*dbp && (isspace(*dbp) || *dbp == '(')) dbp++;
- get_scheme ();
- }
- if (dbp[0] == '(' &&
- (dbp[1] == 'S' || dbp[1] == 's') &&
- (dbp[2] == 'E' || dbp[2] == 'e') &&
- (dbp[3] == 'T' || dbp[3] == 't') &&
- (dbp[4] == '!' || dbp[4] == '!') &&
- (isspace(dbp[5])))
- {
- while (!isspace(*dbp)) dbp++;
- /* Skip over white space */
- while (isspace(*dbp)) dbp++;
- get_scheme ();
- }
- }
-}
-
-static
-get_scheme()
-{
- register char *cp;
- char c;
- char nambuf[BUFSIZ];
-
- if (*dbp == 0) return;
- /* Go till you get to white space or a syntactic break */
- for (cp = dbp+1; *cp && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
- continue;
- /* Null terminate the string there. */
- c = cp[0];
- cp[0] = 0;
- /* Copy the string */
- strcpy(nambuf, dbp);
- /* Unterminate the string */
- cp[0] = c;
- /* Announce the change */
- pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
- pfcnt++;
-}
-static get_mcode ();
-Mcode_funcs (fi)
- FILE *fi;
-{
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno += readline (&lb, fi) + 1;
- dbp = lb.buffer;
-
- while (*dbp != 0)
- {
- /* Skip over white space */
- while (isspace(*dbp)) dbp++;
- get_mcode();
- }
- }
-}
-
-static
-get_mcode()
-{
- register char *cp;
- char c;
- char nambuf[BUFSIZ];
-
- if (*dbp == 0) return;
- /* Go till you get to white space or a syntactic break */
- for (cp = dbp; *cp && *cp != ':' && *cp != ';' && !isspace(*cp); cp++)
- continue;
-
- if(*cp == ':')
- {
- /* Null terminate the string there. */
- c = cp[0];
- cp[0] = 0;
- /* Copy the string */
- strcpy(nambuf, dbp);
- /* Unterminate the string */
- cp[0] = c;
- /* Announce the change */
- pfnote(nambuf, TRUE, lb.buffer, strlen(lb.buffer), lineno, linecharno);
- pfcnt++;
- *dbp = 0;
- }
- if (*cp == ';')
- *dbp = 0;
- else
- dbp = cp;
-}
-\f
-/* Find tags in TeX and LaTeX input files. */
-
-/* TEX_toktab is a table of TeX control sequences that define tags.
- Each TEX_tabent records one such control sequence. */
-
-struct TEX_tabent
-{
- char *name;
- int len;
-};
-
-struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
-
-/* Default set of control sequences to put into TEX_toktab.
- The value of environment var TEXTAGS is prepended to this. */
-
-static char *TEX_defenv =
- ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
-
-struct TEX_tabent *TEX_decode_env ();
-
-static char TEX_esc = '\\';
-static char TEX_opgrp = '{';
-static char TEX_clgrp = '}';
-
-/*
- * TeX/LaTeX scanning loop.
- */
-
-TEX_funcs (fi)
- FILE *fi;
-{
- char *lasthit;
-
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- /* Select either \ or ! as escape character. */
- TEX_mode (fi);
-
- /* Initialize token table once from environment. */
- if (!TEX_toktab)
- TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno += readline (&lb, fi) + 1;
- dbp = lb.buffer;
- lasthit = dbp;
-
- while (!feof (fi))
- { /* Scan each line in file */
- lineno++;
- linecharno = charno;
- charno += readline (&lb, fi) + 1;
- dbp = lb.buffer;
- lasthit = dbp;
- while (dbp = index (dbp, TEX_esc)) /* Look at each escape in line */
- {
- register int i;
-
- if (! *(++dbp))
- break;
- linecharno += dbp - lasthit;
- lasthit = dbp;
- i = TEX_Token (lasthit);
- if (0 <= i)
- {
- TEX_getit (lasthit, TEX_toktab[i].len);
- break; /* We only save a line once */
- }
- }
- }
- }
-}
-
-#define TEX_LESC '\\'
-#define TEX_SESC '!'
-
-/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
-/* chars accordingly. */
-
-TEX_mode (f)
- FILE *f;
-{
- int c;
-
- while ((c = getc (f)) != EOF)
- if (c == TEX_LESC || c == TEX_SESC)
- break;
-
- if (c == TEX_LESC)
- {
- TEX_esc = TEX_LESC;
- TEX_opgrp = '{';
- TEX_clgrp = '}';
- }
- else
- {
- TEX_esc = TEX_SESC;
- TEX_opgrp = '<';
- TEX_clgrp = '>';
- }
- rewind (f);
-}
-
-/* Read environment and prepend it to the default string. */
-/* Build token table. */
-
-struct TEX_tabent *
-TEX_decode_env (evarname, defenv)
- char *evarname;
- char *defenv;
-{
- register char *env, *p;
- extern char *savenstr (), *index ();
-
- struct TEX_tabent *tab;
- int size, i;
-
- /* Append deafult string to environment. */
- env = (char *) getenv (evarname);
- if (!env)
- env = defenv;
- else
- env = concat (env, defenv, "");
-
- /* Allocate a token table */
- for (size = 1, p=env; p;)
- if ((p = index (p, ':')) && *(++p))
- size++;
- tab = (struct TEX_tabent *) xmalloc (size * sizeof (struct TEX_tabent));
-
- /* Unpack environment string into token table. Be careful about */
- /* zero-length strings (leading ':', "::" and trailing ':') */
- for (i = 0; *env;)
- {
- p = index (env, ':');
- if (!p) /* End of environment string. */
- p = env + strlen (env);
- if (p - env > 0)
- { /* Only non-zero strings. */
- tab[i].name = savenstr (env, p - env);
- tab[i].len = strlen (tab[i].name);
- i++;
- }
- if (*p)
- env = p + 1;
- else
- {
- tab[i].name = NULL; /* Mark end of table. */
- tab[i].len = 0;
- break;
- }
- }
- return tab;
-}
-
-/* Record a tag defined by a TeX command of length LEN and starting at NAME.
- The name being defined actually starts at (NAME + LEN + 1).
- But we seem to include the TeX command in the tag name. */
-
-TEX_getit (name, len)
- char *name;
- int len;
-{
- char *p = name + len;
- char nambuf[BUFSIZ];
-
- if (*name == 0) return;
-
- /* Let tag name extend to next group close (or end of line) */
- while (*p && *p != TEX_clgrp)
- p++;
- strncpy (nambuf, name, p - name);
- nambuf[p - name] = 0;
-
- pfnote (nambuf, TRUE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
- pfcnt++;
-}
-
-/* If the text at CP matches one of the tag-defining TeX command names,
- return the index of that command in TEX_toktab.
- Otherwise return -1. */
-
-/* Keep the capital `T' in `Token' for dumb truncating compilers
- (this distinguishes it from `TEX_toktab' */
-TEX_Token (cp)
- char *cp;
-{
- int i;
-
- for (i = 0; TEX_toktab[i].len > 0; i++)
- if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
- return i;
- return -1;
-}
-\f
-/* Initialize a linebuffer for use */
-
-void
-initbuffer (linebuffer)
- struct linebuffer *linebuffer;
-{
- linebuffer->size = 200;
- linebuffer->buffer = (char *) xmalloc (200);
-}
-
-/* Read a line of text from `stream' into `linebuffer'.
- Return the length of the line. */
-
-long
-readline (linebuffer, stream)
- struct linebuffer *linebuffer;
- register FILE *stream;
-{
- char *buffer = linebuffer->buffer;
- register char *p = linebuffer->buffer;
- register char *pend = p + linebuffer->size;
-
- while (1)
- {
- int c = getc (stream);
- if (p == pend)
- {
- linebuffer->size *= 2;
- buffer = (char *) xrealloc (buffer, linebuffer->size);
- p += buffer - linebuffer->buffer;
- pend = buffer + linebuffer->size;
- linebuffer->buffer = buffer;
- }
- if (c < 0 || c == '\n')
- {
- *p = 0;
- break;
- }
- *p++ = c;
- }
-
- return p - buffer;
-}
-\f
-char *
-savestr(cp)
- char *cp;
-{
- return savenstr (cp, strlen (cp));
-}
-
-char *
-savenstr(cp, len)
- char *cp;
- int len;
-{
- register char *dp;
-
- dp = (char *) xmalloc (len + 1);
- strncpy (dp, cp, len);
- dp[len] = '\0';
- 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);
-}
-
-/*
- * Return the ptr in sp at which the character c first
- * appears; NULL if not found
- *
- * Identical to v7 index, included for portability.
- */
-
-char *
-index(sp, c)
- register char *sp, c;
-{
- do
- {
- if (*sp == c)
- return (sp);
- } while (*sp++);
- return (NULL);
-}
-
-/* Print error message and exit. */
-
-fatal (s1, s2)
- char *s1, *s2;
-{
- error (s1, s2);
- exit (BAD);
-}
-
-/* Print error message. `s1' is printf control string, `s2' is arg for it. */
-
-error (s1, s2)
- char *s1, *s2;
-{
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, s1, s2);
- fprintf (stderr, "\n");
-}
-
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
-
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
-}
-
-/* Like malloc but get fatal error if memory is exhausted. */
-
-int
-xmalloc (size)
- int size;
-{
- int result = malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0);
- return result;
-}
-
-int
-xrealloc (ptr, size)
- char *ptr;
- int size;
-{
- int result = realloc (ptr, size);
- if (!result)
- fatal ("virtual memory exhausted");
- return result;
-}