[comp.sources.misc] v09i090: Etags for MicroEmacs

jb@altair.csustan.edu (John Birchfield) (12/28/89)

Posting-number: Volume 9, Issue 90
Submitted-by: jb@altair.csustan.edu (John Birchfield)
Archive-name: me-etags

#! /bin/sh
# 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:
#	etags
# This archive created: Tue Dec 26 22:32:03 1989
export PATH; PATH=/bin:$PATH
if test ! -d 'etags'
then
	echo shar: creating directory "'etags'"
	mkdir 'etags'
fi
echo shar: entering directory "'etags'"
cd 'etags'
echo shar: extracting "'makefile'" '(660 characters)'
sed 's/^X//' << \SHAR_EOF > 'makefile'
X#
X# Makefile for MSDOS version of ETAGS
X#
X# You can use this with the TurboC Make, the Zortech Make or
X# one of the less brain damaged public domain makes but not with
X# Microsoft Make.
X
Xnone         :
X	@echo Usage: make ztc or make msc or make tc2 tc15
X
X
Xztc          :
X	ztc -p -D__MSDOS__ etags.c $(LIB)\_mains.obj
X	ztc -mti striptag.c
X
Xtc2          :
X	tcc etags.c \tc2\lib\wildargs.obj
X	tcc -mt striptag.c
X	exe2bin striptag.exe striptag.com
X	del striptag.exe
X
Xtc15         :
X	tcc etags.c setargv.c
X	tcc -mt striptag.c
X	exe2bin striptag.exe striptag.com
X	del striptag.exe
X
Xmsc          :
X	cl -D__MSDOS__ etags.c $(LIB)\setargv.obj -link /NOE
X	cl striptag.c
X
SHAR_EOF
echo shar: extracting "'etags.c'" '(35244 characters)'
sed 's/^X//' << \SHAR_EOF > 'etags.c'
X/* Tags file maker to go with GNUmacs
X   Copyright (C) 1984, 1987 Free Software Foundation, Inc. and Ken Arnold
X
X			   NO WARRANTY
X
X  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
XRICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
XFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
XAND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
XDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
XCORRECTION.
X
X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
XSTALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
XWHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
XLIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
XOTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
XUSE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
XDATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
XA FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
XPROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
XDAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
X
X		GENERAL PUBLIC LICENSE TO COPY
X
X  1. You may copy and distribute verbatim copies of this source file
Xas you receive it, in any medium, provided that you conspicuously
Xand appropriately publish on each copy a valid copyright notice
X"Copyright (C) 1986 Free Software Foundation"; and include
Xfollowing the copyright notice a verbatim copy of the above disclaimer
Xof warranty and of this License.
X
X  2. You may modify your copy or copies of this source file or
Xany portion of it, and copy and distribute such modifications under
Xthe terms of Paragraph 1 above, provided that you also do the following:
X
X    a) cause the modified files to carry prominent notices stating
X    that you changed the files and the date of any change; and
X
X    b) cause the whole of any work that you distribute or publish,
X    that in whole or in part contains or is a derivative of this
X    program or any part thereof, to be licensed at no charge to all
X    third parties on terms identical to those contained in this
X    License Agreement (except that you may choose to grant more extensive
X    warranty protection to some or all third parties, at your option).
X
X    c) You may charge a distribution fee for the physical act of
X    transferring a copy, and you may at your option offer warranty
X    protection in exchange for a fee.
X
XMere aggregation of another unrelated program with this program (or its
Xderivative) on a volume of a storage or distribution medium does not bring
Xthe other program under the scope of these terms.
X
X  3. You may copy and distribute this program (or a portion or derivative
Xof it, under Paragraph 2) in object code or executable form under the terms
Xof Paragraphs 1 and 2 above provided that you also do one of the following:
X
X    a) accompany it with the complete corresponding machine-readable
X    source code, which must be distributed under the terms of
X    Paragraphs 1 and 2 above; or,
X
X    b) accompany it with a written offer, valid for at least three
X    years, to give any third party free (except for a nominal
X    shipping charge) a complete machine-readable copy of the
X    corresponding source code, to be distributed under the terms of
X    Paragraphs 1 and 2 above; or,
X
X    c) accompany it with the information you received as to where the
X    corresponding source code may be obtained.  (This alternative is
X    allowed only for noncommercial distribution and only if you
X    received the program in object code or executable form alone.)
X
XFor an executable file, complete source code means all the source code for
Xall modules it contains; but, as a special exception, it need not include
Xsource code for modules which are standard libraries that accompany the
Xoperating system on which the executable file runs.
X
X  4. You may not copy, sublicense, distribute or transfer this program
Xexcept as expressly provided under this License Agreement.  Any attempt
Xotherwise to copy, sublicense, distribute or transfer this program is void and
Xyour rights to use the program under this License agreement shall be
Xautomatically terminated.  However, parties who have received computer
Xsoftware programs from you with this License Agreement will not have
Xtheir licenses terminated so long as such parties remain in full compliance.
X
XIn other words, you are welcome to use, share and improve this program.
XYou are forbidden to forbid anyone else to use, share and improve
Xwhat you give them.   Help stamp out software-hoarding!  */
X
X#include <stdio.h>
X#include <ctype.h>
X
X/* Define the symbol ETAGS to make the program "etags",
X which makes emacs-style tag tables by default.
X Define CTAGS to make the program "ctags" compatible with the usual one.
X Define neither one to get behavior that depends
X on the name with which the program is invoked
X (but we don't normally compile it that way).  */
X
X#define	reg	register
X#define	logical	char
X
X#define	TRUE	(1)
X#define	FALSE	(0)
X
X#define	iswhite(arg)	(_wht[arg])	/* T if char is white		*/
X#define	begtoken(arg)	(_btk[arg])	/* T if char can start token	*/
X#define	intoken(arg)	(_itk[arg])	/* T if char can be in token	*/
X#define	endtoken(arg)	(_etk[arg])	/* T if char ends tokens	*/
X#define	isgood(arg)	(_gd[arg])	/* T if char can be after ')'	*/
X
X#define	max(I1,I2)	(I1 > I2 ? I1 : I2)
X
Xstruct	nd_st {			/* sorting structure			*/
X	char	*name;			/* function or type name	*/
X	char	*file;			/* file name			*/
X	logical f;			/* use pattern or line no	*/
X	int	lno;			/* line number tag is on	*/
X	long    cno;			/* character number line starts on */
X	char	*pat;			/* search pattern		*/
X	logical	been_warned;		/* set if noticed dup		*/
X	struct	nd_st	*left,*right;	/* left and right sons		*/
X};
X
Xlong	ftell();
Xtypedef	struct	nd_st	NODE;
X
Xint number; /* tokens found so far on line starting with # (including #) */
Xlogical gotone,				/* found a func already on line	*/
X					/* boolean "func" (see init)	*/
X	_wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
X
X	/* typedefs are recognized using a simple finite automata,
X	 * tydef is its state variable.
X	 */
Xtypedef enum {none, begin, middle, end } TYST;
X
XTYST tydef = none;
X
Xchar	searchar = '/';			/* use /.../ searches 		*/
X
Xint	lineno;			/* line number of current line */
Xlong	charno;			/* current character number */
Xlong	linecharno;		/* character number of start of line */
X
Xchar    *curfile,		/* current input file name		*/
X	*outfile= 0,		/* output file				*/
X	*white	= " \f\t\n\r",	/* white chars				*/
X	*endtk	= " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
X				/* token ending chars			*/
X	*begtk	= "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz",
X				/* token starting chars			*/
X	*intk	= "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789",
X				/* valid in-token chars			*/
X	*notgd	= ",;";		/* non-valid after-function chars	*/
X
Xint	file_num;		/* current file number			*/
Xint	aflag;			/* -a: append to tags */
Xint	tflag;			/* -t: create tags for typedefs */
Xint	uflag;			/* -u: update tags */
Xint	wflag;			/* -w: suppress warnings */
Xint	vflag;			/* -v: create vgrind style index output */
Xint	xflag;			/* -x: create cxref style output */
Xint	eflag;			/* -e: emacs style output */
X
X/* Name this program was invoked with.  */
Xchar *progname;
X
XFILE	*inf,			/* ioptr for current input file		*/
X	*outf;			/* ioptr for tags file			*/
X
XNODE	*head;			/* the head of the sorted binary tree	*/
X
Xchar *savestr();
Xchar *savenstr ();
Xchar *rindex();
Xchar *index();
Xchar *concat ();
Xvoid initbuffer ();
Xlong readline ();
X
X/* A `struct linebuffer' is a structure which holds a line of text.
X `readline' reads a line from a stream into a linebuffer
X and works regardless of the length of the line.  */
X
Xstruct linebuffer
X  {
X    long size;
X    char *buffer;
X  };
X
Xstruct linebuffer lb, lb1;
X
X#ifdef VMS
X
X#include <descrip.h>
X
Xvoid
Xsystem (buf)
X     char *buf;
X{
X  struct dsc$descriptor_s command =
X    {
X      strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf
X    };
X
X  LIB$SPAWN(&command);
X}
X#endif /* VMS */
X
X
Xmain(ac,av)
X     int	ac;
X     char	*av[];
X{
X  char cmd[100];
X  int i;
X  int fflag = 0;
X
X  progname = av[0];
X
X#ifdef ETAGS
X  eflag = 1;
X#else
X#ifdef CTAGS
X  eflag = 0;
X#else
X  {
X    char *subname = rindex (progname, '/');
X    if (subname++ == NULL)
X      subname = progname;
X    eflag = ! strcmp(subname, "ctags");
X  }
X#endif
X#endif
X
X  while (ac > 1 && av[1][0] == '-')
X    {
X      for (i=1; av[1][i]; i++)
X	{
X	  switch(av[1][i])
X	    {
X	    case 'B':
X	      searchar='?';
X	      eflag = 0;
X	      break;
X	    case 'F':
X	      searchar='/';
X	      eflag = 0;
X	      break;
X	    case 'a':
X	      aflag++;
X	      break;
X	    case 'e':
X	      eflag++;
X	      break;
X	    case 'f':
X	      if (fflag > 0)
X		{
X		  fprintf(stderr,
X			  "%s: -f flag may only be given once\n", progname);
X		  goto usage;
X		}
X	      fflag++, ac--; av++;
X	      if (ac <= 1 || av[1][0] == '\0')
X		{
X		  fprintf(stderr,
X			  "%s: -f flag must be followed by a filename\n",
X			  progname);
X		  goto usage;
X		}
X	      outfile = av[1];
X	      goto end_loop;
X	    case 't':
X	      tflag++;
X	      break;
X	    case 'u':
X	      uflag++;
X	      eflag = 0;
X	      break;
X	    case 'w':
X	      wflag++;
X	      break;
X	    case 'v':
X	      vflag++;
X	      xflag++;
X	      eflag = 0;
X	      break;
X	    case 'x':
X	      xflag++;
X	      eflag = 0;
X	      break;
X	    default:
X	      goto usage;
X	    }
X	}
X    end_loop: ;
X      ac--; av++;
X    }
X
X  if (ac <= 1)
X    {
X    usage:
X      fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname);
X      exit(1);
X    }
X
X  if (outfile == 0)
X    {
X      outfile = eflag ? "TAGS" : "tags";
X    }
X
X  init();			/* set up boolean "functions"		*/
X
X  initbuffer (&lb);
X  initbuffer (&lb1);
X  /*
X   * loop through files finding functions
X   */
X  if (eflag)
X    {
X      outf = fopen (outfile, aflag ? "a" : "w");
X      if (!outf)
X	{
X	  fprintf (stderr, "%s: ", progname);
X	  perror (outfile);
X	  exit (1);
X	}
X    }
X
X  for (file_num = 1; file_num < ac; file_num++)
X    {
X      find_entries(av[file_num]);
X      if (eflag)
X	{
X	  fprintf (outf, "\f\n%s,%d\n",
X		   av[file_num], total_size_of_entries (head));
X	  put_entries (head);
X	  free_tree (head);
X	  head = NULL;
X	}
X    }
X
X  if (eflag)
X    {
X      fclose (outf);
X      exit (0);
X    }
X
X  if (xflag)
X    {
X      put_entries(head);
X      exit(0);
X    }
X  if (uflag)
X    {
X      for (i=1; i<ac; i++)
X	{
X	  sprintf(cmd,
X		  "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
X		  outfile, av[i], outfile);
X	  system(cmd);
X	}
X      aflag++;
X    }
X  outf = fopen(outfile, aflag ? "a" : "w");
X  if (outf == NULL)
X    {
X      fprintf (stderr, "%s: ", outfile);
X      perror(outfile);
X      exit(1);
X    }
X  put_entries(head);
X  fclose(outf);
X  if (uflag)
X    {
X      sprintf(cmd, "sort %s -o %s", outfile, outfile);
X      system(cmd);
X    }
X  exit(0);
X}
X
X/*
X * This routine sets up the boolean psuedo-functions which work
X * by seting boolean flags dependent upon the corresponding character
X * Every char which is NOT in that string is not a white char.  Therefore,
X * all of the array "_wht" is set to FALSE, and then the elements
X * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
X * of a char is TRUE if it is the string "white", else FALSE.
X */
Xinit()
X{
X
X  reg char *sp;
X  reg int i;
X
X  for (i = 0; i < 0177; i++)
X    {
X      _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
X      _gd[i] = TRUE;
X    }
X  for (sp = white; *sp; sp++)
X    _wht[*sp] = TRUE;
X  for (sp = endtk; *sp; sp++)
X    _etk[*sp] = TRUE;
X  for (sp = intk; *sp; sp++)
X    _itk[*sp] = TRUE;
X  for (sp = begtk; *sp; sp++)
X    _btk[*sp] = TRUE;
X  for (sp = notgd; *sp; sp++)
X    _gd[*sp] = FALSE;
X  _wht[0] = _wht['\n'];
X  _etk[0] = _etk['\n'];
X  _btk[0] = _btk['\n'];
X  _itk[0] = _itk['\n'];
X  _gd[0] = _gd['\n'];
X}
X
X/*
X * This routine opens the specified file and calls the function
X * which finds the function and type definitions.
X */
Xfind_entries (file)
X     char *file;
X{
X  char *cp;
X
X#ifdef __MSDOS__
X  strlwr(file);
X  if ((inf=fopen(file,"rb")) == NULL)
X#else
X  if ((inf=fopen(file,"r")) == NULL)
X#endif
X    {
X      fprintf (stderr, "%s: ", progname);
X      perror(file);
X      return;
X    }
X  curfile = savestr(file);
X  cp = rindex(file, '.');
X  /* .tex, .aux or .bbl implies LaTeX source code */
X  if (cp && (!strcmp (cp + 1, "tex") || !strcmp (cp + 1, "aux")
X	     || !strcmp (cp + 1, "bbl")))
X    {
X      TEX_funcs(inf);
X      fclose(inf);
X      return;
X    }
X  /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
X  if (cp && (!strcmp (cp + 1, "l") ||
X	     !strcmp (cp + 1, "el") ||
X	     !strcmp (cp + 1, "lsp") ||
X	     !strcmp (cp + 1, "lisp") ||
X	     !strcmp (cp + 1, "cl") ||
X	     !strcmp (cp + 1, "clisp")))
X    {
X      L_funcs(inf);
X      fclose(inf);
X      return;
X    }
X  /* .scm or .sm or .scheme implies scheme source code */
X  if (cp && (!strcmp (cp + 1, "sm")
X	     || !strcmp (cp + 1, "scm")
X	     || !strcmp (cp + 1, "scheme")
X	     || !strcmp (cp + 1, "t")
X	     || !strcmp (cp + 1, "sch")
X	     || !strcmp (cp + 1, "SM")
X	     || !strcmp (cp + 1, "SCM")
X             /* The `SCM' or `scm' prefix with a version number */
X             || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's')
X             || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S')))
X    {
X      Scheme_funcs(inf);
X      fclose(inf);
X      return;
X    }
X  /* if not a .c or .h or .y file, try fortran */
X  if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
X      && cp[2] == '\0')
X    {
X      if (PF_funcs(inf) != 0)
X	{
X	  fclose(inf);
X	  return;
X	}
X      rewind(inf);	/* no fortran tags found, try C */
X    }
X  C_entries();
X  fclose(inf);
X}
X
X/* Record a tag on the current line.
X  name is the tag name,
X  f is nonzero to use a pattern, zero to use line number instead. */
X
Xpfnote (name, f, linestart, linelen, lno, cno)
X     char *name;
X     logical f;			/* f == TRUE when function */
X     char *linestart;
X     int linelen;
X     int lno;
X     long cno;
X{
X  register char *fp;
X  register NODE *np;
X  char *altname;
X  char tem[51];
X
X  if ((np = (NODE *) malloc (sizeof (NODE))) == NULL)
X    {
X      fprintf(stderr, "%s: too many entries to sort\n", progname);
X      put_entries(head);
X      free_tree(head);
X      head = NULL;
X      np = (NODE *) xmalloc(sizeof (NODE));
X    }
X  /* Change name "main" to M<thisfilename>. */
X  if (!eflag && !xflag && !strcmp(name, "main"))
X    {
X      fp = rindex(curfile, '/');
X      if (fp == 0)
X	fp = curfile;
X      else
X	fp++;
X      altname = concat ("M", fp, "");
X      fp = rindex(altname, '.');
X      if (fp && fp[2] == 0)
X	*fp = 0;
X      name = altname;
X    }
X  np->name = savestr(name);
X  np->file = curfile;
X  np->f = f;
X  np->lno = lno;
X  np->cno = cno;
X  np->left = np->right = 0;
X  if (eflag)
X    {
X      linestart[linelen] = 0;
X    }
X  else if (xflag == 0)
X    {
X      sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
X      linestart = tem;
X    }
X  np->pat = savestr (linestart);
X  if (head == NULL)
X    head = np;
X  else
X    add_node(np, head);
X}
X
Xfree_tree(node)
X     NODE *node;
X{
X  while (node)
X    {
X      free_tree(node->right);
X      free(node);
X      node = node->left;
X    }
X}
X
Xadd_node(node, cur_node)
X     NODE *node,*cur_node;
X{
X  register int dif;
X
X  dif = strcmp(node->name, cur_node->name);
X
X  /* If this tag name matches an existing one, then
X     unless -e was given, do not add the node, but maybe print a warning */
X  if (!eflag && !dif)
X    {
X      if (node->file == cur_node->file)
X	{
X	  if (!wflag)
X	    {
X	      fprintf(stderr,"%s: Duplicate entry in file %s, line %d: %s\n",
X		      progname, node->file,lineno,node->name);
X	      fprintf(stderr,"Second entry ignored\n");
X	    }
X	  return;
X	}
X      if (!cur_node->been_warned)
X	if (!wflag)
X	  fprintf(stderr,"%s: Duplicate entry in files %s and %s: %s (Warning only)\n",
X		  progname, node->file, cur_node->file, node->name);
X      cur_node->been_warned = TRUE;
X      return;
X    } 
X
X  /* Actually add the node */
X  if (dif < 0) 
X    {
X      if (cur_node->left != NULL)
X	add_node(node,cur_node->left);
X      else
X	cur_node->left = node;
X      return;
X    }
X  if (cur_node->right != NULL)
X    add_node(node,cur_node->right);
X  else
X    cur_node->right = node;
X}
X
Xput_entries(node)
X     reg NODE *node;
X{
X  reg char *sp;
X
X  if (node == NULL)
X    return;
X
X  /* Output subentries that precede this one */
X  put_entries (node->left);
X
X  /* Output this entry */
X
X  if (eflag)
X    {
X      fprintf (outf, "%s%c%d,%d\n",
X	       node->pat, 0177, node->lno, node->cno);
X    }
X  else if (!xflag)
X    {
X      fprintf (outf, "%s\t%s\t",
X	       node->name, node->file);
X
X      if (node->f)
X	{		/* a function */
X	  putc (searchar, outf);
X	  putc ('^', outf);
X
X	  for (sp = node->pat; *sp; sp++)
X	    {
X	      if (*sp == '\\' || *sp == searchar)
X		putc ('\\', outf);
X	      putc (*sp, outf);
X	    }
X	  putc (searchar, outf);
X	}
X      else
X	{		/* a typedef; text pattern inadequate */
X	  fprintf (outf, "%d", node->lno);
X	}
X      putc ('\n', outf);
X    }
X  else if (vflag)
X    fprintf (stdout, "%s %s %d\n",
X	     node->name, node->file, (node->lno+63)/64);
X  else
X    fprintf (stdout, "%-16s%4d %-16s %s\n",
X	     node->name, node->lno, node->file, node->pat);
X
X  /* Output subentries that follow this one */
X  put_entries (node->right);
X}
X
X/* Return total number of characters that put_entries will output for
X the nodes in the subtree of the specified node.
X Works only if eflag is set, but called only in that case.  */
X
Xtotal_size_of_entries(node)
X     reg NODE *node;
X{
X  reg int total = 0;
X  reg long num;
X
X  if (node == NULL)
X    return 0;
X
X  /* Count subentries that precede this one */
X  total = total_size_of_entries (node->left);
X
X  /* Count subentries that follow this one */
X  total += total_size_of_entries (node->right);
X
X  /* Count this entry */
X
X  total += strlen (node->pat) + 3;
X
X  num = node->lno;
X  while (num)
X    {
X      total++;
X      num /= 10;
X    }
X
X  num = node->cno;
X  if (!num) total++;
X  while (num)
X    {
X      total++;
X      num /= 10;
X    }
X  return total;
X}
X
X/*
X * This routine finds functions and typedefs in C syntax and adds them
X * to the list.
X */
X#define CNL_SAVE_NUMBER \
X{ \
X  linecharno = charno; lineno++; \
X  charno += 1 + readline (&lb, inf); \
X  lp = lb.buffer; \
X}
X
X#define CNL \
X{ \
X  CNL_SAVE_NUMBER; \
X  number = 0; \
X}
X
XC_entries ()
X{
X  register int c;
X  register char *token, *tp, *lp;
X  logical incomm, inquote, inchar, midtoken;
X  int level;
X  char tok[BUFSIZ];
X
X  lineno = 0;
X  charno = 0;
X  lp = lb.buffer;
X  *lp = 0;
X
X  number = 0;
X  gotone = midtoken = inquote = inchar = incomm = FALSE;
X  level = 0;
X
X  while (!feof (inf))
X    {
X      c = *lp++;
X      if (c == 0)
X	{
X	  CNL;
X	  gotone = FALSE;
X	}
X      if (c == '\\')
X	{
X	  c = *lp++;
X	  if (c == 0)
X	    CNL_SAVE_NUMBER;
X	  c = ' ';
X	} 
X      else if (incomm)
X	{
X	  if (c == '*')
X	    {
X	      while ((c = *lp++) == '*')
X		continue;
X	      if (c == 0)
X		CNL;
X	      if (c == '/')
X		incomm = FALSE;
X	    }
X	}
X      else if (inquote)
X	{
X	  /*
X	  * Too dumb to know about \" not being magic, but
X	  * they usually occur in pairs anyway.
X	  */
X	  if (c == '"')
X	    inquote = FALSE;
X	  continue;
X	}
X      else if (inchar)
X	{
X	  if (c == '\'')
X	    inchar = FALSE;
X	  continue;
X	}
X      else switch (c)
X	{
X	case '"':
X	  inquote = TRUE;
X	  continue;
X	case '\'':
X	  inchar = TRUE;
X	  continue;
X	case '/':
X	  if (*lp == '*')
X	    {
X	      lp++;
X	      incomm = TRUE;
X	    }
X	  continue;
X	case '#':
X	  if (lp == lb.buffer + 1)
X	    number = 1;
X	  continue;
X	case '{':
X	  if (tydef == begin)
X	    {
X	      tydef=middle;
X	    }
X	  level++;
X	  continue;
X	case '}':
X	  if (lp == lb.buffer + 1)
X	    level = 0;	/* reset */
X	  else
X	    level--;
X	  if (!level && tydef==middle)
X	    {
X	      tydef=end;
X	    }
X	  continue;
X	}
X      if (!level && !inquote && !incomm && gotone == FALSE)
X	{
X	  if (midtoken)
X	    {
X	      if (endtoken(c))
X		{
X		  int f;
X		  char *buf = lb.buffer;
X		  int endpos = lp - lb.buffer;
X		  char *lp1 = lp;
X		  int line = lineno;
X		  long linestart = linecharno;
X		  int tem = consider_token (&lp1, token, &f);
X		  lp = lp1;
X		  if (tem)
X		    {
X		      if (linestart != linecharno)
X			{
X			  getline (linestart);
X			  strncpy (tok, token + (lb1.buffer - buf),
X				   tp-token+1);
X			  tok[tp-token+1] = 0;
X			  pfnote(tok, f, lb1.buffer, endpos, line, linestart);
X			}
X		      else
X			{
X			  strncpy (tok, token, tp-token+1);
X			  tok[tp-token+1] = 0;
X			  pfnote(tok, f, lb.buffer, endpos, line, linestart);
X			}
X		      gotone = f;	/* function */
X		    }
X		  midtoken = FALSE;
X		  token = lp - 1;
X		}
X	      else if (intoken(c))
X		tp++;
X	    }
X	  else if (begtoken(c))
X	    {
X	      token = tp = lp - 1;
X	      midtoken = TRUE;
X	    }
X	}
X      if (c == ';'  &&  tydef==end)	/* clean with typedefs */
X	tydef=none;
X    }
X}
X
X/*
X * This routine  checks to see if the current token is
X * at the start of a function, or corresponds to a typedef
X * It updates the input line * so that the '(' will be
X * in it when it returns.
X */
Xconsider_token (lpp, token, f)
X     char **lpp, *token;
X     int *f;
X{
X  reg char *lp = *lpp;
X  reg char c;
X  static logical next_token_is_func;
X  logical firsttok;	/* T if have seen first token in ()'s */
X  int bad, win;
X
X  *f = 1;			/* a function */
X  c = lp[-1];
X  bad = FALSE;
X  if (!number)
X    {		/* space is not allowed in macro defs	*/
X      while (iswhite(c))
X	{
X	  c = *lp++;
X	  if (c == 0)
X	    {
X	      if (feof (inf))
X		break;
X	      CNL;
X	    }
X	}
X      /* the following tries to make it so that a #define a b(c)	*/
X      /* doesn't count as a define of b.				*/
X    }
X  else
X    {
X      number++;
X      if (number >= 4  || (number==2 && strncmp (token, "define", 6)))
X	{
X	  gotone = TRUE;
X	badone:
X	  bad = TRUE;
X	  goto ret;
X	}
X    }
X  /* check for the typedef cases		*/
X  if (tflag && !strncmp(token, "typedef", 7))
X    {
X      tydef=begin;
X      goto badone;
X    }
X  if (tydef==begin && (!strncmp(token, "struct", 6) ||
X		       !strncmp(token, "union", 5) || !strncmp(token, "enum", 4)))
X  {
X    goto badone;
X  }
X  if (tydef==begin)
X    {
X      tydef=end;
X      goto badone;
X    }
X  if (tydef==end)
X    {
X      *f = 0;
X      win = 1;
X      goto ret;
X    }
X  /* Detect GNUmacs's function-defining macros. */
X  if (!number && !strncmp (token, "DEF", 3))
X	 
X    {
X      next_token_is_func = 1;
X      goto badone;
X    }
X  if (next_token_is_func)
X    {
X      next_token_is_func = 0;
X      win = 1;
X      goto ret;
X    }
X  if (c != '(')
X    goto badone;
X  firsttok = FALSE;
X  while ((c = *lp++) != ')')
X    {
X      if (c == 0)
X	{
X	  if (feof (inf))
X	    break;
X	  CNL;
X	}
X      /*
X	* This line used to confuse ctags:
X	*	int	(*oldhup)();
X	* This fixes it. A nonwhite char before the first
X	* token, other than a / (in case of a comment in there)
X	* makes this not a declaration.
X	*/
X      if (begtoken(c) || c=='/') firsttok++;
X      else if (!iswhite(c) && !firsttok) goto badone;
X    }
X  while (iswhite (c = *lp++))
X    {
X      if (c == 0)
X	{
X	  if (feof (inf))
X	    break;
X	  CNL;
X	}
X    }
X  win = isgood (c);
Xret:
X  *lpp = lp - 1;
X  return !bad && win;
X}
X
Xgetline (atchar)
X     long atchar;
X{
X  long saveftell = ftell (inf);
X
X  fseek (inf, atchar, 0);
X  readline (&lb1, inf);
X  fseek (inf, saveftell, 0);
X}
X
X/* Fortran parsing */
X
Xchar	*dbp;
Xint	pfcnt;
X
XPF_funcs(fi)
X     FILE *fi;
X{
X  lineno = 0;
X  charno = 0;
X  pfcnt = 0;
X
X  while (!feof (fi))
X    {
X      lineno++;
X      linecharno = charno;
X      charno += readline (&lb, fi) + 1;
X      dbp = lb.buffer;
X      if (*dbp == '%') dbp++ ;	/* Ratfor escape to fortran */
X      while (isspace(*dbp))
X	dbp++;
X      if (*dbp == 0)
X	continue;
X      switch (*dbp |' ')
X	{
X	case 'i':
X	  if (tail("integer"))
X	    takeprec();
X	  break;
X	case 'r':
X	  if (tail("real"))
X	    takeprec();
X	  break;
X	case 'l':
X	  if (tail("logical"))
X	    takeprec();
X	  break;
X	case 'c':
X	  if (tail("complex") || tail("character"))
X	    takeprec();
X	  break;
X	case 'd':
X	  if (tail("double"))
X	    {
X	      while (isspace(*dbp))
X		dbp++;
X	      if (*dbp == 0)
X		continue;
X	      if (tail("precision"))
X		break;
X	      continue;
X	    }
X	  break;
X	}
X      while (isspace(*dbp))
X	dbp++;
X      if (*dbp == 0)
X	continue;
X      switch (*dbp|' ')
X	{
X	case 'f':
X	  if (tail("function"))
X	    getit();
X	  continue;
X	case 's':
X	  if (tail("subroutine"))
X	    getit();
X	  continue;
X	case 'p':
X	  if (tail("program"))
X	    {
X	      getit();
X	      continue;
X	    }
X	  if (tail("procedure"))
X	    getit();
X	  continue;
X	}
X    }
X  return (pfcnt);
X}
X
Xtail(cp)
X     char *cp;
X{
X  register int len = 0;
X
X  while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
X    cp++, len++;
X  if (*cp == 0)
X    {
X      dbp += len;
X      return (1);
X    }
X  return (0);
X}
X
Xtakeprec()
X{
X  while (isspace(*dbp))
X    dbp++;
X  if (*dbp != '*')
X    return;
X  dbp++;
X  while (isspace(*dbp))
X    dbp++;
X  if (!isdigit(*dbp))
X    {
X      --dbp;		/* force failure */
X      return;
X    }
X  do
X    dbp++;
X  while (isdigit(*dbp));
X}
X
Xgetit()
X{
X  register char *cp;
X  char c;
X  char nambuf[BUFSIZ];
X
X  while (isspace(*dbp))
X    dbp++;
X  if (*dbp == 0 || !isalpha(*dbp))
X    return;
X  for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
X    continue;
X  c = cp[0];
X  cp[0] = 0;
X  strcpy(nambuf, dbp);
X  cp[0] = c;
X  pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
X  pfcnt++;
X}
X
X/*
X * lisp tag functions
X * just look for (def or (DEF
X */
X
XL_funcs (fi)
X     FILE *fi;
X{
X  lineno = 0;
X  charno = 0;
X  pfcnt = 0;
X
X  while (!feof (fi))
X    {
X      lineno++;
X      linecharno = charno;
X      charno += readline (&lb, fi) + 1;
X      dbp = lb.buffer;
X      if (dbp[0] == '(' && 
X	  (dbp[1] == 'D' || dbp[1] == 'd') &&
X	    (dbp[2] == 'E' || dbp[2] == 'e') &&
X	      (dbp[3] == 'F' || dbp[3] == 'f'))
X	{
X	  while (!isspace(*dbp)) dbp++;
X	  while (isspace(*dbp)) dbp++;
X	  L_getit();
X	}
X    }
X}
X
XL_getit()
X{
X  register char *cp;
X  char c;
X  char nambuf[BUFSIZ];
X
X  if (*dbp == 0) return;
X  for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
X    continue;
X  c = cp[0];
X  cp[0] = 0;
X  strcpy(nambuf, dbp);
X  cp[0] = c;
X  pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
X  pfcnt++;
X}
X
X/*
X * Scheme tag functions
X * look for (def... xyzzy
X * look for (def... (xyzzy
X * look for (def ... ((...(xyzzy ....
X * look for (set! xyzzy
X */
X
Xstatic get_scheme ();
XScheme_funcs (fi)
X     FILE *fi;
X{
X  lineno = 0;
X  charno = 0;
X  pfcnt = 0;
X
X  while (!feof (fi))
X    {
X      lineno++;
X      linecharno = charno;
X      charno += readline (&lb, fi) + 1;
X      dbp = lb.buffer;
X      if (dbp[0] == '(' && 
X	  (dbp[1] == 'D' || dbp[1] == 'd') &&
X	    (dbp[2] == 'E' || dbp[2] == 'e') &&
X	      (dbp[3] == 'F' || dbp[3] == 'f'))
X	{
X	  while (!isspace(*dbp)) dbp++;
X          /* Skip over open parens and white space */
X          while (*dbp && (isspace(*dbp) || *dbp == '(')) dbp++;
X	  get_scheme ();
X	}
X      if (dbp[0] == '(' && 
X	  (dbp[1] == 'S' || dbp[1] == 's') &&
X	    (dbp[2] == 'E' || dbp[2] == 'e') &&
X	      (dbp[3] == 'T' || dbp[3] == 't') &&
X                (dbp[4] == '!' || dbp[4] == '!') &&
X                  (isspace(dbp[5])))
X	{
X	  while (!isspace(*dbp)) dbp++;
X          /* Skip over white space */
X          while (isspace(*dbp)) dbp++;
X	  get_scheme ();
X	}
X    }
X}
X
Xstatic
Xget_scheme()
X{
X  register char *cp;
X  char c;
X  char nambuf[BUFSIZ];
X
X  if (*dbp == 0) return;
X  /* Go till you get to white space or a syntactic break */
X  for (cp = dbp+1; *cp && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
X    continue;
X  /* Null terminate the string there. */
X  c = cp[0];
X  cp[0] = 0;
X  /* Copy the string */
X  strcpy(nambuf, dbp);
X  /* Unterminate the string */
X  cp[0] = c;
X  /* Announce the change */
X  pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
X  pfcnt++;
X}
X
X/* Find tags in TeX and LaTeX input files.  */
X
X/* TEX_toktab is a table of TeX control sequences that define tags.
X   Each TEX_tabent records one such control sequence.  */
X
Xstruct TEX_tabent
X{
X  char *name;
X  int len;
X};
X
Xstruct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
X
X/* Default set of control sequences to put into TEX_toktab.
X   The value of environment var TEXTAGS is prepended to this.  */
X
Xstatic char *TEX_defenv =
X  ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
X
Xstruct TEX_tabent *TEX_decode_env (); 
X
Xstatic char TEX_esc = '\\';
Xstatic char TEX_opgrp = '{';
Xstatic char TEX_clgrp = '}';
X
X/*
X * TeX/LaTeX scanning loop.
X */
X
XTEX_funcs (fi)
X    FILE *fi;
X{
X  char *lasthit;
X
X  lineno = 0;
X  charno = 0;
X  pfcnt = 0;
X
X  /* Select either \ or ! as escape character.  */
X  TEX_mode (fi);
X
X  /* Initialize token table once from environment. */
X  if (!TEX_toktab)
X    TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
X
X  while (!feof (fi))
X    {
X      lineno++;
X      linecharno = charno;
X      charno += readline (&lb, fi) + 1;
X      dbp = lb.buffer;
X      lasthit = dbp;
X
X      while (!feof (fi))
X	{	/* Scan each line in file */
X	  lineno++;
X	  linecharno = charno;
X	  charno += readline (&lb, fi) + 1;
X	  dbp = lb.buffer;
X	  lasthit = dbp;
X	  while (dbp = index (dbp, TEX_esc)) /* Look at each escape in line */
X	    {
X	      register int i;
X
X	      if (! *(++dbp))
X		break;
X	      linecharno += dbp - lasthit;
X	      lasthit = dbp;
X	      i = TEX_Token (lasthit);
X	      if (0 <= i)
X		{
X		  TEX_getit (lasthit, TEX_toktab[i].len);
X		  break;		/* We only save a line once */
X		}
X	    }
X	}
X    }
X}
X
X#define TEX_LESC '\\'
X#define TEX_SESC '!'
X
X/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
X/* chars accordingly. */
X
XTEX_mode (f)
X     FILE *f;
X{
X  int c;
X
X  while ((c = getc (f)) != EOF)
X    if (c == TEX_LESC || c == TEX_SESC)
X      break;
X
X  if (c == TEX_LESC)
X    {
X      TEX_esc = TEX_LESC;
X      TEX_opgrp = '{';
X      TEX_clgrp = '}';
X    } 
X  else
X    {
X      TEX_esc = TEX_SESC;
X      TEX_opgrp = '<';
X      TEX_clgrp = '>';
X    }
X  rewind (f);
X}
X
X/* Read environment and prepend it to the default string. */
X/* Build token table. */
X
Xstruct TEX_tabent *
XTEX_decode_env (evarname, defenv)
X     char *evarname;
X     char *defenv;
X{
X  register char *env, *p;
X  extern char *savenstr (), *index ();
X
X  struct TEX_tabent *tab;
X  int size, i;
X
X  /* Append deafult string to environment. */
X  env = (char *) getenv (evarname);
X  if (!env)
X    env = defenv;
X  else
X    env = concat (env, defenv, "");
X
X  /* Allocate a token table */
X  for (size = 1, p=env; p;)
X    if ((p = index (p, ':')) && *(++p))
X      size++;
X  tab = (struct TEX_tabent *) xmalloc (size * sizeof (struct TEX_tabent));
X
X  /* Unpack environment string into token table. Be careful about */
X  /* zero-length strings (leading ':', "::" and trailing ':') */
X  for (i = 0; *env;)
X    {
X      p = index (env, ':');
X      if (!p)			/* End of environment string. */
X	p = env + strlen (env);
X      if (p - env > 0)
X	{	/* Only non-zero strings. */
X	  tab[i].name = savenstr (env, p - env);
X	  tab[i].len = strlen (tab[i].name);
X	  i++;
X	}
X      if (*p)
X	env = p + 1;
X      else
X	{
X	  tab[i].name = NULL;	/* Mark end of table. */
X	  tab[i].len = 0;
X	  break;
X	}
X    }
X  return tab;
X}
X
X/* Record a tag defined by a TeX command of length LEN and starting at NAME.
X   The name being defined actually starts at (NAME + LEN + 1).
X   But we seem to include the TeX command in the tag name.  */
X
XTEX_getit (name, len)
X    char *name;
X    int len;
X{
X  char *p = name + len;
X  char nambuf[BUFSIZ];
X
X  if (*name == 0) return;
X
X  /* Let tag name extend to next group close (or end of line) */
X  while (*p && *p != TEX_clgrp)
X    p++;
X  strncpy (nambuf, name, p - name);
X  nambuf[p - name] = 0;
X
X  pfnote (nambuf, TRUE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
X  pfcnt++;
X}
X
X/* If the text at CP matches one of the tag-defining TeX command names,
X   return the index of that command in TEX_toktab.
X   Otherwise return -1.  */
X
X/* Keep the capital `T' in `Token' for dumb truncating compilers
X   (this distinguishes it from `TEX_toktab' */
XTEX_Token (cp)
X    char *cp;
X{
X  int i;
X
X  for (i = 0; TEX_toktab[i].len > 0; i++)
X    if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
X      return i;
X  return -1;
X}
X
X/* Initialize a linebuffer for use */
X
Xvoid
Xinitbuffer (linebuffer)
X     struct linebuffer *linebuffer;
X{
X  linebuffer->size = 200;
X  linebuffer->buffer = (char *) xmalloc (200);
X}
X
X/* Read a line of text from `stream' into `linebuffer'.
X Return the length of the line.  */
X
Xlong
Xreadline (linebuffer, stream)
X     struct linebuffer *linebuffer;
X     register FILE *stream;
X{
X  char *buffer = linebuffer->buffer;
X  register char *p = linebuffer->buffer;
X  register char *pend = p + linebuffer->size;
X
X  while (1)
X    {
X      int c = getc (stream);
X      if (p == pend)
X	{
X	  buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
X	  p += buffer - linebuffer->buffer;
X	  pend = buffer + linebuffer->size;
X	  linebuffer->buffer = buffer;
X	}
X      if (c < 0 || c == '\n')
X	{
X	  *p = 0;
X	  break;
X	}
X      *p++ = c;
X    }
X
X  return p - buffer;
X}
X
Xchar *
Xsavestr(cp)
X     char *cp;
X{
X  return savenstr (cp, strlen (cp));
X}
X
Xchar *
Xsavenstr(cp, len)
X    char *cp;
X    int len;
X{
X  register char *dp;
X
X  dp = (char *) xmalloc (len + 1);
X  strncpy (dp, cp, len);
X  dp[len] = '\0';
X  return dp;
X}
X
X/*
X * Return the ptr in sp at which the character c last
X * appears; NULL if not found
X *
X * Identical to v7 rindex, included for portability.
X */
X
Xchar *
Xrindex(sp, c)
X     register char *sp, c;
X{
X  register char *r;
X
X  r = NULL;
X  do
X    {
X      if (*sp == c)
X	r = sp;
X    } while (*sp++);
X  return(r);
X}
X#ifndef __ZTC__
X/*
X * Return the ptr in sp at which the character c first
X * appears; NULL if not found
X *
X * Identical to v7 index, included for portability.
X */
X
Xchar *
Xindex(sp, c)
X     register char *sp, c;
X{
X  do
X    {
X      if (*sp == c)
X	return (sp);
X    } while (*sp++);
X  return (NULL);
X}
X#endif
X/* Print error message and exit.  */
X
Xfatal (s1, s2)
X     char *s1, *s2;
X{
X  error (s1, s2);
X  exit (1);
X}
X
X/* Print error message.  `s1' is printf control string, `s2' is arg for it. */
X
Xerror (s1, s2)
X     char *s1, *s2;
X{
X  fprintf (stderr, "%s: ", progname);
X  fprintf (stderr, s1, s2);
X  fprintf (stderr, "\n");
X}
X
X/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
X
Xchar *
Xconcat (s1, s2, s3)
X     char *s1, *s2, *s3;
X{
X  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
X  char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
X
X  strcpy (result, s1);
X  strcpy (result + len1, s2);
X  strcpy (result + len1 + len2, s3);
X  *(result + len1 + len2 + len3) = 0;
X
X  return result;
X}
X
X/* Like malloc but get fatal error if memory is exhausted.  */
X
Xint
Xxmalloc (size)
X     int size;
X{
X  int result = malloc (size);
X  if (!result)
X    fatal ("virtual memory exhausted", 0);
X  return result;
X}
X
Xint
Xxrealloc (ptr, size)
X     char *ptr;
X     int size;
X{
X  int result = realloc (ptr, size);
X  if (!result)
X    fatal ("virtual memory exhausted");
X  return result;
X}
SHAR_EOF
echo shar: extracting "'etags.dif'" '(112 characters)'
sed 's/^X//' << \SHAR_EOF > 'etags.dif'
X433c433
X< #ifdef __TURBOC__
X---
X> #ifdef __MSDOS__
X1533c1533
X< 
X---
X> #ifndef __ZTC__
X1552c1552
X< 
X---
X> #endif
SHAR_EOF
echo shar: extracting "'etags.cmd'" '(3068 characters)'
sed 's/^X//' << \SHAR_EOF > 'etags.cmd'
X; Find C tags for MicroEMACS 3.10
X; Author: Reimer Mellin
X; Modified by: David MacKenzie
X; Latest revision: 13 May 1989
X
X; These macros go to the tag in a second window using a vi format tags
X; file (not a GNU Emacs format TAGS file).
X
Xset $discmd FALSE ; Don't display messages on command line.
Xset %tags "tags"
X
X
X
X; Search for the tag of the identifier that starts at point.
Xstore-procedure find-point-tag
X	setup-tags
X	!if &not %ok
X		!return
X		!endif
X	set %savemode $cmode
X	add-mode "magic"
X	!force search-forward "[^0-9A-Za-z_]"	; search for end of identifier
X	set $cmode %savemode
X	backward-character
X	copy-region		; get identifier
X	!if &sequal $kill ""
X		write-message "No tag specified"
X		set $discmd TRUE
X		!return
X		!endif
X	set %ident $kill
X	set %ffirst TRUE
X	find-tags
X	!endm
Xmacro-to-key find-point-tag M-T
X
X
X
X
X; Search for the tag of the identifier prompted for in the message line.
Xstore-procedure find-msg-tag
X	setup-tags
X	!if &not %ok
X		!return
X		!endif
X	set %ident @"Search for tag: "
X	!if &sequal %ident "ERROR"
X		write-message "[Aborted]"
X		!return
X		!endif
X	set %ffirst TRUE
X	find-tags
X	!endm
Xmacro-to-key find-msg-tag ^XT
X
X
X
X
Xstore-procedure find-next-tag
X	setup-tags
X	set %o-buf $cbufname
X	set %ffirst FALSE
X	find-tags
X	!endm
Xmacro-to-key find-next-tag M-^T
X
X
Xstore-procedure setup-tags
X	set $discmd FALSE
X
X	!if &not  &exist %tags
X		write-message "No tags file"
X		set %ok FALSE
X		!return
X		!endif
X	set %startcwl $cwline
X	set-mark
X	set %ok TRUE
X	!endm
X
X
X
X
Xstore-procedure find-tags
X	write-message  &cat  "Searching for tag "  &cat %ident " . . ."
X
X	!if %ffirst
X		delete-other-windows
X		set %lfrombot  &sub $wline $cwline
X		%lfrombot next-line	; go to last line of window
X		split-current-window
X		previous-window
X		; complicated calculation for restoring the old context
X		%lfrombot previous-line
X		exchange-point-and-mark	; return to original point
X		!if &less $wline %startcwl
X			set %startcwl $wline
X			!endif
X		!if &less $cwline %startcwl
X			&sub %startcwl $cwline  move-window-up
X			!endif
X		next-window
X		!endif
X	find-file %tags
X	add-mode "exact"
X	add-mode "magic"
X	!if %ffirst
X		beginning-of-file	; rewind tags file
X		!endif
X	!force  search-forward  &cat "[^a-zA-Z0-9_]" &cat %ident &cat "[( ]" &chr 127
X	!if &not $status
X		!if %ffirst
X			set %errmesg &cat %ident ": No such tag in tags file"
X*error1
X			!force 		delete-window
X*error2
X		!else
X			set %errmesg &cat "No more occurences of tag " %ident
X			select-buffer %o-buf
X			%lno goto-line
X			!endif
X		write-message %errmesg
X		set $discmd TRUE
X		!return
X		!endif
X	set-mark
X	search-forward ","
X	backward-character
X	copy-region
X	set %lno $kill
X	set %slno $curline
X	; extract filename
X	search-reverse "~f"
X	2 forward-character
X	set-mark
X	search-forward ","	; find tab after filename
X	backward-character
X	copy-region
X	set %tagfile $kill
X	%slno goto-line
X	end-of-line
X	!force  find-file %tagfile
X	!if &not $status
X		set %errmesg  &cat %tagfile " not found"
X		!goto error1
X		!endif
X	%lno goto-line
X	clear-message-line
X	set $discmd TRUE
X	!endm
X
Xset $discmd TRUE ; Display messages on command line.
SHAR_EOF
echo shar: extracting "'read.me'" '(4386 characters)'
sed 's/^X//' << \SHAR_EOF > 'read.me'
X
X
X
X                       ETAGS For MicroEmacs
X
X    I had been using the CTAGS macros for MicroEmacs as
Xoriginally written Reimer Mellin and David MacKenzie for some
Xtime.  The tools worked quite well except for the problem of
Xmultiple definitions of the same function (either in the same
Xmodule via #ifdef, or different modules).  The macros could be
Xmodified to handle multiple inclusions in different files but
XCTAGS will not include multiple declarations in the same file.
XSince I mainly work with systems made up of several programs  and
Xmany files with multiple declarations of functions whose
Xcompilation is controlled by #ifdef directives, I needed a little
Xmore.  The end result is the macros defined in ETAGS.CMD and the
Xprogram ETAGS.EXE. The ETAGS program is directly from FSF by way
Xof a Freemacs ETAGS package with  very slight changes to allow it
Xto compile under MSDOS with either TurboC, Micrtosoft C, or
XZortech C.  
X
X    The procedures defined in ETAGS.CMD work with a TAGS file
Xformat generated with the -e option to the etags program. If you
Xare initially creating the TAGS file for your set of sources you
Xcan simply enter
X
X                           ETAGS -e *.C
X
XThe STRIPTAG program is provided so that you may update the TAGS
Xfile without having to rerun ETAGS across the entire set of
Xfiles. Striptag removes references to any file specified on the
Xcommand line. If you update one of the source files you can
Xupdate the TAGS file by entering the following command sequence
X(assuming that the file you are updating is foo.c)
X
X                          STRIPTAG  foo.c
X                          ETAGS -ea foo.c
X
XThen (after executing the etags.cmd file from within MicroEmacs,
Xyou can easily (?) find any function within any of the c functions
Xcontained in the .C files with the
X
X             M-T  (<Esc>T)     - Find-Tag-At-Point  or
X             ^X-T (CtrlX T)    - Find-Tag-Message or
X             M-^T (<Esc>CtrlT) - Find-Next-Tag
X
Xkeys. If the function you are interested in is defined in multiple
Xfiles, or multiple times in the same file you may look for the
Xadditional occurences of it by using the Find-Next-Tag key.
X
X    It is also possible to use the -f tagfilename option with
XETAGS and STRIPTAG to use a tagfile with a different name.  This
Xtag file can be used from within MicroEmacs by changing the value
Xof the variable %tags from "tags" to whatever your tagfile is
Xnamed - after loading the etags.cmd file.
X
X    With the exception of STRIPTAG.C, the files in this
Xarchive have all been written by someone other than me.  I just
Xput them together in a slightly different manner.
X
X    ETAGS.CMD  - Is based on the TAGS Macros produced by Reimer
X                 Mellin and David MacKenzie.  Essentially, all I
X                 did was tweek their code to use an Etags Format
X                 TAGS file. 
X
X    ETAGS.C    - It comes from GNU and was originally slightly
X                 modified for MSDOS Use and was part of a FREEMACS
X                 distribution.  I modified it Very slightly to get
X                 it to compile with the Zortech and MSC compilers.
X
X    MAKEFILE   - A makefile to use with TCC, ZTC, or MSC (if you
X                 have a reasonable make utility).
X
X    SETARGV.C  - Source to wildcard argument expansion module
X                 needed with TCC V1.5.
X
X    STRIPTAG.C - Source to program to remove tags file entries for
X                 a specific program source.
X
X    If you look at the various invocations in the makefile
Xfor ETAGS.EXE, you will notice that the ETAGS.C is linked in with
Xdifferent object modules depending upon the version of compiler
Xyou are using.  This is to provide wildcard filename expansion
Xfrom the command line when ETAGS is executed.  The Zortech and
XMicrosoft compilers are pretty cut and dried about the process. 
XThat is to say that setargv.obj is provided to you directly in
Xthe Microsoft distribution (as is _MAINS.OBJ in the Zortech
Xdistribution).  Borland is another matter.  The file setargv.c is
Xprovided for use by users of TC V1.5 (in case thay haven't
Xalready snarfed it up somewhere else). If you have TC V2.0 you
Xwill have to snoop around in the sources provided in your
Xdistribution and find the file SETARGV.ASM and assemble it with
Xthe proper switch settings to create WILDARGV.OBJ.
X
X- jb@altair.csustan.edu
X- John Birchfield
X- 1575 Quail Court
X- Turlock, CA 95380
SHAR_EOF
echo shar: extracting "'striptag.c'" '(2325 characters)'
sed 's/^X//' << \SHAR_EOF > 'striptag.c'
X/*
X *                              STRIPTAG.C
X *
X * A little program to strip out tags entries from a TAGS file
X * created with the -e option to etags.  Let's say you wanted to
X * update the portion of TAGS pertaining to foo.c.  You would enter
X * the following sequence of commands...
X *
X *     striptag  foo.c
X *     etags -ea foo.c
X *
X *                            ---   jb   ---
X *                             Dec 26, 1989
X */
X
X#include <stdio.h>
X#include <io.h>
X
Xchar TagName [74] = { "TAGS" };
X
Xint copyfile (char *, char *);
X
Xmain (int argc, char *argv [])
X{
X	FILE *in, *out;
X	char  line [256];
X	int   i;
X
X	if (argc > 2 && !strcmp (argv [1], "-f"))
X	{
X		strcpy (TagName, argv [2]);
X		argc -= 2;
X		argv += 2;
X	}
X	if (argc < 2)
X	{
X		fputs ("StripTag: No Arguments\n", stderr);
X		fputs ("Usage:  striptag [-f tagfilename] sourcefile [sourcefile]\n",
X               stderr);
X		exit (1);
X	}
X	if (!copyfile (TagName, "OTAGS"))
X	{
X		fputs ("StripTag: Couldn't create backup file OTAGS\n", stderr);
X		exit (1);
X	}
X	if ((in=fopen ("OTAGS", "r"))== (FILE *) 0)
X	{
X		unlink ("OTAGS");
X		fputs ("StripTag: Couldn't open backup file OTAGS for input\n", stderr);
X		exit (1);
X	}
X	if ((out=fopen (TagName, "w"))== (FILE *) 0)
X	{
X		fputs ("StripTag: Couldn't open file ", stderr);
X		fputs (TagName, stderr);
X		fputs (" for output\n", stderr);
X		exit (1);
X	}
X	while (fgets (line, 256, in))
X	{
X		if (!strncmp (line, "\f", 1))
X		{
Xnextgroup:
X			if (!fgets (line, 256, in))
X				goto eofile;
X			for (i = 1; i < argc; i++)
X			{
X				if (!strncmp (line, argv [i], strlen (argv [i])))
X				{
X					while (fgets (line, 256, in))
X					{
X						if (!strncmp (line, "\f", 1))
X							goto nextgroup;
X					}
X					goto eofile;
X				}
X			}
X			fputs ("\f\n", out);
X			fputs (line, out);
X		}
X		else
X			fputs (line, out);
X	}
Xeofile:
X	fclose (in);
X	fclose (out);
X	unlink ("OTAGS");
X}
X
X
X
X
X/*--------------------------- copyfile () ---------------------------*/
X/*
X * Duplicate the file "iname" to "oname".
X */
Xint
Xcopyfile (char *iname, char *oname)
X{
X	FILE *in, *out;
X	char buffer [512];
X	int count;
X	if ((in=fopen (iname, "rb"))==(FILE *) 0)
X		return 0;
X	if ((out=fopen (oname, "wb"))==(FILE *) 0)
X	{
X		fclose (in);
X		return (0);
X	}
X	while (count = fread (buffer, 1, 512, in))
X	{
X		fwrite (buffer, 1, count, out);
X	}
X	fclose (in);
X	fclose (out);
X	return 1;
X}
SHAR_EOF
echo shar: extracting "'setargv.c'" '(5142 characters)'
sed 's/^X//' << \SHAR_EOF > 'setargv.c'
X/* setargv -- setup argv with wild card expansion                           */
X/* copyright 1987  Michael M Rubenstein                                     */
X
X/* This program may be freely distributed provided no fee is assessed.      */
X
X/* This file implements wild card expansion in argv for Turbo C 1.5.        */
X/* Strings of characters in either quotes (") or appostrophes (') on the    */
X/* command line are considered a single argument.  However, backslash       */
X/* escapes are not implemented.  A quote may be included in an argument     */
X/* which is enclosed in appostrophes and an appostrophe may be included     */
X/* in an argument enclosed in quotes.  Either may be included as an         */
X/* in an argument starting with any other character.                        */
X
X/* Any argument which is not enclosed in quotes or appostrophes, does not   */
X/* begin with a hyphen (-), and which contains an asterisk (*) or question  */
X/* mark (?) will be expanded.  It is NOT an error for an argument to have a */
X/* null expansion (no matching files).  Only ordinary files (not            */
X/* directories or hidden or system files) will be included in the           */
X/* expansion.                                                               */
X
X/* To use this function, simply compile it with the appropriate memory      */
X/* model and include in the link.  This can be accomplished very simply     */
X/* in the integrated environment by simply including this file in the       */
X/* project file.  In the command line version, simply include this file     */
X/* (or a precompiled .OBJ version) on the command line.                     */
X
X#include <ctype.h>
X#include <dir.h>
X#include <dos.h>
X#include <process.h>
X
X#define FALSE           0
X#define TRUE            1
X
Xvoid                    putarg(unsigned char far *, unsigned char far *);
X
Xextern int              _argc;  /* NB: for TC 1.0, change to __argc */
Xextern char             **_argv;  /* NB: for TC 1.0, change to __argv */
Xextern unsigned         _psp;
Xextern unsigned         _envseg;
Xextern unsigned         _envLng;
Xextern unsigned char    _osmajor;
Xextern void             _abort();
Xextern char             *sbrk(int);
X
Xvoid _setargv()
X{
X  unsigned char         far *cmdtail;
X  unsigned char         *firstarg;
X  unsigned char         far *cmdarg;
X  int                   wild;
X  int                   c;
X  unsigned char         buffer[129];
X  unsigned char         *p, *q;
X  unsigned char         *lastdir;
X  char                  **wargv;
X  int                   i;
X  struct ffblk          ffb;
X
X  cmdtail = MK_FP(_psp, 0x81);
X  cmdtail[cmdtail[-1]] = '\0';      /* make sure null at end */
X  firstarg = (unsigned char *) sbrk(0);
X  _argc = 1;
X
X  while (*cmdtail != '\0')
X  {
X    /* skip white space */
X    while (isascii(*cmdtail) && isspace(*cmdtail))
X      ++cmdtail;
X
X    /* done with command loop if end of command tail */
X    if (*cmdtail == '\0')
X      break;
X
X    /* if quoted string, just save the argument */
X    if ((c = *cmdtail) == '"' || c == '\'')
X    {
X      cmdarg = ++cmdtail;
X      while (*cmdtail != c && *cmdtail != '\0')
X        ++cmdtail;
X      putarg(cmdarg, cmdtail);
X      if (*cmdtail != '\0')
X        ++cmdtail;
X      continue;
X    }
X
X    /* find word */
X    cmdarg = cmdtail;
X    wild = FALSE;
X    p = lastdir = buffer;
X    while ((c = *cmdtail) != '\0'
X        && (!isascii(c) || !isspace(c)))
X    {
X      /* wild is TRUE if word contains * or ? */
X      wild |= (c == '*' || c == '?');
X/*  Next line was added to make the treatment of / and \ alike     */
X      if (c == '/') c = '\\'; 
X      *(p++) = c;
X
X      /* lastdir points to the first character of the base file name */
X      if (c == '\\' || c == ':')
X        lastdir = p;
X      ++cmdtail;
X    }
X    *p = '\0';
X
X    if (wild && *cmdarg != '-')
X      for (c = findfirst((char *) buffer, &ffb, 0);
X           c == 0;
X           c = findnext(&ffb))
X      {
X        /* use lower case for wild card expanded names (my prejudice) */
X        for (p = lastdir, q = (unsigned char *) ffb.ff_name; *q != '\0';)
X             *(p++) = tolower(*(q++));
X          ;
X        putarg(buffer, p);
X      }
X    else
X      putarg(cmdarg, cmdtail);
X  }
X
X  /* allocate argv */
X  if ((wargv = (char **) sbrk(sizeof(char *) * (_argc + 1))) == (char **) -1)
X    abort();
X  _argv = wargv;
X
X  /* store program name */
X  if (_osmajor < 3)
X    *(wargv++) = "C";
X  else
X  {
X      cmdtail = cmdarg = MK_FP(_envseg, _envLng + 2);
X#   if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
X      *(wargv++) = sbrk(0);
X      while (*cmdtail != '\0')
X        ++cmdtail;
X      putarg(cmdarg, cmdtail);
X      --_argc;
X#   else
X      *(wargv++) = (char *) cmdarg;
X#   endif
X  }
X
X  /* store arguments */
X  for (i = _argc; --i;)
X  {
X    *(wargv++) = (char *) firstarg;
X    while(*++firstarg != '\0')
X      ;
X    ++firstarg;
X  }
X  *wargv = (char *) 0;
X}
X
Xstatic void putarg(from, to)
X  unsigned char         far *from, far *to;
X{
X  char                  *p;
X
X  if ((p = sbrk(to - from + 1)) == (char *) -1)
X    abort();
X  while (from < to)
X   *(p++) = *(from++);
X  *p = '\0';
X  ++_argc;
X}
SHAR_EOF
echo shar: done with directory "'etags'"
cd ..
#	End of shell archive
exit 0
+----------------------
| John Birchfield      
| jb@altair.csustan.edu
+----------------------