Subject: ctags/etags for Perl
From: [email-masked] (ADAM P JENKINS)
Date: 15 Jul 1995 12:50:39 GMT
Newsgroups: comp.lang.perl.announce,comp.lang.perl.misc,comp.lang.perl

Hope this hasn't already been done, but I wrote two small perl
programs that make a tags file for emacs or elvis from a Perl script,
like etags and ctags.  They only make tags for functions, because I'm
not sure what use tagging variables would be since they're not
declared.
	The elvis version can also optionally prepend the package name
to the name of a subroutine, which is useful if you write a file
which contains several packages, each of which have functions with the
same name.
	I'm including both programs below since they are very small.
Please let me know if you have any problems with them.

--

Adam P. Jenkins
[email-masked]

---------------------- perltags for elvis ---------------------------
#!/usr/local/bin/perl
# Makes a tags file suitable for elvis. To make a tags file, just type:
#   perltags <files>
# and it will output a tags file with tags for all of the functions from 
# the files on the commandline.  
# 	Use the '-o <filename>' option to output to different filename
# than 'tags'.
# 	If your perl file contains several packages, each with
# functions that have the same name, you can use the '-p' option.  This
# will cause all of the tags to be prefixed by the package name to which
# they belong.  Then to go to 'Package1::new' you can type at the colon
# prompt:
# 	:tag Package1::new
# and to go to 'Package2::new' type:
# 	:tag Package2::new

require 5.000;
use Getopt::Std;
use File::Basename;

$myname = basename($0);
$Usage = <<EOT;
usage: $myname [-p] <perl files>
Generates a tags file suitable for use with elvis.

  -p         -- Prefix tags with the name of the package they belong to.
  -o <file>  -- Output to <file> instead of 'tags'.
EOT

getopts('po:') or die "$Usage";

die $Usage if ($#ARGV < 0);

$TAGF = $opt_o ? $opt_o : 'tags';
if (grep(/^$TAGF$/, @ARGV) > 0) {	# avoid overwriting an input file
   warn "Skipping inclusion of $TAGF in self.\n";
   @ARGV = grep(!/^$TAGF$/, @ARGV);
   die $Usage if ($#ARGV < 0);
}

open(TAGF, ">$TAGF") or die "Couldn't open tags file,";

while (<>) {
   $line = $_;
   s/\\.//g;   		# get rid of escaped characters
   s/\".*?\"//g;  	# get rid of quotes
   s/\#.*$//;		# get rid of comments
   if ($opt_p) {
      if (/\bpackage\s+([:\w]+)/) {
         $Package = $1 . "::";
      }
   }

   if (/\bsub\s+(\w+)/) {
      $symbol = $1;

      if ($opt_p && $Package) {
         $symbol = $Package . $symbol;
         print TAGF "$symbol\t$ARGV\t$.\n";
      } else {
         chop $line;
         $line =~ s/\//\\$&/g;	# escape slashes
         print TAGF "$symbol\t$ARGV\t/^$line\$/\n";
      }
   } 
   
   if (eof) {
      close ARGV;   # to reset line numbering
      $Package = "";
   }
}
close TAGF;

------------------- perlTAGS for emacs --------------------
#!/usr/local/bin/perl
# Makes a tags file suitable for emacs. To make a tags file, just type:
#   perlTAGS <files>
# and it will output a tags file with tags for all of the functions from 
# the files on the commandline.  
# 	Use the '-o <filename>' option to output to different filename 
# than 'TAGS'.

require 5.000;
use Getopt::Std;
use File::Basename;

$myname = basename($0);
$Usage = <<EOT;
usage: $myname <perl files>
Generates a TAGS file suitable for use with emacs.

  -o <file> -- Output to <file> instead of 'TAGS'.
EOT

$DEL = pack("C", 0177);		# Needed for emacs format tags file.

getopts("o:") or die $Usage;

die $Usage if ($#ARGV < 0);

$TAGF = $opt_o ? $opt_o : 'TAGS';
if (grep(/^$TAGF$/, @ARGV) > 0) {	# avoid overwriting an input file
   warn "Skipping inclusion of $TAGF in self.\n";
   @ARGV = grep(!/^$TAGF$/, @ARGV);
   die $Usage if ($#ARGV < 0);
}

open(TAGF, ">$TAGF") or die "Couldn't open tags file,";

$pos = 0;
while (<>) {
   $line = $_;		# save a copy of line
   s/\\.//g;   		# get rid of escaped characters
   s/\".*?\"//g;  	# get rid of quotes
   s/\#.*$//;		# get rid of comments

   if (/\bsub\s+\w+/) {
     $line =~ m/^.*?\bsub\s+\w+/;
     $tagline = "$&$DEL$.,$pos";
     push @tags, $tagline;
   }
   $pos += length $line;

   if (eof) {
     close ARGV;
     foreach $tag (@tags) {
       $nodelength += length $tag;
     }
     print TAGF "\f\n$ARGV,$nodelength\n";
     foreach $tag (@tags) {
       print TAGF "$tag\n";
     }
     $pos = 0;
     $nodelength = 0;
     @tags = ();
   }
}
close TAGF;