[gnu.emacs.bug] Convert etags output to ctags output

roland@AI.MIT.EDU (Roland McGrath) (08/17/89)

Here is etags2ctags.el.  It converts Emacs TAGS files generated by etags to
what look like ex/vi tags files generated by ctags.

I'm not sure how useful this is, but I while ago I decided it was for some
reason and put it on my list.  I had initially thought of doing it in C; but it
occurred to me that it would be much easier to do in Emacs lisp, and I was
surprised at how little code it took.

Enjoy!

;;; Convert Emacs TAGS files (the output of the `etags' program)
;;; to ex/vi tags files (like the output of the `ctags' program).
;;;
;;; Copyright (C) 1989 Roland McGrath
;;;
;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 1, or (at your option)
;;; any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; A copy of the GNU General Public License can be obtained from this
;;; program's author (send electronic mail to kyle@cs.odu.edu) or from
;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
;;; 02139, USA.
;;;
;;; Send bug reports to roland@ai.mit.edu.

;; To use this, byte-compile this file, and then put the following line
;; in your .emacs (or site-init.el, etc.):
;;  (autoload 'etags2ctags-buffer "etags2ctags" "Convert a TAGS buffer." t)
;;  (autoload 'etags2ctags-file "etags2ctags" "Convert a TAGS file." t)


(defmacro match-text (arg)
  "Return the string of text matched by the last regexp searched for.
ARG, a number, specifies which parenthesized expression in the last regexp.
The value is nil if ARGth pair didn't match, or there were less than ARG pairs.
Zero means the entire text matched by the whole regexp."
  (` (buffer-substring (match-beginning (, arg)) (match-end (, arg)))))

(defun etags2ctags-buffer (&optional buffer)
  "Convert output from `etags' in BUFFER to what looks like output from `ctags'.
If BUFFER is nil or missing, the current buffer is used."
  (interactive "bConvert buffer: ")
  (save-excursion
    (if buffer
	(set-buffer buffer))
    (goto-char (point-min))
    ;; We will write output into the temporary buffer
    ;; and then move it to BUFFER all at once.
    (let ((standard-output (generate-new-buffer " *etags2ctags*")))
      (while (not (eobp))
	(or (looking-at "\f\n")
	    (error "Invalid tags file format"))
	(forward-line 1)
	(let ((file (buffer-substring (point)
				      (progn (search-forward ",")
					     (1- (point)))))
	      (end (let ((len (string-to-int
			       (buffer-substring (point)
						 (progn (forward-line 1)
							(point))))))
		     (+ (point) len))))
	  (while
	      ;; This monster regexp matches an etags tag line.
	      ;;   \1 is the string to match;
	      ;;   \2 is not interesting;
	      ;;   \3 is the symbol;
	      ;;   \4 is the char to start searching at;
	      ;;   \5 is the line to start searching at.
	      (re-search-forward
	       "^\\(\\(.+[ \t]+\\)?\\([-a-zA-Z0-9_$]+\\)[^-a-zA-Z0-9_$]*\\)\^?\\([0-9]+\\),\\([0-9]+\\)\n"
		  end t)
	    ;; Turn the matched etags tag line into the ctags tag line:
	    ;;   FILE	SYMBOL	/^STRING/
	    ;; The string is regexp-quoted.
	    (princ (regexp-quote (match-text 3)))
	    (princ "\t")
	    (princ file)
	    (princ "\t/^")
	    (princ (regexp-quote (match-text 1)))
	    (princ "/")
	    (terpri)
	    )))
      ;; Sort the temporary buffer.
      (save-excursion
	(set-buffer standard-output)
	(sort-lines nil (point-min) (point-max)))
      ;; Replace the contents of BUFFER with those of the temporary buffer.
      (undo-boundary)
      (erase-buffer)
      (insert-buffer standard-output)
      (kill-buffer standard-output)
      )))

(defun etags2ctags-file (from to)
  "Convert the Emacs TAGS file in FROM to a ex/vi tags file in TO.
See  etags2ctags-buffer ."
  (interactive "fConvert Emacs TAGS file: \nFConvert %s to ex/vi tags file: ")
  (let ((buf (generate-new-buffer " *etags2ctags*")))
    (save-excursion
      (set-buffer buf)
      (insert-file from)
      (etags2ctags-buffer buf)
      (write-file to)
      (kill-buffer buf)
      )))