[comp.emacs] MicroEmacs 3.9 ctags package

cassirer@batgirl.rtp.dg.com (Fred Cassirer) (08/10/89)

I've recently completed a tags package using MicroEmacs 3.9e, it's not
all that big so I figured I'd post it.  It works with all the versions of
emacs that I've tried, Amiga, Sun and DG/UX.

I have a poor mans version of "dired", an enhanced version MicroSpell's
"scan.cmd" that will spell check an emacs buffer within emacs, and
a version of "list-buffers" that will allow you to delete the buffers
in the list-buffers window by hitting a "d" on the line the buffer is on.

If anyone is interested I'll send them via email, or if there is enough
interest, I'll post.  The "dired" procedures only run on the Amiga version
because &gtkey does not work under Unix, I'm not sure why ... yet.

I' cross-posting this to comp.sys.amiga and comp.emacs.


P.S.

	Does anyone know where I can get a copy of MicroEmacs 3.10??

=========================================================================
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	tags.doc
#	tags.cmd
# This archive created: Thu Aug  3 23:23:05 1989
cat << \SHAR_EOF > tags.doc


  -=-=-=-=-=-=-=-=- MicroEmacs 3.9e Ftags package =-=-=-=-=-=-=-=-=-=

  FTags provide a convenient method of browsing source code.  Typically
  a file called "tags" is created by the Unix utility "ctags".  "ctags"
  creates a list of symbols, the file they are defined in, and a line
  number or unique search string within the file.  There is a public
  domain version of ctags in the unix mod.sources library vol_03 written
  by Ken Arnold.  This version of ctags successfully compiles on the Amiga
  with the -u options commented out (uses unix system() call).

  With some small modifications (included) Ftags will also work with the
  Manx ctags output.

  These macros have successfully run on an Amiga 1000 under WorkBench 1.3, 
  Data General MV and Aviion DG/UX Unix, and Sun/3 OS.

  
  How it works:

	 *Update MicroEmacs source as specified in tags.cmd
          Place tags.cmd in a known directory.
	  Modify your emacs startup file to call "tags.cmd" as per
  	  the following macros -


	set %home &env "HOME"

	3 store-macro
	  execute-file &cat %home "/tags.cmd"    ; Unix
	  execute-file "s:tags.cmd"		 ; Amiga
	  execute-macro-21
	!endm

	bind-to-key execute-macro-3          M-t

	4 store-macro
	  execute-file &cat %home "/tags.cmd"	  ; Unix (home directory)
	  execute-file "s:tags.cmd"		  ; Amiga
	  execute-macro-22
	!endm

	bind-to-key execute-macro-4          ^]

	26 store-macro
	execute-file "s:tags.cmd"
	execute-macro-27
	!endm

	bind-to-key execute-macro-26	     M-^t

	Macros 3&4 will allow you a much faster .emacsrc.  The only time
	that emacs will parse the tags.cmd file is the first time you 
	actually need to tag to a symbol.  Macro 26 will allow you to
	redefine the default tag file by prompting you for a different
	tags file.
  
   *Note:  You may not need these changes, they have to do with handling
	   long %string variables in emacs's macro language.  
           

	To start everything rolling, go to the source directory that 
	contains the tags file.  Bring up emacs and hit escape-t (M-t).
	You will be prompted for a tag.  Enter the name of the tag and
	hit return.  At this point emacs will load the tags file, escape
	any * meta-characters, and add magic mode.  It will then search
	out the tag, load the corresponding file, and search for the
	symbol.

	Once you have a file, you can either use M-t to enter new tags,
	or you can position the cursor near a symbol and hit ^].  
	^] will skip over white space and various non-identifier characters
	before starting to gather a symbol, for example

		status = ++(*(myfunc(arg)))
	 	      ^       ^

		if the cursor is anywhere between the 1st and 2nd ^, the
		^] would lookup the routine "myfunc()"

	You can use ^] or M-t in any combination.  As you tag thru a file,
	a stack is being kept of tagg'd buffer locations.  You can back
	out from the current tag by hitting M-p (escape p).  This should
	return to the previously tagged buffer/position.
	

	
	This package is PD all the way, if you have any improvements or
	problems let me know.

					-FredC
					

 /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
<  Fred Cassirer			   ... rti!rtp48!cassirer     	   >
<  Data General Corporation               Research Triangle Park, NC       >
 \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

SHAR_EOF
cat << \SHAR_EOF > tags.cmd
;
; Use a standard tags file so that source browsing is easier within 
;  MicroEMACS 3.9e.
;
;			file - "tags.cmd"
;
; Written July 5, 1989 - Fred Cassirer (rti!dg.rtp.com!cassirer)
;
; Parse a "tags" file to bounce around source easily.  This set of macros
; runs on a slightly modified version of MicroEMACS3.9e.  The modifications 
; are some bug fixes I made in order for the &mid and &left functions to 
; work correctly.  Basically, in eval.c, UFLEFT and UFMID switch labels
; return an strncpy which did/does not properly terminate the result string.
;
;	At line 78 in eval.c:
;
;		case UFLEFT:	strncpy(result, arg1, atoi(arg2));
;				result[atoi(arg2)] = '\0';  /* term string */
;				return(result);
;		case UFRIGHT:	return(strcpy(result,
;					&arg1[(strlen(arg1) - atoi(arg2))]));
;		case UFMID:	strncpy(result, &arg1[atoi(arg2)-1],
;					atoi(arg3));
;				result[atoi(arg3)] = '\0'; /* term string */
;				return(result);
;
;  In .emacsrc bind  M-t (or whatever you like) to:
;3 store-macro
;  execute-file "tags.cmd"
;  execute-macro-21
;!endm
;
;4 store-macro
;  execute-file "tags.cmd"
;  execute-macro-22
;!endm
;
; Macros 3&4 will allow you a much faster .emacsrc.  The only time that emacs
; will parse the tags.cmd file is the first time you actually need to tag to
; a symbol.
;
;bind-to-key execute-macro-3          M-t
;bind-to-key execute-macro-4          ^]
;
;  Now that everything is set, just hit M-t and you will be prompted for
; a tag.  Enter a tag and the file will be located and displayed at the
; needed place.  You can continue from here to tag further, using either
; ^] or M-t (^] will look up the symbol under the cursor).  When you are
; done you can hit M-p to "pop" back to each previous tag buffer, deleting
; the pop'd buffer as you go.
;
;  The format of the tag buffer is as follows:
;
;  symbol-name<tab>file-name<tab>/regular expression/
;     		or
;  symbol-name<tab>file-name<tab>#####  (where #### is a line number)
;
;  There can only be one <tab> seperating the 1st two fields.
;
;  This macro package also works on the Amiga version of MicroEmacs3.9e using
;  the Manx ctags command.  The one difference is that Manx ctags use's spaces
;  to delimit the fields and doesn't place an ending slash on the regular-exp.
;  To use this with Manx ctags command change the marked lines.
;

set $discmd 0

set %ctags_sep "~t"  ;The sepeartor character in the tags file (Unix)
;set %ctags_sep " "  ;The sepeartor character in the tags file (Manx/Amiga)

set %tagsfile "tags"

27 store-macro
    set %tagsfile @"tag file? "
    write-message "Append?(y/n)"
    run push-buffer
    !if &sequal &upper &gtk "N"
    	    set %load-tags 0
            run load-tags
    !else
            run append-tags
    !endif
    run pop-buffer
!endm

bind-to-key execute-macro-27  M-^t

set %load-tags 0
; Load the tags file
store-procedure load-tags
	set $discmd 0
	!if &equal %load-tags 0
		select-buffer "_tags"
		name-buffer "$$_killtags"
		find-file %tagsfile
		name-buffer "_tags"
		!force delete-buffer "$$_killtags"
		set $cmode 0
		replace-string "*" "\*"
		unmark-buffer
		set $cmode 72
		set %load-tags 1
	!endif
	set $discmd 1
	!return
!endm

; Append a tags buffer to the current one, this is good for multiple
; directories each with it's own tags file

store-procedure append-tags
	set $discmd 0
	!if &equal %load-tags 1
		select-buffer "_tags"
		end-of-file
		set-mark
		insert-file %tagsfile
		exchange-point-and-mark
		set $cmode 0
		replace-string "*" "\*"
		set $cmode 72
		unmark-buffer
		write-message &cat "[ " &cat %tagsfile " appended to tag buffer ]"
	!endif
	set $discmd 1
	!return
!endm

; Input a tag at the command line
21 store-macro
	set %savesearch $search
	set %search &cat "^" @"tag? "
	set $search %savesearch
	set %search &cat %search %ctags_sep
	run tag-to-buffer
!endm

; Take the current word in the buffer and use it as a tag
; This command will skip over white space and any characters
;  in "%tokenizer" before it starts to look for the symbol.

set %tokenizer " ~t~n;!@#$%^&*()-+=~~|?/<>~":[]"
22 store-macro
	set %tmp &sindex %tokenizer &chr $curchar
	!if &greater %tmp 0
		!while &greater %tmp 0
			forward-character
			set %tmp &sindex %tokenizer &chr $curchar
		!endwhile
	!endif

	set %search "^"

	!while &equal %tmp 0
		set %search &cat %search &chr $curchar
		forward-character
		set %tmp &sindex %tokenizer &chr $curchar
	!endwhile
	!if &sequal %search "^"
		write-message "[Couldn't find a symbol!]"
		!return
	!endif
	set %search &cat %search %ctags_sep
	run tag-to-buffer
!endm

; Given %search, go track down the file and get to the spot
; This is the real guts of the work here, push the current location
; and locate the new %search string in the _tags buffer

store-procedure tag-to-buffer
	run push-buffer
	set %savesearch $search
	run load-tags
	select-buffer "_tags"
	beginning-of-file
	!force search-forward %search
	!if &not $status
		run pop-buffer
		write-message "[Couldn't find tag in tags file, sorry.]"
		!return
	!endif
	beginning-of-line
	set %tagline #_tags
	set %l &sub &sindex %tagline %ctags_sep 1
	set %func &left %tagline %l
	set %l &add %l 2
	set %ln &len %tagline
	set %tagline &mid %tagline %l %ln
	set %l &sub &sindex %tagline %ctags_sep 1
	set %file &left %tagline %l

	!force find-file %file
	!if &not $status
		if &not &sequal $cbufname %file
			run pop-buffer
			write-message "[Couldn't find file for tag, sorry.]"
			set $search %savesearch
			!return
		!endif
		beginning-of-file
	!endif

	set $cmode 74
	set %l &add %l 2
	set %search &mid %tagline %l 127
	set %tmp &left %search 1
	!if &sindex "0123456789" %tmp
		%search goto-line 
	!else

;  If using Manx ctags, comment this line out.  It strips off the ending slash
;   in the regular expression.

		set %ln &sub &len %search 2   ; Manx Ctags doesn't have a 
					      ; trailing slash

		set %search &mid %search 2 %ln
		!force search-forward %search
		!if &not $status 	; Found the file, but not the tag
			run pop-buffer
			write-message "[Couldn't find tag. Tag file out of date? ]"
			set $search %savesearch
			!return
		!endif
	!endif
	beginning-of-line
	update-screen
	set $search %savesearch
	!return
!endm

set %stack ""
set %stklvl 0

; Push a buffer on the psuedo-stack.  Actually variables of the form
;  %# where # is 1-? get allocated for each new push.  The buffer name
;  and the $curline we are at is saved in the %# variable.

store-procedure push-buffer

	set %arg &cat "%" %stklvl
	set %tmp &cat $cbufname " "
	set %tmp &cat %tmp $curline
	set &ind %arg %tmp

	set %stklvl &add %stklvl 1
	!return
!endm

; Pop back to the buffer/line on the top of the psuedo stack.

store-procedure pop-buffer
	!if &equal %stklvl 0
		write-message "[No more buffers on stack]"
		!return
	!endif
 	set %stklvl &sub %stklvl 1

	set %arg &cat "%" %stklvl
	set %stack &ind %arg 
 	set %tmp &sindex %stack " "
	set %tmp &sub %tmp 1
	set %pop &left %stack %tmp
	set %tmp &add %tmp 1
	set %tmp &sub &len %stack %tmp
	set %col &right %stack %tmp

	set %tmp $cbufname
	!if &not &sequal %pop $cbufname
		!force select-buffer %pop
	!endif

	%col goto-line

	!if &not &sequal %tmp "_tags"
		!if &not &sequal %tmp $cbufname
			delete-buffer %tmp
		!endif
	!endif
	!return
!endm

; Debug stuff.  Dump the psuedo stack to a window.

store-procedure dump-stack

select-buffer "_stack_dump"

set %lvl %stklvl

!while &greater %lvl 0
 	set %lvl &sub %lvl 1

	set %arg &cat "%" %lvl
	set %stack &ind %arg 
 	set %tmp &sindex %stack " "
	set %tmp &sub %tmp 1
	set %pop &left %stack %tmp
	set %tmp &add %tmp 1
	set %tmp &sub &len %stack %tmp
	set %col &right %stack %tmp

	insert-string %arg
	insert-string " "
	insert-string %pop
	insert-string " "
;	insert-string %tmp
;	insert-string " "
	insert-string %col
	newline
	
 !endwhile

!endm

bind-to-key execute-macro-21	M-t
bind-to-key execute-macro-22	^]

; Pop previous tag buffer
25 store-macro
 run pop-buffer
!endm

bind-to-key execute-macro-25 	M-p

set $discmd 1
SHAR_EOF
#	End of shell archive
exit 0
 /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
<  Fred Cassirer                           ...rti!dg.rtp.com!cassirer      >
<  Data General Corporation               Research Triangle Park, NC       >
 \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/