;**  File:       ctags.m           8/24/85              
;**  Writen by:  Yellow Pig XVII
;**
;**  BRIEF macros to do vi-like tag.  Assumes the existence of a file
;**  called "tags" which can be created using the "ctags" utility.  If
;**  this file doesn't exist, tag is simply reported as "Not found."
;**  The format of each line of the tags file must be:
;**
;**  tagword  filename  ?^pattern$?
;**
;**  This is the normal output produced by the Unix utility "ctags".
;**
;**  For those unfamiliar with tagging, it is really useful.  If you
;**  create a tags file for all your C source files you can locate the
;**  file and line where a given function is declared when you're in
;**  the editor, even if that function is declared in a different
;**  source file from the one you are editing.  Tagging will move you
;**  to that line in that file.
;**
;**  To use these BRIEF macros, you can call "tag" directly as a
;**  command.  It will ask you to enter a tag.  Give the name of the
;**  function you are searching for (case sensitivity will depend on
;**  the current setting in your editing session).  Or you can assign
;**  the macro "ctag" to a key.  If you do this, you can place the
;**  cursor anywhere on the name of a function you wish to tag to 
;**  (presumably an occurrence of it where it is being called, but
;**  this is not necessary -- you can tag to a function if you are
;**  already there!!) and hit the key you assigned.
;**


;**  ctag
;**
;**  Checks to make sure cursor is on a valid function name.  A valid
;**  function name is considered to be any string of alphanumeric
;**  characters (including the underscore) which begins with a letter.
;**
;**  If the tag is invalid, the cursor position remains the same.
;**  Otherwise the full word is read and passed to "tag".

(macro ctag
   (
      (string tagstr badchar)
      (int cch row col col2)

      (inq_position row col)
      (if (!= col 1)
         (
            (search_back "[~A-Za-z0-9_]")
            (inq_position NULL col2)
            (if (!= col col2)
               (next_char)
            )
         )
      )

      (if (== 0 (index "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" (= badchar (read 1))))
         (
            (message "Invalid tag: %s" badchar)
            (move_abs row col)
         )
      ;else
			(	
      		(read_word 0 cch tagstr)
            (tag tagstr)
         )
      )
   )
)


;**  tag
;**
;**  Looks in tags file for given tag, gets the filename and search
;**  pattern to use in locating the tag, edits the given file and
;**  searches for the pattern.  If the tag isn't found, reports an
;**  error.  There is no error checking in this macro for a valid
;**  function name (tag).  This macro will most often be used in
;**  conjunction with the "ctag" macro which does this error checking.

(macro tag
   (
      (string tagstr file pattern)
      (int cch buf tagbuf)

      (= buf (inq_buffer))
      (get_parm 0 tagstr "Enter tag: ")
      (message "Tagging: %s ..." tagstr)
      (= tagbuf (create_buffer "tags" "tags" 0))
      (set_buffer tagbuf)
      (move_abs 1 1)
      (if (> (search_fwd (+ "%" tagstr)) 0)
         (
            (search_fwd "[\t ]")
            (search_fwd "[~\t ]")
            (read_word 1 cch file)
            (search_fwd "[\t ]")
            (search_fwd "[~\t ]")
            (= pattern (read))
            (= pattern (+ "%" (substr pattern 3 (- (strlen pattern) 4))))
            (edit_file file)
            (end_of_buffer)
            (search_back pattern)
            (message "")
         )
      ;else
         (
            (message "Tag not found: %s" tagstr)
            (set_buffer buf)
         )
      )
      (if (!= tagbuf buf)
         (delete_buffer tagbuf)
      )
   )
)


;**  read_word <srch_code> <cch> <word>
;**
;**  Reads one alphanumeric word starting at current position.
;**  Returns length of word and the word itself.  Srch_code is
;**  a code that determines what type of "word" to search for.
;**  0 - alphanumeric word
;**  1 - non whitespace word
;**

(macro read_word
   (
      (int cch row col srch_code)
      (string alphanum char word)

      (= alphanum "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")
      (get_parm 0 srch_code)
      (inq_position row col)
      (= cch 0)
      (if (== srch_code 1)
         (while (!(index "\n\t " (= char (read 1))))
            (
               (++ cch)
               (right)
            )
         )
      ;else
         (while (index alphanum (= char (read 1)))
            (   
               (++ cch)
               (right)
            )
         )
      )

      (move_abs row col)
      (= word (read cch))
      (put_parm 1 cch)
      (put_parm 2 word)
   )
)
